Getting the definition of a CLR Stored Procedure - sql-server

I wrote a CLR stored procedure (to send emails, and not depend from DatabaseMail, as I was told it was more safer).
It works as expected. The thing I want to learn now is how to get the definition from a CLR object (CLR SP, CLR scalar function, etc).
I already tried with:
sys.sql_modules,
sys.system_sql_modules,
OBJECT_DEFINITION()
But it returns a null definition.
Is there any other way to get the definition of a CLR object?

SQLCLR objects have no T-SQL code so there is nothing to store that could be retrieved using the sys.* _sql_modules DMVs or the OBJECT_DEFINITION() built-in function.
If you want the underlying .NET code, that is in the Assembly, which is found in: sys.assembly_files.
SELECT *
FROM sys.assembly_files
WHERE [file_id] = 1;
If you don't have the source code, that can be extracted by disassembling the Assembly.
If you want the CREATE PROCEDURE ... AS EXTERNAL NAME ... ; statement then that would need to be pieced together from several DMVs: sys.assembly_modules, sys.types, sys.parameters, sys.columns. You would also need to use OBJECT_NAME and OBJECT_SCHEMA_NAME built-in functions. If you are trying to recreate a CREATE TYPE statement, then you will need to check the sys.assembly_types DMV.
Also, to learn more about working with SQLCLR in general, please see the series of articles I am writing on this topic on SQL Server Central: Stairway to SQLCLR (free registration is required to read their content).

Related

SQL Server SQLCLR function receives parameter error after copying from one DB to another

I am trying to copy the send email assembly from one database to another. I clicked on script assembly as create to and created it in the new db.
When I try to send an email with the function in the newer db I get the following error:
The parameter 'fileName' cannot be an empty string. Parameter name: fileName
How can I copy the assembly across databases?
Some details:
Both DBs are on the same instance
Both DBs are owned by the same login
Using SQL Server 2016
Assembly is marked as UNSAFE in both DBs
Both DBs have TRUSTWORTHY enabled
T-SQL wrapper object is a scalar function / UDF
Function is being called the same way in both DBs
How can I copy the assembly across databases?
So far I am not seeing how this is a SQLCLR issue. You clearly copied the Assembly and the T-SQL wrapper object else you would be getting T-SQL errors instead of a .NET error.
I clicked on script assembly as create to and created it in the new db.
Given that you scripted out the T-SQL wrapper object and you are getting an error related to an input parameter, you might be running into a bug that causes defaults for NVARCHAR parameters to not script out correctly:
SSMS scripting CLR stored procedure NVARCHAR parameter NULL default as N'' (empty string)
Execute the following in both old and new DBs to make sure that all parameter definitions are the same, including any potential default values (paying close attention to rows that have a 1 for [has_default_value]):
SELECT [name], [user_type_id], [max_length], [is_output],
[has_default_value], [default_value]
FROM sys.parameters prm
WHERE prm.[object_id] = OBJECT_ID(N'dbo.ObjectName')
ORDER BY prm.[parameter_id];
If you find any differences, you will need to update your CREATE statement to include the correct default value(s). For example, if you have:
#SomeParam [nvarchar](1 - 4000) = N``
Then you will need to update that part of your T-SQL script to instead be:
#SomeParam [nvarchar](1 - 4000) = NULL
And then re-run the CREATE (you might need to either first DROP the existing T-SQL wrapper object, or change the CREATE to be ALTER).
Please vote for that Feedback bug report that I linked above. Thanks!
For more info on working with SQLCLR in general, please visit: SQLCLR Info

How to retrieve full definition of external func/proc?

I'd like to write a procedure to build the sql code to define all func/procs in given assembly.
It is simple for procedures and scalar functions -
iterating sys.assemblies/modules/objects/parameters I can prepare code for create func/proc.
But I cannot find where the definition of the table returned by the tv function is stored. Scripting of the functions like that is possible, so - the definition of the table have to be written somwhere..
By the way - second question: is there some tool to create sql definition of func/proc basing on C# code ?
Just like Tables, Table-Valued Functions (Inline, SQL MultiStatement, and SQLCLR), and Views are maintained in the sys.columns system catalog view (and sys.all_columns).
SELECT obj.[name], obj.[type_desc], col.[name]
FROM sys.objects obj
INNER JOIN sys.columns col
ON col.[object_id] = obj.[object_id]
ORDER BY obj.[type_desc], obj.[name], col.[name];
You will need to join to sys.types to get the full datatype name.
However, there is very little point to scripting things out as you are doing since:
If the T-SQL wrapper objects (for the SQLCLR methods within the Assembly) were created by a script you wrote, then you already have those CREATE statements, and
If the T-SQL wrapper objects were created by SSDT (with or without Visual Studio), then you already have the "create" script (if you opted to have it get generated upon each build) and the incremental "publish" script.
In either case, those objects were created from a T-SQL script that you should already have. Unless, I suppose, you were handed a Database that had the objects and the deployment scripts aren't available for some reason.
Is there some tool to create T-SQL definition of func/proc based on C# code ?
From the database or the DLL / Assembly? There are some tools that can be used to script any type of object out of the database. You can also use the .NET SMO classes to script out the definitions from the database. If you want to scan the DLL / Assembly, you would need to use the .NET Reflection classes to iterate over each method and look at the SqlFunction, SqlProcedure, SqlFacet attributes / decorators.

How to list all jobs which operate with specified database object?

Is there a way to list in Sql Server all the jobs which operate on a mentioned Sql Server object, for example a certain table (directly or indirectly through a stored procedure for example)?
An example: I am interested in a certain table or view, so if there is a job which invokes (in any step) a procedure, which in its turn does any operation on that table/view (like insert or select or update etc), I'd like to see it listed.
Side note: sp_depends seems to list only the procedures and functions, but not the jobs.
There is no built-in way to find indirect dependencies. You can check which jobs directly call a certain stored procedure, but no way to see which tables or other objects get used by that stored procedure unless you check the direct dependencies of that stored procedure.
So if you are looking for a specific table, you can find objects that reference it directly, but not objects that reference THOSE objects (indirect dependency).
You would either have to write your own script or search around and see if someone else has written one.

SQL Server doesn't find my function

I use SQL Server 2008 with Borland Delphi in order to develop my applications. Since recently I'm getting a very weird error. I have created several scalar functions that I use in my application, but I'm having a problem with a customer, in his company my software returns the following error when I call my scalar functions:
Cannot find either column “dbo” or the user-defined function or aggregate “dbo.FunctionName”, or the name is ambiguous."
I've already searched a lot, even here, so keep in mind that:
The function exists;
I'm quering the correct database;
There's no typos;
Owner schema is dbo;
This problem occurs with ALL MY FUNCTIONS;
And the weirdest...
It only happens when I call them from my application, if i run the EXACTLY SAME code at the Query Analyzer using the same user, it will run just fine.
I have this same functions in several other customers, and they don't have any problem. Could it be a SQL Server problem?
Ps: Sorry for my poor English, first question here.
I don't know how QueryAnalyzer calls your functions, but I know this error.
Usually, when you have user-defined functions, you need to prefix the function with the schema name.
So if your function is in schema "dbo", and the name is "fnPadLeft", you need to call the function in code like this:
SELECT
id
,some_field
,dbo.fnPadLeft(some_other_field)
FROM YOUR_TABLE_NAME
If you call it like this:
SELECT
id
,some_field
,fnPadLeft(some_other_field) -- lacks dbo.
FROM YOUR_TABLE_NAME
Then you'll get "no such function".
This only happens to scalar functions btw. (you specifically mentioned this), table-valued functions (and all other non-function things) are not affected by this "feature".
It might also be that you have the same functionname in two schemas (also take a look at the functions in the master database). Maybe your "other functions" are table valued functions.

What is a SQL Server module?

I just came across the system view sys.sql_modules today. What is a module versus a DB object? The view returns, most prominently, a column containing the definition text, as returned by sys.syscomments.
A module, in SQL-Server-speak is a stand-alone object that contains sql batches, such as a view, table valued function, stored procedure, trigger or scalar function. A SQL object is a more all-encompassing term that includes some that contain SQL Expressions, such as check or default constraints. A module used to be referred to as a 'routine' before SQL Server 2005, but I think the two terms are used interchangeably.
The table build script is not stored in SQL Server because of the ease with which components of a table can be altered separately. Therefore it is treated as an object but not a module.
Typical objects that aren't also considered to be modules are system tables, default constraints, foreign key constraints, service queues, check constraints, user tables, primary key constraints, internal tables and unique constraints.
Columns aren't considered to be objects. Neither are indexes.
Yes, it is all more complex than one might first think.
It's the blocks of T-SQL statements that make up a stored procedure, a stored function, a trigger or a view definition.
From "Books Online" in the "CREATE PROCEDURE" section:
Getting Information About Stored
Procedures To display the definition
of a Transact-SQL stored procedure,
use the sys.sql_modules catalog view
in the database in which the procedure
exists.
In sys.sql_modules, you'll find the actual T-SQL code.
Marc
A modules are functions, procedures, queues, and triggers. These Modules call Objects. That's what I understood from this article which describes "EXECUTE AS":
EXECUTE AS
I came across to this question when I wanted to get detailed explanation of EXECUTE command. I wanted to have deep understanding how to read t-sql help of command and realized that I haven't known what module means.
I just want to add these these to the list of sql modules:
system stored procedure,
user-defined stored procedure,
CLR stored procedure,
scalar-valued user-defined function,
or extended stored procedure.
Executes a command string or character string within a Transact-SQL batch, or one of the following modules: system stored procedure, user-defined stored procedure, CLR stored procedure, scalar-valued user-defined function, or extended stored procedure. The EXECUTE statement can be used to send pass-through commands to linked servers. Additionally, the context in which a string or command is executed can be explicitly set. Metadata for the result set can be defined by using the WITH RESULT SETS options.
https://learn.microsoft.com/en-us/sql/t-sql/language-elements/execute-transact-sql?view=sql-server-2017

Resources