Tengo este pequeño CLR que hace una función RegEX en una cadena en columnas.
Cuando se ejecuta en SQL Server 2014 (12.0.2000) en Windows Server 2012R2, el proceso se bloquea con
Mensaje 0, Nivel 11, Estado 0, Línea 0 Se produjo un error grave en el comando actual. Los resultados, si los hay, deben descartarse.
y da un volcado de pila si lo hago
select count (*) from table where (CLRREGEX,'Regex')
pero cuando lo hago
select * from table where (CLRREGEX,'Regex')
devuelve las filas.
Funciona perfectamente en la misma compilación de SQL Server que se ejecuta en Windows 8.1.
¿Algunas ideas?
- Editar Es tan simple como puede ser
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);
}
}
Entonces, con pequeños cambios, esto funciona ahora: la lección principal en C # parece ser la misma que en TSQL, tenga cuidado con la conversión de datos implícita.
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);
}
sql-server
sql-server-2014
sql-clr
Spörri
fuente
fuente
SqlFunction
método está marcado comoIsDeterministic=true
? ¿El conjunto está marcado comoSAFE
?[SqlFunction]
atributo duplicado . ¿Es ese el código exacto? No creo que eso compile. La distinción de Framework versión 2.0 / 3.0 / 3.5 no es un problema ya que está utilizando 4.0 / 4.5 / 4.5.x / etc o lo que sea que esté en ese servidor ya que está en SQL Server 2014, que está vinculado a CLR versión 4. Es el servidor que muestra el problema de 32 bits? ¿Cuánta memoria tiene en comparación con los otros servidores? ¿Y ha verificado los registros de SQL Server justo después de recibir ese error?MatchTimeout
propiedad. Pero tampoco creo que ese sea realmente el problema si solo está pasando 5 caracteres como máximo. Que es posible que éste equipo dispone de una instalación corrupta de .NET Framework, y que puede ser reparada una vez trucha actividades pesqueras han dejado ;-). Además,[0-9].*
es simple pero también ineficiente, ya que coincide con todos los caracteres, si los hay, después del primer dígito; usar solo[0-9]
para unIsMatch
es mejor.DataAccessKind
aRead
? Eso solo lo ralentiza y no está haciendo ningún acceso a datos. Además, me doy cuenta de que parece estar funcionando ahora, pero sería cauteloso con el uso delToString()
método en lugar de laValue
propiedad, ya que no creo que ToString maneje las codificaciones correctamente, o algo así. ¿Para qué está configurada la recopilación de sus bases de datos? Por supuesto, acabo de volver a leer uno de sus comentarios anteriores y veo que la columna es VARCHAR en lugar de NVARCHAR. ¿Ese campo tiene una clasificación diferente a la de la base de datos?Respuestas:
El problema es un conflicto de configuración regional entre el sistema operativo Windows y SQL Server (específicamente la base de datos donde se carga el ensamblado). Puede ejecutar la siguiente consulta para ver en qué están configurados ambos:
Si son diferentes, entonces definitivamente puede tener un comportamiento "extraño", como lo que está viendo. El problema es que:
SqlString
incluye más que solo el texto en sí: incluye la clasificación predeterminada de la base de datos en la que existe el ensamblado. La recopilación se compone de dos piezas de información: la información de la configuración regional (es decir, LCID) y las opciones de comparación (es decir, SqlCompareOptions) que detallan la sensibilidad a mayúsculas, acentos, kana, ancho o todo (binario y binario2).El conflicto generalmente ocurre cuando se hace referencia a un parámetro SqlString sin usar
.Value
o.ToString()
tal que haga una conversión implícita aSqlString
. En ese caso, causaría una excepción diciendo que los LCID no coinciden.Aparentemente, existen otros escenarios, como realizar comparaciones de cadenas (¿algunas / todas?), Incluso cuando se usa Regex como lo muestra este caso (aunque hasta ahora no he podido reproducir esto).
Algunas ideas para soluciones:
Ideal (siempre se cumplirán las expectativas con respecto a cómo funcionan las comparaciones):
Menos que ideal (el comportamiento de la configuración regional de Windows podría no ser las mismas reglas para la igualdad y la clasificación, por lo que podría haber resultados inesperados):
.ToString
método o la.Value
propiedad, que devuelven la cadena sin el LCID de SQL Server para que todas las operaciones usen el LCID del sistema operativo.Podría ayudar:
SqlChars
lugar de,SqlString
ya que no trae consigo la información LCID y de recopilación de SQL ServerStringComparison.InvariantCulture
:String.Compare(string, string, StringComparison.InvariantCulture)
oString.Compare(string, string, StringComparison.InvariantCultureIgnoreCase)
RegexOptions.CultureInvariant
fuente
Actualizado..
La localización es diferente entre el motor SQL y el servidor de ventana como @srutzky señala:
El siguiente cambio en el código: la configuración de la opción
RegexOptions.CultureInvariant
evita el error. El código sin cambios no bloqueará SQL Server 2012 en Windows Server 2012R2 con la misma configuración de idioma, pero lo hace en SQL Server 2014.fuente
SELECT os_language_version, SERVERPROPERTY('LCID') AS 'SqlServerLCID' FROM sys.dm_os_windows_info;
? Es muy posible que el problema haya sido un conflicto en la configuración del idioma. Su solución aún podría ser la mejor opción, pero en general no debería ser necesario usarla enToString()
lugar de laValue
propiedad enSqlString
s. Por lo tanto, sería bueno confirmar la situación.RegexOptions.CultureInvariant
ya que no pasa laOptions
variableRegex.IsMatch(sqldata, regex)
. Lo que cambió entre su código original y el nuevo código de trabajo es que pasó de usarSqlString.Value
aSqlString.ToString()
. Sospecho que verías el mismo comportamiento fijo si cambias a usarSqlChars
. Pero solo haría eso como prueba. El mejor enfoque es cambiar el LCID de Windows o SQL Server para que coincida con el otro. También puede eliminar la variable estática Opciones..Value
propiedad de unSqlString
que aparentemente devuelve el mismo valor interno que el.ToString()
método. Todavía estoy investigando y actualizaré mi respuesta con lo que encuentre :).RegexOptions.IgnoreCase
y el otro no. He configurado un entorno similar: Windows (8.0) usando LCID de 1033, SQL Server DB tiene LCID de 1039, usando el mismo RegEx que publicó, haciendo unCOUNT(*)
en unVARCHAR
campo lleno de GUID, usando un patrón de'[0-3â].*'
, en una tabla con 10 millones de hileras. Es SQL Server 2012, no 2014, aunque no creo que eso deba importar.