我正在尝试将现有的C DLL(明显未管理),实现模糊匹配,作为用户定义函数(UDF)集成到SQL Server中。 UDF是通过一个CLR VB项目实现的。我已经使用这个C代码将近20年来在文本文件上进行字符串匹配而没有困难。它已经被编译在关于太阳下的每个平台上,并且从未崩溃或者给出错误的结果。永远。到现在。从VB中调用非托管C DLL在SQL Server中的UDF UDF
此UDF在SQL SELECT语句的使用看起来是这样的:
SELECT Field FROM Table WHERE xudf_fuzzy('doppler effect', Field) = 1;
xudf_fuzzy(参数1,参数2)= 1是神奇在哪里发生。参数1是我们尝试匹配的线索词,而参数2是要测试的表中的字段。如果匹配在一定数量的错误内成功,则UDF返回1,否则返回0.迄今为止这么好。
这里是CLR代码定义模糊UDF并调用C DLL:
Imports System
Imports System.Data
Imports System.Data.SqlClient
Imports System.Data.SqlTypes
Imports System.Text
Imports Microsoft.SqlServer.Server
Imports System.Runtime.InteropServices
Partial Public Class fuzzy
<DllImport("C:\Users\Administrator\Desktop\fuzzy64.dll", _
CallingConvention:=CallingConvention.StdCall)> _
Public Shared Function setClue(ByRef clue As String, ByVal misses As Integer) As Integer
End Function
<DllImport("C:\Users\Administrator\Desktop\fuzzy64.dll", _
CallingConvention:=CallingConvention.StdCall)> _
Public Shared Function srchString(ByRef text1 As String) As Integer
End Function
<Microsoft.SqlServer.Server.SqlFunction()> Public Shared Function _
xudf_fuzzy(ByVal strSearchClue As SqlString, ByVal strStringtoSearch As SqlString) As Long
Dim intMiss As Integer = 0
Dim intRet As Integer
Static Dim sClue As String = ""
xudf_fuzzy = 0
' we only need to set the clue whenever it changes '
If (sClue <> strSearchClue.ToString) Then
sClue = strSearchClue.ToString
intMiss = (Len(sClue) \ 4) + 1
intRet = setClue(sClue, intMiss)
End If
' return the fuzzy match result (0 or 1) '
xudf_fuzzy = srchString(strStringtoSearch.ToString)
End Function
下面是C代码的前端被调用。 STRCT是所有全球存储所在的地方。
fuzzy.h
typedef struct {
short int INVRT, AND, LOWER, COMPL, Misses;
long int num_of_matched;
int D_length;
unsigned long int endposition, D_endpos;
unsigned long int Init1, NOERRM;
unsigned long int Mask[SYMMAX];
unsigned long int Init[MaxError];
unsigned long int Bit[WORDSIZE+1];
unsigned char prevpat[MaxDelimit];
unsigned char _buffer[Max_record+Max_record+256];
unsigned char _myPatt[MAXPAT];
} SRCH_STRUCT;
fuzzy.c
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <wtypes.h>
#include <time.h>
#include "fuzzy.h"
// call exports
__declspec(dllexport) int CALLBACK setClue(char**, int*);
__declspec(dllexport) int CALLBACK srchString(char**);
SRCH_STRUCT STRCT = { 0 };
int cluePrep(unsigned char []);
int srchMin(unsigned char [], int);
BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
int CALLBACK setClue(char **pattern, int *misses)
{
int i;
unsigned char *p;
// code to do initialization stuff, set flags etc. etc.
STRCT.Misses = (int)misses;
p = &(STRCT._myPatt[2]);
STRCT._myPatt[0] = '\n';
STRCT._myPatt[1] = SEPCHAR;
strcpy((char *)p, *pattern);
//blah blah
// end setup stuff
i = cluePrep(STRCT._myPatt);
return 0;
}
int CALLBACK srchString(char **textstr)
{
int res,i = Max_record;
unsigned char c;
char *textPtr = *textstr;
STRCT.matched = 0;
//clean out any non alphanumeric characters while we load the field to be tested
while ((c = *textPtr++)) if (isalpha(c) || isdigit(c) || c == ' ') STRCT._buffer[i++] = c;
STRCT._buffer[i] = 0;
// do the search
res = srchMin(STRCT.pattern, STRCT.Misses);
if (res < 0) return res;
return STRCT.matched;
}
运行时库是针对链接:多线程DLL(/ MD)
调用约定是:__cdecl(/ Gd)的
这是它会很奇怪。如果我有一个普通的网络应用程序(代码未显示),它抓取测试数据库中的整个记录集,并一次一个地遍历所有记录,调用该DLL来调用模糊匹配,我每次都会得到正确的结果时间。
如果我使用反对使用,而只使用一个线程上面显示的SQL语句测试数据库上面显示的CLR UDF应用(单核VM)我回到正确的结果每一次为好。
当这个DLL在多核心机器上以CLR UDF模式使用时,一些结果是错误的。结果总是有点偏离,但并不一致。
292条记录应该在前两个测试用例中匹配并执行。
在CLR UDF多线程情况下的结果会回来用273,284,298,290等
所有的C DLL存储的是字符数组。没有使用内存分配。我的理解是,如果SQL Server在多线程模式下使用这个CLR应用程序,那么这些线程都被分配了各自的数据空间。
我需要以某种方式“销”的字符串之前,我把它们发送到C DLL?我无法弄清楚如何继续。
shf301我希望我知道如何给你评分或将问题标记为已回答。你给的答案解决了眼前的问题。谢谢。我还决定尝试将模糊代码转换为C#,以避免从托管VB跳转到C DLL导致的压倒性性能下降。无论如何,感谢帮助队友! – codeThug