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
设置的依赖,请使用以下准则:
避免创建与内置函数同名的可加载函数或存储函数。
避免在非表达式上下文中使用函数名称。例如,以下语句使用了
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 语句(用于可加载函数)”。内置函数和存储函数:
可以创建与内置函数同名的存储函数,但要调用存储函数,必须使用模式名称对其进行限定。例如,如果在
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 实现了一个与现有存储函数同名的内置函数或可加载函数,则您有两个选择:重命名存储函数以使用非冲突名称,或更改对该函数的任何调用(如果尚未这样做)以使用架构限定符(
语法)。无论哪种情况,都要相应地修改任何受影响的代码。schema_name
.func_name
()