SQL Server 擴展預存程序允許將 C/C++ 編寫的 DLL 函數註冊為 T-SQL 可呼叫的預存程序,突破 T-SQL 功能限制 (如檔案 I/O、加密演算法、硬體存取)。本文示範使用 C++Builder 6 開發計算 MD5 雜湊的 XP,並解決 BCB 自帶 OPENDS60.LIB 版本過舊不支援 SQL Server 2000 的問題。
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 必須匯出兩個標準函數:
// 1. 主處理函數
__declspec(dllexport) SRVRETCODE WINAPI xp_md5(SRV_PROC* pSrvProc)
// 2. 版本資訊函數 (必要)
__declspec(dllexport) ULONG WINAPI __GetXpVersion()
{
return ODS_VERSION; // 定義於 srv.h
}
#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 匯出 |
xp_md5.dll 複製至 SQL Server 伺服器目錄 (建議 C:\Program Files\Microsoft SQL Server\MSSQL\Binn)。sa 登入 master 資料庫,執行:
EXEC sp_addextendedproc 'xp_md5', 'xp_md5.dll'; -- 僅檔名即可,SQL 會在 Binn 目錄尋找
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 角色授權。透過 C++Builder 開發 SQL Server 擴展預存程序,可將高效能原生演算法 (如 MD5、AES、檔案操作) 直接整合進 T-SQL 工作流。關鍵在於使用正確版本的 OPENDS60.LIB、遵循 XP 函數簽名規範、妥善處理參數傳遞與記憶體管理。本文提供的 MD5 範例可直接應用於密碼雜湊、資料完整性驗證等實務場景。