首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

C++Builder 開發 SQL Server 2000 擴展預存程序:以 MD5 加密為例

     編輯:關於C++

擴展預存程序 (XP) 簡介

SQL Server 擴展預存程序允許將 C/C++ 編寫的 DLL 函數註冊為 T-SQL 可呼叫的預存程序,突破 T-SQL 功能限制 (如檔案 I/O、加密演算法、硬體存取)。本文示範使用 C++Builder 6 開發計算 MD5 雜湊的 XP,並解決 BCB 自帶 OPENDS60.LIB 版本過舊不支援 SQL Server 2000 的問題。

開發環境與關鍵檔案

  • IDE:C++Builder 6.0
  • 專案類型:DLL (Dynamic Link Library)
  • 核心檔案:
    • xp_md5.bpr - 專案檔
    • OPENDS60.LIB - 更新版 SQL Server Open Data Services API 庫 (支援 SQL 2000)
    • md5.h / md5.cpp - Christophe Devine 公開版 MD5 實作 (無修改)
    • xp_md5_main.cpp - XP 進入點與參數處理 (參考 Vic Mackey 範例修改)

XP 函數簽名規範

每個 XP 必須匯出兩個標準函數:


// 1. 主處理函數
__declspec(dllexport) SRVRETCODE WINAPI xp_md5(SRV_PROC* pSrvProc)

// 2. 版本資訊函數 (必要)
__declspec(dllexport) ULONG WINAPI __GetXpVersion()
{
    return ODS_VERSION; // 定義於 srv.h
}

核心實作:xp_md5_main.cpp


#include           // SQL Server XP API
#include "md5.h"          // MD5 演算法

__declspec(dllexport) SRVRETCODE WINAPI xp_md5(SRV_PROC* srvproc)
{
    // 1. 參數檢查:預期 1 輸入參數 (字串), 1 輸出參數 (CHAR(32))
    if (srv_rpcparams(srvproc) != 2) {
        srv_sendmsg(srvproc, SRV_MSG_ERROR, "xp_md5 需要 2 參數: @input VARCHAR(8000), @output CHAR(32) OUTPUT", SRV_UNLIMITED);
        return SRV_FAIL;
    }

    // 2. 取得輸入字串 (參數 1)
    BYTE* pbInput = NULL;
    ULONG cbInput = 0;
    if (srv_paraminfo(srvproc, 1, NULL, &cbInput, NULL, &pbInput, NULL, NULL) != SUCCEED || cbInput == 0) {
        srv_sendmsg(srvproc, SRV_MSG_ERROR, "輸入字串不可為空", SRV_UNLIMITED);
        return SRV_FAIL;
    }
    // 注意:pbInput 指向資料緩衝區,長度為 cbInput,不一定以 null 結尾
    std::string input((char*)pbInput, cbInput);

    // 3. 計算 MD5
    md5_state_t state;
    md5_byte_t digest[16];
    md5_init(&state);
    md5_append(&state, (const md5_byte_t*)input.c_str(), input.length());
    md5_finish(&state, digest);

    // 4. 轉為 32 字元十六進位字串
    char hexOut[33];
    for (int i = 0; i < 16; ++i)
        sprintf(hexOut + i*2, "%02x", digest[i]);
    hexOut[32] = '\0';

    // 5. 設定輸出參數 (參數 2)
    // 先宣告參數型別為 CHAR(32) OUTPUT
    srv_paramsetoutput(srvproc, 2, (BYTE*)hexOut, 32, 0);

    return SRV_DONE;
}

專案設定關鍵點

設定項目值/說明
目標平台Win32 DLL
字元集多位元組字元集 (MBCS) 或 Unicode (需對應 T-SQL 型別)
連結庫OPENDS60.LIB (放置於專案目錄或庫路徑)
定義巨集WIN32;_WINDOWS;_MBCS (或 _UNICODE)
匯出函數.def 檔或 __declspec(dllexport) 確保 xp_md5、__GetXpVersion 匯出

SQL Server 部署與註冊

  1. 將編譯產生的 xp_md5.dll 複製至 SQL Server 伺服器目錄 (建議 C:\Program Files\Microsoft SQL Server\MSSQL\Binn)。
  2. 以 sa 登入 master 資料庫,執行:
    EXEC sp_addextendedproc 'xp_md5', 'xp_md5.dll'; -- 僅檔名即可,SQL 會在 Binn 目錄尋找
    
  3. 在使用者資料庫建立包裝函數支援 SELECT 呼叫:
    
    CREATE FUNCTION fn_md5 (@string VARCHAR(8000))
    RETURNS CHAR(32) AS
    BEGIN
        DECLARE @hash CHAR(32);
        EXEC master.dbo.xp_md5 @string, @hash OUTPUT;
        RETURN @hash;
    END;
    

使用範例


-- 直接呼叫 XP (需 master.dbo 前綴)
EXEC master.dbo.xp_md5 'Hello World!';
-- 結果: 86fb269d190d2c85f6e0468ceca42a20

-- 透過函數呼叫 (支援 SELECT)
SELECT dbo.fn_md5('Hello World!');
-- 可用於 WHERE, JOIN, UPDATE 等
UPDATE Users SET pwd_hash = dbo.fn_md5(new_pwd) WHERE uid = 100;

常見問題排查

  • 「找不到進入點」:檢查 __GetXpVersion 是否正確匯出並回傳 ODS_VERSION。
  • 參數亂碼/截斷:確認 srv_paraminfo 正確取得長度,Unicode 專案需轉換編碼。
  • 權限不足:呼叫者需具備 EXECUTE 權限於該 XP 或 public 角色授權。
  • 版本衝突:務必使用 SQL Server 2000 版 OPENDS60.LIB,BCB 自帶舊版僅支援 SQL 7.0。

參考資源

總結

透過 C++Builder 開發 SQL Server 擴展預存程序,可將高效能原生演算法 (如 MD5、AES、檔案操作) 直接整合進 T-SQL 工作流。關鍵在於使用正確版本的 OPENDS60.LIB、遵循 XP 函數簽名規範、妥善處理參數傳遞與記憶體管理。本文提供的 MD5 範例可直接應用於密碼雜湊、資料完整性驗證等實務場景。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved