Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it safe to change static readonly variables in C# SQLCLR?

I wrote some code in C# 6.0 .NET 3.5 CLR assembly with safety level = external_access.

Reduced code:

 public static readonly DataTable warnings_table = init_warnings_table();

 public static void set_warning(string msg)
 {
        var row = warnings_table.NewRow();
        row[1] = DateTime.Now;
        row[2] = msg;
                ...
        warnings_table.Rows.Add(row);
 }
 [Microsoft.SqlServer.Server.SqlProcedure]
 public static SqlInt32 wrapper_func(SqlInt32 param)
 { 
   return big_func(Param.Value);
 }

 int big_func(int param)
 { 
   SqlBulkCopy bulkcopy;
   ....
   set_warning("Message");
   ....
   write_warnings(bulkcopy); 
   warnings_table.Clear();
 }

What will be happen with warnings_table if wrapper_func will be called from 2 or more different connections / sessions simultaneously? There are write operations to static field warnings_table. So, I suppose, but am not sure, it will lead to data race-condition here.

In other words:

  1. Are static read-only variables in SQLCLR unique for every sql connection/sql query/transactions or do they share data between different SQLCLR procedures calls?

  2. Is it possible to have painless global state, safe from other SQLCLR procedures calls?

like image 516
R. S. Avatar asked Dec 09 '16 14:12

R. S.


People also ask

Are readonly variables static?

The keyword readonly has a value that may be changed or assigned at runtime, but only through the non-static constructor. There isn't even a method or static method.

Can readonly be modified?

A read-only input field cannot be modified (however, a user can tab to it, highlight it, and copy the text from it). The readonly attribute can be set to keep a user from changing the value until some other conditions have been met (like selecting a checkbox, etc.).

What is difference between static and readonly?

Static members can only be accessed within the static methods. The non-static methods cannot access static members. Readonly fields can be initialized at declaration or in the constructor. Therefore, readonly variables are used for the run-time constants.

What is difference between static constant and readonly variables?

Difference between const and readonlyconst variables can declared in methods ,while readonly fields cannot be declared in methods. const fields cannot be used with static modifier, while readonly fields can be used with static modifier.


1 Answers

Are static read-only variables in SQLCLR unique for every sql connection/sql query/transactions or do they share data between different SQLCLR procedures calls?

An Assembly residing inside of SQL Server (i.e. SQLCLR) gets loaded into a single App Domain which is shared across all sessions. There can be multiple App Domains since they are specific to each Database and owner (i.e. Authorization) combination. But any one particular SQLCLR object will only reside in one particular Assembly, so all calls to it do share that single instance. This is why all SQLCLR methods need to be static, since they are not per-Session. So yes, static member/class variables are shared, which is why they need to be declared as readonly, else the Assembly needs to have a PERMISSION_SET of UNSAFE if a static class variable is not marked as readonly.

Is it possible to have painless global state, safe from other SQLCLR procedures calls?

No, at least not in any simple, built-in fashion. A static class variable that is a Collection can be thought of as a real table created in tempdb (not the same as a Global Temporary Table -- ##Table). Once the variable is created it will remain and won't disappear once the "session" that created it ends, but it is accessible to all sessions. So if you need to have per-Session separation, then you need to have a property of the static collection be a differentiator -- something to tell each session apart. And you could possibly get the current session_id / @@SPID and use that, as long as you clear out all entries having that same session_id at the beginning of each process since session_id values are re-used by SQL Server. But there is no way to clean up entries for session_id values that are not re-used, unless you do that as a final step at the end of the process (a step that might not be called if the process runs into an exception). So, not impossible, but will take a little but of work and a lot of testing :-).

It should also be understood that this is not specific to SQLCLR Stored Procedures, but affects all methods and objects running in a particular App Domain. Meaning, static class variables are shared with all code that can access the class, which can be SQLCLR Triggers, Functions, and probably also User-Defined Aggregates and User-Defined Types.

PLEASE NOTE, one nuance that you need to be aware of with regards to static variables and how SQL Server manages memory is:

Occasionally SQL Server, if it is running out of physical memory, may decide to unload one or more App Domains. You can see this behavior in the SQL Server error log by searching for "memory pressure" since there will be entries in the form of:

AppDomain X ({database_name}.{owner_name}[runtime].Y) is marked for unload due to memory pressure.

Unloading the App Domain will clear out the static variables. When it gets reloaded upon the next call to the SQLCLR object, the static variables will be created again.

SO, if the static variable is being used to maintain state between calls that is necessary for "proper" operation, then you need to find another way as that data cannot be guaranteed to exist between calls.

If you need per-Session global state, then you need to use SQL Servers built-in mechanisms by executing T-SQL statements using Context Connection = true; as the Connection String. You can use:

  • local temporary table
  • SET CONTEXT_INFO / CONTEXT_INFO()
  • (as of SQL Server 2016) sp_set_session_context / SESSION_CONTEXT

For more information on working with SQLCLR in general, please see the series I am writing on this topic on SQL Server Central (free registration is required):

Stairway to SQLCLR

like image 129
Solomon Rutzky Avatar answered Oct 25 '22 12:10

Solomon Rutzky