Ich habe diese kleine CLR, die eine RegEX-Funktion für eine Zeichenfolge in Spalten ausführt.
Bei der Ausführung unter SQL Server 2014 (12.0.2000) unter Windows Server 2012R2 stürzt der Prozess mit ab
Meldung 0, Ebene 11, Status 0, Zeile 0 Beim aktuellen Befehl ist ein schwerwiegender Fehler aufgetreten. Die Ergebnisse sollten, falls vorhanden, verworfen werden.
und gibt einen Stapelspeicherauszug, wenn ich tue
select count (*) from table where (CLRREGEX,'Regex')
Aber wenn ich das mache
select * from table where (CLRREGEX,'Regex')
es gibt die Zeilen zurück.
Funktioniert perfekt mit demselben SQL Server-Build, der unter Windows 8.1 ausgeführt wird.
Irgendwelche Ideen?
- Bearbeiten Es ist so einfach wie es nur geht
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);
}
}
Durch kleine Änderungen funktioniert dies jetzt: Die Hauptstunde in C # scheint dieselbe zu sein wie in TSQL. Achten Sie auf implizite Datenkonvertierung.
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);
}
quelle
SqlFunction
Methode als markiertIsDeterministic=true
? Ist die Baugruppe markiert alsSAFE
?[SqlFunction]
Attributs. Ist das der genaue Code? Ich denke nicht, dass das kompilieren würde. Die Unterscheidung zwischen Framework Version 2.0 / 3.0 / 3.5 ist kein Problem, da Sie 4.0 / 4.5 / 4.5.x / etc verwenden oder was auch immer sich auf diesem Server befindet, da Sie sich in SQL Server 2014 befinden, das an CLR Version 4 gebunden ist Server zeigt das Problem 32-Bit? Wie viel Speicher hat es im Vergleich zu den anderen Servern? Haben Sie die SQL Server-Protokolle überprüft, nachdem Sie diesen Fehler erhalten haben?MatchTimeout
Eigenschaft verwenden können. Aber ich denke nicht, dass das wirklich das Problem ist, auch wenn Sie nur maximal 5 Zeichen eingeben. Es ist möglich, dass auf diesem Computer eine beschädigte Installation von .NET Framework vorhanden ist, die repariert werden kann, sobald die Forellenfischerei eingestellt wurde ;-). Auch[0-9].*
ist einfach, aber auch ineffizient, da es allen Zeichen nach der ersten Ziffer entspricht, falls vorhanden; mit nur[0-9]
für eineIsMatch
ist besser.DataAccessKind
zuRead
? Das verlangsamt es nur und Sie machen keinen Datenzugriff. Außerdem ist mir klar, dass es jetzt zu funktionieren scheint, aber ich würde vorsichtig sein, wenn ich dieToString()
MethodeValue
anstelle der Eigenschaft verwende, da ich denke, dass ToString Kodierungen oder ähnliches nicht richtig handhabt. Auf welche Sortierung ist Ihre Datenbank eingestellt? Natürlich habe ich einen Ihrer Kommentare oben noch einmal gelesen und festgestellt, dass die Spalte VARCHAR anstelle von NVARCHAR ist. Hat dieses Feld eine andere Sortierung als die Datenbank?Antworten:
Das Problem ist ein Gebietsschemakonflikt zwischen dem Windows-Betriebssystem und SQL Server (insbesondere der Datenbank, in die die Assembly geladen wird). Sie können die folgende Abfrage ausführen, um festzustellen, auf welche Werte beide festgelegt sind:
Wenn sie sich unterscheiden, können Sie auf jeden Fall ein merkwürdiges Verhalten feststellen, wie z. B. das, was Sie sehen. Das Problem ist, dass:
SqlString
enthält mehr als nur den Text selbst: Er enthält die Standardkollatierung der Datenbank, in der die Assembly vorhanden ist. Die Kollatierung besteht aus zwei Informationen: den Informationen zum Gebietsschema (z. B. LCID) und den Vergleichsoptionen (z. B. SqlCompareOptions), die die Empfindlichkeit für Groß- und Kleinschreibung, Akzente, Kana, Breite oder alles (binär und binär2) angeben.Der Konflikt tritt normalerweise auf, wenn auf einen SqlString-Parameter verwiesen wird, ohne dass
.Value
oder.ToString()
eine implizite Konvertierung in ausgeführt wirdSqlString
. In diesem Fall würde eine Ausnahme ausgelöst, die besagt, dass die LCIDs nicht übereinstimmen.Es gibt anscheinend andere Szenarien, wie das Durchführen (einiger / aller?) Zeichenfolgenvergleiche, einschließlich der Verwendung von Regex, wie dieser Fall zeigt (obwohl ich dies bisher nicht reproduzieren konnte).
Einige Ideen für Korrekturen:
Ideal (Erwartungen bezüglich der Funktionsweise der Vergleiche werden immer erfüllt):
Weniger als ideal (das Verhalten des Windows - Gebietsschemas möglicherweise nicht die gleichen Regeln für die Gleichstellung und das Sortieren und so es könnte unerwartete Ergebnisse):
.ToString
Methode oder.Value
Eigenschaft, die beide die Zeichenfolge ohne die SQL Server-LCID zurückgeben, sodass alle Vorgänge die Betriebssystem-LCID verwenden.Könnte helfen:
SqlChars
stattdessen möglicherweise,SqlString
da die LCID- und Sortierungsinformationen von SQL Server nicht mitgebracht werdenStringComparison.InvariantCulture
:String.Compare(string, string, StringComparison.InvariantCulture)
oderString.Compare(string, string, StringComparison.InvariantCultureIgnoreCase)
RegexOptions.CultureInvariant
quelle
Aktualisiert..
Die Lokalisierung unterscheidet sich zwischen der SQL Engine und dem Windows Server, wie @srutzky hervorhebt:
Die folgende Änderung am Code - Setzen der Option
RegexOptions.CultureInvariant
umgeht den Fehler. Der unveränderte Code führt unter Windows Server 2012R2 nicht zu einem Absturz von SQL Server 2012 mit denselben Spracheinstellungen, jedoch unter SQL Server 2014.quelle
SELECT os_language_version, SERVERPROPERTY('LCID') AS 'SqlServerLCID' FROM sys.dm_os_windows_info;
. Es ist durchaus möglich, dass das Problem ein Konflikt in den Spracheinstellungen war. Ihre Lösung ist zwar immer noch der beste Weg, aber im Allgemeinen sollte keine VerwendungToString()
anstelle derValue
Eigenschaft aufSqlString
s erforderlich sein . Es wäre also schön, die Situation zu bestätigen.RegexOptions.CultureInvariant
da Sie dieOptions
Variable nicht übergebenRegex.IsMatch(sqldata, regex)
. Das, was sich zwischen Ihrem ursprünglichen Code und dem neuen, funktionierenden Code geändert hat, ist, dass Sie von der VerwendungSqlString.Value
zu gegangen sindSqlString.ToString()
. Ich vermute, Sie würden dasselbe Verhalten feststellen, wenn Sie auf die Verwendung umsteigen würdenSqlChars
. Aber ich würde das nur als Test machen. Der beste Ansatz besteht darin, die LCID von Windows oder SQL Server so zu ändern, dass sie mit der anderen übereinstimmt. Sie können auch die statische Variable Options entfernen..Value
Eigenschaft zu tun oder sollte es auch nicht sein von aSqlString
as gibt anscheinend denselben internen Wert wie die.ToString()
Methode zurück. Ich recherchiere noch und werde meine Antwort mit allem, was ich finde, aktualisieren :).RegexOptions.IgnoreCase
während der andere dies nicht tut. Ich habe eine ähnliche Umgebung eingerichtet: Windows (8.0) verwendet eine LCID von 1033, SQL Server DB eine LCID von 1039 und verwendet dieselbe RegEx, die Sie veröffentlicht haben. Dabei wirdCOUNT(*)
in einemVARCHAR
mit GUIDs gefüllten Feld ein Muster von'[0-3â].*'
für eine Tabelle verwendet mit 10 Millionen Zeilen. Es ist SQL Server 2012, nicht 2014, obwohl ich nicht denke, dass das wichtig sein sollte.