MySQL 9.0 參考手冊  /  ...  /  函數名稱剖析與解析

11.2.5 函數名稱剖析與解析

MySQL 支援內建(原生)函數、可載入函數和儲存函數。本節說明伺服器如何識別內建函數的名稱是用作函數呼叫還是識別符,以及在具有給定名稱的不同類型函數存在時,伺服器如何確定要使用的函數。

內建函數名稱剖析

剖析器使用預設規則來剖析內建函數的名稱。這些規則可以透過啟用 IGNORE_SPACE SQL 模式來變更。

當剖析器遇到一個內建函數名稱的單字時,它必須確定該名稱是指函數呼叫還是對識別符的非運算式參照,例如資料表或欄名稱。例如,在下列陳述式中,第一個對 count 的參照是函數呼叫,而第二個參照是資料表名稱

SELECT COUNT(*) FROM mytable;
CREATE TABLE count (i INT);

剖析器應僅在剖析預期為運算式時,才將內建函數的名稱識別為指示函數呼叫。也就是說,在非運算式上下文中,允許函數名稱作為識別符。

但是,某些內建函數具有特殊的剖析或實作考量,因此剖析器預設使用以下規則來區分其名稱是用作函數呼叫還是用作非運算式上下文中的識別符

  • 若要在運算式中將名稱用作函數呼叫,則名稱和後面的 ( 左括號字元之間不得有空格。

  • 相反地,若要將函數名稱用作識別符,則其後面不得緊接著括號。

函數呼叫必須在名稱和括號之間沒有空格的要求,僅適用於具有特殊考量的內建函數。COUNT 就是其中一個名稱。sql/lex.h 原始程式碼檔案會列出這些特殊函數的名稱,這些特殊函數的後續空格決定了它們的解釋:symbols[] 陣列中由 SYM_FN() 巨集定義的名稱。

以下清單列出 MySQL 9.0 中受 IGNORE_SPACE 設定影響,並在 sql/lex.h 原始程式碼檔案中列為特殊的函數。您可能會發現最簡單的方法是將無空格要求視為適用於所有函數呼叫。

  • ADDDATE

  • BIT_AND

  • BIT_OR

  • BIT_XOR

  • CAST

  • COUNT

  • CURDATE

  • CURTIME

  • DATE_ADD

  • DATE_SUB

  • EXTRACT

  • GROUP_CONCAT

  • MAX

  • MID

  • MIN

  • NOW

  • POSITION

  • SESSION_USER

  • STD

  • STDDEV

  • STDDEV_POP

  • STDDEV_SAMP

  • SUBDATE

  • SUBSTR

  • SUBSTRING

  • SUM

  • SYSDATE

  • SYSTEM_USER

  • TRIM

  • VARIANCE

  • VAR_POP

  • VAR_SAMP

對於未在 sql/lex.h 中列為特殊的函數,空格並不重要。它們僅在運算式上下文中使用時才被解釋為函數呼叫,否則可以自由地用作識別符。ASCII 就是其中一個名稱。但是,對於這些未受影響的函數名稱,解釋可能會在運算式上下文中有所不同:如果存在具有給定名稱的內建函數,則 func_name () 會被解釋為內建函數;如果沒有,則如果存在具有該名稱的可載入函數或儲存函數,則 func_name () 會被解釋為可載入函數或儲存函數。

IGNORE_SPACE SQL 模式可用於修改剖析器處理對空格敏感的函數名稱的方式

  • 停用 IGNORE_SPACE 時,剖析器會將名稱解釋為函數呼叫,前提是名稱和後面的括號之間沒有空格。即使函數名稱在非運算式上下文中使用,也會發生這種情況

    mysql> CREATE TABLE count(i INT);
    ERROR 1064 (42000): You have an error in your SQL syntax ...
    near 'count(i INT)'

    若要消除錯誤並使名稱被視為識別符,請在名稱後面使用空格或將其寫為帶引號的識別符(或兩者都使用)

    CREATE TABLE count (i INT);
    CREATE TABLE `count`(i INT);
    CREATE TABLE `count` (i INT);
  • 啟用 IGNORE_SPACE 時,剖析器會放寬函數名稱和後面的括號之間不得有空格的要求。這提供了更大的函數呼叫寫入彈性。例如,以下任一函數呼叫都是合法的

    SELECT COUNT(*) FROM mytable;
    SELECT COUNT (*) FROM mytable;

    但是,啟用 IGNORE_SPACE 也會產生副作用,即剖析器將受影響的函數名稱視為保留字(請參閱 第 11.3 節,「關鍵字和保留字」)。這表示名稱後面的空格不再表示其用作識別符。該名稱可以在有或沒有後續空格的情況下用於函數呼叫中,但在非運算式上下文中會導致語法錯誤,除非它被加上引號。例如,在啟用 IGNORE_SPACE 的情況下,以下兩個陳述式都會因語法錯誤而失敗,因為剖析器將 count 解釋為保留字

    CREATE TABLE count(i INT);
    CREATE TABLE count (i INT);

    若要在非運算式上下文中使用函數名稱,請將其寫為帶引號的識別符

    CREATE TABLE `count`(i INT);
    CREATE TABLE `count` (i INT);

若要啟用 IGNORE_SPACE SQL 模式,請使用此陳述式

SET sql_mode = 'IGNORE_SPACE';

IGNORE_SPACE 也可以透過某些其他複合模式啟用,例如在其值中包含 ANSI 的模式

SET sql_mode = 'ANSI';

檢查 第 7.1.11 節,「伺服器 SQL 模式」,以查看哪些複合模式會啟用 IGNORE_SPACE

若要盡量減少 SQL 程式碼對 IGNORE_SPACE 設定的相依性,請使用以下準則

  • 避免建立與內建函數同名的可載入函數或儲存函數。

  • 避免在非運算式上下文中使用函數名稱。例如,這些陳述式使用 countIGNORE_SPACE 影響的受影響函數名稱之一),因此如果啟用 IGNORE_SPACE,則無論名稱後面是否有空格,它們都會失敗

    CREATE TABLE count(i INT);
    CREATE TABLE count (i INT);

    如果必須在非運算式上下文中使用函數名稱,請將其寫為帶引號的識別符

    CREATE TABLE `count`(i INT);
    CREATE TABLE `count` (i INT);

函數名稱解析

以下規則說明伺服器如何解析對函數名稱的參照,以進行函數建立和調用

  • 內建函數和可載入函數

    如果您嘗試建立與內建函數同名的可載入函數,則會發生錯誤。

    IF NOT EXISTS 在此類情況下沒有任何作用。如需更多資訊,請參閱 第 15.7.4.1 節,「可載入函數的 CREATE FUNCTION 陳述式」

  • 內建函數和儲存函數

    可以建立一個與內建函式同名的儲存函式,但要呼叫該儲存函式,必須使用綱要名稱來限定。例如,如果在 test 綱要中建立一個名為 PI 的儲存函式,則需使用 test.PI() 來呼叫它,因為伺服器會將沒有限定詞的 PI() 解析為對內建函式的參照。如果儲存函式名稱與內建函式名稱衝突,伺服器會產生警告。可以使用 SHOW WARNINGS 來顯示警告。

    IF NOT EXISTS 在這種情況下無效;請參閱 第 15.1.17 節,「CREATE PROCEDURE 和 CREATE FUNCTION 陳述式」

  • 可載入函式和儲存函式

    可以建立一個與現有可載入函式同名的儲存函式,反之亦然。如果建議的儲存函式名稱與現有可載入函式名稱衝突,或者如果建議的可載入函式名稱與現有儲存函式的名稱相同,伺服器會產生警告。在兩種情況下,一旦這兩個函式都存在,之後在呼叫儲存函式時,必須使用綱要名稱來限定;在這種情況下,伺服器會假設不合格的名稱是指可載入函式。

    MySQL 9.0 支援 CREATE FUNCTION 陳述式中的 IF NOT EXISTS,但在這種情況下無效。

上述函式名稱解析規則對於升級到實作新內建函式的 MySQL 版本有影響。

  • 如果您已經建立了一個具有特定名稱的可載入函式,並且將 MySQL 升級到實作具有相同名稱的新內建函式的版本,則該可載入函式將變得無法存取。要修正此問題,請使用 DROP FUNCTION 來刪除該可載入函式,並使用 CREATE FUNCTION 來重新建立具有不同且不衝突名稱的可載入函式。然後修改任何受影響的程式碼以使用新名稱。

  • 如果新版本的 MySQL 實作了一個與現有儲存函式同名的內建函式或可載入函式,您有兩個選擇:重新命名儲存函式以使用不衝突的名稱,或將任何尚未這樣做的函式呼叫更改為使用綱要限定詞(綱要名稱.函式名稱() 語法)。在任何一種情況下,請相應地修改任何受影響的程式碼。