### 9.2.5 函数名解析与解析

[](<>)[](<>)

MySQL 支持内置（本机）函数、可加载函数和存储函数。本节介绍服务器如何识别内置函数的名称是用作函数调用还是用作标识符，以及在存在具有给定名称的不同类型的函数的情况下，服务器如何确定使用哪个函数。

-   [内置函数名解析](function-resolution.html#function-name-parsing)

-   [函数名称解析](function-resolution.html#function-name-resolution)

#### 内置函数名解析

解析器使用默认规则来解析内置函数的名称。这些规则可以通过启用[`忽略空格`](sql-mode.html#sqlmode_ignore_space)SQL 模式。

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

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

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

但是，某些内置函数有特殊的解析或实现注意事项，因此解析器默认使用以下规则来区分它们的名称是用作函数调用还是用作非表达式上下文中的标识符：

-   要将名称用作表达式中的函数调用，名称和以下内容之间不得有空格`(`括号字符。

-   相反，要将函数名用作标识符，则不能紧跟括号。

    函数调用在名称和括号之间没有空格的要求仅适用于具有特殊考虑的内置函数。`数数`就是这样一个名字。这`sql/lex.h`源文件列出了这些特殊函数的名称，下面的空格决定了它们的解释：`SYM_FN()`中的宏`符号[]`大批。

    以下列表列出了 MySQL 8.0 中受[`忽略空格`](sql-mode.html#sqlmode_ignore_space)设置并列为特殊的`sql/lex.h`源文件。您可能会发现将无空格要求视为适用于所有函数调用最容易。

-   `添加日期`

-   `位与`

-   `BIT_OR`

-   `BIT_XOR`

-   `投掷`

-   `数数`

-   `凝乳`

-   `CURTIME`

-   `DATE_ADD`

-   `DATE_SUB`

-   `提炼`

-   `GROUP_CONCAT`

-   `最大限度`

-   `中`

-   `最小`

-   `现在`

-   `位置`

-   `SESSION_USER`

-   `性病`

-   `标准开发`

-   `STDDEV_POP`

-   `STDDEV_SAMP`

-   `子日期`

-   `SUBSTR`

-   `子串`

-   `和`

-   `日期`

-   `SYSTEM_USER`

-   `修剪`

-   `方差`

-   `VAR_POP`

-   `VAR_SAMP`

    对于未列为特殊功能的`sql/lex.h`, 空格无关紧要。它们仅在表达式上下文中使用时才被解释为函数调用，否则可以自由地用作标识符。`ASCII`就是这样一个名字。但是，对于这些不受影响的函数名称，在表达式上下文中的解释可能会有所不同：`*`func_name`* ()`如果存在具有给定名称的函数，则将其解释为内置函数；如果不，`*`func_name`* ()`如果存在具有该名称的函数，则将其解释为可加载函数或存储函数。

    这[`忽略空格`](sql-mode.html#sqlmode_ignore_space)SQL 模式可用于修改解析器如何处理对空格敏感的函数名称：

-   和[`忽略空格`](sql-mode.html#sqlmode_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);
    ```

-   和[`忽略空格`](sql-mode.html#sqlmode_ignore_space)启用后，解析器放宽了函数名称和以下括号之间没有空格的要求。这为编写函数调用提供了更大的灵活性。例如，以下任一函数调用都是合法的：

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

    但是，启用[`忽略空格`](sql-mode.html#sqlmode_ignore_space)还有一个副作用是解析器将受影响的函数名称视为保留字（参见[第 9.3 节，“关键字和保留字”](keywords.html)）。这意味着名称后面的空格不再表示将其用作标识符。该名称可用于带或不带空格的函数调用，但在非表达式上下文中会导致语法错误，除非它被引用。例如，与[`忽略空格`](sql-mode.html#sqlmode_ignore_space)启用，以下两个语句都失败并出现语法错误，因为解析器解释`数数`作为保留字：

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

    要在非表达式上下文中使用函数名，请将其写为带引号的标识符：

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

    要启用[`忽略空格`](sql-mode.html#sqlmode_ignore_space)SQL模式，使用这条语句：


```
SET sql_mode = 'IGNORE_SPACE';
```

[`忽略空格`](sql-mode.html#sqlmode_ignore_space)也可以通过某些其他复合模式启用，例如[`ANSI`](sql-mode.html#sqlmode_ansi)将其包含在其价值中：

```
SET sql_mode = 'ANSI';
```

查看[第 5.1.11 节，“服务器 SQL 模式”](sql-mode.html), 查看启用了哪些复合模式[`忽略空格`](sql-mode.html#sqlmode_ignore_space).

尽量减少 SQL 代码对[`忽略空格`](sql-mode.html#sqlmode_ignore_space)设置，使用以下指南：

-   避免创建与内置函数同名的可加载函数或存储函数。

-   避免在非表达式上下文中使用函数名。例如，这些语句使用`数数`（受影响的函数名称之一受[`忽略空格`](sql-mode.html#sqlmode_ignore_space))，因此如果在名称后面有或没有空格，它们就会失败[`忽略空格`](sql-mode.html#sqlmode_ignore_space)已启用：

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

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

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

#### 函数名称解析

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

-   内置函数和可加载函数

    如果您尝试创建与内置函数同名的可加载函数，则会发生错误。

    `如果不存在`（从 MySQL 8.0.29 开始可用）在这种情况下无效。看[第 13.7.4.1 节，“可加载函数的 CREATE FUNCTION 语句”](create-function-loadable.html)， 了解更多信息。

-   内置函数和存储函数

    可以创建与内置函数同名的存储函数，但要调用存储函数，必须使用模式名称对其进行限定。例如，如果您创建一个名为`PI`在里面`测试`架构，将其调用为`测试.PI()`因为服务器解析[`PI()`](mathematical-functions.html#function_pi)没有限定符作为对内置函数的引用。如果存储的函数名与内置函数名冲突，服务器会生成警告。警告可以显示为[`显示警告`](show-warnings.html).

    `如果不存在`（MySQL 8.0.29及更高版本）在此类情况下无效；看见[第13.1.17节，“创建程序和创建函数语句”](create-procedure.html).

-   可加载函数和存储函数

    可以创建一个与现有可加载函数同名的存储函数，或者以其他方式创建。如果建议的存储函数名与现有可加载函数名冲突，或者建议的可加载函数名与现有存储函数名相同，服务器将生成警告。在任何一种情况下，一旦这两个函数都存在，在调用存储的函数时，都需要使用模式名来限定它；在这种情况下，服务器假定非限定名称指的是可加载函数。

    从MySQL 8.0.29开始，`如果不存在`支持[`创建函数`](create-function.html)声明，但在此类情况下无效。

    在MySQL 8.0.28之前，可以创建一个与现有可加载函数同名的存储函数，但不能反过来（Bug#33301931）。

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

-   如果已经创建了具有给定名称的可加载函数，并将MySQL升级到实现具有相同名称的新内置函数的版本，则可加载函数将无法访问。要更正此问题，请使用[`下降函数`](drop-function.html)删除可加载函数并[`创建函数`](create-function.html)使用不同的非冲突名称重新创建可加载函数。然后修改任何受影响的代码以使用新名称。

-   如果新版本的MySQL实现了与现有存储函数同名的内置函数或可加载函数，那么您有两个选择：重命名存储函数以使用非冲突名称，或者将对函数的任何调用更改为使用模式限定符(`*`模式名称`*.*`func\_名称`*()`语法）。无论哪种情况，都要相应地修改任何受影响的代码。
