MySQL支持内置(native)函数、可加载函数和存储函数。本节描述服务器如何识别内置函数名称是否用作函数调用或标识符,以及在存在多种类型的函数时如何确定使用哪个函数。
解析器使用默认规则来解析内置函数名称。这些规则可以通过启用IGNORE_SPACE
SQL模式来更改。
当解析器遇到内置函数名称时,它必须确定该名称是否表示函数调用还是非表达式引用标识符,例如表或列名称。例如,在以下语句中,第一个count
引用是函数调用,而第二个引用是表名:
SELECT COUNT(*) FROM mytable;
CREATE TABLE count (i INT);
解析器应该仅在解析表达式时将内置函数名称识别为函数调用。在非表达式上下文中,函数名称被允许作为标识符。
然而,一些内置函数具有特殊的解析或实现考虑,因此解析器使用以下默认规则来区分它们的名称是否用于函数调用或非表达式上下文中的标识符:
-
要在表达式中使用名称作为函数调用,必须没有空格在名称和后续
(
括号字符之间。 -
相反,要使用函数名称作为标识符,它不能紧跟在括号后面。
要求函数调用在名称和括号之间没有空格仅适用于具有特殊考虑的内置函数。COUNT
是其中之一。sql/lex.h
源文件列出了这些特殊函数的名称,它们的后续空格确定了它们的解释:在symbols[]
数组中的SYM_FN()
宏定义的名称。
以下列表了MySQL 8.3中受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 语句 for 可加载函数”,以获取更多信息。 -
内置函数和存储函数
可以创建一个与内置函数同名的存储函数,但要调用存储函数,需要使用架构名称限定它。例如,如果您在
test
架构中创建了一个名为PI
的存储函数,则需要以test.PI()
的形式调用它,因为服务器将PI()
解析为内置函数的引用。如果存储函数的名称与内置函数的名称冲突,服务器将生成警告。可以使用SHOW WARNINGS
显示警告。IF NOT EXISTS
在这种情况下无效;请参阅 第 15.1.17 节,“CREATE PROCEDURE 和 CREATE FUNCTION 语句”。 -
可加载函数和存储函数
可以创建一个与现有可加载函数同名的存储函数,反之亦然。如果存储函数的名称与可加载函数的名称冲突,服务器将生成警告。在这种情况下,一旦两个函数都存在,需要在调用存储函数时使用架构名称限定它;服务器假设在这种情况下未限定名称是指可加载函数。
MySQL 8.3 支持
IF NOT EXISTS
与CREATE FUNCTION
语句,但是在这种情况下无效。
前面的函数名称解析规则对升级到实现新内置函数的 MySQL 版本有影响:
-
如果您已经创建了一个名为某个名称的可加载函数,并升级到实现该名称的新内置函数的 MySQL 版本,那么可加载函数将变得不可访问。要纠正这一点,请使用
DROP FUNCTION
删除可加载函数,然后使用CREATE FUNCTION
重新创建可加载函数,使用不同的非冲突名称。然后,修改任何受影响的代码以使用新名称。 -
如果新的 MySQL 版本实现了一个与现有存储函数同名的内置函数或可加载函数,您有两个选择:重命名存储函数以使用非冲突名称,或者更改任何不使用架构限定符的函数调用,以使用
语法。在任何情况下,请修改任何受影响的代码。schema_name
.func_name
()