web-dev-qa-db-ja.com

SQL Server 2014(Windows 2012R2)でCLRがクラッシュする

列の文字列に対して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);
 }
12
Spörri

問題は、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つの情報で構成されます。
  • .NETでの文字列操作では、明示的にロケールが指定されていない限り、Windowsで設定されている現在のスレッドのロケール情報を使用します(オペレーティングシステム/ OSなど)。

_.Value_または.ToString()を使用せずにSqlStringパラメータを参照すると、SqlStringへの暗黙の変換が行われるため、通常、競合が発生します。その場合、LCIDが一致しないという例外が発生します。

このケースが示すようにRegexを使用する場合など、(一部/すべて?)文字列比較を実行するなど、明らかに他のシナリオがあります(これまでのところ、これを再現することはできませんでした)。

修正に関するいくつかのアイデア:

理想的(比較がどのように機能するかについては常に期待が満たされます):

  • WindowsまたはSQL Server LCID(デフォルト言語)を変更して、両方が一致するようにします。

理想的ではない(Windowsロケールの動作は、等式と並べ替えのルールと同じではない可能性があるため、可能性があります予期しない結果):

  • _.ToString_メソッドまたは_.Value_プロパティを使用します。どちらもSQL Server LCIDなしで文字列を返すため、すべての操作でOS LCIDが使用されます。

Might help:

  • SQL ServerからLCIDと照合情報を取得しないため、SqlCharsではなくSqlStringを使用する可能性があります。
  • _StringComparison.InvariantCulture_:を使用して、カルチャが重要ではないことを指定します
    • String.Compare(string, string, StringComparison.InvariantCulture)またはString.Compare(string, string, StringComparison.InvariantCultureIgnoreCase)
    • 正規表現の場合、_RegexOptions.CultureInvariant_を指定します
4
Solomon Rutzky

更新しました..

@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);
 }
1
Spörri