MySQL8-中文参考-五十-

84 阅读1小时+

MySQL8 中文参考(五十)

原文:docs.oracle.com/javase/tutorial/reallybigindex.html

14.12 位函数和运算符

原文:dev.mysql.com/doc/refman/8.0/en/bit-functions.html

表 14.17 位函数和运算符

名称描述
&按位与
>>右移
<<左移
^按位异或
BIT_COUNT()返回设置的位数
&#124;按位或
~按位取反

以下列表描述了可用的位函数和运算符:

  • |

    按位或。

    结果类型取决于参数是作为二进制字符串还是数字进行评估:

    • 当参数具有二进制字符串类型且至少有一个不是十六进制文字、位文字或NULL文字时,进行二进制字符串运算。否则进行数值运算,必要时将参数转换为无符号 64 位整数。

    • 二进制字符串运算会产生与参数相同长度的二进制字符串。如果参数长度不相等,则会出现ER_INVALID_BITWISE_OPERANDS_SIZE错误。数值运算会产生一个无符号 64 位整数。

    更多信息,请参阅本节的介绍性讨论。

    mysql> SELECT 29 | 15;
     -> 31
    mysql> SELECT _binary X'40404040' | X'01020304';
     -> 'ABCD'
    

    如果在mysql客户端中调用按位或运算,二进制字符串结果将以十六进制表示,具体取决于--binary-as-hex的值。有关该选项的更多信息,请参阅 Section 6.5.1, “mysql — The MySQL Command-Line Client”。

  • &

    按位与。

    结果类型取决于参数是作为二进制字符串还是数字进行评估:

    • 当参数具有二进制字符串类型且至少有一个不是十六进制文字、位文字或NULL文字时,进行二进制字符串运算。否则进行数值运算,必要时将参数转换为无符号 64 位整数。

    • 二进制字符串运算会产生与参数相同长度的二进制字符串。如果参数长度不相等,则会出现ER_INVALID_BITWISE_OPERANDS_SIZE错误。数值运算会产生一个无符号 64 位整数。

    更多信息,请参阅本节的介绍性讨论。

    mysql> SELECT 29 & 15;
     -> 13
    mysql> SELECT HEX(_binary X'FF' & b'11110000');
     -> 'F0'
    

    如果在mysql客户端中调用按位与,二进制字符串结果将以十六进制表示,具体取决于--binary-as-hex的值。有关该选项的更多信息,请参阅第 6.5.1 节,“mysql — MySQL 命令行客户端”。

  • ^

    按位异或。

    结果类型取决于参数是作为二进制字符串还是数字进行评估:

    • 当参数具有二进制字符串类型且至少一个参数不是十六进制文字、比特文字或NULL文字时,进行二进制字符串运算。否则进行数值运算,并根据需要将参数转换为无符号 64 位整数。

    • 二进制字符串运算产生与参数长度相同的二进制字符串。如果参数长度不相等,则会出现ER_INVALID_BITWISE_OPERANDS_SIZE错误。数值运算产生一个无符号 64 位整数。

    更多信息,请参阅本节的介绍性讨论。

    mysql> SELECT 1 ^ 1;
     -> 0
    mysql> SELECT 1 ^ 0;
     -> 1
    mysql> SELECT 11 ^ 3;
     -> 8
    mysql> SELECT HEX(_binary X'FEDC' ^ X'1111');
     -> 'EFCD'
    

    如果在mysql客户端中调用按位异或,二进制字符串结果将以十六进制表示,具体取决于--binary-as-hex的值。有关该选项的更多信息,请参阅第 6.5.1 节,“mysql — MySQL 命令行客户端”。

  • <<

    将一个长整型(BIGINT)数字或二进制字符串向左移位。

    结果类型取决于比特参数是作为二进制字符串还是数字进行评估:

    • 当比特参数具有二进制字符串类型且不是十六进制文字、比特文字或NULL文字时,进行二进制字符串运算。否则进行数值运算,并根据需要将参数转换为无符号 64 位整数。

    • 二进制字符串运算产生与比特参数长度相同的二进制字符串。数值运算产生一个无符号 64 位整数。

    超出值末尾的位将被丢弃,不会有警告,无论参数类型如何。特别是,如果移位计数大于或等于比特参数中的位数,则结果中的所有位都为 0。

    更多信息,请参阅本节的介绍性讨论。

    mysql> SELECT 1 << 2;
     -> 4
    mysql> SELECT HEX(_binary X'00FF00FF00FF' << 8);
     -> 'FF00FF00FF00'
    

    如果在mysql客户端内调用位移操作,则根据--binary-as-hex的值,二进制字符串结果将以十六进制表示。有关该选项的更多信息,请参阅 Section 6.5.1, “mysql — The MySQL Command-Line Client”。

  • >>

    将一个长整型(BIGINT - INTEGER, INT, SMALLINT, TINYINT, MEDIUMINT, BIGINT"))数字或二进制字符串向右移动。

    结果类型取决于位参数是作为二进制字符串还是数字进行评估:

    • 当位参数具有二进制字符串类型且不是十六进制文字、位文字或NULL文字时,进行二进制字符串评估。否则进行数值评估,必要时将参数转换为无符号 64 位整数。

    • 二进制字符串评估会产生与位参数相同长度的二进制字符串。数值评估会产生一个无符号 64 位整数。

    无论参数类型如何,超出值末尾的位都会被丢弃而不发出警告。特别是,如果位移计数大于或等于位参数中的位数,则结果中的所有位都为 0。

    有关更多信息,请参阅本节中的介绍性讨论。

    mysql> SELECT 4 >> 2;
     -> 1
    mysql> SELECT HEX(_binary X'00FF00FF00FF' >> 8);
     -> '0000FF00FF00'
    

    如果在mysql客户端内调用位移操作,则根据--binary-as-hex的值,二进制字符串结果将以十六进制表示。有关该选项的更多信息,请参阅 Section 6.5.1, “mysql — The MySQL Command-Line Client”。

  • ~

    反转所有位。

    结果类型取决于位参数是作为二进制字符串还是数字进行评估:

    • 当位参数具有二进制字符串类型且不是十六进制文字、位文字或NULL文字时,进行二进制字符串评估。否则进行数值评估,必要时将参数转换为无符号 64 位整数。

    • 二进制字符串评估会产生与位参数相同长度的二进制字符串。数值评估会产生一个无符号 64 位整数。

    有关更多信息,请参阅本节中的介绍性讨论。

    mysql> SELECT 5 & ~1;
     -> 4
    mysql> SELECT HEX(~X'0000FFFF1111EEEE');
     -> 'FFFF0000EEEE1111'
    

    如果在mysql客户端内调用位求反操作,则根据--binary-as-hex的值,二进制字符串结果将以十六进制表示。有关该选项的更多信息,请参阅 Section 6.5.1, “mysql — The MySQL Command-Line Client”。

  • BIT_COUNT(*N*)

    返回参数 N 中设置的位数作为无符号 64 位整数,如果参数为 NULL 则返回 NULL

    mysql> SELECT BIT_COUNT(64), BIT_COUNT(BINARY 64);
     -> 1, 7
    mysql> SELECT BIT_COUNT('64'), BIT_COUNT(_binary '64');
     -> 1, 7
    mysql> SELECT BIT_COUNT(X'40'), BIT_COUNT(_binary X'40');
     -> 1, 1
    

位函数和运算符包括 BIT_COUNT(), BIT_AND(), BIT_OR(), BIT_XOR(), &, |, ^, ~, <<, 以及 >>。(BIT_AND(), BIT_OR(), 和 BIT_XOR() 聚合函数在 第 14.19.1 节,“聚合函数描述” 中有描述。)在 MySQL 8.0 之前,位函数和运算符需要 BIGINT(64 位整数)参数,并返回 BIGINT 值,因此它们的最大范围为 64 位。非 BIGINT 参数在执行操作之前被转换为 BIGINT,并且可能发生截断。

在 MySQL 8.0 中,位函数和运算符允许二进制字符串类型的参数(BINARY, VARBINARY, 以及 BLOB 类型),并返回相同类型的值,这使它们能够接受参数并生成大于 64 位的返回值。非二进制字符串参数被转换为 BIGINT 并按照此类处理,就像以前一样。

这种行为变化的一个影响是,在 MySQL 8.0 中对二进制字符串参数进行位操作可能会产生与 5.7 中不同的结果。有关如何在 MySQL 5.7 中准备可能的 MySQL 5.7 和 8.0 之间不兼容性的信息,请参阅 位函数和运算符,在 MySQL 5.7 参考手册 中。

  • MySQL 8.0 之前的位操作

  • MySQL 8.0 中的位操作

  • 二进制字符串位操作示例

  • 位与、或和异或操作

  • 位取反和移位操作

  • BIT_COUNT() 操作 操作")

  • BIT_AND(), BIT_OR(), 和 BIT_XOR() 操作, BIT_OR(), 和 BIT_XOR() 操作")

  • 十六进制文字面量、位文字面量和 NULL 文字面量的特殊处理

  • 与 MySQL 5.7 不兼容的位操作

MySQL 8.0 之前的位操作

MySQL 8.0 之前的位操作仅处理无符号 64 位整数参数和结果值(即无符号BIGINT 值)。必要时将其他类型的参数转换为BIGINT。示例:

  • 此语句操作数字文字面量,将其视为无符号 64 位整数:

    mysql> SELECT 127 | 128, 128 << 2, BIT_COUNT(15);
    +-----------+----------+---------------+
    | 127 | 128 | 128 << 2 | BIT_COUNT(15) |
    +-----------+----------+---------------+
    |       255 |      512 |             4 |
    +-----------+----------+---------------+
    
  • 在执行此语句之前,对字符串参数进行了数字转换(例如,'127' 转换为 127),然后执行与第一个语句相同的操作并产生相同的结果:

    mysql> SELECT '127' | '128', '128' << 2, BIT_COUNT('15');
    +---------------+------------+-----------------+
    | '127' | '128' | '128' << 2 | BIT_COUNT('15') |
    +---------------+------------+-----------------+
    |           255 |        512 |               4 |
    +---------------+------------+-----------------+
    
  • 此语句使用十六进制文字面量作为位操作参数。MySQL 默认将十六进制文字面量视为二进制字符串,但在数字上下文中将其评估为数字(参见第 11.1.4 节,“十六进制文字面量”)。在 MySQL 8.0 之前,数字上下文包括位操作。示例:

    mysql> SELECT X'7F' | X'80', X'80' << 2, BIT_COUNT(X'0F');
    +---------------+------------+------------------+
    | X'7F' | X'80' | X'80' << 2 | BIT_COUNT(X'0F') |
    +---------------+------------+------------------+
    |           255 |        512 |                4 |
    +---------------+------------+------------------+
    

    在位操作中处理位值文字面量类似于十六进制文字面量(即作为数字)。

MySQL 8.0 中的位操作

MySQL 8.0 扩展了位操作,直接处理二进制字符串参数(无需转换)并产生二进制字符串结果。(不是整数或二进制字符串的参数仍然会像以前一样转换为整数。)此扩展以以下方式增强了位操作:

  • 可以对超过 64 位的值执行位操作。

  • 对于更自然地表示为二进制字符串而不是整数的值执行位操作更容易。

例如,考虑 UUID 值和 IPv6 地址,它们具有人类可读的文本格式,如下所示:

UUID: 6ccd780c-baba-1026-9564-5b8c656024db
IPv6: fe80::219:d1ff:fe91:1a72

在这些格式的文本字符串上操作是繁琐的。一个替代方法是将它们转换为没有分隔符的固定长度二进制字符串。UUID_TO_BIN()INET6_ATON()分别产生数据类型为BINARY(16)的值,一个 16 字节(128 位)长的二进制字符串。以下语句说明了这一点(HEX()用于生成可显示的值):

mysql> SELECT HEX(UUID_TO_BIN('6ccd780c-baba-1026-9564-5b8c656024db'));
+----------------------------------------------------------+
| HEX(UUID_TO_BIN('6ccd780c-baba-1026-9564-5b8c656024db')) |
+----------------------------------------------------------+
| 6CCD780CBABA102695645B8C656024DB                         |
+----------------------------------------------------------+
mysql> SELECT HEX(INET6_ATON('fe80::219:d1ff:fe91:1a72'));
+---------------------------------------------+
| HEX(INET6_ATON('fe80::219:d1ff:fe91:1a72')) |
+---------------------------------------------+
| FE800000000000000219D1FFFE911A72            |
+---------------------------------------------+

那些二进制值可以通过位操作轻松操作,执行诸如从 UUID 值中提取时间戳或从 IPv6 地址中提取网络和主机部分等操作。(有关示例,请参见本讨论后面。)

计为二进制字符串的参数包括列值、例程参数、局部变量和具有二进制字符串类型的用户定义变量:BINARYVARBINARYBLOB类型之一。

那么十六进制文字和位文字呢?回想一下,在 MySQL 中,默认情况下这些是二进制字符串,但在数字上下文中是数字。在 MySQL 8.0 中,它们如何处理用于位操作?MySQL 是否继续在数字上下文中评估它们,就像在 MySQL 8.0 之前所做的那样?还是位操作现在将它们作为二进制字符串进行评估,因为二进制字符串可以“原生”处理而无需转换?

答案:通常会使用十六进制文字或位文字指定位操作的参数,以表示数字,因此当所有位参数都是十六进制或位文字时,MySQL 继续在数字上下文中评估位操作,以保持向后兼容性。如果您需要将其评估为二进制字符串,那很容易实现:至少使用一个文字的_binary引入者。

  • 这些位操作将十六进制文字和位文字作为整数进行评估:

    mysql> SELECT X'40' | X'01', b'11110001' & b'01001111';
    +---------------+---------------------------+
    | X'40' | X'01' | b'11110001' & b'01001111' |
    +---------------+---------------------------+
    |            65 |                        65 |
    +---------------+---------------------------+
    
  • 这些位操作将十六进制文字和位文字作为二进制字符串进行评估,这是由_binary引入者引起的:

    mysql> SELECT _binary X'40' | X'01', b'11110001' & _binary b'01001111';
    +-----------------------+-----------------------------------+
    | _binary X'40' | X'01' | b'11110001' & _binary b'01001111' |
    +-----------------------+-----------------------------------+
    | A                     | A                                 |
    +-----------------------+-----------------------------------+
    

尽管两个语句中的位操作都产生数值为 65 的结果,但第二个语句在二进制字符串上下文中运行,65 在 ASCII 中是A

在数字评估上下文中,十六进制文字和位文字参数的允许值最多为 64 位,结果也是如此。相比之下,在二进制字符串评估上下文中,允许的参数(和结果)可以超过 64 位:

mysql> SELECT _binary X'4040404040404040' | X'0102030405060708';
+---------------------------------------------------+
| _binary X'4040404040404040' | X'0102030405060708' |
+---------------------------------------------------+
| ABCDEFGH                                          |
+---------------------------------------------------+

有几种方法可以引用位操作中的十六进制文字或位文字,以导致二进制字符串评估:

_binary *literal*
BINARY *literal*
CAST(*literal* AS BINARY)

将十六进制文字或位文字分配给用户定义变量是产生二进制字符串评估的另一种方法,这将导致具有二进制字符串类型的变量:

mysql> SET @v1 = X'40', @v2 = X'01', @v3 = b'11110001', @v4 = b'01001111';
mysql> SELECT @v1 | @v2, @v3 & @v4;
+-----------+-----------+
| @v1 | @v2 | @v3 & @v4 |
+-----------+-----------+
| A         | A         |
+-----------+-----------+

在二进制字符串上下文中,位操作的参数必须具有相同的长度,否则会出现ER_INVALID_BITWISE_OPERANDS_SIZE错误:

mysql> SELECT _binary X'40' | X'0001';
ERROR 3513 (HY000): Binary operands of bitwise
operators must be of equal length

为满足等长要求,使用前导零位填充较短值,或者如果较长值以前导零位开始且可以接受较短结果值,则剥离它们:

mysql> SELECT _binary X'0040' | X'0001';
+---------------------------+
| _binary X'0040' | X'0001' |
+---------------------------+
|  A                        |
+---------------------------+
mysql> SELECT _binary X'40' | X'01';
+-----------------------+
| _binary X'40' | X'01' |
+-----------------------+
| A                     |
+-----------------------+

填充或剥离也可以使用函数来完成,例如LPAD()RPAD()SUBSTR()CAST()。在这种情况下,表达式参数不再都是文字,并且_binary变得不必要。示例:

mysql> SELECT LPAD(X'40', 2, X'00') | X'0001';
+---------------------------------+
| LPAD(X'40', 2, X'00') | X'0001' |
+---------------------------------+
|  A                              |
+---------------------------------+
mysql> SELECT X'40' | SUBSTR(X'0001', 2, 1);
+-------------------------------+
| X'40' | SUBSTR(X'0001', 2, 1) |
+-------------------------------+
| A                             |
+-------------------------------+

二进制字符串位操作示例

以下示例说明了使用位操作来提取 UUID 值的部分,例如时间戳和 IEEE 802 节点号。此技术需要为每个提取部分准备位掩码。

将文本 UUID 转换为相应的 16 字节二进制值,以便在二进制字符串上下文中使用位操作进行操作:

mysql> SET @uuid = UUID_TO_BIN('6ccd780c-baba-1026-9564-5b8c656024db');
mysql> SELECT HEX(@uuid);
+----------------------------------+
| HEX(@uuid)                       |
+----------------------------------+
| 6CCD780CBABA102695645B8C656024DB |
+----------------------------------+

为值的时间戳和节点号部分构造位掩码。时间戳包括前三部分(64 位,位 0 到 63),节点号是最后一部分(48 位,位 80 到 127):

mysql> SET @ts_mask = CAST(X'FFFFFFFFFFFFFFFF' AS BINARY(16));
mysql> SET @node_mask = CAST(X'FFFFFFFFFFFF' AS BINARY(16)) >> 80;
mysql> SELECT HEX(@ts_mask);
+----------------------------------+
| HEX(@ts_mask)                    |
+----------------------------------+
| FFFFFFFFFFFFFFFF0000000000000000 |
+----------------------------------+
mysql> SELECT HEX(@node_mask);
+----------------------------------+
| HEX(@node_mask)                  |
+----------------------------------+
| 00000000000000000000FFFFFFFFFFFF |
+----------------------------------+

这里使用CAST(... AS BINARY(16))函数,因为掩码必须与其应用的 UUID 值长度相同。可以使用其他函数将掩码填充到所需长度以产生相同的结果:

SET @ts_mask= RPAD(X'FFFFFFFFFFFFFFFF' , 16, X'00');
SET @node_mask = LPAD(X'FFFFFFFFFFFF', 16, X'00') ;

使用掩码提取时间戳和节点号部分:

mysql> SELECT HEX(@uuid & @ts_mask) AS 'timestamp part';
+----------------------------------+
| timestamp part                   |
+----------------------------------+
| 6CCD780CBABA10260000000000000000 |
+----------------------------------+
mysql> SELECT HEX(@uuid & @node_mask) AS 'node part';
+----------------------------------+
| node part                        |
+----------------------------------+
| 000000000000000000005B8C656024DB |
+----------------------------------+

前面的示例使用了这些位操作:右移(>>)和按位与(&)。

注意

UUID_TO_BIN()接受一个标志,导致生成的二进制 UUID 值中的一些位重新排列。如果使用该标志,请相应修改提取掩码。

下一个示例使用位操作来提取 IPv6 地址的网络和主机部分。假设网络部分长度为 80 位。那么主机部分长度为 128 − 80 = 48 位。要提取地址的网络和主机部分,将其转换为二进制字符串,然后在二进制字符串上下文中使用位操作。

将文本 IPv6 地址转换为相应的二进制字符串:

mysql> SET @ip = INET6_ATON('fe80::219:d1ff:fe91:1a72');

定义网络长度(以位为单位):

mysql> SET @net_len = 80;

通过将全为 1 的地址左移或右移来构造网络和主机掩码。为此,从地址::开始,这是所有零的简写,可以通过将其转换为二进制字符串来查看:

mysql> SELECT HEX(INET6_ATON('::')) AS 'all zeros';
+----------------------------------+
| all zeros                        |
+----------------------------------+
| 00000000000000000000000000000000 |
+----------------------------------+

要生成补码值(全为 1),使用~运算符来反转位:

mysql> SELECT HEX(~INET6_ATON('::')) AS 'all ones';
+----------------------------------+
| all ones                         |
+----------------------------------+
| FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF |
+----------------------------------+

将全为 1 的值左移或右移以生成网络和主机掩码:

mysql> SET @net_mask = ~INET6_ATON('::') << (128 - @net_len);
mysql> SET @host_mask = ~INET6_ATON('::') >> @net_len;

显示掩码以验证其覆盖地址的正确部分:

mysql> SELECT INET6_NTOA(@net_mask) AS 'network mask';
+----------------------------+
| network mask               |
+----------------------------+
| ffff:ffff:ffff:ffff:ffff:: |
+----------------------------+
mysql> SELECT INET6_NTOA(@host_mask) AS 'host mask';
+------------------------+
| host mask              |
+------------------------+
| ::ffff:255.255.255.255 |
+------------------------+

提取并显示地址的网络部分和主机部分:

mysql> SET @net_part = @ip & @net_mask;
mysql> SET @host_part = @ip & @host_mask;
mysql> SELECT INET6_NTOA(@net_part) AS 'network part';
+-----------------+
| network part    |
+-----------------+
| fe80::219:0:0:0 |
+-----------------+
mysql> SELECT INET6_NTOA(@host_part) AS 'host part';
+------------------+
| host part        |
+------------------+
| ::d1ff:fe91:1a72 |
+------------------+

前面的示例使用了这些位操作:补码(~)、左移(<<)和按位与(&)。

剩余的讨论提供了每组位操作的参数处理细节,位操作中字面值处理的更多信息,以及 MySQL 8.0 与旧版 MySQL 之间的潜在不兼容性。

按位与、或和异或操作

对于&|^位操作,结果类型取决于参数是作为二进制字符串还是数字进行评估:

  • 当参数具有二进制字符串类型且至少有一个参数不是十六进制字面值、位字面值或NULL字面值时,进行二进制字符串评估。否则进行数值评估,必要时将参数转换为无符号 64 位整数。

  • 二进制字符串评估产生与参数相同长度的二进制字符串。如果参数长度不相等,则会出现 ER_INVALID_BITWISE_OPERANDS_SIZE 错误。数值评估产生一个无符号 64 位整数。

数值评估的示例:

mysql> SELECT 64 | 1, X'40' | X'01';
+--------+---------------+
| 64 | 1 | X'40' | X'01' |
+--------+---------------+
|     65 |            65 |
+--------+---------------+

二进制字符串评估的示例:

mysql> SELECT _binary X'40' | X'01';
+-----------------------+
| _binary X'40' | X'01' |
+-----------------------+
| A                     |
+-----------------------+
mysql> SET @var1 = X'40', @var2 = X'01';
mysql> SELECT @var1 | @var2;
+---------------+
| @var1 | @var2 |
+---------------+
| A             |
+---------------+

按位补码和移位操作

对于~<<>>位操作,结果类型取决于位参数是作为二进制字符串还是数字进行评估:

  • 当位参数具有二进制字符串类型且不是十六进制字面值、位字面值或NULL字面值时,进行二进制字符串评估。否则进行数值评估,必要时将参数转换为无符号 64 位整数。

  • 二进制字符串评估产生与位参数相同长度的二进制字符串。数值评估产生一个无符号 64 位整数。

对于移位操作,超出值末尾的位将被丢弃,而不会有警告,无论参数类型如何。特别是,如果移位计数大于或等于位参数中的位数,则结果中的所有位都为 0。

数值评估的示例:

mysql> SELECT ~0, 64 << 2, X'40' << 2;
+----------------------+---------+------------+
| ~0                   | 64 << 2 | X'40' << 2 |
+----------------------+---------+------------+
| 18446744073709551615 |     256 |        256 |
+----------------------+---------+------------+

二进制字符串评估的示例:

mysql> SELECT HEX(_binary X'1111000022220000' >> 16);
+----------------------------------------+
| HEX(_binary X'1111000022220000' >> 16) |
+----------------------------------------+
| 0000111100002222                       |
+----------------------------------------+
mysql> SELECT HEX(_binary X'1111000022220000' << 16);
+----------------------------------------+
| HEX(_binary X'1111000022220000' << 16) |
+----------------------------------------+
| 0000222200000000                       |
+----------------------------------------+
mysql> SET @var1 = X'F0F0F0F0';
mysql> SELECT HEX(~@var1);
+-------------+
| HEX(~@var1) |
+-------------+
| 0F0F0F0F    |
+-------------+

BIT_COUNT() 操作

BIT_COUNT() 函数始终返回一个无符号 64 位整数,如果参数为NULL,则返回NULL

mysql> SELECT BIT_COUNT(127);
+----------------+
| BIT_COUNT(127) |
+----------------+
|              7 |
+----------------+
mysql> SELECT BIT_COUNT(b'010101'), BIT_COUNT(_binary b'010101');
+----------------------+------------------------------+
| BIT_COUNT(b'010101') | BIT_COUNT(_binary b'010101') |
+----------------------+------------------------------+
|                    3 |                            3 |
+----------------------+------------------------------+

BIT_AND()、BIT_OR() 和 BIT_XOR() 操作

对于BIT_AND()BIT_OR()BIT_XOR()位函数,结果类型取决于函数参数值是作为二进制字符串还是数字进行评估:

  • 当参数值具有二进制字符串类型且参数不是十六进制文字、位文字或NULL文字时,会发生二进制字符串评估。否则会发生数值评估,必要时将参数值转换为无符号 64 位整数。

  • 二进制字符串评估会产生与参数值相同长度的二进制字符串。如果参数值长度不相等,则会出现ER_INVALID_BITWISE_OPERANDS_SIZE错误。如果参数大小超过 511 字节,则会出现ER_INVALID_BITWISE_AGGREGATE_OPERANDS_SIZE错误。数值评估会产生一个无符号 64 位整数。

NULL值不会影响结果,除非所有值都是NULL。在这种情况下,结果是一个中性值,其长度与参数值的长度相同(对于BIT_AND()为所有位为 1,对于BIT_OR()为所有位为 0,以及BIT_XOR())。

例子:

mysql> CREATE TABLE t (group_id INT, a VARBINARY(6));
mysql> INSERT INTO t VALUES (1, NULL);
mysql> INSERT INTO t VALUES (1, NULL);
mysql> INSERT INTO t VALUES (2, NULL);
mysql> INSERT INTO t VALUES (2, X'1234');
mysql> INSERT INTO t VALUES (2, X'FF34');
mysql> SELECT HEX(BIT_AND(a)), HEX(BIT_OR(a)), HEX(BIT_XOR(a))
       FROM t GROUP BY group_id;
+-----------------+----------------+-----------------+
| HEX(BIT_AND(a)) | HEX(BIT_OR(a)) | HEX(BIT_XOR(a)) |
+-----------------+----------------+-----------------+
| FFFFFFFFFFFF    | 000000000000   | 000000000000    |
| 1234            | FF34           | ED00            |
+-----------------+----------------+-----------------+

十六进制文字、位文字和 NULL 文字的特殊处理

为了向后兼容,当所有位参数为十六进制文字、位文字或NULL文字时,MySQL 8.0 会在数值上评估位操作。也就是说,如果所有位参数都是未修饰的十六进制文字、位文字或NULL文字,则对二进制字符串位参数的位操作不会使用二进制字符串评估。(如果它们是用_binary引导符、BINARY运算符或其他明确指定为二进制字符串的方式写入的,则不适用于这些文字。)

刚才描述的文字处理与 MySQL 8.0 之前的版本相同。例如:

  • 这些位操作在数值上评估文字并产生一个BIGINT结果:

    b'0001' | b'0010'
    X'0008' << 8
    
  • 这些位操作在数值上评估NULL并产生一个具有NULL值的BIGINT结果:

    NULL & NULL
    NULL >> 4
    

在 MySQL 8.0 中,您可以通过明确指示至少一个参数是二进制字符串来导致这些操作在二进制字符串上下文中评估参数:

_binary b'0001' | b'0010'
_binary X'0008' << 8
BINARY NULL & NULL
BINARY NULL >> 4

最后两个表达式的结果是NULL,就像没有BINARY运算符一样,但结果的数据类型是二进制字符串类型而不是整数类型。

与 MySQL 5.7 不兼容的位操作

因为 MySQL 8.0 可以原生处理二进制字符串参数的位操作,一些表达式在 MySQL 8.0 中产生的结果与 5.7 中不同。需要注意的五种问题表达式类型是:

*nonliteral_binary* { & | ^ } *binary*
*binary*  { & | ^ } *nonliteral_binary*
*nonliteral_binary* { << >> } *anything*
~ *nonliteral_binary*
*AGGR_BIT_FUNC*(*nonliteral_binary*)

这些表达式在 MySQL 5.7 中返回BIGINT,在 8.0 中返回二进制字符串。

符号说明:

  • { *op1* *op2* ... }:适用于给定表达式类型的运算符列表。

  • binary:任何类型的二进制字符串参数,包括十六进制文字、位文字或NULL文字。

  • nonliteral_binary:一个不是十六进制文字、位文字或NULL文字的二进制字符串值的参数。

  • AGGR_BIT_FUNC:一个接受位值参数的聚合函数:BIT_AND()BIT_OR()BIT_XOR()

有关如何在 MySQL 5.7 中准备可能的 MySQL 5.7 和 8.0 之间不兼容性的信息,请参阅位函数和运算符,在 MySQL 5.7 参考手册中。

14.13 加密和压缩函数

原文:dev.mysql.com/doc/refman/8.0/en/encryption-functions.html

表 14.18 加密函数

名称描述
AES_DECRYPT()使用 AES 解密
AES_ENCRYPT()使用 AES 加密
COMPRESS()以二进制字符串形式返回结果
MD5()计算 MD5 校验和
RANDOM_BYTES()返回一个随机字节向量
SHA1(), SHA()计算 SHA-1 160 位校验和
SHA2()计算 SHA-2 校验和
STATEMENT_DIGEST()计算语句摘要哈希值
STATEMENT_DIGEST_TEXT()计算规范语句摘要
UNCOMPRESS()解压缩压缩的字符串
UNCOMPRESSED_LENGTH()返回压缩前字符串的长度
VALIDATE_PASSWORD_STRENGTH()确定密码强度
名称描述

许多加密和压缩函数返回的字符串可能包含任意字节值。如果您想存储这些结果,请使用具有VARBINARYBLOB二进制字符串数据类型的列。这样可以避免由于使用非二进制字符串数据类型(CHAR, VARCHAR, TEXT)可能导致的尾随空格删除或字符集转换等潜在问题,从而改变数据值。

一些加密函数返回 ASCII 字符的字符串:MD5(), SHA(), SHA1(), SHA2(), STATEMENT_DIGEST(), STATEMENT_DIGEST_TEXT()。它们的返回值是一个由character_set_connectioncollation_connection系统变量确定的具有字符集和排序规则的字符串。这是一个非二进制字符串,除非字符集是binary

如果应用程序存储来自诸如MD5()SHA1()的函数返回十六进制数字字符串的值,可以通过使用UNHEX()将十六进制表示转换为二进制形式并将结果存储在BINARY(*N*)列中获得更有效的存储和比较。每对十六进制数字在二进制形式中需要一个字节,因此N的值取决于十六进制字符串的长度。对于MD5()值,N为 16,对于SHA1()值为 20。对于SHA2()N的范围从 28 到 32,具体取决于指定结果所需位长度的参数。

CHAR列中存储十六进制字符串的大小惩罚至少是两倍,如果该值存储在使用utf8mb4字符集的列中(其中每个字符使用 4 个字节),则最多是八倍。存储字符串还会导致比较速度变慢,因为数值更大,需要考虑字符集排序规则。

假设一个应用程序将MD5()字符串值存储在CHAR(32)列中:

CREATE TABLE md5_tbl (md5_val CHAR(32), ...);
INSERT INTO md5_tbl (md5_val, ...) VALUES(MD5('abcdef'), ...);

要将十六进制字符串转换为更紧凑的形式,请修改应用程序以使用UNHEX()BINARY(16)如下:

CREATE TABLE md5_tbl (md5_val BINARY(16), ...);
INSERT INTO md5_tbl (md5_val, ...) VALUES(UNHEX(MD5('abcdef')), ...);

应用程序应准备处理散列函数为两个不同输入值产生相同值的极为罕见的情况。使碰撞可检测的一种方法是将哈希列设为主键。

注意

MD5 和 SHA-1 算法的漏洞已经被发现。您可能希望考虑使用本节中描述的其他单向加密函数,例如SHA2()

警告

作为加密函数参数提供的密码或其他敏感值在未使用 SSL 连接的情况下以明文形式发送到 MySQL 服务器。此外,这些值会出现在写入的任何 MySQL 日志中。为了避免这些类型的暴露,应用程序可以在将敏感值发送到服务器之前在客户端端对其进行加密。相同的考虑也适用于加密密钥。为了避免暴露这些,应用程序可以使用存储过程在服务器端对值进行加密和解密。

  • AES_DECRYPT(*crypt_str*,*key_str*[,*init_vector*][,*kdf_name*][,*salt*][,*info | iterations*])

    此函数使用官方 AES(高级加密标准)算法解密数据。更多信息,请参阅AES_ENCRYPT()的描述。

    使用AES_DECRYPT()的语句对基于语句的复制不安全。

  • AES_ENCRYPT(*str*,*key_str*[,*init_vector*][,*kdf_name*][,*salt*][,*info | iterations*])

    AES_ENCRYPT()AES_DECRYPT() 实现使用官方 AES(高级加密标准)算法加密和解密数据,此前被称为“Rijndael”。AES 标准允许使用各种密钥长度。默认情况下,这些函数使用 128 位密钥长度实现 AES。可以使用 196 位或 256 位的密钥长度,如后面所述。密钥长度是性能和安全性之间的权衡。

    AES_ENCRYPT() 使用密钥字符串 key_str 对字符串 str 进行加密,并返回包含加密输出的二进制字符串。AES_DECRYPT() 使用密钥字符串 key_str 对加密字符串 crypt_str 进行解密,并以十六进制格式返回原始(二进制)字符串。(要将字符串作为明文获取,将结果转换为 CHAR。或者,使用 --skip-binary-as-hex 启动mysql客户端,以使所有二进制值显示为文本。)如果任一函数参数为 NULL,函数将返回 NULL。如果AES_DECRYPT()检测到无效数据或不正确的填充,它将返回 NULL。但是,如果输入数据或密钥无效,AES_DECRYPT()可能会返回一个非 NULL 值(可能是垃圾)。

    截至 MySQL 8.0.30,这些函数支持使用密钥派生函数(KDF)从传递给 key_str 的信息创建一个密码强度强的秘密密钥。派生密钥用于加密和解密数据,并保留在 MySQL 服务器实例中,用户无法访问。强烈建议使用 KDF,因为它提供比指定自己预制密钥或通过更简单的方法派生密钥更好的安全性。这些函数支持 HKDF(自 OpenSSL 1.1.0 起可用),您可以指定一个可选的盐和上下文特定信息以包含在密钥材料中,以及 PBKDF2(自 OpenSSL 1.0.2 起可用),您可以指定一个可选的盐并设置用于生成密钥的迭代次数。

    AES_ENCRYPT()AES_DECRYPT()允许控制块加密模式。block_encryption_mode系统变量控制基于块的加密算法的模式。其默认值为aes-128-ecb,表示使用 128 位密钥长度和 ECB 模式进行加密。有关此变量允许的值的描述,请参见第 7.1.8 节,“服务器系统变量”。可选的*init_vector*参数用于为需要初始化向量的块加密模式提供初始化向量。

    使用AES_ENCRYPT()AES_DECRYPT()的语句对于基于语句的复制是不安全的。

    如果在mysql客户端内调用AES_ENCRYPT(),二进制字符串将使用十六进制表示,取决于--binary-as-hex的值。有关该选项的更多信息,请参见第 6.5.1 节,“mysql — The MySQL Command-Line Client”。

    AES_ENCRYPT()AES_DECRYPT()函数的参数如下:

    str

    用于AES_ENCRYPT()加密的字符串,使用密钥字符串*key_str,或者(从 MySQL 8.0.30 开始)使用指定 KDF 派生的密钥。字符串可以是任意长度。根据块为单位的算法(如 AES)的要求,str*会自动添加填充以使其成为块的倍数。此填充会被AES_DECRYPT()函数自动移除。

    crypt_str

    用于AES_DECRYPT()解密的加密字符串,使用密钥字符串*key_str,或者(从 MySQL 8.0.30 开始)使用指定 KDF 派生的密钥。字符串可以是任意长度。crypt_str*的长度可以根据原始字符串的长度使用以下公式计算:

    16 * (trunc(*string_length* / 16) + 1)
    

    key_str

    加密密钥,或者作为基础使用密钥派生函数(KDF)派生密钥的输入密钥材料。对于相同的数据实例,使用相同的*key_str*值进行使用AES_ENCRYPT()进行加密和使用AES_DECRYPT()进行解密。

    如果您使用 KDF,可以从 MySQL 8.0.30 开始,*key_str*可以是任意信息,如密码或口令。在函数的进一步参数中,您指定 KDF 名称,然后添加进一步选项以根据 KDF 适当增加安全性。

    当您使用 KDF 时,函数会从*key_str*中传递的信息以及您在其他参数中提供的盐或其他信息创建一个密码学强大的密钥。派生密钥用于加密和解密数据,并保留在 MySQL 服务器实例中,用户无法访问。强烈建议使用 KDF,因为它提供比指定自己的预制密钥或通过更简单的方法派生密钥更好的安全性。

    如果不使用 KDF,对于 128 位的密钥长度,将密钥传递给*key_str*参数的最安全方式是创建一个真正随机的 128 位值并将其作为二进制值传递。例如:

    INSERT INTO t
    VALUES (1,AES_ENCRYPT('text',UNHEX('F3229A0B371ED2D9441B830D21A390C3')));
    

    可以使用口令通过哈希口令生成 AES 密钥。例如:

    INSERT INTO t
    VALUES (1,AES_ENCRYPT('text', UNHEX(SHA2('My secret passphrase',512))));
    

    如果超过 128 位的最大密钥长度,将返回警告。如果不使用 KDF,请不要直接将密码或口令传递给*key_str*,先对其进行哈希处理。本文档的早期版本建议采用前一种方法,但不再建议,因为这里显示的示例更安全。

    init_vector

    用于需要的块加密模式的初始化向量。block_encryption_mode系统变量控制模式。对于相同的数据实例,使用相同的*init_vector*值进行AES_ENCRYPT()加密和AES_DECRYPT()解密。

    注意

    如果使用 KDF,必须为此参数指定一个初始化向量或空字符串,以便访问后续参数以定义 KDF。

    对于需要初始化向量的模式,它必须是 16 字节或更长(超过 16 字节的字节将被忽略)。如果缺少*init_vector,则会发生错误。对于不需要初始化向量的模式,如果指定了init_vector*,则会被忽略并生成警告,除非您使用 KDF。

    block_encryption_mode系统变量的默认值为aes-128-ecb,或 ECB 模式,不需要初始化向量。允许的替代块加密模式 CBC、CFB1、CFB8、CFB128 和 OFB 都需要初始化向量。

    可以通过调用RANDOM_BYTES(16)生成一个用于初始化向量的随机字节字符串。

    kdf_name

    创建密钥派生函数(KDF)的名称,用于从传递给KDF的输入密钥材料中创建密钥,并根据 KDF 的要求提供其他参数。此可选参数从 MySQL 8.0.30 起可用。

    对于相同的数据实例,使用相同的*kdf_name值进行AES_ENCRYPT()加密和AES_DECRYPT()解密。当指定kdf_name时,必须指定init_vector*,使用有效的初始化向量或如果加密模式不需要初始化向量则使用空字符串。

    支持以下值:

    hkdf

    HKDF,从 OpenSSL 1.1.0 起可用。HKDF 从密钥材料中提取一个伪随机密钥,然后将其扩展为其他密钥。使用 HKDF,您可以指定一个可选的盐(salt)和上下文特定信息,如应用程序细节(info)以包含在密钥材料中。

    pbkdf2_hmac

    PBKDF2,从 OpenSSL 1.0.2 起可用。PBKDF2 将一个伪随机函数应用于密钥材料,并重复这个过程多次以生成密钥。使用 PBKDF2,您可以指定一个可选的盐(salt)以包含在密钥材料中,并设置用于生成密钥的迭代次数(iterations)。

    在此示例中,HKDF 被指定为密钥派生函数,提供了盐和上下文信息。初始化向量的参数被包含在内,但为空字符串:

    SELECT AES_ENCRYPT('mytext','mykeystring', '', 'hkdf', 'salt', 'info');
    

    在此示例中,PBKDF2 被指定为密钥派生函数,提供了盐,并且迭代次数是推荐最小值的两倍。

    SELECT AES_ENCRYPT('mytext','mykeystring', '', 'pbkdf2_hmac','salt', '2000');
    

    salt

    传递给密钥派生函数(KDF)的盐。此可选参数从 MySQL 8.0.30 起可用。HKDF 和 PBKDF2 都可以使用盐,建议使用盐以帮助防止基于常见密码字典或彩虹表的攻击。

    盐由随机数据组成,为了安全起见,每次加密操作必须使用不同的盐。可以通过调用RANDOM_BYTES()生成一个随机字节字符串作为盐。以下示例生成一个 64 位盐:

    SET @salt = RANDOM_BYTES(8);
    

    对于相同的数据实例,使用相同的*salt*值进行AES_ENCRYPT()加密和AES_DECRYPT()解密。盐可以安全地与加密数据一起存储。

    info

    用于在密钥材料中包含 HKDF 的上下文特定信息,例如有关应用程序的信息。当您将hkdf指定为 KDF 名称时,此可选参数从 MySQL 8.0.30 起可用。HKDF 将此信息添加到*key_str中指定的密钥材料和salt*中指定的盐中以生成密钥。

    对于相同的数据实例,使用相同的*info*值进行使用AES_ENCRYPT()进行加密和使用AES_DECRYPT()进行解密。

    迭代

    生成密钥时 PBKDF2 使用的迭代次数。当您将pbkdf2_hmac作为 KDF 名称指定时,此可选参数从 MySQL 8.0.30 开始可用。较高的计数值使得对抗暴力破解攻击更加困难,因为对于攻击者来说,计算成本更高,但对于密钥派生过程也是如此。如果不指定此参数,则默认值为 1000,这是 OpenSSL 标准推荐的最低值。

    对于相同的数据实例,使用相同的*迭代*值进行使用AES_ENCRYPT()进行加密和使用AES_DECRYPT()进行解密。

    mysql> SET block_encryption_mode = 'aes-256-cbc';
    mysql> SET @key_str = SHA2('My secret passphrase',512);
    mysql> SET @init_vector = RANDOM_BYTES(16);
    mysql> SET @crypt_str = AES_ENCRYPT('text',@key_str,@init_vector);
    mysql> SELECT CAST(AES_DECRYPT(@crypt_str,@key_str,@init_vector) AS CHAR);
    +-------------------------------------------------------------+
    | CAST(AES_DECRYPT(@crypt_str,@key_str,@init_vector) AS CHAR) |
    +-------------------------------------------------------------+
    | text                                                        |
    +-------------------------------------------------------------+
    
  • COMPRESS(*string_to_compress*)

    压缩字符串并将结果作为二进制字符串返回。此函数要求 MySQL 已经使用诸如zlib之类的压缩库进行编译。否则,返回值始终为NULL。如果*string_to_compress*为NULL,返回值也为NULL。压缩后的字符串可以使用UNCOMPRESS()进行解压缩。

    mysql> SELECT LENGTH(COMPRESS(REPEAT('a',1000)));
     -> 21
    mysql> SELECT LENGTH(COMPRESS(''));
     -> 0
    mysql> SELECT LENGTH(COMPRESS('a'));
     -> 13
    mysql> SELECT LENGTH(COMPRESS(REPEAT('a',16)));
     -> 15
    

    压缩后的字符串内容存储如下:

    • 空字符串存储为空字符串。

    • 非空字符串存储为未压缩字符串的 4 字节长度(低字节在前),后跟压缩字符串。如果字符串以空格结尾,则会添加额外的.字符,以避免在将结果存储在CHARVARCHAR列中时出现末尾空格修剪问题。(但是,不建议使用诸如CHARVARCHAR之类的非二进制字符串数据类型来存储压缩字符串,因为可能会发生字符集转换。请改用VARBINARYBLOB二进制字符串列。)

    如果从mysql客户端中调用COMPRESS(),二进制字符串将使用十六进制表示,具体取决于--binary-as-hex的值。有关该选项的更多信息,请参见 Section 6.5.1, “mysql — The MySQL Command-Line Client”。

  • MD5(*str*)

    为字符串计算 MD5 128 位校验和。返回值是一个包含 32 个十六进制数字的字符串,如果参数为NULL则返回NULL。返回值可以用作哈希键。有关有效存储哈希值的注意事项,请参阅本节开头的注释。

    返回值是连接字符集中的字符串。

    如果启用了 FIPS 模式,MD5()将返回NULL。请参阅第 8.8 节,“FIPS 支持”。

    mysql> SELECT MD5('testing');
     -> 'ae2b1fca515949e5d54fb22b8ed95575'
    

    这是“RSA 数据安全公司 MD5 消息摘要算法”。

    请参阅本节开头关于 MD5 算法的注意事项。

  • RANDOM_BYTES(*len*)

    此函数返回使用 SSL 库的随机数生成器生成的*len个随机字节的二进制字符串。允许的len值范围从 1 到 1024。对于超出该范围的值,将发生错误。如果len*为NULL,则返回NULL

    RANDOM_BYTES()可用于为AES_DECRYPT()AES_ENCRYPT()函数提供初始化向量。在该上下文中使用时,*len*必须至少为 16。允许使用更大的值,但超过 16 的字节将被忽略。

    RANDOM_BYTES()生成一个随机值,使其结果是不确定的。因此,使用此函数的语句对于基于语句的复制是不安全的。

    如果从mysql客户端调用RANDOM_BYTES(),则二进制字符串将使用十六进制表示,具体取决于--binary-as-hex的值。有关该选项的更多信息,请参阅第 6.5.1 节,“mysql — MySQL 命令行客户端”。

  • SHA1(*str*), SHA(*str*)

    为字符串计算 SHA-1 160 位校验和,如 RFC 3174(安全哈希算法)中所述。返回值是一个包含 40 个十六进制数字的字符串,如果参数为NULL则返回NULL。此函数的一个可能用途是作为哈希键。有关有效存储哈希值的注意事项,请参阅本节开头的注释。SHA()SHA1()是同义词。

    返回值是连接字符集中的字符串。

    mysql> SELECT SHA1('abc');
     -> 'a9993e364706816aba3e25717850c26c9cd0d89d'
    

    SHA1()可以被视为MD5()的密码学上更安全的等价物。然而,请参阅本节开头关于 MD5 和 SHA-1 算法的注意事项。

  • SHA2(*str*, *hash_length*)

    计算 SHA-2 哈希函数族(SHA-224、SHA-256、SHA-384 和 SHA-512)。第一个参数是要进行哈希处理的明文字符串。第二个参数表示所需结果的位长度,必须为 224、256、384、512 或 0(等同于 256)。如果任一参数为 NULL 或哈希长度不是允许的值之一,则返回值为 NULL。否则,函数结果是包含所需位数的哈希值。请参阅本节开头关于高效存储哈希值的注意事项。

    返回值是连接字符集中的字符串。

    mysql> SELECT SHA2('abc', 224);
     -> '23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7'
    

    仅当 MySQL 配置了 SSL 支持时,此函数才有效。请参阅 Section 8.3, “Using Encrypted Connections”。

    SHA2() 在密码学上比 MD5()SHA1() 更安全。

  • STATEMENT_DIGEST(*statement*)

    给定一个作为字符串的 SQL 语句,返回连接字符集中的语句摘要哈希值作为字符串,如果参数为 NULL 则返回 NULL。相关的 STATEMENT_DIGEST_TEXT() 函数返回规范化语句摘要。有关语句摘要的信息,请参阅 Section 29.10, “Performance Schema Statement Digests and Sampling”。

    两个函数都使用 MySQL 解析器来解析语句。如果解析失败,将会出现错误。如果语句以文字字符串形式提供,则错误消息仅包含解析错误。

    max_digest_length 系统变量确定这些函数用于计算规范化语句摘要的最大字节数。

    mysql> SET @stmt = 'SELECT * FROM mytable WHERE cola = 10 AND colb = 20';
    mysql> SELECT STATEMENT_DIGEST(@stmt);
    +------------------------------------------------------------------+
    | STATEMENT_DIGEST(@stmt)                                          |
    +------------------------------------------------------------------+
    | 3bb95eeade896657c4526e74ff2a2862039d0a0fe8a9e7155b5fe492cbd78387 |
    +------------------------------------------------------------------+
    mysql> SELECT STATEMENT_DIGEST_TEXT(@stmt);
    +----------------------------------------------------------+
    | STATEMENT_DIGEST_TEXT(@stmt)                             |
    +----------------------------------------------------------+
    | SELECT * FROM `mytable` WHERE `cola` = ? AND `colb` = ?  |
    +----------------------------------------------------------+
    
  • STATEMENT_DIGEST_TEXT(*statement*)

    给定一个作为字符串的 SQL 语句,返回连接字符集中的规范化语句摘要作为字符串,如果参数为 NULL 则返回 NULL。有关更多讨论和示例,请参阅相关 STATEMENT_DIGEST() 函数的描述。

  • UNCOMPRESS(*string_to_uncompress*)

    解压由COMPRESS()函数压缩的字符串。如果参数不是压缩值,则结果为NULL;如果*string_to_uncompress*为NULL,则结果也为NULL。此函数要求 MySQL 已经使用诸如zlib之类的压缩库进行编译。否则,返回值始终为NULL

    mysql> SELECT UNCOMPRESS(COMPRESS('any string'));
     -> 'any string'
    mysql> SELECT UNCOMPRESS('any string');
     -> NULL
    
  • UNCOMPRESSED_LENGTH(*compressed_string*)

    返回压缩前的字符串长度。如果*compressed_string*为NULL,则返回NULL

    mysql> SELECT UNCOMPRESSED_LENGTH(COMPRESS(REPEAT('a',30)));
     -> 30
    
  • VALIDATE_PASSWORD_STRENGTH(*str*)

    给定表示明文密码的参数,此函数返回一个整数,指示密码的强度,如果参数为NULL,则返回NULL。返回值范围从 0(弱)到 100(强)。

    VALIDATE_PASSWORD_STRENGTH()进行密码评估,由validate_password组件执行。如果未安装该组件,函数始终返回 0。有关安装validate_password的信息,请参见第 8.4.3 节,“密码验证组件”。要检查或配置影响密码测试的参数,请查看或设置validate_password实现的系统变量。请参见第 8.4.3.2 节,“密码验证选项和变量”。

    密码将经过越来越严格的测试,返回值反映了满足的测试,如下表所示。此外,如果启用了validate_password.check_user_name系统变量,并且密码与用户名匹配,VALIDATE_PASSWORD_STRENGTH()无论如何返回 0,不管其他validate_password系统变量如何设置。

    密码测试返回值
    长度 < 40
    长度 ≥ 4 且 < validate_password.length25
    符合策略 1(LOW50
    符合策略 2(MEDIUM75
    符合策略 3(STRONG100

14.14 锁定函数

原文:dev.mysql.com/doc/refman/8.0/en/locking-functions.html

本节描述用于操作用户级别锁的函数。

表 14.19 锁定函数

名称描述
GET_LOCK()获取命名锁
IS_FREE_LOCK()命名锁是否空闲
IS_USED_LOCK()命名锁是否正在使用;如果是,则返回连接标识符
RELEASE_ALL_LOCKS()释放所有当前命名锁
RELEASE_LOCK()释放命名锁
  • GET_LOCK(*str*,*timeout*)

    尝试使用字符串*str给出的名称以及timeout秒的超时获取锁。负的timeout*值表示无限超时。该锁是排他的。当一个会话持有锁时,其他会话无法获取相同名称的锁。

    如果成功获取锁,则返回1,如果尝试超时(例如,因为另一个客户端先前锁定了名称),则返回0,如果发生错误(例如,内存耗尽或线程被mysqladmin kill杀死),则返回NULL

    使用GET_LOCK()获取的锁通过执行RELEASE_LOCK()显式释放,或者在会话终止时(正常或异常)隐式释放。使用GET_LOCK()获取的锁在事务提交或回滚时不会释放。

    GET_LOCK()是使用元数据锁定(MDL)子系统实现的。可以获取多个同时锁,并且GET_LOCK()不会释放任何现有锁。例如,假设您执行以下语句:

    SELECT GET_LOCK('lock1',10);
    SELECT GET_LOCK('lock2',10);
    SELECT RELEASE_LOCK('lock2');
    SELECT RELEASE_LOCK('lock1');
    

    第二个GET_LOCK()获取第二个锁,两个RELEASE_LOCK()调用都返回 1(成功)。

    甚至可以让给定会话为同一名称获取多个锁。其他会话在获取会话释放该名称的所有锁之前无法获取具有该名称的锁。

    使用GET_LOCK()获取的具有唯一名称的锁会出现在性能模式metadata_locks表中。OBJECT_TYPE列显示USER LEVEL LOCKOBJECT_NAME列指示锁名称。在为相同名称获取多个锁的情况下,只有第一个名称的锁会在metadata_locks表中注册一行。对于该名称的后续锁将在锁中递增计数器,但不会获取额外的元数据锁。当名称上的最后一个锁实例被释放时,锁的metadata_locks行将被删除。

    获得多个锁的能力意味着客户端之间可能发生死锁。当这种情况发生时,服务器会选择一个调用者,并以ER_USER_LOCK_DEADLOCK错误终止其锁获取请求。此错误不会导致事务回滚。

    MySQL 对锁名称的最大长度强制为 64 个字符。

    GET_LOCK()可用于实现应用程序锁或模拟记录锁。名称在整个服务器范围内被锁定。如果一个名称在一个会话中被锁定,那么GET_LOCK()会阻止另一个会话对具有相同名称的锁发出的任何请求。这使得同意给定锁名称的客户端可以使用该名称执行协作性咨询锁定。但请注意,这也使得不属于协作客户端集的客户端可以锁定一个名称,无论是无意还是故意,从而阻止任何协作客户端锁定该名称。减少这种可能性的一种方法是使用特定于数据库或应用程序的锁名称。例如,使用形式为*db_name.strapp_name.str*的锁名称。

    如果多个客户端正在等待一个锁,它们获取锁的顺序是不确定的。应用程序不应假设客户端按照发出锁请求的顺序获取锁。

    binlog_format设置为STATEMENT时,GET_LOCK()对基于语句的复制是不安全的。如果在此函数在此情况下使用,将记录一个警告。

    由于GET_LOCK()仅在单个mysqld上建立锁,因此不适用于 NDB Cluster,后者无法强制执行跨多个 MySQL 服务器的 SQL 锁。有关更多信息,请参见第 25.2.7.10 节,“与多个 NDB Cluster 节点相关的限制”。

    注意

    具有获取多个命名锁的能力,一个语句可以获取大量的锁。例如:

    INSERT INTO ... SELECT GET_LOCK(t1.col_name) FROM t1;
    

    这些类型的语句可能会产生某些不良影响。例如,如果语句在中途失败并回滚,则在失败点之前获取的锁仍然存在。如果意图是要求插入的行与获取的锁对应,那么这个意图就无法满足。此外,如果重要的是按特定顺序授予锁,请注意结果集顺序可能会因优化器选择的执行计划而有所不同。因此,最好限制每个语句对单个锁获取调用。

    另一种不同的锁定接口可作为插件服务或一组可加载函数提供。该接口提供锁定命名空间和不同的读写锁,与GET_LOCK()及相关函数提供的接口不同。有关详细信息,请参见第 7.6.9.1 节,“锁定服务”。

  • IS_FREE_LOCK(*str*)

    检查名为*str*的锁是否可用(即未被锁定)。如果锁可用(没有人在使用锁),则返回1,如果锁正在使用,则返回0,如果发生错误(例如参数不正确),则返回NULL

    此函数对基于语句的复制不安全。如果在binlog_format设置为STATEMENT时使用此函数,将记录警告。

  • IS_USED_LOCK(*str*)

    检查名为*str*的锁是否正在使用(即已锁定)。如果是,则返回持有锁的客户会话的连接标识符。否则,返回NULL

    此函数对基于语句的复制不安全。如果在binlog_format设置为STATEMENT时使用此函数,将记录警告。

  • RELEASE_ALL_LOCKS()

    释放当前会话持有的所有命名锁,并返回释放的锁数(如果没有锁则返回 0)

    此函数对基于语句的复制不安全。如果在binlog_format设置为STATEMENT时使用此函数,将记录警告。

  • RELEASE_LOCK(*str*)

    释放由字符串*str*命名的锁,该锁是使用GET_LOCK()获取的。如果释放了锁,则返回1,如果该线程未建立锁(在这种情况下不会释放锁),则返回0,如果命名的锁不存在,则返回NULL。如果从未通过调用GET_LOCK()获取过锁,或者之前已释放锁,则该锁不存在。

    DO语句与RELEASE_LOCK()一起使用非常方便。请参阅第 15.2.3 节,“DO 语句”。

    binlog_format设置为STATEMENT时,此函数对基于语句的复制不安全。如果在此函数中使用binlog_format设置为STATEMENT时,将记录警告。

14.15 信息函数

原文:dev.mysql.com/doc/refman/8.0/en/information-functions.html

表 14.20 信息函数

名称描述
BENCHMARK()反复执行一个表达式
CHARSET()返回参数的字符集
COERCIBILITY()返回字符串参数的排序强制性值
COLLATION()返回字符串参数的排序规则
CONNECTION_ID()返回连接的连接 ID(线程 ID)
CURRENT_ROLE()返回当前活动角色
CURRENT_USER(), CURRENT_USER认证用户的用户名和主机名
DATABASE()返回默认(当前)数据库名称
FOUND_ROWS()对于带有 LIMIT 子句的 SELECT,如果没有 LIMIT 子句,将返回的行数
ICU_VERSION()ICU 库版本
LAST_INSERT_ID()最后一次 INSERT 的 AUTOINCREMENT 列的值
ROLES_GRAPHML()返回表示内存角色子图的 GraphML 文档
ROW_COUNT()更新的行数
SCHEMA()DATABASE() 的同义词
SESSION_USER()USER() 的同义词
SYSTEM_USER()USER() 的同义词
USER()客户端提供的用户名和主机名
VERSION()返回指示 MySQL 服务器版本的字符串
名称描述
  • BENCHMARK(*count*,*expr*)

    BENCHMARK() 函数重复执行表达式 expr count 次。它可用于计算 MySQL 处理表达式的速度。结果值为 0,对于不合适的参数(如 NULL 或负重复计数)为 NULL

    预期的用法是在mysql客户端内部,报告查询执行时间:

    mysql> SELECT BENCHMARK(1000000,AES_ENCRYPT('hello','goodbye'));
    +---------------------------------------------------+
    | BENCHMARK(1000000,AES_ENCRYPT('hello','goodbye')) |
    +---------------------------------------------------+
    |                                                 0 |
    +---------------------------------------------------+
    1 row in set (4.74 sec)
    

    报告的时间是客户端端的经过时间,而不是服务器端的 CPU 时间。建议多次执行BENCHMARK(),并根据服务器机器的负载情况解释结果。

    BENCHMARK()旨在衡量标量表达式的运行时性能,这对于您使用它和解释结果有一些重要影响:

    • 只能使用标量表达式。虽然表达式可以是子查询,但必须返回单列且最多一行。例如,如果表t有多于一列或多于一行,则BENCHMARK(10, (SELECT * FROM t))会失败。

    • 执行SELECT *expr*语句*N次与执行SELECT BENCHMARK(*N*, *expr*)在涉及的开销量方面有所不同。两者具有非常不同的执行概况,您不应该期望它们花费相同的时间。前者涉及解析器、优化器、表锁定和运行时评估各执行N次。后者仅涉及运行时评估N*次,而所有其他组件仅执行一次。已分配的内存结构将被重用,并且运行时优化,例如对已为聚合函数评估的结果进行本地缓存,可能会改变结果。因此,使用BENCHMARK()通过给予该组件更多权重来衡量运行时组件的性能,并消除网络、解析器、优化器等引入的“噪音”。

  • CHARSET(*str*)

    返回字符串参数的字符集,如果参数为NULL,则返回NULL

    mysql> SELECT CHARSET('abc');
     -> 'utf8mb3'
    mysql> SELECT CHARSET(CONVERT('abc' USING latin1));
     -> 'latin1'
    mysql> SELECT CHARSET(USER());
     -> 'utf8mb3'
    
  • COERCIBILITY(*str*)

    返回字符串参数的排序强制性值。

    mysql> SELECT COERCIBILITY('abc' COLLATE utf8mb4_swedish_ci);
     -> 0
    mysql> SELECT COERCIBILITY(USER());
     -> 3
    mysql> SELECT COERCIBILITY('abc');
     -> 4
    mysql> SELECT COERCIBILITY(1000);
     -> 5
    

    返回值的含义如下表所示。较低的值具有更高的优先级。

    强制性含义示例
    0显式排序带有COLLATE子句的值
    1无排序具有不同排序的字符串连接
    2隐式排序列值、存储过程参数或本地变量
    3系统常量USER()返回值
    4可强制字面字符串
    5数值数值或时间值
    6可忽略NULL或从NULL派生的表达式

    更多信息,请参见第 12.8.4 节,“表达式中的排序强制性”。

  • COLLATION(*str*)

    返回字符串参数的排序。

    mysql> SELECT COLLATION('abc');
     -> 'utf8mb4_0900_ai_ci'
    mysql> SELECT COLLATION(_utf8mb4'abc');
     -> 'utf8mb4_0900_ai_ci'
    mysql> SELECT COLLATION(_latin1'abc');
     -> 'latin1_swedish_ci'
    
  • CONNECTION_ID()

    返回连接的连接 ID(线程 ID)。每个连接都有一个在当前连接的客户端集合中唯一的 ID。

    CONNECTION_ID()返回的值与信息模式PROCESSLIST表的ID列、SHOW PROCESSLIST输出的Id列以及性能模式threads表的PROCESSLIST_ID列中显示的值类型相同。

    mysql> SELECT CONNECTION_ID();
     -> 23786
    

    警告

    更改pseudo_thread_id系统变量的会话值会更改CONNECTION_ID()函数返回的值。

  • CURRENT_ROLE()

    返回一个包含当前会话中当前活动角色的utf8mb3字符串,用逗号分隔,如果没有则返回NONE。该值反映了sql_quote_show_create系统变量的设置。

    假设一个账户被授予以下角色:

    GRANT 'r1', 'r2' TO 'u1'@'localhost';
    SET DEFAULT ROLE ALL TO 'u1'@'localhost';
    

    u1的会话中,初始CURRENT_ROLE()值命名默认账户角色。使用SET ROLE更改该值:

    mysql> SELECT CURRENT_ROLE();
    +-------------------+
    | CURRENT_ROLE()    |
    +-------------------+
    | `r1`@`%`,`r2`@`%` |
    +-------------------+
    mysql> SET ROLE 'r1'; SELECT CURRENT_ROLE();
    +----------------+
    | CURRENT_ROLE() |
    +----------------+
    | `r1`@`%`       |
    +----------------+
    
  • CURRENT_USER, CURRENT_USER()

    返回 MySQL 服务器用于验证当前客户端的用户名称和主机名组合的账户。此账户确定您的访问权限。返回值是utf8mb3字符集中的字符串。

    CURRENT_USER()的值可能与USER()的值不同。

    mysql> SELECT USER();
     -> 'davida@localhost'
    mysql> SELECT * FROM mysql.user;
    ERROR 1044: Access denied for user ''@'localhost' to
    database 'mysql'
    mysql> SELECT CURRENT_USER();
     -> '@localhost'
    

    该示例说明,尽管客户端指定了用户名为davida(如USER()函数的值所示),但服务器却使用匿名用户账户对客户端进行了身份验证(如CURRENT_USER()值的空用户部分所示)。这种情况可能发生的一种方式是在授权表中没有列出davida的账户。

    在存储过程或视图中,CURRENT_USER()返回定义对象的用户账户(由其DEFINER值给出),除非使用SQL SECURITY INVOKER特性定义。在后一种情况下,CURRENT_USER()返回对象的调用者。

    触发器和事件没有选项来定义SQL SECURITY特性,因此对于这些对象,CURRENT_USER()返回定义对象的用户账户。要返回调用者,请使用USER()SESSION_USER()

    以下语句支持使用CURRENT_USER()函数来代替受影响用户或定义者的名称(可能还有主机);在这种情况下,CURRENT_USER()会根据需要进行扩展:

    • DROP USER

    • RENAME USER

    • GRANT

    • REVOKE

    • CREATE FUNCTION

    • CREATE PROCEDURE

    • CREATE TRIGGER

    • CREATE EVENT

    • CREATE VIEW

    • ALTER EVENT

    • ALTER VIEW

    • SET PASSWORD

    对于这种扩展CURRENT_USER()的含义的信息,参见 Section 19.5.1.8, “CURRENT_USER()的复制”的复制")。

    从 MySQL 8.0.34 开始,此函数可用于VARCHARTEXT列的默认值,如下所示的CREATE TABLE语句:

    CREATE TABLE t (c VARCHAR(288) DEFAULT (CURRENT_USER()));
    
  • DATABASE()

    返回以utf8mb3字符集中的字符串形式的默认(当前)数据库名称。如果没有默认数据库,DATABASE()返回NULL。在存储过程中,默认数据库是与存储过程关联的数据库,并不一定与调用上下文中的默认数据库相同。

    mysql> SELECT DATABASE();
     -> 'test'
    

    如果没有默认数据库,DATABASE()返回NULL

  • FOUND_ROWS()

    注意

    自 MySQL 8.0.17 起,SQL_CALC_FOUND_ROWS查询修饰符和相应的FOUND_ROWS()函数已被弃用;预计它们将在未来的 MySQL 版本中被移除。作为替代方案,考虑使用带有LIMIT的查询,然后再执行一个不带LIMIT但带有COUNT(*)的第二个查询,以确定是否有额外的行。例如,不要使用这些查询:

    SELECT SQL_CALC_FOUND_ROWS * FROM *tbl_name* WHERE id > 100 LIMIT 10;
    SELECT FOUND_ROWS();
    

    改用以下查询:

    SELECT * FROM *tbl_name* WHERE id > 100 LIMIT 10;
    SELECT COUNT(*) FROM *tbl_name* WHERE id > 100;
    

    COUNT(*)受到某些优化的影响。SQL_CALC_FOUND_ROWS会导致某些优化被禁用。

    一个SELECT语句可以包括一个LIMIT子句,以限制服务器返回给客户端的行数。在某些情况下,希望知道没有LIMIT时语句会返回多少行,但又不想再次运行该语句。要获取这个行数,需要在SELECT语句中包含一个SQL_CALC_FOUND_ROWS选项,然后在之后调用FOUND_ROWS()

    mysql> SELECT SQL_CALC_FOUND_ROWS * FROM *tbl_name*
     -> WHERE id > 100 LIMIT 10;
    mysql> SELECT FOUND_ROWS();
    

    第二个SELECT返回一个数字,指示第一个不带LIMIT子句的SELECT将返回多少行。

    在最近成功的不带SQL_CALC_FOUND_ROWS选项的SELECT语句中,FOUND_ROWS()返回该语句返回的结果集中的行数。如果语句包含LIMIT子句,FOUND_ROWS()返回限制之前的行数。例如,如果语句包含LIMIT 10LIMIT 50, 10,则FOUND_ROWS()分别返回 10 或 60。

    通过FOUND_ROWS()获取的行数是瞬时的,不打算在SELECT SQL_CALC_FOUND_ROWS语句后的语句中使用。如果需要稍后引用该值,请保存它:

    mysql> SELECT SQL_CALC_FOUND_ROWS * FROM ... ;
    mysql> SET @rows = FOUND_ROWS();
    

    如果你使用SELECT SQL_CALC_FOUND_ROWS,MySQL 必须计算完整结果集中有多少行。然而,这比再次运行不带LIMIT的查询要快,因为不需要将结果集发送给客户端。

    SQL_CALC_FOUND_ROWSFOUND_ROWS() 在需要限制查询返回行数的情况下非常有用,同时又要确定完整结果集中的行数而不需要重新运行查询时。例如,一个 Web 脚本显示分页显示,包含指向显示搜索结果其他部分页面的链接。使用 FOUND_ROWS() 可以帮助确定还需要多少其他页面来显示剩余的结果。

    对于 UNION 语句,使用 SQL_CALC_FOUND_ROWSFOUND_ROWS() 比简单的 SELECT 语句更复杂,因为 LIMIT 可能出现在 UNION 中的多个位置。它可以应用于 UNION 中的各个 SELECT 语句,或者全局应用于整个 UNION 结果。

    SQL_CALC_FOUND_ROWS 用于 UNION 的目的是应返回在没有全局 LIMIT 的情况下将返回的行数。使用 SQL_CALC_FOUND_ROWSUNION 的条件是:

    • SQL_CALC_FOUND_ROWS 关键字必须出现在 UNION 的第一个 SELECT 中。

    • FOUND_ROWS() 的值仅在使用 UNION ALL 时是精确的。如果使用不带 ALLUNION,会发生重复移除,并且 FOUND_ROWS() 的值只是近似值。

    • 如果 UNION 中没有 LIMIT,则会忽略 SQL_CALC_FOUND_ROWS 并返回用于处理 UNION 的临时表中的行数。

    除了这里描述的情况外,FOUND_ROWS() 的行为是未定义的(例如,在出现错误的 SELECT 语句后其值是多少)。

    重要

    使用基于语句的复制时,FOUND_ROWS() 无法可靠地复制。此函数会在基于行的复制中自动复制。

  • ICU_VERSION()

    用于支持正则表达式操作的国际组件库(ICU)的版本(参见 Section 14.8.2, “Regular Expressions”)。此函数主要用于测试案例。

  • LAST_INSERT_ID(), LAST_INSERT_ID(*expr*)

    没有参数时,LAST_INSERT_ID() 返回一个BIGINT UNSIGNED(64 位)值,表示作为最近执行的INSERT语句的结果成功插入的第一个自动生成值,用于AUTO_INCREMENT列。如果没有成功插入行,则LAST_INSERT_ID()的值保持不变。

    有参数时,LAST_INSERT_ID() 返回一个无符号整数,如果参数为NULL,则返回NULL

    例如,在插入生成AUTO_INCREMENT值的行之后,您可以像这样获取该值:

    mysql> SELECT LAST_INSERT_ID();
     -> 195
    

    当前执行的语句不会影响LAST_INSERT_ID()的值。假设您使用一个语句生成AUTO_INCREMENT值,然后在一个多行INSERT语句中引用LAST_INSERT_ID(),该语句将行插入到具有自己的AUTO_INCREMENT列的表中。LAST_INSERT_ID()的值在第二个语句中保持稳定;其值对第二行及后续行不受先前行插入的影响。(您应该注意,如果混合引用LAST_INSERT_ID()LAST_INSERT_ID(*expr*),效果是未定义的。)

    如果前一个语句返回错误,则LAST_INSERT_ID()的值是未定义的。对于事务表,如果由于错误而回滚语句,则LAST_INSERT_ID()的值将保持未定义。对于手动ROLLBACKLAST_INSERT_ID()的值不会恢复到事务之前的值;它将保持在ROLLBACK点时的值。

    在存储过程(procedure)或触发器的主体内,LAST_INSERT_ID() 的值与在这些对象的主体外执行语句时的方式相同。存储过程或触发器对后续语句看到的LAST_INSERT_ID()的值的影响取决于存储过程的类型:

    • 如果存储过程执行改变LAST_INSERT_ID()值的语句,那么这个改变的值会被调用存储过程后的语句所看到。

    • 对于改变值的存储函数和触发器,在函数或触发器结束时值会被恢复,因此在其后的语句不会看到改变的值。

    生成的 ID 在服务器上以每个连接为基础进行维护。这意味着函数返回给特定客户端的值是该客户端最近影响AUTO_INCREMENT列的大多数最新语句生成的第一个AUTO_INCREMENT值。即使其他客户端生成了自己的AUTO_INCREMENT值,这个值也不会受到影响。这种行为确保每个客户端可以检索自己的 ID,而不必担心其他客户端的活动,也不需要锁定或事务。

    如果将行的AUTO_INCREMENT列设置为非“魔术”值(即不是NULL且不是0),则LAST_INSERT_ID()的值不会改变。

    重要提示

    如果使用单个INSERT语句插入多行,LAST_INSERT_ID()仅返回第一插入行生成的值。这样做的原因是为了能够轻松地在其他服务器上重现相同的INSERT语句。

    例如:

    mysql> USE test;
    
    mysql> CREATE TABLE t (
           id INT AUTO_INCREMENT NOT NULL PRIMARY KEY,
           name VARCHAR(10) NOT NULL
           );
    
    mysql> INSERT INTO t VALUES (NULL, 'Bob');
    
    mysql> SELECT * FROM t;
    +----+------+
    | id | name |
    +----+------+
    |  1 | Bob  |
    +----+------+
    
    mysql> SELECT LAST_INSERT_ID();
    +------------------+
    | LAST_INSERT_ID() |
    +------------------+
    |                1 |
    +------------------+
    
    mysql> INSERT INTO t VALUES
           (NULL, 'Mary'), (NULL, 'Jane'), (NULL, 'Lisa');
    
    mysql> SELECT * FROM t;
    +----+------+
    | id | name |
    +----+------+
    |  1 | Bob  |
    |  2 | Mary |
    |  3 | Jane |
    |  4 | Lisa |
    +----+------+
    
    mysql> SELECT LAST_INSERT_ID();
    +------------------+
    | LAST_INSERT_ID() |
    +------------------+
    |                2 |
    +------------------+
    

    尽管第二个INSERT语句向t插入了三行新记录,但为这些行中的第一行生成的 ID 是2,并且这个值会被后续的SELECT语句中的LAST_INSERT_ID()返回。

    如果使用INSERT IGNORE并且行被忽略,LAST_INSERT_ID()保持不变(或者如果连接尚未执行成功的INSERT,则返回 0),对于非事务表,AUTO_INCREMENT计数器不会增加。对于InnoDB表,如果innodb_autoinc_lock_mode设置为12AUTO_INCREMENT计数器会增加,如下例所示:

    mysql> USE test;
    
    mysql> SELECT @@innodb_autoinc_lock_mode;
    +----------------------------+
    | @@innodb_autoinc_lock_mode |
    +----------------------------+
    |                          1 |
    +----------------------------+
    
    mysql> CREATE TABLE `t` (
           `id` INT(11) NOT NULL AUTO_INCREMENT,
           `val` INT(11) DEFAULT NULL,
           PRIMARY KEY (`id`),
           UNIQUE KEY `i1` (`val`)
           ) ENGINE=InnoDB;
    
    # Insert two rows
    
    mysql> INSERT INTO t (val) VALUES (1),(2);
    
    # With auto_increment_offset=1, the inserted rows
    # result in an AUTO_INCREMENT value of 3
    
    mysql> SHOW CREATE TABLE t\G
    *************************** 1\. row ***************************
           Table: t
    Create Table: CREATE TABLE `t` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `val` int(11) DEFAULT NULL,
      PRIMARY KEY (`id`),
      UNIQUE KEY `i1` (`val`)
    ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
    
    # LAST_INSERT_ID() returns the first automatically generated
    # value that is successfully inserted for the AUTO_INCREMENT column 
    mysql> SELECT LAST_INSERT_ID();
    +------------------+
    | LAST_INSERT_ID() |
    +------------------+
    |                1 |
    +------------------+
    
    # The attempted insertion of duplicate rows fail but errors are ignored
    
    mysql> INSERT IGNORE INTO t (val) VALUES (1),(2);
    Query OK, 0 rows affected (0.00 sec)
    Records: 2  Duplicates: 2  Warnings: 0
    
    # With innodb_autoinc_lock_mode=1, the AUTO_INCREMENT counter
    # is incremented for the ignored rows
    
    mysql> SHOW CREATE TABLE t\G
    *************************** 1\. row ***************************
           Table: t
    Create Table: CREATE TABLE `t` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `val` int(11) DEFAULT NULL,
      PRIMARY KEY (`id`),
      UNIQUE KEY `i1` (`val`)
    ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
    
    # The LAST_INSERT_ID is unchanged because the previous insert was unsuccessful 
    mysql> SELECT LAST_INSERT_ID();
    +------------------+
    | LAST_INSERT_ID() |
    +------------------+
    |                1 |
    +------------------+
    

    有关更多信息,请参阅 Section 17.6.1.6, “InnoDB 中的 AUTO_INCREMENT 处理”。

    如果将*expr*作为参数传递给LAST_INSERT_ID(),则函数将返回参数的值,并记住作为下一个由LAST_INSERT_ID()返回的值。这可以用来模拟序列:

    1. 创建一个表来保存序列计数器并初始化它:

      mysql> CREATE TABLE sequence (id INT NOT NULL);
      mysql> INSERT INTO sequence VALUES (0);
      
    2. 使用表来生成类似这样的序列号:

      mysql> UPDATE sequence SET id=LAST_INSERT_ID(id+1);
      mysql> SELECT LAST_INSERT_ID();
      

      UPDATE语句递增序列计数器,并导致下一次调用LAST_INSERT_ID()返回更新后的值。SELECT语句检索该值。mysql_insert_id() C API 函数也可用于获取该值。请参阅 mysql_insert_id()。

    您可以在不调用LAST_INSERT_ID()的情况下生成序列,但以这种方式使用函数的实用性在于 ID 值在服务器中作为最后一个自动生成的值保持。它是多用户安全的,因为多个客户端可以发出UPDATE语句并使用SELECT语句(或mysql_insert_id())获取自己的序列值,而不会影响或受其他生成自己序列值的客户端的影响。

    请注意,只有在执行INSERTUPDATE语句后,mysql_insert_id()才会更新,因此您不能在执行其他 SQL 语句(如SELECTSET)后使用 C API 函数检索LAST_INSERT_ID(*expr*)的值。

  • ROLES_GRAPHML()

    返回一个包含表示内存角色子图的 GraphML 文档的utf8mb3字符串。需要ROLE_ADMIN权限(或已弃用的SUPER权限)才能查看<graphml>元素中的内容。否则,结果只显示一个空元素:

    mysql> SELECT ROLES_GRAPHML();
    +---------------------------------------------------+
    | ROLES_GRAPHML()                                   |
    +---------------------------------------------------+
    | <?xml version="1.0" encoding="UTF-8"?><graphml /> |
    +---------------------------------------------------+
    
  • ROW_COUNT()

    ROW_COUNT()返回如下值:

    • DDL 语句:0。这适用于诸如CREATE TABLEDROP TABLE之类的语句。

    • 除了 SELECT 之外的 DML 语句:受影响的行数。这适用于诸如 UPDATEINSERTDELETE(如前所述)的语句,但现在也适用于诸如 ALTER TABLELOAD DATA 的语句。

    • SELECT:如果语句返回结果集,则返回 -1,否则返回“受影响”的行数。例如,对于 SELECT * FROM t1ROW_COUNT() 返回 -1。对于 SELECT * FROM t1 INTO OUTFILE '*file_name*'ROW_COUNT() 返回写入文件的行数。

    • SIGNAL 语句:0。

    对于 UPDATE 语句,默认情况下受影响的行数是实际更改的行数。如果在连接到 mysqld 时使用 CLIENT_FOUND_ROWS 标志到 mysql_real_connect(),受影响的行数是“找到”的行数;也就是,被 WHERE 子句匹配的行数。

    对于 REPLACE 语句,如果新行替换了旧行,则受影响的行数为 2,因为在这种情况下,删除重复项后插入了一行。

    对于 INSERT ... ON DUPLICATE KEY UPDATE 语句,每行的受影响行数为 1(如果将行插入为新行)、2(如果更新现有行)或 0(如果将现有行设置为当前值)。如果指定了 CLIENT_FOUND_ROWS 标志,则如果将现有行设置为当前值,则受影响的行数为 1(而不是 0)。

    ROW_COUNT() 的值类似于 mysql_affected_rows() C API 函数的值以及 mysql 客户端在语句执行后显示的行数。

    mysql> INSERT INTO t VALUES(1),(2),(3);
    Query OK, 3 rows affected (0.00 sec)
    Records: 3  Duplicates: 0  Warnings: 0
    
    mysql> SELECT ROW_COUNT();
    +-------------+
    | ROW_COUNT() |
    +-------------+
    |           3 |
    +-------------+
    1 row in set (0.00 sec)
    
    mysql> DELETE FROM t WHERE i IN(1,2);
    Query OK, 2 rows affected (0.00 sec)
    
    mysql> SELECT ROW_COUNT();
    +-------------+
    | ROW_COUNT() |
    +-------------+
    |           2 |
    +-------------+
    1 row in set (0.00 sec)
    

    重要

    ROW_COUNT() 在基于语句的复制中无法可靠地复制。此函数会自动使用基于行的复制进行复制。

  • SCHEMA()

    此函数是 DATABASE() 的同义词。

  • SESSION_USER()

    SESSION_USER()USER() 的同义词。

    从 MySQL 8.0.34 开始,类似于USER(),这个函数可以用作VARCHARTEXT列的默认值,如下所示的CREATE TABLE语句:

    CREATE TABLE t (c VARCHAR(288) DEFAULT (SESSION_USER()));
    
  • SYSTEM_USER()

    SYSTEM_USER()USER()的同义词。

    注意

    SYSTEM_USER()函数与SYSTEM_USER权限是不同的。前者返回当前的 MySQL 账户名。后者区分系统用户和普通用户账户类别(参见第 8.2.11 节,“账户类别”)。

    从 MySQL 8.0.34 开始,类似于USER(),这个函数可以用作VARCHARTEXT列的默认值,如下所示的CREATE TABLE语句:

    CREATE TABLE t (c VARCHAR(288) DEFAULT (SYSTEM_USER()));
    
  • USER()

    返回当前的 MySQL 用户名和主机名作为一个字符串,使用utf8mb3字符集。

    mysql> SELECT USER();
     -> 'davida@localhost'
    

    该值指示您连接到服务器时指定的用户名,以及您连接的客户端主机。该值可能与CURRENT_USER()的值不同。

    从 MySQL 8.0.34 开始,类似于USER(),这个函数可以用作VARCHARTEXT列的默认值,如下所示的CREATE TABLE语句:

    CREATE TABLE t (c VARCHAR(288) DEFAULT (USER()));
    
  • VERSION()

    返回一个指示 MySQL 服务器版本的字符串。该字符串使用utf8mb3字符集。该值可能除了版本号外还有后缀。请参阅第 7.1.8 节,“服务器系统变量”中的version系统变量的描述。

    此函数在基于语句的复制中是不安全的。如果在binlog_format设置为STATEMENT时使用此函数,将记录警告。

    mysql> SELECT VERSION();
     -> '8.0.36-standard'
    

14.16 空间分析函数

原文:dev.mysql.com/doc/refman/8.0/en/spatial-analysis-functions.html

14.16.1 空间函数参考

14.16.2 空间函数参数处理

14.16.3 从 WKT 值创建几何值的函数

14.16.4 从 WKB 值创建几何值的函数

14.16.5 MySQL 特定函数创建几何值

14.16.6 几何格式转换函数

14.16.7 几何属性函数

14.16.8 空间操作函数

14.16.9 测试几何对象之间空间关系的函数

14.16.10 空间 Geohash 函数

14.16.11 空间 GeoJSON 函数

14.16.12 空间聚合函数

14.16.13 空间便利函数

MySQL 提供了执行空间数据各种操作的函数。这些函数可以根据它们执行的操作类型分为几个主要类别:

  • 以各种格式(WKT、WKB、内部)创建几何体的函数

  • 在不同格式之间转换几何体的函数

  • 访问几何体的定性或定量属性的函数

  • 描述两个几何体之间关系的函数

  • 从现有几何体创建新几何体的函数

有关 MySQL 支持使用空间数据的一般背景,请参见第 13.4 节,“空间数据类型”。

14.16.1 空间函数参考

原文:dev.mysql.com/doc/refman/8.0/en/spatial-function-reference.html

以下表格列出了每个空间函数并提供了每个函数的简短描述。

表格 14.21 空间函数

名称描述引入版本
GeomCollection()从几何图形构造几何集合
GeometryCollection()从几何图形构造几何集合
LineString()从 Point 值构造 LineString
MBRContains()判断一个几何图形的 MBR 是否包含另一个几何图形的 MBR
MBRCoveredBy()判断一个 MBR 是否被另一个 MBR 覆盖
MBRCovers()判断一个 MBR 是否覆盖另一个 MBR
MBRDisjoint()判断两个几何图形的 MBR 是否不相交
MBREquals()判断两个几何图形的 MBR 是否相等
MBRIntersects()判断两个几何图形的 MBR 是否相交
MBROverlaps()判断两个几何图形的 MBR 是否重叠
MBRTouches()判断两个几何图形的 MBR 是否相接触
MBRWithin()判断一个几何图形的 MBR 是否在另一个几何图形的 MBR 内部
MultiLineString()从 LineString 值构造 MultiLineString
MultiPoint()从 Point 值构造 MultiPoint
MultiPolygon()从多边形值构造 MultiPolygon
Point()从坐标构造点
Polygon()从 LineString 参数构造多边形
ST_Area()返回多边形或 MultiPolygon 的面积
ST_AsBinary(), ST_AsWKB()将内部几何格式转换为 WKB
ST_AsGeoJSON()从几何图形生成 GeoJSON 对象
ST_AsText(), ST_AsWKT()从内部几何格式转换为 WKT
ST_Buffer()返回距离给定距离内的几何体的几何体
ST_Buffer_Strategy()为 ST_Buffer()生成策略选项
ST_Centroid()返回几何体的质心点
ST_Collect()将空间值聚合成集合8.0.24
ST_Contains()一个几何体是否包含另一个
ST_ConvexHull()返回几何体的凸包
ST_Crosses()一个几何体是否与另一个相交
ST_Difference()两个几何体的点集差
ST_Dimension()几何体的维度
ST_Disjoint()一个几何体是否与另一个不相交
ST_Distance()一个几何体到另一个的距离
ST_Distance_Sphere()两个几何体在地球上的最小距离
ST_EndPoint()线串的终点
ST_Envelope()返回几何体的最小边界矩形
ST_Equals()一个几何体是否等于另一个
ST_ExteriorRing()返回多边形的外环
ST_FrechetDistance()一个几何体到另一个的离散弗雷歇距离8.0.23
ST_GeoHash()生成地理哈希值
ST_GeomCollFromText(), ST_GeometryCollectionFromText(), ST_GeomCollFromTxt()从 WKT 返回几何体集合
ST_GeomCollFromWKB(), ST_GeometryCollectionFromWKB()从 WKB 返回几何体集合
ST_GeometryN()从几何体集合返回第 N 个几何体
ST_GeometryType()返回几何类型的名称
ST_GeomFromGeoJSON()从 GeoJSON 对象生成几何图形
ST_GeomFromText(), ST_GeometryFromText()从 WKT 返回几何图形
ST_GeomFromWKB(), ST_GeometryFromWKB()从 WKB 返回几何图形
ST_HausdorffDistance()一个几何图形到另一个的离散豪斯多夫距离8.0.23
ST_InteriorRingN()返回多边形的第 N 个内环
ST_Intersection()返回两个几何图形的点集交集
ST_Intersects()一个几何图形是否与另一个相交
ST_IsClosed()几何图形是否闭合且简单
ST_IsEmpty()几何图形是否为空
ST_IsSimple()几何图形是否简单
ST_IsValid()几何图形是否有效
ST_LatFromGeoHash()从 geohash 值返回纬度
ST_Latitude()返回 Point 的纬度8.0.12
ST_Length()返回 LineString 的长度
ST_LineFromText(), ST_LineStringFromText()从 WKT 构造 LineString
ST_LineFromWKB(), ST_LineStringFromWKB()从 WKB 构造 LineString
ST_LineInterpolatePoint()沿着 LineString 给定百分比的点8.0.24
ST_LineInterpolatePoints()沿着 LineString 给定百分比的点8.0.24
ST_LongFromGeoHash()从 geohash 值返回经度
ST_Longitude()返回 Point 的经度8.0.12
ST_MakeEnvelope()两点周围的矩形
ST_MLineFromText(), ST_MultiLineStringFromText()从 WKT 构建 MultiLineString
ST_MLineFromWKB(), ST_MultiLineStringFromWKB()从 WKB 构建 MultiLineString
ST_MPointFromText(), ST_MultiPointFromText()从 WKT 构建 MultiPoint
ST_MPointFromWKB(), ST_MultiPointFromWKB()从 WKB 构建 MultiPoint
ST_MPolyFromText(), ST_MultiPolygonFromText()从 WKT 构建 MultiPolygon
ST_MPolyFromWKB(), ST_MultiPolygonFromWKB()从 WKB 构建 MultiPolygon
ST_NumGeometries()返回几何集合中的几何对象数量
ST_NumInteriorRing(), ST_NumInteriorRings()返回多边形中内部环的数量
ST_NumPoints()返回 LineString 中的点数
ST_Overlaps()一个几何对象是否与另一个重叠
ST_PointAtDistance()沿着 LineString 给定距离的点8.0.24
ST_PointFromGeoHash()将 geohash 值转换为 POINT 值
ST_PointFromText()从 WKT 构建 Point
ST_PointFromWKB()从 WKB 构建 Point
ST_PointN()返回 LineString 中的第 N 个点
ST_PolyFromText(), ST_PolygonFromText()从 WKT 构建 Polygon
ST_PolyFromWKB(), ST_PolygonFromWKB()从 WKB 构建 Polygon
ST_Simplify()返回简化的几何对象
ST_SRID()返回几何对象的空间参考系统 ID
ST_StartPoint()LineString 的起始点
ST_SwapXY()返回交换 X/Y 坐标的参数
ST_SymDifference()返回两个几何对象的点集对称差
ST_Touches()一个几何体是否与另一个几何体相接触
ST_Transform()转换几何体的坐标8.0.13
ST_Union()返回两个几何体的点集并集
ST_Validate()返回经过验证的几何体
ST_Within()一个几何体是否在另一个几何体内部
ST_X()返回点的 X 坐标
ST_Y()返回点的 Y 坐标
名称描述引入版本

14.16.2 空间函数的参数处理

原文:dev.mysql.com/doc/refman/8.0/en/spatial-function-argument-handling.html

空间值或几何图形具有第 13.4.2.2 节,“几何类”中描述的属性。以下讨论列出了一般空间函数参数处理特性。特定函数或函数组可能具有额外或不同的参数处理特性,如在这些函数描述出现的部分中所讨论的那样。在这种情况下,这些描述优先于此处的一般讨论。

空间函数仅针对有效的几何值定义。请参阅第 13.4.4 节,“几何形态和有效性”。

每个几何值都与空间参考系统(SRS)相关联,这是用于地理位置的基于坐标的系统。请参阅第 13.4.5 节,“空间参考系统支持”。

几何的空间参考标识符(SRID)标识定义几何的 SRS。在 MySQL 中,SRID 值是与几何值关联的整数。可用的最大 SRID 值为 2³²−1。如果给出一个更大的值,则只使用低 32 位。

SRID 0 表示一个无限的平面笛卡尔平面,其轴没有分配单位。要确保 SRID 0 行为,使用 SRID 0 创建几何值。如果未指定 SRID,则 SRID 0 是新几何值的默认值。

对于多个几何值的计算,所有值必须在相同的 SRS 中,否则会出错。因此,需要多个几何参数的空间函数要求这些参数在相同的 SRS 中。如果空间函数返回ER_GIS_DIFFERENT_SRIDS,这意味着几何参数不都在相同的 SRS 中。您必须修改它们以具有相同的 SRS。

空间函数返回的几何图形位于几何参数的 SRS 中,因为任何空间函数产生的几何值都继承了几何参数的 SRID。

开放地理空间联盟的指南要求输入多边形必须已经封闭,因此未封闭的多边形将被拒绝为无效而不是被封闭。

在 MySQL 中,唯一有效的空几何图形以空几何集合的形式表示。空几何集合的处理如下:可以将空的 WKT 输入几何集合指定为'GEOMETRYCOLLECTION()'。这也是产生空几何集合的空间操作的输出 WKT。

在解析嵌套几何集合时,集合被展平,并且其基本组件被用于各种 GIS 操作以计算结果。这为用户提供了额外的灵活性,因为不必担心几何数据的唯一性。嵌套几何集合可以从嵌套的 GIS 函数调用中产生,而无需事先显式展平。

14.16.3 从 WKT 值创建几何值的函数

原文:dev.mysql.com/doc/refman/8.0/en/gis-wkt-functions.html

这些函数的参数是一个 Well-Known Text(WKT)表示,可选地,一个空间参考系统标识符(SRID)。它们返回相应的几何。有关 WKT 格式的描述,请参阅 Well-Known Text (WKT) Format Format")。

本节中的函数检测笛卡尔或地理空间参考系统(SRS)中的参数,并返回适合 SRS 的结果。

ST_GeomFromText()接受任何几何类型的 WKT 值作为其第一个参数。其他函数提供了针对每种几何类型构造几何值的特定类型构造函数。

诸如ST_MPointFromText()ST_GeomFromText()这样接受MultiPoint值的 WKT 格式表示的函数允许值内的各个点被括在括号中。例如,以下两个函数调用都是有效的:

ST_MPointFromText('MULTIPOINT (1 1, 2 2, 3 3)')
ST_MPointFromText('MULTIPOINT ((1 1), (2 2), (3 3))')

诸如ST_GeomFromText()这样接受 WKT 几何集合参数的函数理解 OpenGIS 'GEOMETRYCOLLECTION EMPTY'标准语法和 MySQL 'GEOMETRYCOLLECTION()'非标准语法。诸如ST_AsWKT()这样产生 WKT 值的函数产生'GEOMETRYCOLLECTION EMPTY'标准语法:

mysql> SET @s1 = ST_GeomFromText('GEOMETRYCOLLECTION()');
mysql> SET @s2 = ST_GeomFromText('GEOMETRYCOLLECTION EMPTY');
mysql> SELECT ST_AsWKT(@s1), ST_AsWKT(@s2);
+--------------------------+--------------------------+
| ST_AsWKT(@s1)            | ST_AsWKT(@s2)            |
+--------------------------+--------------------------+
| GEOMETRYCOLLECTION EMPTY | GEOMETRYCOLLECTION EMPTY |
+--------------------------+--------------------------+

除非另有说明,本节中的函数处理其几何参数如下:

  • 如果任何几何参数为NULL或不是语法上良好形式的几何,或者 SRID 参数为NULL,则返回值为NULL

  • 默认情况下,地理坐标(纬度、经度)按照几何参数的空间参考系统指定的顺序进行解释。可以提供一个可选的*options*参数来覆盖默认的轴顺序。options由逗号分隔的*key*=*value*列表组成。唯一允许的*key*值是axis-order,允许的值为lat-longlong-latsrid-defined`(默认值)。

    如果*options参数为NULL,则返回值为NULL。如果options*参数无效,则会发生错误以指示原因。

  • 如果 SRID 参数引用未定义的空间参考系统(SRS),则会发生ER_SRS_NOT_FOUND错误。

  • 对于地理 SRS 几何参数,如果任何参数的经度或纬度超出范围,则会发生错误:

    • 如果经度值不在范围(−180, 180]内,则会发生ER_LONGITUDE_OUT_OF_RANGE错误。

    • 如果纬度值不在范围[−90, 90]内,则会发生ER_LATITUDE_OUT_OF_RANGE错误。

    显示的范围以度为单位。如果 SRS 使用另一个单位,则范围使用其单位中的相应值。由于浮点运算,确切的范围限制略有偏差。

可用于从 WKT 值创建几何体的这些函数:

14.16.4 从 WKB 值创建几何值的函数

原文:dev.mysql.com/doc/refman/8.0/en/gis-wkb-functions.html

这些函数的参数是包含 Well-Known Binary (WKB) 表示的 BLOB,可选地还有空间参考系统标识符(SRID)。它们返回相应的几何图形。有关 WKB 格式的描述,请参阅 Well-Known Binary (WKB) 格式 格式")。

本节中的函数检测笛卡尔或地理空间参考系统(SRS)中的参数,并返回适合 SRS 的结果。

ST_GeomFromWKB() 接受任何几何类型的 WKB 值作为其第一个参数。其他函数为每种几何类型的几何值构造提供类型特定的构造函数。

在 MySQL 8.0 之前,这些函数还接受由 第 14.16.5 节,“MySQL 特定函数创建几何值” 中的函数返回的几何对象。不再允许几何参数,并产生错误。要将调用从使用几何参数迁移到使用 WKB 参数,请遵循以下准则:

  • 重写类似 ST_GeomFromWKB(Point(0, 0)) 的结构为 Point(0, 0)

  • 重写类似 ST_GeomFromWKB(Point(0, 0), 4326) 的结构为 ST_SRID(Point(0, 0), 4326)ST_GeomFromWKB(ST_AsWKB(Point(0, 0)), 4326)

除非另有说明,本节中的函数处理其几何参数如下:

  • 如果 WKB 或 SRID 参数为 NULL,则返回值为 NULL

  • 默认情况下,地理坐标(纬度、经度)按照几何参数的空间参考系统指定的顺序解释。可以提供一个可选的 options 参数来覆盖默认轴顺序。options 包括一个逗号分隔的 *key*=*value* 列表。唯一允许的 key 值是 axis-order,其允许的值为 lat-longlong-latsrid-defined(默认值)。

    如果 options 参数为 NULL,则返回值为 NULL。如果 options 参数无效,则会发生错误以指示原因。

  • 如果 SRID 参数引用未定义的空间参考系统(SRS),则会发生 ER_SRS_NOT_FOUND 错误。

  • 对于地理 SRS 几何参数,如果任何参数的经度或纬度超出范围,则会发生错误:

    • 如果经度值不在范围 (−180, 180] 内,则会发生 ER_LONGITUDE_OUT_OF_RANGE 错误。

    • 如果纬度值不在范围[−90, 90]内,则会发生ER_LATITUDE_OUT_OF_RANGE错误。

    显示的范围是以度为单位。如果 SRS 使用另一个单位,则范围使用其单位中的相应值。由于浮点运算,确切的范围限制略有偏差。

这些函数可用于从 WKB 值创建几何图形: