Saya punya CLR kecil ini yang melakukan fungsi RegEX pada string di kolom.
Saat berjalan pada SQL Server 2014 (12.0.2000) pada Windows Server 2012R2 proses macet
Msg 0, Level 11, Negara 0, Baris 0 Terjadi kesalahan parah pada perintah saat ini. Hasilnya, jika ada, harus dibuang.
dan memberikan stack stack jika saya melakukannya
select count (*) from table where (CLRREGEX,'Regex')
tetapi ketika saya melakukannya
select * from table where (CLRREGEX,'Regex')
mengembalikan baris.
Bekerja dengan sempurna pada build SQL Server yang sama yang berjalan pada Windows 8.1.
Ada ide?
- Sunting Ini sesederhana mungkin
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);
}
}
Jadi dengan sedikit perubahan ini berfungsi sekarang: Pelajaran utama dalam C # tampaknya sama seperti di TSQL Waspadalah terhadap konversi data implisit.
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
sumber
sumber
SqlFunction
metode ini ditandaiIsDeterministic=true
? Apakah majelis ditandai sebagaiSAFE
?[SqlFunction]
atribut duplikat . Apakah itu kode yang tepat? Saya tidak berpikir itu akan dikompilasi. Perbedaan Framework versi 2.0 / 3.0 / 3.5 adalah non-masalah karena Anda menggunakan 4.0 / 4.5 / 4.5.x / etc atau apa pun yang ada di server itu karena Anda berada di SQL Server 2014 yang terikat ke CLR versi 4. Apakah server menunjukkan masalah 32-bit? Berapa banyak memori yang dibandingkan dengan server lain? Dan sudahkah Anda memeriksa log SQL Server setelah mendapatkan kesalahan itu?MatchTimeout
properti baru . Tapi saya tidak berpikir itu benar-benar masalah baik jika Anda hanya melewati 5 karakter maks. Hal ini mungkin bahwa mesin satu ini memiliki rusak menginstal .NET Framework, dan yang dapat diperbaiki sekali trout kegiatan penangkapan ikan telah berhenti ;-). Juga,[0-9].*
sederhana tetapi juga tidak efisien karena cocok dengan semua karakter, jika ada, setelah digit pertama; menggunakan hanya[0-9]
untuk yangIsMatch
lebih baik.DataAccessKind
keRead
? Itu hanya memperlambatnya dan Anda tidak melakukan akses data apa pun. Juga, saya menyadari bahwa ini tampaknya berfungsi sekarang, tetapi saya akan berhati-hati dengan menggunakanToString()
metode yang bertentangan denganValue
properti karena saya tidak berpikir ToString menangani pengodean dengan benar, atau sesuatu seperti itu. Di mana pengaturan pengumpulan basis data Anda? Tentu saja, saya baru saja membaca kembali salah satu komentar Anda di atas dan melihat bahwa kolomnya adalah VARCHAR, bukan NVARCHAR. Apakah bidang itu memiliki susunan yang berbeda dari basis data?Jawaban:
Masalahnya adalah konflik lokal antara OS Windows dan SQL Server (khususnya database tempat Majelis dimuat). Anda dapat menjalankan kueri berikut untuk melihat keduanya diatur:
Jika mereka berbeda maka Anda pasti bisa mendapatkan perilaku "aneh", seperti apa yang Anda lihat. Masalahnya adalah:
SqlString
termasuk lebih dari sekedar teks itu sendiri: itu termasuk susunan default dari database di mana majelis ada. Susunan terdiri dari dua bagian informasi: info lokal (yaitu LCID), dan opsi perbandingan (yaitu SqlCompareOptions) yang merinci sensitivitas terhadap huruf besar-kecil, aksen, kana, lebar, atau semuanya (biner dan biner2).Konflik biasanya terjadi ketika mereferensikan parameter SqlString tanpa menggunakan
.Value
atau.ToString()
sedemikian rupa sehingga ia melakukan konversi implisitSqlString
. Dalam hal itu akan menyebabkan pengecualian yang mengatakan bahwa LCID tidak cocok.Tampaknya ada skenario lain, seperti melakukan perbandingan string (sebagian / semua?), Termasuk ketika menggunakan Regex seperti yang ditunjukkan oleh kasus ini (meskipun sejauh ini saya belum dapat mereproduksi ini).
Beberapa ide untuk perbaikan:
Ideal (harapan akan selalu dipenuhi tentang bagaimana perbandingan bekerja):
Kurang dari ideal (perilaku lokal Windows mungkin bukan aturan yang sama untuk kesetaraan dan penyortiran sehingga mungkin ada hasil yang tidak terduga):
.ToString
metode atau.Value
properti, yang keduanya mengembalikan string tanpa SQL Server LCID sehingga semua operasi akan menggunakan OS LCID.Mungkin membantu:
SqlChars
alih-alihSqlString
karena tidak membawa informasi LCID dan pemeriksaan dari SQL ServerStringComparison.InvariantCulture
:String.Compare(string, string, StringComparison.InvariantCulture)
atauString.Compare(string, string, StringComparison.InvariantCultureIgnoreCase)
RegexOptions.CultureInvariant
sumber
Diperbarui ..
Lokalisasi berbeda antara SQL Engine dan jendela Server seperti yang ditunjukkan @srutzky:
Perubahan berikut pada kode - pengaturan opsi
RegexOptions.CultureInvariant
mengatasi kesalahan. Kode tidak berubah tidak akan crash SQL Server 2012 pada Windows Server 2012R2 dengan pengaturan bahasa yang sama tetapi melakukannya pada SQL Server 2014.sumber
SELECT os_language_version, SERVERPROPERTY('LCID') AS 'SqlServerLCID' FROM sys.dm_os_windows_info;
. Sangat mungkin bahwa masalahnya adalah konflik dalam pengaturan bahasa. Solusi Anda mungkin masih merupakan cara terbaik untuk pergi, tetapi secara umum tidak seharusnya ada kebutuhan untuk menggunakanToString()
alih-alihValue
properti diSqlString
s. Jadi akan lebih baik untuk mengkonfirmasi situasinya.RegexOptions.CultureInvariant
karena Anda tidak meneruskanOptions
variabel ke dalamnyaRegex.IsMatch(sqldata, regex)
. Hal yang berubah antara kode asli Anda dan kode baru yang berfungsi adalah Anda beralih dari menggunakanSqlString.Value
keSqlString.ToString()
. Saya menduga Anda akan melihat perilaku tetap yang sama jika Anda beralih menggunakanSqlChars
. Tapi saya hanya akan melakukan itu sebagai ujian. Pendekatan terbaik adalah mengubah LCID Windows atau SQL Server agar sesuai dengan yang lain. Anda juga dapat menghapus variabel statis Opsi..Value
properti dariSqlString
yang ternyata mengembalikan nilai internal yang sama dengan.ToString()
metode. Saya masih menyelidiki dan akan memperbarui jawaban saya dengan apa pun yang saya temukan :).RegexOptions.IgnoreCase
sementara yang lain tidak. Saya telah menyiapkan lingkungan yang serupa: Windows (8.0) menggunakan LCID 1033, SQL Server DB memiliki LCID 1039, menggunakan RegEx yang sama yang Anda posting, melakukanCOUNT(*)
padaVARCHAR
bidang yang diisi dengan GUID, menggunakan pola'[0-3â].*'
, di atas meja dengan 10 juta baris. Ini adalah SQL Server 2012, bukan 2014, meskipun saya pikir itu tidak masalah.