列の文字列に対してRegEX関数を実行するこの小さなCLRがあります。
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 OSとSQL Server(特に、アセンブリがロードされるデータベース)間のロケールの競合です。次のクエリを実行して、両方の設定を確認できます。
_SELECT os_language_version,
DATABASEPROPERTYEX(N'{name of DB where Assembly exists}', 'LCID') AS 'DatabaseLCID'
FROM sys.dm_os_windows_info;
_
それらが異なる場合は、表示されているものなど、「奇妙な」動作を確実に得ることができます。問題は次のとおりです。
SqlString
には、テキスト自体だけでなく、アセンブリが存在するデータベースのデフォルトの照合も含まれます。照合順序は、ロケール情報(LCIDなど)と、大文字小文字の区別、アクセント、かな、幅、またはすべて(バイナリとバイナリ2)の詳細を比較する比較オプション(SqlCompareOptions)の2つの情報で構成されます。_.Value
_または.ToString()
を使用せずにSqlStringパラメータを参照すると、SqlString
への暗黙の変換が行われるため、通常、競合が発生します。その場合、LCIDが一致しないという例外が発生します。
このケースが示すようにRegexを使用する場合など、(一部/すべて?)文字列比較を実行するなど、明らかに他のシナリオがあります(これまでのところ、これを再現することはできませんでした)。
修正に関するいくつかのアイデア:
理想的(比較がどのように機能するかについては常に期待が満たされます):
理想的ではない(Windowsロケールの動作は、等式と並べ替えのルールと同じではない可能性があるため、可能性があります予期しない結果):
.ToString
_メソッドまたは_.Value
_プロパティを使用します。どちらもSQL Server LCIDなしで文字列を返すため、すべての操作でOS LCIDが使用されます。Might help:
SqlChars
ではなくSqlString
を使用する可能性があります。StringComparison.InvariantCulture
_:を使用して、カルチャが重要ではないことを指定しますString.Compare(string, string, StringComparison.InvariantCulture)
またはString.Compare(string, string, StringComparison.InvariantCultureIgnoreCase)
RegexOptions.CultureInvariant
_を指定します更新しました..
@srutzkyが指摘するように、ローカリゼーションはSQLエンジンとウィンドウサーバーで異なります。
os_language_version SqlServerLCID 1033 1039
次のコードの変更-オプションの設定RegexOptions.CultureInvariant
はエラーを回避します。変更されていないコードは、同じ言語設定のWindows Server 2012R2上のSQL Server 2012をクラッシュさせませんが、SQL Server 2014ではクラッシュさせます。
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)]
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);
}