小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

MySQL :: MySQL 5.1參考手冊 :: 27. 擴展MySQL

 322yangxinxing 2012-02-15

27.2. 為MySQL添加新函數(shù)

有兩個途徑來為MySQL添加新函數(shù):

  • 你可以通過自行醫(yī)函數(shù)接口 (UDF)來添加函數(shù)。自定義函數(shù)被編譯為目標文件,然后用CREATE FUNCTION 和DROP FUNCTION 聲明動態(tài)地添入到服務(wù)器中及從服務(wù)器中移出。參閱27.2.2節(jié),“CREATE FUNCTION/DROP FUNCTION 語法”

  • 你可以將函數(shù)添加為MySQL固有(內(nèi)建)函數(shù)。固有函數(shù)被編譯進mysqld服務(wù)器中,成為永久可用的。

每種途徑都有其優(yōu)點和缺點:

  • 如果你編寫自定義函數(shù),你除了安裝服務(wù)器本身之外還要安裝目標文件。如果將你的函數(shù)編譯進服務(wù)器中,你就不需要這么做了。

  • 你可以給二進制版本的MySQL分發(fā)版添加UDF。固有函數(shù)需要你去修正源碼分發(fā)版。.

  • 如果你升級你的MySQL分發(fā)版,你可以繼續(xù)使用先前安裝了的UDF, 除非你升級到一個UDF接口改變了的新版本。對固有函數(shù)而言,每次升級你都必須重復(fù)一次修正。

無論你使用哪種方法去添加新函數(shù),它們都可以被SQL聲明調(diào)用,就像 ABS() 或 SOUNDEX()這樣的固有函數(shù)一樣。

另一個添加函數(shù)的方法時創(chuàng)建存儲函數(shù)。這些函數(shù)時用SQL聲明編寫的,而不是編譯目標代碼。編寫存儲函數(shù)的語法在第20章:存儲程序和函數(shù) 中描述。

下面的小節(jié)描述UDF接口的特性,給出編寫UDF的指令,并討論MySQL為防止UDF被誤用而采取的安全預(yù)防措施。

給出源代碼的例子來說明如何編寫UDF,看一看MySQL源碼分發(fā)版中提供的sql/udf_example.cc 文件。

27.2.1. 自定義函數(shù)接口的特性

MySQL自定義函數(shù)接口有如下特性和功能:

  • 函數(shù)能分÷返回字符串,整數(shù)或?qū)崝?shù)。

  • 你可以定義一次作用于一行的簡單函數(shù),或作用于多行的組的集合函數(shù)。

  • 提供給函數(shù)的信息使得函數(shù)可以檢查傳遞給它們的參量的數(shù)目和類型。

  • 你可以讓MySQL在將某參量傳遞給函數(shù)之前強制其為某一類型。

  • 你可以表示函數(shù)返回NULL 或發(fā)生錯誤。

27.2.2. CREATE FUNCTION/DROP FUNCTION 語法

CREATE [AGGREGATE] FUNCTION function_name RETURNS {STRING|INTEGER|REAL}
       SONAME shared_library_name

DROP FUNCTION function_name

一個自定義函數(shù) (UDF)就是用一個象ABS() 或 CONCAT()這樣的固有(內(nèi)建)函數(shù)一樣作用的新函數(shù)去擴展MySQL。

function_name 是 用在SQL聲明中以備調(diào)用的函數(shù)名字。RETURNS 子句說明函數(shù)返回值的類型。 shared_library_name 是共享目標文件的基本名,共享目標文件含有實現(xiàn)函數(shù)的代碼。該文件必須位于一個能被你系統(tǒng)的動態(tài)連接者搜索的目錄里。

你必須有mysql 數(shù)據(jù)庫的INSERT 權(quán)限才能創(chuàng)建一個函數(shù),你必須有mysql 數(shù)據(jù)庫的DELETE權(quán)限才能撤銷一個函數(shù)。這是因為CREATE FUNCTION 往記錄函數(shù)名字,類型和共享名的mysql.func系統(tǒng)表里添加了一行,而DROP FUNCTION則是從表中刪掉這一行。如果你沒有這個系統(tǒng)表,你應(yīng)該運行mysql_fix_privilege_tables腳本來創(chuàng)建一個。請參閱2.10.2節(jié),“升級授權(quán)表”。

一個有效的函數(shù)是一個用CREATE FUNCTION加載且沒有用DROP FUNCTION移除的函數(shù)。每次服務(wù)器啟動的時候會重新加載所有有效函數(shù),除非你使用--skip-grant-tables參數(shù)啟動mysqld。在這種情況下, 將跳過UDF的初始化,UDF不可用。

要了解編寫自定義函數(shù)的說明,請參閱27.2.3節(jié),“添加新的自定義函數(shù)”。要使得UDF機制能夠起作用,必須使用C或者C++編寫函數(shù),你的系統(tǒng)必須支持動態(tài)加載,而且你必須是動態(tài)編譯的mysqld(非靜態(tài))。

一個AGGREGATE函數(shù)就像一個MySQL固有的集合(總和)函數(shù)一樣起作用,比如,SUM或COUNT()函數(shù)。要使得AGGREGATE 起作用,你的mysql.func表必須包括一個type列。如果你的mysql.func表沒有這一 列,你應(yīng)該運行mysql_fix_privilege_tables腳本來創(chuàng)建此 列。

27.2.3. 添加新的自定義函數(shù)

要使得UDF機制能夠起作用,必須使用C或者C++編寫函數(shù),你的系統(tǒng)必須支持動態(tài)加載。MySQL 源碼分發(fā)版包括一個sql/udf_example.cc 文件,此文件定義了5個新函數(shù)??梢詤⒖歼@個文件,看UDF是如何調(diào)用常規(guī)工作。

為了能使用UDF,你需要動態(tài)鏈接mysqld。不要配置MySQL使用--with-mysqld-ldflags=-all-static參數(shù)。如果你想使用一個需要從mysqld 訪問符號的UDF(例如在使用default_charset_info的sql/udf_example.cc文件中的metaphone函數(shù)),你必須使用-rdynamic參數(shù)來鏈接程序(參閱man dlopen)。如果你計劃使用UDF, 一個經(jīng)驗法則就是,用with-mysqld-ldflags=-rdynamic設(shè)定MySQL,除非你有很好的理由不去這么做。

如果你使用的是預(yù)編譯分發(fā)版的MySQL, 請使用MySQL-Max,其中含有一個動態(tài)鏈接了的服務(wù)器,它可以支持動態(tài)加載。

對于每個你想要使用在SQL聲明中的函數(shù),你應(yīng)該定義相應(yīng)的C (或 C++)函數(shù)。在下面的討論中,xxx用來表示范例函數(shù)的名字,為了區(qū)分使用SQL還是C/C++,xxx()(上標)表示SQL函數(shù)調(diào)用,xxx()(下標)表示C/C++函數(shù)調(diào)用。

你為xxx()編寫來實現(xiàn)接口的C/C++ 函數(shù)如下:

  • xxx() (必有)

    主函數(shù)。 這是函數(shù)結(jié)果被計算的地方。SQL函數(shù)數(shù)據(jù)類型與C/C++函數(shù)返回類型的對應(yīng)關(guān)系如下:

    SQL 類型C/C++ 類型
    STRINGchar *
    INTEGERlong long
    REALdouble
  • xxx_init() (可選)

    對xxx()的初始化函數(shù)。它可以被用來:

    • 檢查傳遞給xxx()的參量數(shù)目。

    • 檢查參量是否為必需的類型,或者,除此之外,在主函數(shù)被調(diào)用的時候告訴MySQL將參量強制為想要的類型。

    • 分配主函數(shù)需要的內(nèi)存。

    • 指定結(jié)果的最大長度。

    • 指定(對于REAL 函數(shù))小數(shù)的最多位數(shù)。

    • 指定結(jié)果是否可以為 NULL。

  • xxx_deinit() (可選)

    對xxx()的去初始化函數(shù)。它釋放初始化函數(shù)分配的內(nèi)存。

當SQL聲明調(diào)用XXX()時,MySQL調(diào)用初始化函數(shù)xxx_init(),讓它執(zhí)行必要的設(shè)置,比如,檢查 參量或分配內(nèi)存。如果xxx_init() 返回一個錯誤,SQL聲明會退出并給出錯誤信息,而主函數(shù)和去初始化函數(shù)并沒有被調(diào)用。 否則,主函數(shù)xxx() 對每一行都被調(diào)用一次。所有行都處理完之后,調(diào)用去初始化函數(shù)xxx_deinit() 執(zhí)行必要的清除。

對于象SUM()一樣工作的集合函數(shù),你也必須提供如下的函數(shù):

  • xxx_clear() (在5.1節(jié)中必須)

    對一個新組重置當前集合值為初試集合值,但不插入任何參量。

  • xxx_add() (必須)

    添加參量到當前集合值。

MySQL 按下列操作來處理集合UDF:

  1. 調(diào)用 xxx_init() 讓集合函數(shù)分配它需要用來存儲結(jié)果的內(nèi)存。

  2. 按照GROUP BY表達式來排序表。

  3. 為每個新組中的第一行調(diào)用xxx_clear()函數(shù)。

  4. 為屬于同組的每一個新行調(diào)用xxx_add()函數(shù)。

  5. 當組改變時或每組的最后一行被處理完之后,調(diào)用xxx()來獲取集合結(jié)果。

  6. 重復(fù),以上3-步直到所有行被處理完。

  7. 調(diào)用xxx_deinit() 函數(shù)去釋放UDF分配的內(nèi)存。.

所有函數(shù)必須時線程安全的,這不僅對主函數(shù),對初始化和去初始化函數(shù)也一樣,也包括集合函數(shù)要求的附加函數(shù)。這個要求的一個結(jié)果就是,你不能分配任何變化的全局或靜態(tài)變量。如果你需要內(nèi)存,你可以在xxx_init()函數(shù)分配內(nèi)存,然后在xxx_deinit()函數(shù)釋放掉。

27.2.3.1. UDF 對簡單函數(shù)的調(diào)用順序

下面介紹創(chuàng)建簡單UDF時需要定義的不同函數(shù)。27.2.3節(jié),“添加新的自定義函數(shù)”中介紹了MySQL調(diào)用這些函數(shù)的順序。

如本節(jié)所示,應(yīng)該說明主函數(shù)xxx()。注意返回值和參數(shù)會有所不同,這取決于你說明的SQL函數(shù)xxx()在CREATE FUNCTION聲明中返回的是STRING,INTEGER類型還是REAL類型示:

對于STRING 型函數(shù):

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

對于INTEGER型函數(shù):

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

對于REAL型函數(shù):

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

初始化和去初始化函數(shù)如下說明:

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

void xxx_deinit(UDF_INIT *initid);

initid 參數(shù)被傳遞給所有的三個函數(shù)。它指向一個UDF_INIT 結(jié)構(gòu),這個結(jié)構(gòu)被用來在函數(shù)之間交換信息。UDF_INIT 結(jié)構(gòu)項跟隨著。初始化函數(shù)應(yīng)該給任何它想要改變的項賦值。(要使用項的默認值,就讓它不被改變)

  • my_bool maybe_null

    如果xxx() 能返回NULL,xxx_init()應(yīng)maybe_null 為 1 。如果任一參量被說明了 maybe_null值,其 默認值是1 。

  • unsigned int decimals

    小數(shù)位數(shù)。默認值是傳到主函數(shù)的參量里小數(shù)的最大位數(shù)。(例如,如果函數(shù)傳遞 1.34, 1.345, 和1.3, 那么默認值為,因為1.345 有3位小數(shù)。

  • unsigned int max_length

    結(jié)果的最大長度。max_length 的默認值因函數(shù)的結(jié)果類型而異。對字符串函數(shù),默認值是最長參量的長度。對整型函數(shù),默認是21位。對實型函數(shù),默認是13再加上initid->decimals指示的小數(shù)位數(shù)。(對數(shù)字函數(shù),長度包含正負號或者小數(shù)點符)。

    如果想返回團值,你可以把max_length 設(shè)為從65KB到16MB。這個內(nèi)存不會被分配,但是如果有臨時數(shù)據(jù)需要存儲,這個設(shè)置了的值被用來決定使用哪種 列的類型。

  • char *ptr

    函數(shù)可以用作本身目的的指針。比如,函數(shù)可以用initid->ptr 來在分配了的內(nèi)存內(nèi)部通訊。 xxx_init() 應(yīng)該分配內(nèi)存,并指派給這個指針:

    initid->ptr = allocated_memory;
    

    在 xxx() 和 xxx_deinit()中,借用 initid->ptr 來使用或分配內(nèi)存。

27.2.3.2. UDF對集合函數(shù)的調(diào)用順序

本節(jié)介紹創(chuàng)建集合UDF之時需要定義的不同函數(shù)。27.2.3節(jié),“添加新的自定義函數(shù)” 介紹了MySQL調(diào)用這些函數(shù)的順序。

  • xxx_reset()

    當MySQL在一個新組中發(fā)現(xiàn)第一行時調(diào)用這個函數(shù)。它對這個組重置任何內(nèi)部總和變量,然后使用給定的UDF_ARGS參量作為內(nèi)部總和值的第一個值。如下說明 xxx_reset() 函數(shù):

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

     在MySQL5.1版中UDF接口不需要或不使用xxx_reset()函數(shù),而是使用xxx_clear()函數(shù)作為替代。但是如果你想讓UDF也能在老版本的服務(wù)器上運行,你也可以定義 xxx_reset() 和 xxx_clear() 函數(shù)。(如果你使用了這兩個函數(shù),xxx_reset()函數(shù)在很多情況下可以通過調(diào)用函數(shù)來內(nèi)部實現(xiàn),即調(diào)用xxx_clear()函數(shù)重置所有變量,然后添加UDF_ARGS參量作為組的第一個值。)

  • xxx_clear()

    當MySQL需要重置總和結(jié)果時調(diào)用此函數(shù)。對每一個新組,在開始之時調(diào)用它,但是它也可以被調(diào)用來為一個沒有匹配行在其中的查詢重置值。如下說明xxx_clear():

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

    在調(diào)用xxx_clear()之前is_null 被設(shè)置指向 CHAR(0) 。

    如果發(fā)生錯誤,你可以存儲一個值在 error參量指向的變量中。error指向一單字節(jié)變量,而不是一個字符串緩沖區(qū)。

    xxx_clear() 是MySQL 5.1必須的。

  • xxx_add()

    為同組除了第一行之外,所有的行調(diào)用這個函數(shù)。你應(yīng)該用它在UDF_ARGS參量中向內(nèi)部總和變量加值。.

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

對集合UDF而言xxx() 函數(shù)應(yīng)該用與非集合UDF一樣的方法來說明。請參閱27.2.3.1節(jié),“UDF調(diào)用簡單函數(shù)的順序”

對一個集合UDF,MySQL 在組內(nèi)所有行被處理之后調(diào)用xxx()函數(shù)。這里你應(yīng)該一般不會接觸到它的UDF_ARGS參量,但是取而代之地根據(jù)內(nèi)部總和變量返回給你值。

在xxx()中處理的返回值應(yīng)該用與對非集合UDF一樣的方法來操作。請參閱27.2.3.4節(jié),“UDF返回值和錯誤處理”。

xxx_reset() 和 xxx_add() 函數(shù)用與非集合UDF一樣的方法來處理它們的UDF_ARGS 參量。請參閱27.2.3.3節(jié),“UDF參量處理”。

到is_null和error的指針 參量和所有到xxx_reset(), xxx_clear(), xxx_add() 和 xxx()調(diào)用一樣。你可以用這個來提醒你獲取一個錯誤或無論xxx()是否返回NULL的一個結(jié)果。你不能把一個字符串存到*error!error指向單字節(jié)變量而不是字符串緩沖區(qū)。

*is_null 對每一個組都重置(調(diào)用xxx_clear()前), *error 從不重置。

如果 xxx()返回時,*is_null 或 *error 被設(shè)置,MySQL返回 NULL作為組函數(shù)的結(jié)果。

27.2.3.3. UDF參量處理

args 參數(shù)指向列著結(jié)構(gòu)元的 UDF_ARGS 結(jié)構(gòu):

  • unsigned int arg_count

    參量個數(shù)。如果你需要你的函數(shù)帶著某個數(shù)目的參量被調(diào)用,在初始化函數(shù)檢查這個值,例如:

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

    一個指針,對每個參量指向包含類型的一個數(shù)列??赡艿念愋椭凳荢TRING_RESULT, INT_RESULT 和 REAL_RESULT。

    要確信一個參量是給定類型的,并且如果不是的話就返回一個錯誤,請檢查初始化函數(shù)中的arg_type數(shù)列。比如:

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

    要求你函數(shù)的參量是某一類型的另一方法是,使用初始化函數(shù)設(shè)置arg_type元素為你想要的類型。對所有對xxx()的調(diào)用而言,這會導(dǎo)致MySQL強制參量為這些類型。比如,要指定投兩個參量強制成字符串和整數(shù),在xxx_init()中分別:

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

    args->args 與初始化函數(shù)做有關(guān)傳到你函數(shù)的參量的一般情況做通訊。對于常參量i,args->args[i] 指向參量值。(看下面的說明了解如何妥善地訪問這個值)。對非-常參量,args->args[i] 為 0。一個常參量為僅使用參量的表達式,如 3 或 4*7-2 或 SIN(3.14)。一個非常 參量是一個行與行不同的表達式,如,列名或帶非-常參量調(diào)用的函數(shù)。

    對主函數(shù)的每次調(diào)用,args->args 包含為每個當前處理的行傳遞的實際參量。

    如下使用參量i的函數(shù):

    • 給一個STRING_RESULT 型的參量作為一個字符串加一個長度,可以允許所有二進制數(shù)或任意長度的數(shù)處理。字符串內(nèi)容作為args->args[i] 而字符串長度為args->lengths[i]。你不能采用null結(jié)尾的字符串。

    • 對一個INT_RESULT型的參量,你必須轉(zhuǎn)換args->args[i] 為一個long long 值:

      long long int_val;
      int_val = *((long long*) args->args[i]);
      
    • 對一個REAL_RESULT型參量,你必須轉(zhuǎn)換args->args[i]為一個雙精度值:

      double    real_val;
      real_val = *((double*) args->args[i]);
      
  • unsigned long *lengths

    對初始化函數(shù),lengths數(shù)列表示對每個參量的最大字符串長度。你不要改變它。對主函數(shù)的每次調(diào)用,lengths包含了對當前處理行傳遞的任何字符串 參量的實際長度。對于INT_RESULT 或 REAL_RESULT類型的參量,lengths 仍包含參量的最大長度(對初始化函數(shù))。

27.2.3.4. UDF返回值和錯誤處理

如果沒有錯誤發(fā)生,初始化函數(shù)應(yīng)該返回0,否則就返回1。如果有錯誤發(fā)生,xxx_init() 應(yīng)該在message 參數(shù)存儲一個以null結(jié)尾的錯誤消息。該消息被返回給客戶端。消息緩沖區(qū)是 MYSQL_ERRMSG_SIZE 字符長度,但你應(yīng)該試著把消息保持在少于80個字符,以便它能適合標準終端屏幕的寬度。

對于long long 和 double 類型的函數(shù),主函數(shù) xxx()的返回返回值是函數(shù)值。字符函數(shù)返回一個指向結(jié)果的指針,并且設(shè)置 *result 和 *length  為返回值的內(nèi)容和長度。例如:

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

被傳給 xxx() 函數(shù)的結(jié)果緩沖區(qū)是 255 字節(jié)長。如果你的結(jié)果適合這個長度,你就不需要擔(dān)心對結(jié)果的內(nèi)存分配。

如果字符串函數(shù)需要返回一個超過255字節(jié)的字符串,你必須用 malloc() 在你的 xxx_init() 函數(shù)或者 xxx() 函數(shù)里為字符串分配空間,并且在 xxx_deinit() 函數(shù)里釋放此空間。你可以將已分配內(nèi)存存儲在 UDF_INIT  結(jié)構(gòu)里的 ptr  位置以備將來 xxx() 調(diào)用。請參閱27.2.3.1節(jié),“UDF 對簡單函數(shù)的調(diào)用順序”

要在主函數(shù)中指明一個 NULL 的返回值,設(shè)置 *is_null 為 1 :

*is_null = 1;

要在主函數(shù)中指明錯誤返回,設(shè)置 *error 為 1 :

*error = 1;

如果 xxx() 對任意行設(shè)置 *error 為 1  ,對于任何 XXX()被調(diào)用的語句處理的當前行和隨后的任意行,該函數(shù)值為 NULL (甚至都不為隨后的行調(diào)用 xxx())。

27.2.3.5. 編譯和安裝自定義函數(shù)

實現(xiàn)UDF的文件必須在運行服務(wù)器的主機上編譯和安裝。這個步驟在下面介紹,以包含在MySQL源碼分發(fā)版里的UDF文件sql/udf_example.cc 為例。

緊接著下面的指令是對Unix的,對Windows的指令在本節(jié)稍后給出。

 udf_example.cc 文件包含下列函數(shù):

  • metaphon() 返回字符串參量的一個變音位(metaphon)字符串,這有點象一個探測法(soundex)字符串,但是它英語更協(xié)調(diào)。

  • myfunc_double()返回在其參量中所有字符的ASCII值的和,除以其 參量長度之和。

  • myfunc_int()返回其參量長度之和。

  • sequence([const int]) 返回一個序列,從給定數(shù)開始,若沒有給定數(shù)則從1開始。

  • lookup() 返回對應(yīng)主機名的IP數(shù)。

  • reverse_lookup() 返回對應(yīng)一個IP數(shù)的主機名。函數(shù)可以帶'xxx.xxx.xxx.xxx'形式的一個單字符串 參量調(diào)用,要么帶4個數(shù)字調(diào)用。

一個可動態(tài)加載的文件應(yīng)使用如下這樣的命令編譯為一個可共享的對象文件:

shell> gcc -shared -o udf_example.so udf_example.cc

如果你使用gcc,你應(yīng)該能用一個更簡單的命令創(chuàng)建udf_example.so :

shell> make udf_example.so

通過運行MySQL源碼樹下sql里的如下命令,你可以容易地為你的系統(tǒng)決定正確的編譯器選項:

shell> make udf_example.o

你應(yīng)該運行一個類似于make所顯示那樣的編譯命令,除了要在行尾附近刪除-c選項,并在行尾加上加上 -o udf_example.so。(在某些系統(tǒng)上,你可能需要在命令行留著-c 選項)。

編譯好一個包含有UDF的共享目標后,你必須安裝它并通知MySQL。從udf_example.cc編譯一個共享目標文件產(chǎn)生一個名字類似于udf_example.so 的文件(確切名字可能因平臺而異)。把這個文件復(fù)制到 /usr/lib 這樣被你系統(tǒng)的動態(tài)(運行時)鏈接器搜索到的目錄下,或者 把你放共享目標文件的目錄添加到鏈接器配置文件(如,/etc/ld.so.conf )。

動態(tài)鏈接器的名字時系統(tǒng)特定的(如,在FreeBSD上是ld-elf.so.1 ,在Linux上是 ld.so,在Mac OS X上是dyld )。查看一下你系統(tǒng)的文檔,看看鏈接器的名字是什么及如何配置鏈接器。

在許多系統(tǒng)上,你也可以設(shè)置環(huán)境變量LD_LIBRARY 或 LD_LIBRARY_PATH 指向你放UDF的目錄。dlopen 手冊會告訴你,在你系統(tǒng)上用哪個變量名。你可以在mysql.servermysqld_safe 啟動腳本里設(shè)置這個然后重啟 mysqld。

在一些系統(tǒng)上,配置動態(tài)鏈接器的ldconfig不能識別不是以lib做名字開頭的共享目標。在這種情況下,你應(yīng)該把udf_example.so 改名為 libudf_example.so。

在Windows系統(tǒng)上,你可以通過下列步驟編譯自定義函數(shù):

  1. 你需要獲得BitKeeper source repository for MySQL 5.1。 請參閱 2.8.3節(jié),“從開發(fā)源樹安裝”

  2. 在源數(shù)據(jù)倉里的VC++Files/examples/udf_example目錄下,有名為udf_example.def, udf_example.dsp, 和 udf_example.dsw  的文件。

  3. 在數(shù)據(jù)倉的sql目錄下,復(fù)制 udf_example.cc 文件到 VC++Files/examples/udf_example 目錄,并改其名為udf_example.cpp。

  4. Visual Studio VC++用打開 udf_example.dsw 文件,用它把UDF編譯為一個一般項目。

共享目標文件安裝完以后,為新函數(shù)信息修改 mysqld ,做如下聲明:

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

可以使用DROP FUNCTION刪除函數(shù):

mysql> DROP FUNCTION metaphon;
mysql> DROP FUNCTION myfunc_double;
mysql> DROP FUNCTION myfunc_int;
mysql> DROP FUNCTION lookup;
mysql> DROP FUNCTION reverse_lookup;
mysql> DROP FUNCTION avgcost;

CREATE FUNCTION 和 DROP FUNCTION 聲明更新mysql 數(shù)據(jù)庫中的func 系統(tǒng)表。函數(shù)名,類型和共享庫名存進表中。你必須有mysql 數(shù)據(jù)庫的INSERT 和DELETE 權(quán)限來創(chuàng)建和移除函數(shù)。

你不能使用 CREATE FUNCTION 去田間一個先前已經(jīng)被創(chuàng)建的函數(shù)。如果你需要重新安裝一個函數(shù),你可以用DROP FUNCTION移除它,然后再用CREATE FUNCTION重新安裝它。你可能會需要這么做,比如你重新編譯新版本的函數(shù)以便mysqld得到這個新版本。不然,服務(wù)器還繼續(xù)使用舊的版本。

一個有效程序是已被 CREATE FUNCTION加載且沒有被DROP FUNCTION移除的函數(shù)。所有有效函數(shù)在每次服務(wù)器啟動時重新加載,除非你使用--skip-grant-tables選項來啟動mysqld。這種情況下,UDF的初始化將被跳過,UDF不可用。

27.2.3.6. 自定義函數(shù)安全預(yù)防措施

MySQL 采取下列措施來防止誤用自定義函數(shù)。

你必須有 INSERT 權(quán)限才能使用 CREATE FUNCTION 及有 DELETE 權(quán)限才能使用 DROP FUNCTION。這是很必要的,因為這些聲明在mysql.func表里添加合刪除行。

除了對應(yīng)主 xxx()函數(shù)的xxx 符號,UDF應(yīng)該至少定義一個符號。這些輔助符號對應(yīng) xxx_init(), xxx_deinit(), xxx_reset(), xxx_clear() 和 xxx_add() 函數(shù)。mysqld 也支持一個控制僅有一個xxx符號的UDF是否被加載的--allow-suspicious-udfs。這個選項 默認是關(guān),以防止從共享目標文件而不是從這些已包含的合法UDF加載的企圖。如果你有僅含xxx符號的老版本UDF,以及不能重編譯來包含輔助符號的老版本UDF,那就有必要選--allow-suspicious-udfs 選項。否則,你應(yīng)該避免打開這個選項。

UDF 目標文件不能放在任意目錄。它們必須位于動態(tài)鏈接器被配置來搜索到的一些系統(tǒng)目錄。為強制執(zhí)行這個限制并防止指定被動態(tài)鏈接器搜索到的目錄之外的路徑,MySQL在加載函數(shù)的時候檢查在CREATE FUNCTION 中指定的共享目標文件名,以及存在mysql.func表中的文件的路徑分隔符。這防止通過直接操作mysql.func表指定非法路徑名。有關(guān)UDF和運行時鏈接器,請參閱27.2.3.5節(jié),“編譯和安裝自定義函數(shù)”。

27.2.4. 添加新的固有函數(shù)

下面介紹添加新固有函數(shù)的步驟。要注意你不能添加固有函數(shù)到二進制分發(fā)版里,因為這個步驟包含修改MySQL源代碼。你必須從源碼分發(fā)版自己編譯MySQL。另外要注意,如果你把MySQL移植到另一個版本(比如新版本放出來的時候),你需要用新版本重復(fù)這個添加 步驟。

采取下列步驟來添加MySQL新的固有函數(shù):

  1. 在定義函數(shù)名的lex.h文件中的sql_functions[]數(shù)列里添加一行。

  2. 如果函數(shù)原型是簡單的(只有零個,一個,二個或三個參量),你應(yīng)該在lex.h中指定 SYM(FUNC_ARGN) (其中N 是參量的個數(shù))作為sql_functions[]數(shù)列中的第二個 參量,并添加一個在item_create.cc中創(chuàng)建函數(shù)目標的函數(shù)??梢钥纯? "ABS" 和 create_funcs_abs() 作為舉例說明。

    如果函數(shù)原型是復(fù)雜的(舉例,如果函數(shù)有多種參量),你應(yīng)該給sql_yacc.yy添加兩行。一行表示yacc應(yīng)該定義的預(yù)處理程序記號,(這應(yīng)該在文件的開始添加)。然后定義函數(shù) 參數(shù),并添加一個帶這些參數(shù)的項到simple_expr分析規(guī)則中。舉一個例子,你可以檢查 sql_yacc.yy 中所有出現(xiàn)的ATAN 看看這個定義是什么樣子的。

  3. 在 item_func.h中說明一個繼承自Item_num_func 還是 Item_str_func的類,取決于你的函數(shù)是返回一個數(shù)還是一個字符串。

  4. 在 item_func.cc中是否添加下列說明之一,取決于你是定義一個數(shù)字函數(shù)還是字符函數(shù):

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

    如果你從任何標準項繼承了你的目標(類似于Item_num_func),你或許只要定義這些函數(shù)中的一個,然后讓父目標照管別的函數(shù)。比如,Item_str_func 類定義了一個 val() 函數(shù),它這個函數(shù)對::str()返回的值進行 atof()操作。

  5. 你或許也定義了下列目標函數(shù):

    void Item_func_newname::fix_length_and_dec()
    

    這個函數(shù)至少應(yīng)該計算基于給定參量的max_length。 max_length 是函數(shù)可能返回字符的最大個數(shù)。如果主函數(shù)不能返回 NULL值,這個函數(shù)也應(yīng)該設(shè)置 maybe_null = 0。函數(shù)可以通過檢查函數(shù)的maybe_null值來檢查是否有函數(shù) 參量能返回NULL值。你可以看一下Item_func_mod::fix_length_and_dec 作為典型的例子來說明這個問題。

所有函數(shù)都必須是線程安全的,換句話說就是,如果沒有互斥體保護,不要在函數(shù)中使用任何全局或靜態(tài)變量。

如果你想要從函數(shù)::val(), ::val_int()或::str()返回NULL,你應(yīng)該設(shè)null_value為1,并返回0。

對于目標函數(shù) ::str() 有一些需要而外考慮之處::

  • 字符串參量*str 提供一個字符串緩沖可以用來保持結(jié)果(更多關(guān)于字符串類型的信息請參閱 sql_string.h文件)。 

  • 如果結(jié)果為NULL,::str() 函數(shù)應(yīng)該返回保持這個結(jié)果的字符串或(char*) 0。

  • 除非有絕對地需要,所有當前的字符串函數(shù)要避免分配內(nèi)存!

27.3. 為MySQL添加新步驟

在MySQL中,你可以用C++定義一個步驟,在一個查詢被發(fā)送到客戶端之前訪問和修改其中的數(shù)據(jù)。修改可以一行接一行地做,或者按照級別成組(GROUP)地做。

我們創(chuàng)建一個范例步驟來演示你可以做的。

此外,我們推薦你看一下mylua。通過它你可以用  LUA語言把運行時里的一個 步驟加載到mysqld中。

27.3.1. 步驟分析

analyse([max_elements,[max_memory]])

這個步驟在sql/sql_analyse.cc定義,這個步驟檢查你查詢的結(jié)果,并且返回對此結(jié)果的一個分析:

  • max_elements (默認值 256) 是analyse注意到每 列不同值的最高數(shù)目。analyse使用此 參數(shù)來檢查是否最優(yōu)化的列的類型是ENUM類型。

  • max_memory (默認值 8192) 是analyse在查找所有不同值時分配給每 列的最大內(nèi)存數(shù)。i

SELECT ... FROM ... WHERE ... PROCEDURE ANALYSE([max_elements,[max_memory]])

27.3.2. 編寫步驟

當前來說,相關(guān)的文檔只有源碼。

檢查下列文件可以獲得關(guān)于步驟的所有信息:

  • sql/sql_analyse.cc

  • sql/procedure.h

  • sql/procedure.cc

  • sql/sql_select.cc

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多