擴展 MySQL 8.4  /  向 MySQL 新增函數  /  新增原生函數

6.1 新增原生函數

若要新增原生 MySQL 函數,請使用此處描述的程序,此程序要求您使用原始碼發行版。您無法將原生函數新增至二進位發行版,因為必須修改 MySQL 原始碼並從修改後的原始碼編譯 MySQL。如果您遷移至另一個版本的 MySQL(例如,當發布新版本時),您必須使用新版本重複此程序。

如果原生函數將在會複製到複本的語句中引用,您必須確保每個複本也都有該函數可用。否則,當複本嘗試調用該函數時,複寫將在複本上失敗。

若要新增原生函數,請依照下列步驟修改 sql 目錄中的原始碼檔案

  1. item_create.cc 中為函數建立子類別

    • 如果函數採用固定數量的引數,請分別建立 Create_func_arg0Create_func_arg1Create_func_arg2Create_func_arg3 的子類別,具體取決於函數是否採用零個、一個、兩個或三個引數。例如,請參閱 Create_func_uuidCreate_func_absCreate_func_powCreate_func_lpad 類別。

    • 如果函數採用可變數量的引數,請建立 Create_native_func 的子類別。例如,請參閱 Create_func_concat

  2. 若要提供在 SQL 語句中可以引用函數的名稱,請在 item_create.cc 中透過在此陣列中新增一行來註冊名稱

    static Native_func_registry func_array[]

    您可以為同一個函數註冊多個名稱。例如,請參閱 "LCASE""LOWER" 的行,它們是 Create_func_lcase 的別名。

  3. item_func.h 中,根據您的函數是傳回數字還是字串,宣告一個繼承自 Item_num_funcItem_str_func 的類別。

  4. item_func.cc 中,根據您定義的是數字函數還是字串函數,新增下列其中一個宣告

    double   Item_func_newname::val()
    longlong Item_func_newname::val_int()
    String  *Item_func_newname::Str(String *str)

    如果您從任何標準項目(如 Item_num_func)繼承您的物件,您可能只需要定義這些函數中的一個,並讓父物件處理其他函數。例如,Item_str_func 類別定義了一個 val() 函數,該函數在 ::str() 傳回的值上執行 atof()

  5. 如果函數是不確定的,請在項目建構函式中包含下列語句,以指出不應快取函數結果

    current_thd->lex->safe_to_cache_query=0;

    如果給定引數的固定值,函數在不同的調用中可以傳回不同的結果,則該函數是不確定的。

  6. 您可能也應該定義下列物件函數

    void Item_func_newname::fix_length_and_dec()

    此函數應至少根據給定的引數計算 max_lengthmax_length 是函數可能傳回的最大字元數。如果主函數無法傳回 NULL 值,此函數也應設定 maybe_null = 0。該函數可以透過檢查引數的 maybe_null 變數來檢查任何函數引數是否可以傳回 NULL。請參閱 Item_func_mod::fix_length_and_dec,以瞭解如何執行此操作的典型範例。

所有函數都必須是執行緒安全的。換句話說,請勿在函數中使用任何全域或靜態變數,而不使用互斥鎖來保護它們。

如果您想要從 ::val()::val_int()::str() 傳回 NULL,您應該將 null_value 設定為 1 並傳回 0。

對於 ::str() 物件函數,這些額外注意事項適用

  • String *str 引數提供一個字串緩衝區,可用於保存結果。(有關 String 類型的更多資訊,請查看 sql_string.h 檔案。)

  • ::str() 函數應該傳回保存結果的字串,如果結果為 NULL,則傳回 (char*) 0

  • 除非絕對必要,否則目前所有字串函數都會盡力避免分配任何記憶體!