我有一个非常重要的加密算法要在SQL的触发器中使用,因为SQL的加密是可以完整的还原的,但master表中可以增加一些外部的存储过程,而这些存储过程是作为DLL的形式使用的,可以用其他的语言书写,但我写了一个DLL,但不清楚它是怎样附加上去,以及书写时有哪些要求。

解决方案 »

  1.   

    扩展DLL好像是要用VC编写,而且有一定要求,具体地参考SQL联机帮助另一种是编写ole,参考下面的VB代码及调用示例--SQL Server的存储过程调用Com组件
    /*--下面的部分在VB中完成首先我们先用VB 作一个最简单的组件工程名称: testSQLCOM
    类名: TestMath'函数,计算两个整数相加的结果
    Public Function AddMe(a As Long, b As Long) As Long
       AddMe = a + b
    End Function编译生成后,我们就可以在 Sql Server 中对这个 Com 组件进行调用了
    --*//*--下面是SQL中对上面DLL的调用--*/--定义用到的变量
    declare @err int,@src varchar(255),@desc varchar(255)
    declare @obj int,@re int--创建调用实例
    exec @err=sp_OACreate 'testSQLCOM.TestMath', @obj out
    if @err<>0 goto lberr  --如果创建失败,则进行错误处理--调用DLL中的函数
    exec @err=sp_OAMethod @obj,'AddMe',@re out,100,200
    if @err<>0 goto lberr  --如果调用错误,则进行错误处理print '返回的结果是:' + str(@re)--完成后释放
    exec sp_OADestroy @objreturnlberr:
    exec sp_oageterrorinfo 0,@src out,@desc out
    select cast(@err as varbinary(4)) as 错误号
    ,@src as 错误源,@desc as 错误描述
      

  2.   

    我的SQL是2000,DLL是用CBC写的,不知可不可以使用
      

  3.   

    一下实例都来自sqlserver2000 online book。
     使用 CLSID创建对象
    下面的示例通过使用 SQL-DMO SQLServer 对象的 CLSID 创建该对象。DECLARE @object int
    DECLARE @hr int
    DECLARE @src varchar(255), @desc varchar(255)
    EXEC @hr = sp_OACreate '{00026BA1-0000-0000-C000-000000000046}',
        @object OUT
    IF @hr <> 0
    BEGIN
       EXEC sp_OAGetErrorInfo @object, @src OUT, @desc OUT 
       SELECT hr=convert(varbinary(4),@hr), Source=@src, Description=@desc
        RETURN
    END释放对象
    EXEC @hr = sp_OADestroy @object
    IF @hr <> 0
    BEGIN
       EXEC sp_OAGetErrorInfo @object
        RETURN
    END调用 OLE 对象的方法
    EXEC @hr = sp_OAMethod @object, 'Connect', NULL, 'my_server',
        'my_login', 'my_password'
    IF @hr <> 0
    BEGIN
       EXEC sp_OAGetErrorInfo @object
        RETURN
    END
    获取属性
    DECLARE @property varchar(255)
    EXEC @hr = sp_OAMethod @object, 'HostName', @property OUT
    IF @hr <> 0
    BEGIN
       EXEC sp_OAGetErrorInfo @object
        RETURN
    END
    PRINT @property将 OLE 对象的属性设置为新值。
    EXEC @hr = sp_OASetProperty @object, 'HostName', 'Gizmo'
    IF @hr <> 0
    BEGIN
       EXEC sp_OAGetErrorInfo @object
        RETURN
    END获取 OLE 对象的属性值。A. 使用局部变量
    下面的示例获取 HostName 属性(属于先前创建的 SQLServer 对象)并将其存储在局部变量中。DECLARE @property varchar(255)
    EXEC @hr = sp_OAGetProperty @object, 'HostName', @property OUT
    IF @hr <> 0
    BEGIN
       EXEC sp_OAGetErrorInfo @object
        RETURN
    END
    PRINT @propertyB. 使用结果集
    下面的示例获取 HostName 属性(属于先前创建的 SQLServer 对象)并将其作为结果集返回给客户端。EXEC @hr = sp_OAGetProperty @object, 'HostName'
    IF @hr <> 0
    BEGIN
       EXEC sp_OAGetErrorInfo @object
        RETURN
    END
      

  4.   

    非常多谢 libin_ftsafe(子陌红尘:当libin告别ftsafe)及cn_popeye(树上蹭灰)提供的资料。我有十多年没有用BASIC了,用惯了C;并且是要用到字位级的运算,在VB中不太习惯;这个算法十分重要,是涉及到收银机的问题。所在非常希望能用DLL形式的进行调用。
      

  5.   

    我只告诉你哪里找得到帮助在SQLServer2000的联机丛书里的“生成SQLServer应用程序”一章下的“扩展存储过程编程”一节。这里应该有你想要的。
      

  6.   

    下面是我用sql2000所做的一个扩展存储过程。停止sql server后放到bin下,可以通过附加到进程的方式进行调试
    #include <stdafx.h>
    #include <stdlib.h>
    #include <time.h>#define XP_NOERROR              0
    #define XP_ERROR                1
    #define MAXCOLNAME 25
    #define MAXNAME 25
    #define MAXTEXT 255#ifdef __cplusplus
    extern "C" {
    #endif#ifdef _WIN32
    #include <winsock.h>
    #else
    #include <errno.h>
    #endif#if defined(_MSC_VER)
    #   pragma comment(lib,"wsock32.lib")
    #elif defined(__BORLANDC__)
    #   pragma comment(lib,"mswsock.lib")
    #endif#pragma pack(1)
    enum
    {
    LOCAL_USER =0,
    OUTSIDE_USER =1,
    FOREIGN_USER =2,
    ///////////////
    NET_ABIS_PACKET =3,
    NET_HLR_PACKET =4,
    NET_A_PACKET =5,
    NET_SMS_SUBMIT_PACKET =7,//add 2002-9-29 
    NET_SMS_DELIEVER_PACKET =8,//add 2002-9-29 
    SS7_STAT_PACKET =9,
    NET_QUERY_VLR_PACKET = 10,
    };//Define User Type & Packet Type
    typedef struct
    {
    unsigned int msisdn;// 
    unsigned int cgi;// 
    unsigned char updatetype;// 
    int time;//时间
    unsigned char sch;// }VLR_DATA; typedef struct
    {
    __int64 imsi;
    __int64 msisdn;//8613XXXXXXXXX
    unsigned char sch;//UserType;
    unsigned int msc;
    // int sch;
    }NET_HLR_DATA; typedef struct
    {
    __int64 imsi;
    __int64 msisdn;
    }NET_QUERY_VLR;
     typedef struct
    {
    __int64 imsi;//卡号
    VLR_DATA vlrdata;//直取VLR数据
    }NET_QUERY_VLR_RESP;//查询返回数据如果返回的数据全为0 则表标 查询失败
    //网络上所有数据包
    typedef struct
    {
    unsigned short PacketLen;
    unsigned short PacketType;
    union
    {
    NET_QUERY_VLR queryvlr;
    NET_HLR_DATA hlrdata;
    NET_QUERY_VLR_RESP queryvlrresp;
    };
    }NET_DATA;
    #pragma pack()SOCKET sd_client = 0;
    BOOL g_bInitSocket = false;
    char szFileName[MAX_PATH+1];
    //互斥
    CRITICAL_SECTION g_csec;
    BOOL g_bcs = false;
    int InitMySocket();
    void CloseMySocket();RETCODE __declspec(dllexport) xp_GetCurLocation(SRV_PROC *srvproc);
    RETCODE __declspec(dllexport) xp_RegistUser(SRV_PROC *srvproc);#ifdef __cplusplus
    }
    #endifvoid InitCS()
    {
    if (!g_bcs)
    InitializeCriticalSection( &g_csec);
    g_bcs = true;
    }
    void DeleteCS()
    {
    if (g_bcs)
    DeleteCriticalSection( &g_csec);
    g_bcs = false;
    }
    int InitMySocket()
    {
    int iErr; u_short iPort;
    struct sockaddr_in addr_srv;

    char pszFileName[MAX_PATH]; //= "c:\\winnt\\StorProc.ini";
    GetWindowsDirectory(pszFileName,MAX_PATH);
    strcat(pszFileName,"\\StorProc.ini");

    char  pszHost[20];
    GetPrivateProfileString("net","ip","192.168.0.201",pszHost,16,pszFileName);
    iPort = GetPrivateProfileInt(
    "net",
    "port",
    8080,
    pszFileName
    ); WSADATA wsaData;
    WORD wVersionRequested; wVersionRequested = MAKEWORD( 1,1 );
    iErr = WSAStartup( wVersionRequested, &wsaData );
    if ( iErr != 0 ) {
    //WriteInfo("Error: Winsock not available\n" + iErr);
    return 1;
    }else g_bInitSocket = true; sd_client = socket(PF_INET, SOCK_STREAM, 0);
    if (sd_client == INVALID_SOCKET)
    {
    //WriteInfo("没有更多的socket资源");
    return 1;
    }

    addr_srv.sin_family = PF_INET;
    addr_srv.sin_addr.S_un.S_addr = inet_addr(pszHost);
    addr_srv.sin_port = htons(iPort); TIMEVAL timeout;
    FD_SET fdset;
    timeout.tv_sec = 2;
    timeout.tv_usec= 0;
    FD_ZERO( &fdset);
    FD_SET ( sd_client, &fdset);
    iErr = select(
    0,

    NULL,
    &fdset,
    NULL,

    &timeout); iErr = connect(sd_client, (struct sockaddr *) &addr_srv,
    sizeof(addr_srv));
    if (iErr == INVALID_SOCKET)
    {
    return 1;
    }
    else
    {
    return 0;
    }
    }
      

  7.   

    void CloseMySocket()
    {
    closesocket(sd_client);
    if (g_bInitSocket)
    WSACleanup();
    sd_client=0;
    }
    RETCODE __declspec(dllexport) xp_RegistUser(SRV_PROC* pSrvProc)
    {
    RETCODE nRet = XP_NOERROR;
    int iErrCode = 0;
    bool bEnterCS = false;

    int nSizeQ;
    unsigned char szFlag;
    char szMsisdn[14];
    BYTE bType;
    unsigned long cbMaxLen;
    unsigned long cbActualLen;
    BOOL fNull; NET_DATA nData; memset(&nData,0,sizeof(nData));
    memset(szMsisdn,0,14); int paramCount = srv_rpcparams(pSrvProc);
    if (paramCount != 4)
    {
    return XP_ERROR;
    }
    if (sd_client == 0)
    {
    if (InitMySocket() )
    {// 101:网络错误
    iErrCode = 101;
    sd_client = 0;
    goto ERR_TAB;
    }
    }
    nSizeQ = sizeof(NET_HLR_DATA)+4;
    int ret = srv_paraminfo(pSrvProc, 1, &bType, &cbMaxLen, &cbActualLen,
            NULL, &fNull); if (cbActualLen){
    int err; /////////////////////////////////
    nData.PacketLen = nSizeQ;
    nData.PacketType = NET_HLR_PACKET;
    memcpy(szMsisdn, srv_paramdata(pSrvProc, 1), cbActualLen);
    ret = srv_paraminfo(pSrvProc, 2, &bType, &cbMaxLen, &cbActualLen,
        NULL, &fNull);
    memcpy(&nData.hlrdata.imsi,srv_paramdata(pSrvProc, 2),cbActualLen);
    ret = srv_paraminfo(pSrvProc, 3, &bType, &cbMaxLen, &cbActualLen,
        NULL, &fNull);
    memcpy(&szFlag, srv_paramdata(pSrvProc, 3), cbActualLen);

    //nData.hlrdata.imsi = 0;
    nData.hlrdata.msc = 0;
    //if (szFlag == 1) nData.hlrdata.sch = 0x11;
    //if (szFlag == 0) nData.hlrdata.sch = 0x10;
    nData.hlrdata.sch = szFlag;
    nData.hlrdata.msisdn = _atoi64(szMsisdn); /////////////////////////////////
    InitCS();//初始化临界区
    EnterCriticalSection( &g_csec);//开始进行临界区
    bEnterCS = true;
    err = send (sd_client, (char *)&nData, nSizeQ, 0);
    if (err!=nSizeQ)
    {
    CloseMySocket();
    iErrCode = 102;
    goto ERR_TAB;
    }
    }
    else {
    return XP_ERROR;
    } ERR_TAB:
    if (bEnterCS) LeaveCriticalSection( &g_csec);//离开临界区,注意在return之前一定要调用 否则下一次永远不会进入临界区
    srv_paramsetoutput(pSrvProc,4,(BYTE *)&iErrCode,4,FALSE);
    return XP_NOERROR;
    }RETCODE __declspec(dllexport) xp_GetCurLocation(SRV_PROC* pSrvProc)
    {
    RETCODE nRet = XP_NOERROR;
    int iErrCode = 0;
    bool bEnterCS = false; TIMEVAL timeout;
    FD_SET fdset;
    timeout.tv_sec = 2;
    timeout.tv_usec= 0;

    int nSizeQ,nSizeR;
    char szMsisdn[14];
    BYTE bType;
    unsigned long cbMaxLen;
    unsigned long cbActualLen;
    BOOL fNull; char szImsi[20];
    char sTime[20]; int iLac,iCi;
    iLac = 0;
    iCi = 0; NET_DATA nData;
    NET_DATA rData; memset(&rData,0,sizeof(rData));
    memset(szMsisdn,0,14);
    memset(sTime,0,20);
    int paramCount = srv_rpcparams(pSrvProc);
    if (paramCount != 8)
    {
    return XP_ERROR;
    }
    if (sd_client == 0)
    {
    if (InitMySocket() )
    {// 101:网络错误
    iErrCode = 101;
    sd_client = 0;
    goto ERR_TAB;
    }
    } nSizeQ = sizeof(NET_QUERY_VLR)+4;
    nSizeR = sizeof(NET_QUERY_VLR_RESP)+4; int ret = srv_paraminfo(pSrvProc, 1, &bType, &cbMaxLen, &cbActualLen,
            NULL, &fNull);
    if (cbActualLen){
    int err; /////////////////////////////////
    nData.PacketLen = nSizeQ;
    nData.PacketType = NET_QUERY_VLR_PACKET;
    memcpy(szMsisdn, srv_paramdata(pSrvProc, 1), cbActualLen);
    nData.queryvlr.msisdn = _atoi64(szMsisdn);
    nData.queryvlr.imsi = 0;
    /////////////////////////////////
    InitCS();//初始化临界区
    EnterCriticalSection( &g_csec);//开始进行临界区
    bEnterCS = true;
    err = send (sd_client, (char *)&nData, nSizeQ, 0);
    if (err!=nSizeQ)
    {
    CloseMySocket();
    iErrCode = 102;
    goto ERR_TAB;
    } FD_ZERO( &fdset);
    FD_SET ( sd_client, &fdset); err = select(
    0,
    &fdset,
    NULL,
    NULL,
    &timeout);
    if( err != 1)
    nRet =   XP_ERROR;

    err = recv( sd_client, (char*)&rData, nSizeR, 0);
    if(err < nSizeR)
    {
    CloseMySocket();
    iErrCode = 103;
    goto ERR_TAB;
    }
    // 测试值
    //rData.queryvlrresp.imsi = 460001234567890;
    //rData.queryvlrresp.vlrdata.cgi = 1;
    //rData.queryvlrresp.vlrdata.time = time(NULL);
    //rData.queryvlrresp.vlrdata.updatetype=49;
    //////////////////////////////////
    _i64toa(rData.queryvlrresp.imsi,szImsi,10);
    struct tm *now;
    now = localtime( (long *)&rData.queryvlrresp.vlrdata.time);
    sprintf(sTime ,"%04d-%02d-%02d %02d:%02d:%02d",
    now->tm_year+1900,
    now->tm_mon + 1,
    now->tm_mday,
    now->tm_hour,
    now->tm_min,
    now->tm_sec);
    //转换成lac与ci
    iLac = rData.queryvlrresp.vlrdata.cgi>>16;
    iCi = rData.queryvlrresp.vlrdata.cgi & 0xffff;
    }
    else {
    return XP_ERROR;
    }ERR_TAB:
    if (bEnterCS) LeaveCriticalSection( &g_csec);//离开临界区,注意在return之前一定要调用 否则下一次永远不会进入临界区
    srv_paramsetoutput(pSrvProc,2,(BYTE *)szImsi,15,FALSE);
    srv_paramsetoutput(pSrvProc,3,(BYTE *)&(iLac),4,FALSE);
    srv_paramsetoutput(pSrvProc,4,(BYTE *)&(iCi),4,FALSE);
    srv_paramsetoutput(pSrvProc,5,(BYTE *)&(rData.queryvlrresp.vlrdata.updatetype),1,FALSE);
    srv_paramsetoutput(pSrvProc,6,(BYTE *)&sTime,19,FALSE);
    srv_paramsetoutput(pSrvProc,7,(BYTE *)&iErrCode,4,FALSE);
    srv_paramsetoutput(pSrvProc,8,(BYTE *)&(rData.queryvlrresp.vlrdata.sch),1,FALSE);
    return XP_NOERROR;}
      

  8.   

    1> 用vc6的Extend Stored Proc Wizard生成一个工程
    2> 在里面写好你的函数,编译
    3> 把生成好的dll拷贝至 MSSQL/Binn 目录
    4> 使用exec sp_addextendedproc 'xp_example', 'xp_example.dll'
       其中'xp_example'是你调用的存储过程名字,'xp_example.dll'是dll的名字
    5> 最后执行,exec xp_example
      

  9.   

    2000是支持这个功能的,用VC++写win32的dll即可以.
    用ole也可以,通过共享内存或命名管道调用.不过前提都是要声明一个系统扩展存储过程.你去SQL server 2000帮助那里找 系统扩展存储过程 的例子就明白了.