是否有任何多线程缓存机制可以在SQL CLR函数中工作,而不需要将程序集注册为"不安全"?
由于还介绍在这个职位,只需使用一个lock语句将抛出一个安全组件的异常:
System.Security.HostProtectionException:
Attempted to perform an operation that was forbidden by the CLR host.
The protected resources (only available with full trust) were: All
The demanded resources were: Synchronization, ExternalThreading
Run Code Online (Sandbox Code Playgroud)
我希望对我的函数的任何调用都以线程安全的方式使用相同的内部缓存,以便许多操作可以同时执行缓存读取和写入.基本上 - 我需要一个ConcurrentDictionary可以在SQLCLR"安全"程序集中工作的程序.不幸的是,使用ConcurrentDictionary它本身会产生与上面相同的例外.
是否有内置的SQLCLR或SQL Server来处理这个问题?或者我误解了SQLCLR的线程模型?
我已经阅读了关于SQLCLR的安全限制的内容.特别是,以下文章可能有助于理解我在说什么:
此代码最终将成为分发给其他人的库的一部分,因此我真的不希望将其作为"不安全"运行.
我正在考虑的一个选项(由Spender在下面的评论中提出)是从SQLCLR代码中扩展到tempdb并将其用作缓存. 但我不太清楚到底该怎么做.我也不确定它是否会像内存缓存一样高效. 请参阅下面的更新
我对可能提供的任何其他替代方案感兴趣.谢谢.
例
下面的代码使用静态并发字典作为缓存,并通过SQL CLR用户定义的函数访问该缓存.对函数的所有调用都将使用相同的缓存.但除非装配被注册为"不安全",否则这将无效.
public class UserDefinedFunctions
{
private static readonly ConcurrentDictionary<string,string> Cache =
new ConcurrentDictionary<string, string>();
[SqlFunction]
public static SqlString GetFromCache(string key)
{
string value; …Run Code Online (Sandbox Code Playgroud) MSDN对这篇文章说:
CLR使用.NET Framework中的代码访问安全性(CAS),不再支持它作为安全边界.使用PERMISSION_SET = SAFE创建的CLR程序集可能能够访问外部系统资源,调用非托管代码以及获取sysadmin权限.从SQL Server 2017开始,引入了名为clr strict security的sp_configure选项,以增强CLR程序集的安全性.默认情况下启用clr严格安全性,并将SAFE和EXTERNAL_ACCESS程序集视为标记为UNSAFE.可以禁用clr strict security选项以实现向后兼容性,但不建议这样做.Microsoft建议所有程序集都由证书或非对称密钥签名,并且相应的登录名已在master数据库中被授予UNSAFE ASSEMBLY权限.
如何创建CLR程序集PERMISSION_SET = SAFE可以访问外部系统资源,调用非托管代码以及获取sysadmin权限?
为什么不再支持CAS作为安全边界?
据我所知,CLR组件不再安全,这是非常不幸的.
我正在移植一个旧的3 2-bit COM组件,它是VB6为了读写Active Directory服务器而编写的.新解决方案将在C#并将使用SQL CLR用户功能.
我尝试部署的程序集SQL Server包含对它的引用System.DirectoryServices.该项目确实编译没有任何错误,但SQL Server由于以下错误,我无法将程序集部署到该程序集:
Error: Assembly 'system.directoryservices, version=2.0.0.0, culture=neutral, publickeytoken=b03f5f7f11d50a3a.' was not found in the SQL catalog.
System.DirectoryServices在SQL Server上注册的正确步骤是什么?
.net directoryservices sqlclr active-directory sql-server-2008
我需要在Sql中运行.Net代码,我试图在F#和C#之间做出决定.我现在在F#中做的代码越来越多,所以如果它不是太不切实际,我希望它是F#.
是否有可能强制VS2010将我的F#程序集(及其引用)部署到Sql Server,这与C#项目的做法相同?
你会建议/不建议在Sql中运行F#吗?为什么?
编辑: 我同意语言更好,这不是问题.我主要想知道是否有人在SqlClr中使用F#的经验,特别是如果工具可以提供简单的开发工作流程,即在VS2010中部署.
编辑2:
我正在尝试这个,手动注册是非常痛苦的.此外,CREATE ASSEMBLY你必须注册每个函数,sp,聚合等.你还必须先按正确的顺序删除它们,如果它们存在,以免你得到一个DROP ASSEMBLY failed because 'Nibbler' is referenced by object 'Hello'.
然后,我有了使用C#项目作为前端的想法,让这个项目引用一个F#项目,只是为了让所有这些部署自动处理.事实证明,您只能引用其他C#/ VB Sql Clr项目或已在Sql中引用的程序集.这仍然可以简化部署,因为所有功能的创建/删除等都将自动处理.然后,为了从测试部署到生产,我只会从我的测试环境中注册的所有内容生成脚本.
PS.我还尝试摆弄.fsproj文件,与C#Clr项目的.csproj进行区分,以使部署无济于事.
我们有几个本地dbs,我们看到我们是否可以将它们迁移到SQL Azure.其中一些dbs在程序集(SAFE)中用C#编写了几个用户定义的函数.在搜索之后,我发现了几个相互矛盾的帖子.有人说v12支持CLR代码.其他人则表示没有.所以,这是我的问题:
多谢你们!
路易斯
sql-server sqlclr azure azure-sql-database azure-sql-managed-instance
SQLServer CLR比T-SQL有什么优势?使用.NET语法比T-SQL更容易吗?我看到你可以定义用户类型,但我不清楚为什么那样更好.例如,您可以定义电子邮件类型,它将具有前缀属性和域属性.然后,您可以搜索域或前缀或两者.但是,我没有看到与添加一个名为prefix的列和一个名为domain并且单独搜索它们的列有什么不同.也许有人有现实世界的理由为什么这会更好.
情况就是这样:
我有一个Trigger.dll和一个Trigger.XmlSerializer.dll.
我使用CREATE ASSEMBLY在MSSQL中注册它们.
现在,我已经编译了两者的新版本.
我想使用ALTER ASSEMBLY来更新它们,但是你一次只能更新一个.如果您尝试更新具有依赖关系的那个,它会抱怨.这样做的诀窍是什么?
我不想丢弃并重新创建,因为我必须删除所有触发器等,并且有数据库停机时间.
我有一个很大的nvarchar我希望传递给HashBytes函数.我收到错误:
"字符串或二进制文件将被截断.无法将值NULL插入列'colname',tbale'table';列不允许空值.UPDATE失败.语句已终止."
由于资源丰富,我发现这是由于HashBytes函数的最大限制为8000字节.进一步搜索向我展示了一个"解决方案",我的大型varchar将被分开并单独进行散列,然后再与此用户定义的函数结合使用:
function [dbo].[udfLargeHashTable] (@algorithm nvarchar(4), @InputDataString varchar(MAX))
RETURNS varbinary(MAX)
AS
BEGIN
DECLARE
@Index int,
@InputDataLength int,
@ReturnSum varbinary(max),
@InputData varbinary(max)
SET @ReturnSum = 0
SET @Index = 1
SET @InputData = convert(binary,@InputDataString)
SET @InputDataLength = DATALENGTH(@InputData)
WHILE @Index <= @InputDataLength
BEGIN
SET @ReturnSum = @ReturnSum + HASHBYTES(@algorithm, SUBSTRING(@InputData, @Index, 8000))
SET @Index = @Index + 8000
END
RETURN @ReturnSum
END
Run Code Online (Sandbox Code Playgroud)
我打电话给:
set @ReportDefinitionHash=convert(int,dbo.[udfLargeHashTable]('SHA1',@ReportDefinitionForLookup))
Run Code Online (Sandbox Code Playgroud)
其中@ReportDefinitionHash是int,而@ReportDefinitionForLookup是varchar
传递像'test'这样的简单char会产生与我的UDF不同的int,而不是对HashBytes的正常调用.
关于这个问题的任何建议?
我正在尝试部署CLR TVF(表值函数).在代码中我使用JavaScriptSerializer来解析一些JSON字符串,所以我引用了System.Web.Extensions dll,我的问题从那里开始.
项目构建正常,但当我尝试注册该DLL时,我收到以下错误:
程序集"my_assembly_name"引用程序集"system.web.extensions,version = 4.0.0.0,culture = neutral,publickeytoken = 31bf3856ad364e35.",这在当前数据库中不存在.SQL Server尝试从引用程序集来自的相同位置定位并自动加载引用的程序集,但该操作失败(原因:2(系统找不到指定的文件.)).请将引用的程序集加载到当前数据库中,然后重试您的请求.
我从以下引用了system.web.extensions:
C:\ Program Files(x86)\ Reference Assemblies\Microsoft\Framework.NETFramework\v4.0\System.Web.Extensions.dll
我可以将复制加载设置为true或手动复制程序集,但随后引用错误会更深入 -
程序集"my_assembly_name"引用程序集"system.servicemodel.activation,version = 4.0.0.0,culture = neutral,publickeytoken = 31bf3856ad364e35.",这在当前数据库中不存在.SQL Server尝试从引用程序集来自的相同位置定位并自动加载引用的程序集,但该操作失败(原因:2(系统找不到指定的文件.)).请将引用的程序集加载到当前数据库中,然后重试您的请求.
一切正常,直到我引用Web.Extensions.dll.目标框架是.NET 4.
任何想法/解决方案?
我有一个CLR UDT,它将从表值方法中受益匪浅,ala xml.nodes():
-- nodes() example, for reference:
declare @xml xml = '<id>1</id><id>2</id><id>5</id><id>10</id>'
select c.value('.','int') as id from @xml.nodes('/id') t (c)
Run Code Online (Sandbox Code Playgroud)
我想要一些类似我的UDT:
-- would return tuples (1, 4), (1, 5), (1, 6)....(1, 20)
declare @udt dbo.FancyType = '1.4:20'
select * from @udt.AsTable() t (c)
Run Code Online (Sandbox Code Playgroud)
有没有人有这方面的经验?任何帮助将不胜感激.我尝试了一些事情,但都失败了.我找了文档和示例,但没有找到.
是的,我知道我可以创建以UDT为参数的表值UDF,但我非常希望将所有内容捆绑在单一类型中,OO风格.
编辑
Russell Hart发现文档声明不支持表值方法,并修复了我的语法以产生预期的运行时错误(见下文).
在VS2010中,在创建新的UDT之后,我在结构定义的末尾添加了这个:
[SqlMethod(FillRowMethodName = "GetTable_FillRow", TableDefinition = "Id INT")]
public IEnumerable GetTable()
{
ArrayList resultCollection = new ArrayList();
resultCollection.Add(1);
resultCollection.Add(2);
resultCollection.Add(3);
return resultCollection;
}
public static void …Run Code Online (Sandbox Code Playgroud)