首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

Windows 平台 MySQL UDF 開發完整教學:從 Visual C++ 專案建立到部署

     編輯:MySQL 資料庫相關知識

前言

MySQL UDF (User-Defined Function) 允許以 C/C++ 撰寫自訂函數,擴展 SQL 能力。Windows 平台需編譯為 .dll 動態連結庫。本文以 Visual Studio (VC++) 為例,完整示範建立、編譯、部署、註冊與測試流程。

環境需求

  • Windows 10/11 / Server 2016+
  • Visual Studio 2019/2022 (Community 版即可),安裝「使用 C++ 的桌面開發」工作負載。
  • MySQL Server 5.7/8.0 (已安裝並運行),包含 include 目錄與 lib 目錄。
  • MySQL 源碼包 (可選,參考 sql/udf_example.cc)。

步驟 1:建立 DLL 專案

  1. 開啟 VS → 建立新專案 → 動態連結庫 (DLL) → 專案名 my_udf。
  2. 專案屬性 → C/C++ → 一般 → 附加包含目錄 加入 MySQL include 路徑:
    C:\Program Files\MySQL\MySQL Server 8.0\include
  3. 專案屬性 → C/C++ → 前置處理器 → 前置處理器定義 加入:
    HAVE_DLOPEN=1;MYSQL_DYNAMIC_PLUGIN=1
  4. 專案屬性 → 連結器 → 輸入 → 模組定義檔 指定 my_udf.def (下一步建立)。
  5. 設定 執行階段程式庫:多執行緒 (/MT) 或 多執行緒 DLL (/MD),與 MySQL 編譯選項一致 (通常 /MD)。

步驟 2:撰寫 UDF 來源碼 (my_udf.cpp)

#include 
#include 
#include 
#include    // String 類別

extern "C" {
    // 函數宣告
    bool my_name_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
    void my_name_deinit(UDF_INIT *initid);
    char *my_name(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length, char *is_null, char *error);
}

// 初始化:檢查參數、分配記憶體
bool my_name_init(UDF_INIT *initid, UDF_ARGS *args, char *message) {
    if (args->arg_count != 1) {
        strcpy(message, "my_name() requires exactly one argument");
        return true;  // 回傳 true 表示錯誤
    }
    if (args->arg_type[0] != STRING_RESULT) {
        strcpy(message, "my_name() argument must be a string");
        return true;
    }
    // 可分配私有記憶體 initid->ptr = malloc(...)
    initid->maybe_null = 0;  // 回傳非 NULL
    initid->const_item = 0;  // 非常數
    return false;  // 成功
}

// 釋放資源
void my_name_deinit(UDF_INIT *initid) {
    // if (initid->ptr) free(initid->ptr);
}

// 主運算函數
char *my_name(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length, char *is_null, char *error) {
    char *input = args->args[0];
    unsigned long input_len = args->lengths[0];
    
    // 簡單範例:回傳 "Hello, <輸入>!"
    const char *prefix = "Hello, ";
    const char *suffix = "!";
    unsigned long need = strlen(prefix) + input_len + strlen(suffix) + 1;
    
    if (need > 255) {  // UDF 字串回傳上限 255 字節 (舊版限制),新版可更大
        *error = 1;
        *is_null = 1;
        return 0;
    }
    
    char *pos = result;
    memcpy(pos, prefix, strlen(prefix)); pos += strlen(prefix);
    memcpy(pos, input, input_len); pos += input_len;
    memcpy(pos, suffix, strlen(suffix)); pos += strlen(suffix);
    *pos = '\0';
    
    *length = (unsigned long)(pos - result);
    *is_null = 0;
    *error = 0;
    return result;
}

步驟 3:建立模組定義檔 (my_udf.def)

LIBRARY my_udf
EXPORTS
    my_name_init
    my_name_deinit
    my_name

確保匯出函數名稱與來源碼完全一致 (大小寫敏感)。

步驟 4:編譯建置

  1. 建置方案 → Release x64 (MySQL 64位元需 64位元 DLL)。
  2. 輸出:x64/Release/my_udf.dll。

步驟 5:部署 DLL

  1. 將 my_udf.dll 複製到 MySQL plugin_dir 目錄:
    SHOW VARIABLES LIKE 'plugin_dir'; → 通常為 C:\Program Files\MySQL\MySQL Server 8.0\lib\plugin\。
  2. 或放在系統 PATH 目錄 (如 C:\Windows\System32),但強烈建議放在 plugin_dir,便於管理與安全。

步驟 6:在 MySQL 註冊 UDF

mysql -u root -p
CREATE FUNCTION my_name RETURNS STRING SONAME 'my_udf.dll';
-- 成功顯示 Query OK, 0 rows affected
  • RETURNS STRING:回傳類型 (STRING/INTEGER/REAL/DECIMAL)。
  • SONAME:DLL 檔名 (不含路徑),MySQL 會在 plugin_dir 尋找。

步驟 7:測試 UDF

SELECT my_name('World');
-- 預期輸出:Hello, World!

SELECT my_name(column1) FROM test_table;

步驟 8:移除 UDF (如需更新)

DROP FUNCTION my_name;
-- 重新編譯 DLL 覆蓋後,需重啟 MySQL 或執行 FLUSH FUNCTIONS; (8.0.4+ 支援)
-- 8.0.4 前必須重啟 mysqld 才能重新載入 DLL

進階主題

彙總函數 (Aggregate UDF)

需實作 xxx_init, xxx_deinit, xxx_add, xxx_clear, xxx 五個函數,CREATE AGGREGATE FUNCTION 註冊。參考官方文件 sql/udf_example.cc 中的 sum_udf 範例。

除錯技巧

  • VS 專案屬性 → 偵錯 → 命令 設為 C:\Program Files\MySQL\MySQL Server 8.0\bin\mysqld.exe,命令引數 --console --defaults-file="C:\ProgramData\MySQL\MySQL Server 8.0\my.ini",直接附加偵錯。
  • UDF 內用 my_printf_error 或寫入檔案輸出除錯訊息。
  • 檢查 MySQL 錯誤日誌 (.err 檔) 中的 UDF 載入訊息。

常見錯誤與解決

錯誤原因解決
Can't open shared libraryDLL 路徑錯誤、架構不符 (32/64位)確認 plugin_dir、編譯 x64、DLL 置於正確目錄
Symbol not found.def 匯出名稱與來源碼不符、C++ 名稱修飾使用 extern "C"、.def 精確列出函數名
Function registration failed初始化函數回傳 true (錯誤)檢查 init 函數邏輯、參數驗證、message 緩衝區大小
Crash on call記憶體存取違規、緩衝區溢位嚴格檢查 args->lengths、result 緩衝區大小、使用 String 類別

結語

Windows 上開發 MySQL UDF 關鍵在於:正確的 VS 專案設定 (include、定義、.def、x64/Release)、extern "C" 防止名稱修飾、plugin_dir 部署、CREATE FUNCTION 註冊。掌握此流程,即可為 MySQL 注入高效能、領域特定的計算邏輯。

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