我有这个小型 CLR,它对列中的字符串执行 RegEX 函数。
在 Windows Server 2012R2 上的 SQL Server 2014 (12.0.2000) 上运行时,进程崩溃
消息 0,级别 11,状态 0,第 0 行当前命令发生严重错误。结果,如果有的话,应该被丢弃。
如果我这样做的话,给出一个堆栈转储
select count (*) from table where (CLRREGEX,'Regex')
但是当我这样做的时候
select * from table where (CLRREGEX,'Regex')
它返回行。
在 Windows 8.1 上运行的同一 SQL Server 版本上完美运行。
有任何想法吗?
-- 编辑它尽可能简单
using System;
using System.Collections.Generic;
using System.Text;
using System.Data.SqlTypes; //SqlString, SqlInt32, SqlBoolean
using System.Text.RegularExpressions; //Match, Regex
using Microsoft.SqlServer.Server; //SqlFunctionAttribute
public partial class UserDefinedFunctions
{
public static readonly RegexOptions Options = RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline;
[SqlFunction]
[Microsoft.SqlServer.Server.SqlFunction(IsDeterministic = true, IsPrecise = true)]
public static SqlBoolean RegExMatch(SqlString input, SqlString pattern)
{
if (input.IsNull || pattern.IsNull) //nulls dont qualify for a match
return SqlBoolean.False;
return Regex.IsMatch(input.Value, pattern.Value, RegexOptions.IgnoreCase);
}
}
因此,通过一些小的改动,这现在可以工作了:C# 中的主要课程似乎与 TSQL 中的一样,请注意隐式数据转换。
using System;
using System.Text;
using System.Data.SqlTypes; //SqlString, SqlInt32, SqlBoolean
using System.Text.RegularExpressions; //Match, Regex
using Microsoft.SqlServer.Server; //SqlFunctionAttribute
public partial class UserDefinedFunctions
{
public static readonly RegexOptions Options = RegexOptions.IgnorePatternWhitespace | RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant;
[Microsoft.SqlServer.Server.SqlFunction(IsDeterministic = true, IsPrecise = true, DataAccess = DataAccessKind.Read)]
public static SqlBoolean RegExMatch(SqlString input, SqlString pattern)
{
if (input.IsNull || pattern.IsNull) //nulls dont qualify for a match
return SqlBoolean.False;
string sqldata = input.ToString();
string regex = pattern.ToString();
return Regex.IsMatch(sqldata, regex);
}
问题是 Windows 操作系统和 SQL Server(特别是加载程序集的数据库)之间的区域设置冲突。您可以运行以下查询以查看它们都设置为什么:
如果它们不同,那么您肯定会得到一些“奇怪”的行为,例如您所看到的。问题是:
SqlString
包括的不仅仅是文本本身:它包括程序集所在的数据库的默认排序规则。排序规则由两部分信息组成:语言环境信息(即 LCID)和比较选项(即 SqlCompareOptions),后者详细说明了对大小写、重音、假名、宽度或所有内容(二进制和二进制 2)的敏感性。冲突通常发生在引用 SqlString 参数而不使用
.Value
or时.ToString()
,它会隐式转换为SqlString
. 在那种情况下,它会导致异常,指出 LCID 不匹配。显然还有其他场景,例如执行(部分/全部?)字符串比较,包括在本例中使用 Regex 时(尽管到目前为止我还无法重现)。
修复的一些想法:
理想(关于比较如何工作的期望总是会得到满足):
不太理想(Windows 语言环境的行为可能与相等性和排序规则不同,因此可能会出现意外结果):
.ToString
方法或.Value
属性,它们都返回不带 SQL Server LCID 的字符串,因此所有操作都将使用操作系统 LCID。可能有帮助:
SqlChars
而不是SqlString
因为它不会带来来自 SQL Server 的 LCID 和排序规则信息StringComparison.InvariantCulture
:String.Compare(string, string, StringComparison.InvariantCulture)
或者String.Compare(string, string, StringComparison.InvariantCultureIgnoreCase)
RegexOptions.CultureInvariant
更新..
正如@srutzky 指出的那样,SQL 引擎和窗口服务器之间的本地化是不同的:
对代码的以下更改 - 设置选项
RegexOptions.CultureInvariant
可以避免错误。未更改的代码不会使具有相同语言设置的 Windows Server 2012R2 上的 SQL Server 2012 崩溃,但会在 SQL Server 2014 上崩溃。