擴充 MySQL 8.4  /  在 MySQL 中新增函數  /  新增可載入函數

6.2 新增可載入函數

MySQL 可載入函數的介面提供下列特性和功能

  • 函數可以傳回字串、整數或實數值,並且可以接受這些相同類型的引數。

  • 您可以定義一次操作單列的簡單函數,或操作多列群組的彙總函數。

  • 向函數提供資訊,讓它們能夠檢查傳遞給它們的引數數量、類型和名稱。

  • 您可以告知 MySQL 在將引數傳遞給函數之前,將引數強制轉換為給定的類型。

  • 您可以指出函數傳回 NULL 或發生錯誤。

為了使可載入函數機制能夠運作,函數必須以 C++ 撰寫,並且您的作業系統必須支援動態載入。MySQL 原始碼發行版包含一個檔案 sql/udf_example.cc,其中定義了五個可載入函數介面函數。請查閱此檔案,以了解可載入函數呼叫慣例的運作方式。include/mysql_com.h 標頭檔案定義了與可載入函數相關的符號和資料結構,雖然您不需要直接包含此標頭檔案,但 mysql.h 會包含它。

可載入函數包含成為執行中伺服器一部分的程式碼,因此當您撰寫可載入函數時,您會受到適用於撰寫伺服器程式碼的任何及所有限制。例如,如果您嘗試使用 libstdc++ 程式庫中的函數,您可能會遇到問題。這些限制可能會在伺服器的未來版本中變更,因此伺服器升級可能會需要修改原本為較舊伺服器撰寫的可載入函數。有關這些限制的資訊,請參閱MySQL 原始碼組態選項處理編譯 MySQL 的問題

為了能夠使用可載入函數,您必須動態連結 mysqld。如果您想要使用需要存取 mysqld 中符號的可載入函數 (例如,sql/udf_example.cc 中的 metaphone 函數使用 default_charset_info),您必須使用 -rdynamic 連結程式 (請參閱 man dlopen)。

對於您想要在 SQL 陳述式中使用的每個函數,您應該定義對應的 C++ 函數。在以下討論中,名稱 xxx 用於範例函數名稱。為了區分 SQL 和 C++ 的用法,XXX() (大寫) 表示 SQL 函數呼叫,而 xxx() (小寫) 表示 C++ 函數呼叫。

注意

使用 C++ 時,請將您的 C 函數封裝在此結構內

extern "C" { ... }

這可確保您的 C++ 函數名稱在完成的函數中保持可讀性。

可載入函數介面函數

下列清單說明您為了實作名為 XXX() 的函數介面而撰寫的 C++ 函數。主要函數 xxx() 是必要的。此外,可載入函數至少需要此處描述的其他函數之一,原因在可載入函數安全預防措施中討論。

  • xxx()

    主要函數。這是計算函數結果的地方。SQL 函數資料類型與您的 C++ 函數傳回類型之間的對應關係如下所示。

    SQL 類型 C++ 類型
    STRING char *
    INTEGER long long
    REAL double

    也可以宣告 DECIMAL 函數,但該值會以字串形式傳回,因此您應該像撰寫 STRING 函數一樣撰寫函數。ROW 函數未實作。

  • xxx_init()

    xxx() 的初始化函數。如果存在,可用於下列目的

    • 檢查 XXX() 的引數數量。

    • 驗證引數是否為必要的類型,或者,告知 MySQL 在呼叫主要函數時將引數強制轉換為必要的類型。

    • 配置主要函數所需的任何記憶體。

    • 指定結果的最大長度。

    • 指定 (針對 REAL 函數) 結果中的最大小數位數。

    • 指定結果是否可以是 NULL

  • xxx_deinit()

    xxx() 的取消初始化函數。如果存在,它應該釋放初始化函數所配置的任何記憶體。

當 SQL 陳述式調用 XXX() 時,MySQL 會呼叫初始化函數 xxx_init() 以便讓它執行任何必要的設定,例如引數檢查或記憶體配置。如果 xxx_init() 傳回錯誤,MySQL 會中止 SQL 陳述式並顯示錯誤訊息,且不會呼叫主要或取消初始化函數。否則,MySQL 會針對每個資料列呼叫主要函數 xxx() 一次。在所有資料列都已處理完畢後,MySQL 會呼叫取消初始化函數 xxx_deinit(),以便讓它執行任何必要的清除作業。

對於運作方式與 SUM() 類似的彙總函數,您也必須提供下列函數

  • xxx_clear()

    重設目前的彙總值,但不要將引數插入為新群組的初始彙總值。

  • xxx_add()

    將引數新增至目前的彙總值。

MySQL 會依以下方式處理可載入彙總函數

  1. 呼叫 xxx_init() 以便讓彙總函數配置任何它需要用於儲存結果的記憶體。

  2. 根據 GROUP BY 運算式排序表格。

  3. 針對每個新群組中的第一個資料列呼叫 xxx_clear()

  4. 針對屬於同一個群組的每個資料列呼叫 xxx_add()

  5. 當群組變更或在最後一個資料列處理完畢後,呼叫 xxx() 以取得彙總的結果。

  6. 重複步驟 3 到 5,直到處理完所有資料列

  7. 呼叫 xxx_deinit() 以便讓函數釋放它所配置的任何記憶體。

所有函數都必須是執行緒安全的。這不僅包括主要函數,還包括初始化和取消初始化函數,以及彙總函數所需的額外函數。此要求的後果是您不得配置任何會變更的全域或靜態變數!如果您需要記憶體,您必須在 xxx_init() 中配置記憶體,並在 xxx_deinit() 中釋放記憶體。

簡單函數的可載入函數呼叫順序

本節說明您為了建立簡單的可載入函數而必須定義的不同介面函數。有關 MySQL 呼叫這些函數的順序的資訊,請參閱可載入函數介面函數

主要 xxx() 函數應該如本節所示宣告。請注意,傳回類型和參數會有所不同,具體取決於您是否在 CREATE FUNCTION 陳述式中宣告 SQL 函數 XXX() 以傳回 STRINGINTEGERREAL

針對 STRING 函數

char *xxx(UDF_INIT *initid, UDF_ARGS *args,
          char *result, unsigned long *length,
          char *is_null, char *error);

針對 INTEGER 函數

long long xxx(UDF_INIT *initid, UDF_ARGS *args,
              char *is_null, char *error);

針對 REAL 函數

double xxx(UDF_INIT *initid, UDF_ARGS *args,
              char *is_null, char *error);

DECIMAL 函數會傳回字串值,並且宣告方式與 STRING 函數相同。ROW 函數未實作。

像這樣宣告初始化和取消初始化函數

bool xxx_init(UDF_INIT *initid, UDF_ARGS *args, char *message);

void xxx_deinit(UDF_INIT *initid);

initid 參數會傳遞給所有三個函式。它指向一個 UDF_INIT 結構,該結構用於在函式之間傳遞資訊。UDF_INIT 結構的成員如下。初始化函式應填寫任何它希望更改的成員。(若要使用成員的預設值,請保持不變。)

  • bool maybe_null

    如果 xxx() 可能傳回 NULL,則 xxx_init() 應將 maybe_null 設定為 1。如果任何引數宣告為 maybe_null,則預設值為 1

  • unsigned int decimals

    小數點右側的小數位數。預設值是傳遞給主函式的引數中最大的小數位數。例如,如果將 1.341.3451.3 傳遞給函式,則預設值為 3,因為 1.345 有 3 個小數位數。

    對於沒有固定小數位數的引數,decimals 值設定為 31,這比 DECIMALFLOATDOUBLE 資料類型允許的最大小數位數多 1。此值在 mysql_com.h 標頭檔中以常數 NOT_FIXED_DEC 提供。

    在下列情況下,引數會使用 31 的 decimals 值:例如,宣告為沒有明確小數位數的 FLOATDOUBLE 欄位(例如,FLOAT 而不是 FLOAT(10,3)),以及浮點常數(例如 1345E-3)。它也適用於字串和其他可能在函式內轉換為數值形式的非數字引數。

    decimals 成員初始化的值僅為預設值。它可以在函式內進行更改,以反映實際執行的計算。預設值的決定方式是使用引數中最大的小數位數。如果即使只有一個引數的小數位數為 NOT_FIXED_DEC,則該值會用於 decimals

  • unsigned int max_length

    結果的最大長度。預設的 max_length 值會根據函式的結果類型而有所不同。對於字串函式,預設值是最長引數的長度。對於整數函式,預設值為 21 位數。對於實數函式,預設值為 13 加上 initid->decimals 指示的小數位數。(對於數值函式,長度包括任何符號或小數點字元。)

    如果您想要傳回 blob 值,您可以將 max_length 設定為 65KB 或 16MB。此記憶體不會被配置,但是該值會用於決定是否需要暫時儲存資料時所使用的資料類型。

  • char *ptr

    函式可以將此指標用於自己的目的。例如,函式可以使用 initid->ptr 來在彼此之間傳遞已配置的記憶體。xxx_init() 應該配置記憶體並將其指派給此指標。

    initid->ptr = allocated_memory;

    xxx()xxx_deinit() 中,請參閱 initid->ptr 以使用或解除配置記憶體。

  • bool const_item

    如果 xxx() 總是傳回相同的值,則 xxx_init() 應將 const_item 設定為 1,否則設定為 0

可載入函式呼叫序列(適用於彙總函式)

本節描述當您建立彙總可載入函式時需要定義的不同介面函式。如需有關 MySQL 呼叫這些函式的順序的資訊,請參閱可載入函式介面函式

  • xxx_reset()

    當 MySQL 在新的群組中找到第一列時,會呼叫此函式。它應重設任何內部摘要變數,然後使用給定的 UDF_ARGS 引數作為群組內部摘要值中的第一個值。將 xxx_reset() 宣告如下:

    void xxx_reset(UDF_INIT *initid, UDF_ARGS *args,
                   char *is_null, char *error);

    在 MySQL 8.4 中,不需要或不使用 xxx_reset(),在其中可載入函式介面改用 xxx_clear()。但是,如果您希望您的函式能夠與舊版本的伺服器搭配使用,則可以定義 xxx_reset()xxx_clear()。(如果您同時包含這兩個函式,在許多情況下,可以透過呼叫 xxx_clear() 來重設所有變數,然後呼叫 xxx_add() 來將 UDF_ARGS 引數作為群組中的第一個值來在內部實作 xxx_reset() 函式。)

  • xxx_clear()

    當 MySQL 需要重設摘要結果時,會呼叫此函式。它會在每個新群組的開頭呼叫,但也可以呼叫以重設沒有相符列的查詢的值。將 xxx_clear() 宣告如下:

    void xxx_clear(UDF_INIT *initid, char *is_null, char *error);

    在呼叫 xxx_clear() 之前,會將 is_null 設定為指向 CHAR(0)

    如果發生錯誤,您可以將值儲存在 error 引數指向的變數中。error 指向單一位元組變數,而不是字串緩衝區。

    MySQL 8.4 需要 xxx_clear()

  • xxx_add()

    對於屬於同一群組的所有列,都會呼叫此函式。您應該使用它將 UDF_ARGS 引數中的值新增至內部摘要變數。

    void xxx_add(UDF_INIT *initid, UDF_ARGS *args,
                 char *is_null, char *error);

彙總可載入函式的 xxx() 函式應該以與非彙總可載入函式相同的方式宣告。請參閱簡單函式的可載入函式呼叫序列

對於彙總可載入函式,MySQL 會在處理完群組中的所有列之後呼叫 xxx() 函式。您通常不應在這裡存取其 UDF_ARGS 引數,而應根據您的內部摘要變數傳回值。

xxx() 中的傳回值處理應以與非彙總可載入函式相同的方式完成。請參閱可載入函式傳回值和錯誤處理

xxx_reset()xxx_add() 函式會以與非彙總 UDF 的函式相同的方式處理其 UDF_ARGS 引數。請參閱可載入函式引數處理

is_nullerror 的指標引數對於 xxx_reset()xxx_clear()xxx_add()xxx() 的所有呼叫都相同。您可以使用它來記住您是否收到錯誤,或者 xxx() 函式是否應傳回 NULL。您不應將字串儲存到 *error 中!error 指向單一位元組變數,而不是字串緩衝區。

*is_null 會針對每個群組重設(在呼叫 xxx_clear() 之前)。*error 永遠不會重設。

如果在 xxx() 傳回時設定了 *is_null*error,則 MySQL 會傳回 NULL 作為群組函式的結果。

可載入函式引數處理

args 參數指向一個 UDF_ARGS 結構,其中包含此處列出的成員:

  • unsigned int arg_count

    引數的數量。如果您要求函式在呼叫時帶有特定數量的引數,請在初始化函式中檢查此值。例如:

    if (args->arg_count != 2)
    {
        strcpy(message,"XXX() requires two arguments");
        return 1;
    }

    對於其他屬於陣列的 UDF_ARGS 成員值,陣列參考是以零為基礎。也就是說,使用從 0 到 args->arg_count - 1 的索引值來參考陣列成員。

  • enum Item_result *arg_type

    指向陣列的指標,其中包含每個引數的類型。可能的類型值為 STRING_RESULTINT_RESULTREAL_RESULTDECIMAL_RESULT

    為了確保引數為給定類型,並且在引數不屬於給定類型時傳回錯誤,請在初始化函式中檢查 arg_type 陣列。例如:

    if (args->arg_type[0] != STRING_RESULT ||
        args->arg_type[1] != INT_RESULT)
    {
        strcpy(message,"XXX() requires a string and an integer");
        return 1;
    }

    類型為 DECIMAL_RESULT 的引數會以字串的形式傳遞,因此您會以與 STRING_RESULT 值相同的方式處理它們。

    除了要求函式的引數為特定類型之外,您還可以使用初始化函式將 arg_type 元素設定為您想要的類型。這會導致 MySQL 在每次呼叫 xxx() 時強制將引數轉換為這些類型。例如,若要指定前兩個引數應該分別強制轉換為字串和整數,請在 xxx_init() 中執行此操作:

    args->arg_type[0] = STRING_RESULT;
    args->arg_type[1] = INT_RESULT;

    精確值的小數引數,例如 1.3DECIMAL 欄位值,會以 DECIMAL_RESULT 的類型傳遞。但是,這些值會以字串形式傳遞。若要接收數字,請使用初始化函式來指定應將引數強制轉換為 REAL_RESULT 值:

    args->arg_type[2] = REAL_RESULT;
  • char **args

    args->args 會將有關傳遞給函式的引數的一般性質的資訊傳達給初始化函式。對於常數引數 iargs->args[i] 指向引數值。(請參閱稍後有關如何正確存取值的說明。)對於非常數引數,args->args[i]0。常數引數是只使用常數的運算式,例如 34*7-2SIN(3.14)。非常數引數是指可能會逐列變更的值,例如欄位名稱或呼叫時帶有非常數引數的函式。

    對於主函式的每次調用,args->args 都會包含針對目前正在處理的列所傳遞的實際引數。

    如果引數 i 表示 NULL,則 args->args[i] 為空指標 (0)。如果引數不是 NULL,函式可以如下方式參考它:

    • 類型為 STRING_RESULT 的引數會以字串指標加上長度的方式給出,以便能夠處理二進位資料或任意長度的資料。字串內容可以作為 args->args[i] 使用,字串長度為 args->lengths[i]。請勿假設字串是以 null 結尾。

      如需有關字串引數的其他資訊,請參閱可載入函式字元集處理

    • 對於類型為 INT_RESULT 的引數,您必須將 args->args[i] 強制轉換為 long long 值:

      long long int_val;
      int_val = *((long long*) args->args[i]);
    • 對於類型為 REAL_RESULT 的引數,您必須將 args->args[i] 強制轉換為 double 值:

      double    real_val;
      real_val = *((double*) args->args[i]);
    • 對於類型為 DECIMAL_RESULT 的引數,該值會以字串形式傳遞,應像 STRING_RESULT 值一樣處理。

    • ROW_RESULT 引數尚未實作。

  • unsigned long *lengths

    對於初始化函數,lengths 陣列指示每個引數的最大字串長度。您不應變更這些值。對於主函數的每次調用,lengths 包含目前正在處理的列所傳遞的任何字串引數的實際長度。對於 INT_RESULTREAL_RESULT 類型的引數,lengths 仍包含引數的最大長度(如同初始化函數)。

  • char *maybe_null

    對於初始化函數,maybe_null 陣列指示每個引數的值是否可能為 null(如果否則為 0,是則為 1)。

  • char **attributes

    args->attributes 傳達關於函數引數名稱的資訊。對於引數 i,屬性名稱以字串形式存在於 args->attributes[i] 中,而屬性長度則為 args->attribute_lengths[i]。請勿假設字串是以 null 終止的。

    預設情況下,函數引數的名稱是用於指定引數的表示式文字。對於可載入的函數,引數也可以選擇性地包含 [AS] alias_name 子句,在這種情況下,引數名稱是 alias_name。因此,每個引數的 attributes 值取決於是否給定了別名。

    假設可載入的函數 my_udf() 的調用方式如下:

    SELECT my_udf(expr1, expr2 AS alias1, expr3 alias2);

    在這種情況下,attributesattribute_lengths 陣列將具有以下值:

    args->attributes[0] = "expr1"
    args->attribute_lengths[0] = 5
    
    args->attributes[1] = "alias1"
    args->attribute_lengths[1] = 6
    
    args->attributes[2] = "alias2"
    args->attribute_lengths[2] = 6
  • unsigned long *attribute_lengths

    attribute_lengths 陣列指示每個引數名稱的長度。

可載入函數的回傳值與錯誤處理

如果沒有發生錯誤,初始化函數應回傳 0,否則回傳 1。如果發生錯誤,xxx_init() 應在 message 參數中儲存以 null 終止的錯誤訊息。此訊息會回傳給客戶端。訊息緩衝區的長度為 MYSQL_ERRMSG_SIZE 個字元。請嘗試將訊息保持在 80 個字元以下,以便能夠符合標準終端機螢幕的寬度。

主函數 xxx() 的回傳值是函數值,適用於 long longdouble 函數。字串函數應回傳指向結果的指標,並將 *length 設定為回傳值的長度(以位元組為單位)。例如:

memcpy(result, "result string", 13);
*length = 13;

MySQL 會使用 result 參數將緩衝區傳遞給 xxx() 函數。這個緩衝區的長度足以容納 255 個字元,這可以是多位元組字元。xxx() 函數可以在此緩衝區中儲存結果(如果適用),在這種情況下,回傳值應該是指向該緩衝區的指標。如果函數將結果儲存在不同的緩衝區中,則應回傳指向該緩衝區的指標。

如果您的字串函數沒有使用所提供的緩衝區(例如,如果它需要回傳長度超過 255 個字元的字串),您必須在 xxx_init() 函數或 xxx() 函數中使用 malloc() 為您自己的緩衝區配置空間,並在 xxx_deinit() 函數中釋放它。您可以將配置的記憶體儲存在 UDF_INIT 結構中的 ptr 插槽中,以便將來 xxx() 呼叫時重複使用。請參閱簡單函數的可載入函數呼叫序列

如需有關字串引數的其他資訊,請參閱可載入函式字元集處理

若要指示主函數中的回傳值為 NULL,請將 *is_null 設定為 1

*is_null = 1;

若要指示主函數中的錯誤回傳,請將 *error 設定為 1

*error = 1;

如果 xxx() 對於任何列將 *error 設定為 1,則函數值對於目前列以及在調用 XXX() 的陳述式中處理的任何後續列都是 NULL。(不會針對後續列呼叫 xxx())。

可載入函數的字元集處理

依預設,可載入函數不會考慮字串引數或回傳值的字元集或校對。實際上,字串引數和回傳值會被視為二進位字串,這表示只有包含單一位元組字元的字串引數才能可靠地處理。

在 MySQL 8.4 中,用於撰寫可載入函數的介面使可載入函數能夠判斷字串引數的字元集和校對,並回傳具有特定字元集和校對的字串。這些功能對於可載入函數的撰寫者而言是可選的,他們可以根據需要加以利用。

在 MySQL 發佈的可載入函數中,與以下功能和擴充功能相關聯的函數會利用這些字元集功能:MySQL Enterprise Audit、MySQL Enterprise Firewall、MySQL Enterprise Data Masking and De-Identification、MySQL Keyring(僅限通用金鑰環可載入函數,而非特定於特定金鑰環外掛程式的函數)和群組複寫。這僅適用於有意義的情況。例如,回傳加密資料的可載入函數本來就要回傳二進位字串,而不是字元字串。

可載入函數的字元集功能是使用 mysql_udf_metadata 伺服器元件服務來實作的。如需此服務的相關資訊,請參閱 MySQL 伺服器 Doxygen 文件,網址為 https://mysqldev.dev.org.tw/doc/index-other.html(搜尋 s_mysql_mysql_udf_metadataudf_metadata_imp)。MySQL Keyring 可載入函數的原始碼在社群原始碼發佈中提供,可作為想要修改其自己的可載入函數以支援字元集的第三方可載入函數撰寫者的範例進行檢查。

如果可載入函數接受字串引數或回傳字串值,並修改為支援字元集,則適用以下相容性注意事項:

  • 關於傳遞給可載入函數的引數,應用程式將會繼續運作,因為該函數現在能夠處理任何字元集(包括二進位字串)中的字串引數。

  • 如果可載入函數要回傳與其引數字元集不同的字元集中的字串結果,則該函數必須在內部執行字元集轉換。例如,如果函數接受 latin1 引數但回傳 utf8mb4 結果,則會發生這種情況。

可載入函數的編譯與安裝

實作可載入函數的檔案必須在執行伺服器的主機上編譯和安裝。此處描述的流程適用於 MySQL 原始碼發佈中包含的範例可載入函數檔案 sql/udf_example.cc。如需有關可載入函數安裝的其他資訊,請參閱安裝和解除安裝可載入函數

如果將在會複寫到複本的陳述式中引用可載入函數,則您必須確保每個複本也都具有可用的函數。否則,當複本嘗試調用該函數時,複寫會在複本上失敗。

udf_example.cc 檔案包含以下函數:

  • metaphon() 回傳字串引數的 metaphon 字串。這有點像 soundex 字串,但更適合英語。

  • myfunc_double() 回傳其引數字元 ASCII 值的總和,除以其引數的長度總和。

  • myfunc_int() 回傳其引數的長度總和。

  • sequence([const int]) 回傳從給定數字開始的序列,如果未給定數字,則回傳 1。

  • lookup() 回傳主機名稱的 IP 位址。

  • reverse_lookup() 回傳 IP 位址的主機名稱。可以使用 'xxx.xxx.xxx.xxx' 形式的單一字串引數或使用四個數字來調用該函數。

  • avgcost() 回傳平均成本。這是一個彙總函數。

在 Unix 和類似 Unix 的系統上,請使用以下程序編譯可載入函數:

應將動態載入檔案編譯為可共享的程式庫檔案,並使用類似以下的命令:

gcc -shared -o udf_example.so udf_example.cc

如果您將 gccCMake 搭配使用(這是 MySQL 本身的組態方式),您應該可以使用更簡單的命令來建立 udf_example.so

make udf_example

編譯包含可載入函數的共享物件後,您必須安裝它並告知 MySQL。直接使用 gccudf_example.cc 編譯共享物件會產生名為 udf_example.so 的檔案。將共享物件複製到伺服器的外掛程式目錄,並將其命名為 udf_example.so。此目錄由 plugin_dir 系統變數的值指定。

在某些系統上,除非共享物件的名稱以 lib 開頭,否則會設定動態連結器的 ldconfig 程式無法辨識。在這種情況下,您應將 udf_example.so 之類的檔案重新命名為 libudf_example.so

在 Windows 上,請使用以下程序編譯可載入函數:

  1. 取得 MySQL 原始碼發佈。請參閱如何取得 MySQL

  2. 如有必要,請從 http://www.cmake.org 取得 CMake 建置公用程式。(需要 2.6 版或更新版本)。

  3. 在原始碼樹狀結構中,在 sql 目錄中尋找名為 udf_example.defudf_example.cc 的檔案。將這兩個檔案從此目錄複製到您的工作目錄。

  4. 使用以下內容建立 CMake makefile (CMakeLists.txt):

    PROJECT(udf_example)
    
    # Path for MySQL include directory
    INCLUDE_DIRECTORIES("c:/mysql/include")
    
    ADD_DEFINITIONS("-DHAVE_DLOPEN")
    ADD_LIBRARY(udf_example MODULE udf_example.cc udf_example.def)
    TARGET_LINK_LIBRARIES(udf_example wsock32)
  5. 建立 VC 專案與解決方案檔案,並替換成適當的 generator

    cmake -G "generator"

    調用 cmake --help 會顯示有效的產生器清單。

  6. 建立 udf_example.dll

    devenv udf_example.sln /build Release

在所有平台上,將共享程式庫檔案複製到 plugin_dir 目錄後,使用以下敘述通知 mysqld 關於新的函數。檔案名稱的後綴會因平台而異(例如,Unix 和類 Unix 系統為 .so,Windows 為 .dll),因此請根據您的平台調整 .so 後綴。

CREATE FUNCTION metaphon RETURNS STRING
  SONAME 'udf_example.so';
CREATE FUNCTION myfunc_double RETURNS REAL
  SONAME 'udf_example.so';
CREATE FUNCTION myfunc_int RETURNS INTEGER
  SONAME 'udf_example.so';
CREATE FUNCTION sequence RETURNS INTEGER
  SONAME 'udf_example.so';
CREATE FUNCTION lookup RETURNS STRING
  SONAME 'udf_example.so';
CREATE FUNCTION reverse_lookup RETURNS STRING
  SONAME 'udf_example.so';
CREATE AGGREGATE FUNCTION avgcost RETURNS REAL
  SONAME 'udf_example.so';

一旦安裝完成,函數會保持安裝狀態直到被解除安裝。

若要移除函數,請使用 DROP FUNCTION

DROP FUNCTION metaphon;
DROP FUNCTION myfunc_double;
DROP FUNCTION myfunc_int;
DROP FUNCTION sequence;
DROP FUNCTION lookup;
DROP FUNCTION reverse_lookup;
DROP FUNCTION avgcost;

CREATE FUNCTIONDROP FUNCTION 敘述會更新作為可載入函數註冊表的 mysql.func 系統表格。這些敘述分別需要針對 mysql 資料庫的 INSERTDELETE 權限。

在正常的啟動順序期間,伺服器會載入註冊在 mysql.func 表格中的函數。如果伺服器啟動時使用了 --skip-grant-tables 選項,則表格中註冊的函數不會載入且不可用。

可載入函數安全性注意事項

MySQL 採取多項措施來防止濫用可載入函數。

可載入函數程式庫檔案不能放置在任意目錄中。它們必須位於伺服器的外掛程式目錄中。此目錄由 plugin_dir 系統變數的值指定。

若要使用 CREATE FUNCTIONDROP FUNCTION,您必須分別擁有針對 mysql 資料庫的 INSERTDELETE 權限。這是必要的,因為這些敘述會從 mysql.func 表格新增和刪除列。

除了對應於主要 xxx() 函數的 xxx 符號之外,可載入函數應該至少定義一個符號。這些輔助符號對應於 xxx_init()xxx_deinit()xxx_reset()xxx_clear()xxx_add() 函數。mysqld 也支援一個 --allow-suspicious-udfs 選項,該選項控制是否可以載入僅具有 xxx 符號的可載入函數。預設情況下,此選項已停用,以防止嘗試從包含非合法可載入函數的共享程式庫檔案載入函數。如果您有僅包含 xxx 符號且無法重新編譯以包含輔助符號的較舊可載入函數,則可能需要指定 --allow-suspicious-udfs 選項。否則,您應該避免啟用它。