9.2.5 函数名称解析和解析

MySQL 支持内置(本机)函数,用户定义函数(UDF)和存储函数。本节描述服务器如何识别内置函数的名称是用作函数调用还是用作标识符,以及在给定名称存在不同类型的函数的情况下,服务器如何确定使用哪个函数。

内置函数名称解析

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

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

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

解析器应仅在解析预期为 table 达式的内容时才将内置函数的名称识别为指示函数调用。即,在非 table 达式上下文中,允许使用函数名作为标识符。

但是,某些内置函数具有特殊的解析或实现注意事项,因此解析器默认情况下使用以下规则来区分其名称是在非 table 达式上下文中用作函数调用还是用作标识符:

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

  • 相反,要将函数名称用作标识符,切勿在其后立即加上括号。

名称和括号之间不得包含空格的函数调用要求仅适用于具有特殊注意事项的内置函数。 COUNT是这样的名称。 sql/lex.h源文件列出了这些特殊功能的名称,其后的空格决定了它们的解释:symbols[]数组中SYM_FN()宏定义的名称。

以下列 table 列出了受IGNORE_SPACE设置影响并在sql/lex.h源文件中以特殊方式列出的 MySQL 5.7 中的函数。您可能会发现将无空格要求应用于所有函数调用是最容易的。

  • 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中未列出为特殊功能的功能,空格无关紧要。仅当在 table 达式上下文中使用它们时,它们才被解释为函数调用,否则可以自由用作标识符。 ASCII是这样的名称之一。但是,对于这些不受影响的函数名称,在 table 达式上下文中的解释可能有所不同:func_name ()被解释为内置函数(如果存在一个具有给定名称的函数);如果不是,则func_name ()被解释为用户定义的函数或存储的函数(如果存在具有该名称的函数)。

IGNORE_SPACE SQL 模式可用于修改解析器如何处理对空格敏感的函数名称:

  • 在禁用IGNORE_SPACE的情况下,当名称和后面的括号之间没有空格时,解析器会将名称解释为函数调用。即使在非 table 达式上下文中使用了函数名称,也会发生这种情况:
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后,解析器将放宽要求,即函数名称和后面的括号之间不能有空格。这在编写函数调用时提供了更大的灵 Active。例如,以下任何一个函数调用都是合法的:
SELECT COUNT(*) FROM mytable;
SELECT COUNT (*) FROM mytable;

但是,启用IGNORE_SPACE也会带来副作用,即解析器会将受影响的函数名称视为保留字(请参见第 9.3 节“关键字和保留字”)。这意味着名称后的空格不再 table 示其用作标识符。该名称可在带有或不带有空格的函数调用中使用,但除非在引用前加引号,否则会在非 table 达式上下文中引起语法错误。例如,在启用IGNORE_SPACE的情况下,以下两个语句均会因语法错误而失败,因为解析器会将count解释为保留字:

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

要在非 table 达式上下文中使用函数名称,请将其写为带引号的标识符:

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

要启用IGNORE_SPACE SQL 模式,请使用以下语句:

SET sql_mode = 'IGNORE_SPACE';

某些其他复合模式(例如ANSI)也将IGNORE_SPACE启用,并将它们包含在其值中:

SET sql_mode = 'ANSI';

检查第 5.1.10 节“服务器 SQL 模式”,以查看启用IGNORE_SPACE的复合模式。

为了使 SQL 代码对IGNORE_SPACE设置的依赖性最小,请使用以下准则:

  • 避免创建与内置函数同名的 UDF 或存储函数。

  • 避免在非 table 达式上下文中使用函数名称。例如,这些语句使用count(受IGNORE_SPACE影响的受影响的函数名称之一),因此,如果启用了IGNORE_SPACE,则它们在名称后带有或不带有空格的情况将失败:

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

如果必须在非 table 达式上下文中使用函数名称,请将其写为带引号的标识符:

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

函数名称解析

以下规则描述了服务器如何将对函数名称的引用解析为函数创建和调用:

  • 内置功能和用户定义功能

如果尝试创建与内置函数同名的 UDF,则会发生错误。

  • 内置功能和存储功能

可以使用与内置函数相同的名称来创建存储函数,但是要调用该存储函数,必须使用架构名称对其进行限定。例如,如果您在test模式中创建一个名为PI的存储函数,请以test.PI()的形式调用它,因为服务器在不使用限定符的情况下解析PI()作为对内置函数的引用。如果存储的函数名与内置函数名冲突,则服务器会生成警告。可以使用SHOW WARNINGS显示警告。

  • 用户定义的函数和存储的函数

用户定义的函数和存储的函数共享相同的名称空间,因此您无法创建 UDF 和具有相同名称的存储函数。

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

  • 如果您已经使用给定的名称创建了用户定义的函数,并将 MySQL 升级到实现具有相同名称的新内置函数的版本,则 UDF 变得不可访问。若要更正此问题,请使用DROP FUNCTION删除 UDF,并使用CREATE FUNCTION重新创建具有不同名称的 UDF。然后修改任何受影响的代码以使用新名称。

  • 如果新版本的 MySQL 实现的内置函数的名称与现有存储函数的名称相同,则有两种选择:重命名存储函数以使用不冲突的名称,或更改对该函数的调用以使它们使用模式限定符(即使用schema_name.func_name()语法)。在任何一种情况下,请相应地修改任何受影响的代码。