Eu tenho este pequeno CLR que faz uma função RegEX em uma string em colunas.
Ao executar no SQL Server 2014 (12.0.2000) no Windows Server 2012R2, o processo trava com
Msg 0, Nível 11, Estado 0, Linha 0 Ocorreu um erro grave no comando atual. Os resultados, se existirem, deveriam ser descartados.
e dá um despejo de pilha se eu fizer
select count (*) from table where (CLRREGEX,'Regex')
mas quando eu faço
select * from table where (CLRREGEX,'Regex')
ele retorna as linhas.
Funciona perfeitamente na mesma compilação do SQL Server em execução no Windows 8.1.
Alguma ideia?
-- Edit É tão simples quanto pode 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);
}
}
Então, com pequenas mudanças, isso funciona agora: A lição principal em C # parece ser a mesma que em TSQL, cuidado com a conversão implícita de dados.
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);
}
O problema é um conflito de localidade entre o sistema operacional Windows e o SQL Server (especificamente o banco de dados onde o Assembly é carregado). Você pode executar a seguinte consulta para ver o que ambos estão configurados:
Se forem diferentes, você pode definitivamente obter algum comportamento "estranho", como o que está vendo. A questão é que:
SqlString
inclui mais do que apenas o próprio texto: inclui o agrupamento padrão do banco de dados no qual existe o assembly. O agrupamento é composto por duas informações: as informações de localidade (ou seja, LCID) e as opções de comparação (ou seja, SqlCompareOptions) que detalham a sensibilidade a maiúsculas e minúsculas, acentos, kana, largura ou tudo (binário e binário2).O conflito geralmente ocorre ao referenciar um parâmetro SqlString sem usar
.Value
ou.ToString()
fazer uma conversão implícita paraSqlString
. Nesse caso, causaria uma exceção dizendo que os LCIDs não correspondem.Aparentemente, existem outros cenários, como realizar (algumas / todas?) Comparações de strings, inclusive ao usar Regex, como mostra este caso (embora até agora não tenha conseguido reproduzir isso).
Algumas ideias para correções:
Ideal (as expectativas sempre serão atendidas em relação ao funcionamento das comparações):
Menos do que o ideal (o comportamento da localidade do Windows pode não ser as mesmas regras de igualdade e classificação e, portanto, pode haver resultados inesperados):
.ToString
método ou a.Value
propriedade, que retornam a string sem o LCID do SQL Server para que todas as operações usem o LCID do sistema operacional.Pode ajudar:
SqlChars
em vez deSqlString
, pois não traz as informações de LCID e agrupamento do SQL ServerStringComparison.InvariantCulture
:String.Compare(string, string, StringComparison.InvariantCulture)
ouString.Compare(string, string, StringComparison.InvariantCultureIgnoreCase)
RegexOptions.CultureInvariant
Atualizada..
A localização é diferente entre o SQL Engine e o window Server como @srutzky aponta:
A seguinte alteração no código - definir a opção
RegexOptions.CultureInvariant
contorna o erro. O código inalterado não travará o SQL Server 2012 no Windows Server 2012R2 com as mesmas configurações de idioma, mas o fará no SQL Server 2014.