Create Assembly is successful, nothing found in sys.assembly_modules - sql-server

First attempt at a CLR Integration, so I can use Regex tools.
I create the assembly:
CREATE ASSEMBLY SQLRegexTools
FROM 'D:\CODE\SQLRegexTools\SQLRegexTools\bin\Release\SQLRegexTools.dll'
This succeeds, and the assembly appears in SELECT # FROM sys.assemblies.
But there are no records returned to SELECT * FROM sys.Assembly_modules.
And when I try to CREATE FUNCTION to call one of the methods,
CREATE FUNCTION RegExMatch(#pattern varchar(max)
, #SearchIn varchar(max)
, #options int)
RETURNS varchar
EXTERNAL NAME SQLRegexTools.Functions.RegExMatch
I get an error 'Msg 6505, Could not find Type "Functions" in assembly 'SQLRegexTools.'
The class name of the VB module is "Functions". Why is this called a type in the error, and why might I not be seeing anything in the modules?

This error occurs when SQL Server is unable to resolve the name as provided. Try the snippet below to see if this resolves the issue.
CREATE FUNCTION RegExMatch(#pattern varchar(max)
, #SearchIn varchar(max)
, #options int)
RETURNS varchar
AS EXTERNAL NAME SQLRegexTools.[Functions].RegExMatch
The resolution of individual functions/methods for accessing native code is relatively indistinguishable from a multipart object name (e.g. a type).
An additional note is that native code that utilizing nested namespaces must fully qualify nested namespaces within the same pair of quotes. For example, if RegExMatch were located at SQLRegexTools.A.B.C.RegExMatch, you would reference this as SQLRegexTools.[A.B.C].RegExMatch when using it with EXTERNAL NAME in SQL Server.

That hits the answer Joey. Thank you.
There are several gotchas in this process I learned after much sleuthing and testing. They are often buried in long posts about the entire process, I will summarize here:
As Joey explained, the fully qualified name is needed. To be more complete...
Example:
1 2 3 4
[SQLRegexToolsASM].[SQLRegexToolsNS.RegexFunctionsClass].RegExMatch
This is the assembly name in the CREATE ASSEMBLY step.
This is the Root Namespace from the properties of the assembly project. If you declared a namespace or two, they must be included in their proper order, after this item and before item 3 in this list. Observe all these namespaces are enclosed in their own square brackets.
assembly.[rootnamespace.namespace.namespace].classname.methodname”
This is the Class Name you assigned to the class, maybe like this
Public Class RegexFunctionsClass
The name of the method defined in your VB or C# assembly.

Related

checking structure of GLobally defined Varray or nested table in PL/SQL

I am modifying a package. In one of the procedure I got below line.
query_det_arr ecc_query_det_arr_type := ecc_query_det_arr_type(NULL);
this ecc_query_det_arr_type is not defined anywhere inside the package. as per my understanding this must be varray or nested table.
They may have created using separate create command.
Is there anyway to check what ecc_query_det_arr_type contains? I mean any query or anyway in sql developer?
One way to do that is desc <your_type> like below:
desc ecc_query_det_arr_type;
A side note: Since you are taking a guess here, I thought of writing. It is always better to follow a naming convention for Oracle Objects. In your case I would have created that type like below:
ecc_query_det_ntt if it is nested table type
ecc_query_det_aat if it is associative array type
ecc_query_det_vat if it is varray type
Ok, here is another way:
select * from user_source where type = 'TYPE' and lower(name) = 'ecc_query_det_arr_type';

How do I use With XMLNamespaces to create custom name spaces in SQL?

I want to be able to produce the following namesspaces and types for an XML root element
<BaseTransactionRequest xmlns="http://schemas.datacontract.org/2004/07/SomeCompany" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" i:type="AType">
Typically the first 2 (that is, not including i:type="AType") can be produced without issue (with some tradeoffs, when using custom namespaces we cant represent nulls using the xmlns:ni namespace etc)
So, the latter type is problematic. For a referesher,
the WITH XMLNAMESPACES fearure is used like below (FOR XML part omitted):
;WITH XMLNAMESPACES ('http://www.w3.org/2001/XMLSchema-instance' as i, DEFAULT 'http://schemas.datacontract.org/2004/07/SomeCompany',
A solution to overcome was to write XML "literally" using string concatenation. But I believe and hope FOR XML and this can be used together.
EDIT: First cut was added in a real rush. Apologies.
EDIT2: Dyslexic fix
Your question is not very clear... You might have a misconception about your i:type="AType". This is not a namespace (whatever a custom namespace is), but a normal attribute, named type living in your namespace i, which is declared at xmlns:i="blah".
Try this
WITH XMLNAMESPACES ('http://www.w3.org/2001/XMLSchema-instance' as i
,DEFAULT 'http://schemas.datacontract.org/2004/07/SomeCompany')
SELECT 'AType' AS [#i:type]
FOR XML PATH('BaseTransactionRequest');
The result is a self closing tag, declaring two namespaces and containing your attribute:
<BaseTransactionRequest xmlns="http://schemas.datacontract.org/2004/07/SomeCompany"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
i:type="AType" />

Specify and use multiple libraries in ODBC connection string

My odbc connection string for connecting to DB2i looks like this:
Driver={Client Access ODBC Driver (32-bit)};system=xx.xx.xx.xx;dbq=LIB1 LIB2 LIB3 LIB4 LIB5 LIB6 LIB7 LIB8;languageid=ENU;qrystglmt=-1;cmt=0;signon=1
The above connection string specifies multiple libraries/schemas for use. But when I try to access a file/table from a library other than the first one (like from LIB2...LIB8) I get a exception saying "FILE xx not found in LIB1"
Why does not it automatically search for the file/table in other specified libraries, it searches for the file in the first library only?
I need a workaround for this situation.
Use "system naming" mode, by adding naming=1 to your connection string.
In your library list, place a comma before the first library.
Driver={Client Access ODBC Driver (32-bit)};system=systemname;naming=1;
dbq=,LIB1,LIB2,LIB3,LIB4,LIB5,LIB6,LIB7,LIB8;languageid=ENU;cmt=0;signon=1
This works as documented in the manual:
The library list is used for resolving unqualified stored procedure calls and finding libraries in catalog API calls. ...
Note:
The first library listed in this property will also be the default library, which is used to resolve unqualified names in SQL statements.
As stated above, Schema/library list is used to resolve functions/procedure names, not tables.
Let assume you need to read data from lib1.tab1 and lib2.tab2;
Here my personal workarounds (from easy to complex):
a) ask the db admin to have - for each table you need to use - the corresponding schema name, then do "select * from lib1.tab1 join lib2.tab2 on [...]" ;-)
b) ask the db admin to create on schema "MyAlias" several alias (create alias) for each table you want to use. Then do "set current schema=MyAlias" followed by all the SQL statement you need e.g. "select * from tab1 join tab2". Since you’re querying myalias.tab1 which is an alias pointing to table lib1.tab1 it should work.
c) Complex: create your own SQL function that returns the corresponding schema_name for a table (e.g. myfunct('TAB1'). This could be done reading system view “qsys2.systables” where table_name=’TAB1’ and returning TABLE_SCHEMA column, which is a varchar(128). Once you got it, build up a dynamically prepared using the variable you just obtained. E.g.
"set mylib = myfunct('TAB1').
"set mystmt = 'select * from '||table_schema || ‘.tab1’ …”
Prepare mystmt and then execute mystmt.
I did something similar in VBA using ado ibmdrda and it worked.
hope this helps.
f.

SQL CLR Integration - Define Function Parameter Type

I'm working on converting a rather complex .NET WinForms program into a fully-integrated SQL Server set of sprocs and functions.
I'm working on a 3rd party database over which I have no control at all.
The unique identifiers used throughout this database are all numeric(21). It doesn't matter if that's a good idea or not... I have to work within that constraint.
I'm having trouble figuring out how to code functions that use these values. So far, I'm using System.Decimal to do so, which appears to work fine when the code is called from within the .dll itself.
In SSMS, however, when I inspect any of the functions, the input parameter data type is numeric(18,0). I'm assuming it is assuming that based on the System.Decimal type, but that's wrong. And the end result is that when I try to call the function manually (in SSMS), I get the following error:
Arithmetic overflow error converting numeric to data type numeric.
The weird thing is that the calls DON'T fail when I call the functions from within the .dll. How can I override the numeric(18,0) designation?
Man, I hate it when further googling finds the answer like 30 seconds after I post a question!!!
I swear, I've been looking at this for days...
Anyway, I needed to add a SqlFacet to my input parameter.
I went from this:
<Microsoft.SqlServer.Server.SqlProcedure()>
Public Shared Sub Check(ByVal ID As Decimal)
To this:
<Microsoft.SqlServer.Server.SqlProcedure()> _
Public Shared Sub Check(<SqlFacet(Precision:=21, Scale:=0)> ByVal ID As Decimal)

Is there any C SQLite API for quoting/escaping the name of a table?

It's impossible to sqlite3_bind_text a table name because sqlite3_prepare_v2 fails to prepare a statement such as:
SELECT * FROM ? ;
I presume the table name is needed to parse the statement, so the quoting needs to have happened before sqlite3_prepare_v2.
Is there something like a sqlite3_quote_tablename? Maybe it already exists under a name I can't recognize, but I can't find anything in the functions list.
SQLite will escape identifiers for you with the %w format in the https://www.sqlite.org/printf.html family of functions.
your proposed sqlite3_quote_tablename function could sanitize the input to prevent sql injection attacks. To do this it could parse the input to make sure it is a string literal. http://sqlite.org/lang_expr.html#litvalue
If a table name has invalid characters in it you can enclose the table name in double quotes, like this.
sqlite> create table "test table" (id);
sqlite> insert into "test table" values (1);
sqlite> select * from "test table";
id
----------
1
Of course you should avoid using invalid characters whenever possible. It complicates development and is almost always unnecessary (IMO the only time it is necessary is when you inherit a project that is already done this way and it's too big to change).
When using SQLite prepared statements with parameters the parameter: "specifies a placeholder in the expression for a literal value that is filled in at runtime"
Before executing any SQL statement, SQLite "compiles" the SQL string into a series of opcodes that are executed by an internal Virtual Machine. The table names and column names upon which the SQL statement operates are a necessary part of the compilation process.
You can use parameters to bind "values" to prepared statements like this:
SELECT * FROM FOO WHERE name=?;
And then call sqlite3_bind_text() to bind the string gavinbeatty to the already compiled statement. However, this architecture means that you cannot use parameters like this:
SELECT * FROM ? WHERE name=?; // Can't bind table name as a parameter
SELECT * FROM FOO WHERE ?=10; // Can't bind column name as a parameter
If SQLite doesn't accept table names as parameters, I don't think there is a solution for your problem...
Take into account that:
Parameters that are not assigned values using sqlite3_bind() are treated as NULL.
so in the case of your query, the table name would be NULL which of course is invalid.
I was looking for something like this too and couldn't find it either. In my case, the expected table names were always among a fixed set of tables (so those were easy to validate). The field names on the other hand weren't so I ended up filtering the string, pretty much removing everything that was not a letter, number, or underscore (I knew my fields would fit this parameters). That did the trick.

Resources