MySQL 8.4 Reference Manual  /  ...  /  Function Name Parsing and Resolution

11.2.5 函数名称解析和解决

MySQL 支持内置函数、可加载函数和存储函数。这一节描述了服务器如何识别内置函数的名称是否被用作函数调用或标识符,以及在存在多种类型函数时,服务器如何确定使用哪个函数。

解析器使用默认规则来解析内置函数的名称。这些规则可以通过启用IGNORE_SPACE SQL 模式来更改。

当解析器遇到一个单词,该单词是内置函数的名称时,它必须确定该名称是否表示函数调用还是非表达式引用,例如表或列名。例如,在以下语句中,第一个对count的引用是一个函数调用,而第二个引用是一个表名:

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

解析器应该在解析预期为表达式时才将内置函数的名称识别为函数调用。也就是说,在非表达式上下文中,函数名称允许作为标识符。

然而,有些内置函数具有特殊的解析或实现考虑,因此解析器默认使用以下规则来区分它们在非表达式上下文中的用法:

  • 要将名称用作表达式中的函数调用,必须在名称和后续(括号字符之间没有空格。

  • 相反,要将函数名用作标识符,它不能立即被括号所跟随。

只有对内置函数进行特殊考虑的函数名称才需要在名称和括号之间没有空格。COUNT 是这样一个名称。sql/lex.h 源文件列出了这些特殊函数的名称,这些函数的解释取决于它们在symbols[] 数组中的定义:由 SYM_ FN() 宏在sql/lex.h 源文件中定义的名称。

以下列表列出了 MySQL 8.4 中受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 ()如果存在一个具有给定名称的内置函数,则被解释为内置函数;否则,如果存在一个具有该名称的可加载函数或存储函数,则被解释为可加载函数或存储函数。

可以使用IGNORE_SPACE SQL 模式来修改解析器对具有空格敏感性的函数名的处理方式:

  • IGNORE_SPACEdisabled状态下,解析器将名称解释为函数调用,当没有空格分隔名称和括号时。这也发生在函数名在非表达式上下文中使用时:

    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,它们在其值中包含IGNORE_SPACE:

SET sql_mode = 'ANSI';

查看第7.1.11节,“服务器SQL模式”,以了解哪些复合模式启用了IGNORE_SPACE

为了减少对IGNORE_SPACE设置的依赖性,遵循以下指南:

  • 避免创建具有同名的可加载函数或存储函数,以便与内置函数区分开来。

  • 避免在非表达式上下文中使用函数名称。例如,这些语句使用count(受IGNORE_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 Statement for Loadable Functions”,了解更多信息。

  • 内置函数和存储函数

    可以创建与内置函数同名的存储函数,但要调用存储函数需要使用 schema 名称。例如,如果在test schema 中创建一个名为PI的存储函数,调用它时需要使用test.PI(),因为服务器将PI()解析为内置函数的引用。服务器在存储函数名称与内置函数名称冲突时生成警告,可以使用SHOW WARNINGS显示警告。

    IF NOT EXISTS 在这种情况下无效;请参阅第15.1.17节,“CREATE PROCEDURE and CREATE FUNCTION Statements”

  • 可加载函数和存储函数

    可以创建与现有可加载函数同名的存储函数,或者反之。服务器在遇到拟议的存储函数名称与现有可加载函数名称冲突时,或者拟议的可加载函数名称与现有存储函数名称相同时,生成警告。在这两种情况下,一旦两个函数都存在,则需要在调用存储函数时使用 schema 名称来限定其名称;服务器假设在这种情况下,未限定名称指的是可加载函数。

    MySQL 8.4 支持IF NOT EXISTSCREATE FUNCTION语句,但在这种情况下无效。

前面的函数名称解析规则对升级到实现新内置函数的 MySQL 版本有影响:

  • 如果您已经创建了具有给定名称的可加载函数,并且升级 MySQL 到实现了同名新内置函数的版本,那么可加载函数将变得不可访问。要纠正这个问题,请使用DROP FUNCTION删除可加载函数,然后使用CREATE FUNCTION重新创建可加载函数,以不同的非冲突名称。然后,修改任何受影响的代码以使用新名称。

  • 如果 MySQL 的新版本实现了与现有存储函数同名的内置函数或可加载函数,您有两个选择:将存储函数重命名以使用不冲突的名称,或者将不已经这样做的函数调用修改为使用 schema 限定符(schema_ name.func_name() 语法)。在任何情况下,相应地修改受影响的代码。