12.12 位函数和运算符

table12.16 位功能和运算符

NameDescription
&Bitwise AND
>>Right shift
<<Left shift
^Bitwise XOR
BIT_COUNT()返回设置的位数
|Bitwise OR
~Bitwise inversion

位函数和运算符包括BIT_COUNT()BIT_AND()BIT_OR()BIT_XOR()&|^~<<>>。 (BIT_AND()BIT_OR()BIT_XOR()函数是在第 12.20.1 节“聚合函数描述”处描述的聚合函数。)当前,位函数和运算符需要BIGINT(64 位整数)个参数并返回BIGINT值,因此它们的最大范围为 64 位。其他类型的参数将转换为BIGINT,并且可能会发生截断。

MySQL 8.0 的扩展更改了这种强制转换为BIGINT的行为:位函数和运算符允许使用二进制字符串类型的参数(BINARYVARBINARYBLOB类型),使它们能够接受参数并产生大于 64 位的返回值。因此,在 MySQL 5.7 中对二进制参数的位操作可能在 MySQL 8.0 中产生不同的结果。为了提前通知这种潜在的行为变化,从 MySQL 5.7.11 开始,服务器会针对位操作生成警告,这些位操作的二进制参数未在 MySQL 8.0 中转换为整数。这些警告为重写受影响的语句提供了机会。为了显式地产生 MySQL 5.7 行为,使其在升级到 8.0 后不会改变,请转换位操作二进制参数以将其转换为整数。

需要注意的五种有问题的 table 达式类型是:

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

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

符号说明:

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

    • binary *:任何类型的二进制字符串参数,包括十六进制 Literals,位 Literals 或NULLLiterals。
    • nonliteral_binary *:参数是二进制字符串值,而不是十六进制 Literals,位 Literals 或NULLLiterals。

服务器为语句中的每个有问题的 table 达式生成一个警告,而不是为处理的每一行生成一个警告。假定包含两个有问题的 table 达式的语句从 table 中选择三行。每个语句执行的警告数量是两个,而不是六个。以下示例说明了这一点。

mysql> CREATE TABLE t(vbin1 VARBINARY(32), vbin2 VARBINARY(32));
Query OK, 0 rows affected (0.03 sec)

mysql> INSERT INTO t VALUES (3,1), (3,2), (3,3);
Query OK, 3 rows affected (0.01 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> SELECT HEX(vbin1 & vbin2) AS op1,
    -> HEX(vbin1 | vbin2) AS op2
    -> FROM t;
+------+------+
| op1  | op2  |
+------+------+
| 1    | 3    |
| 2    | 3    |
| 3    | 3    |
+------+------+
3 rows in set, 2 warnings (0.00 sec)

mysql> SHOW WARNINGS\G
*************************** 1. row ***************************
  Level: Warning
   Code: 1287
Message: Bitwise operations on BINARY will change behavior in a future
         version, check the 'Bit functions' section in the manual.
*************************** 2. row ***************************
  Level: Warning
   Code: 1287
Message: Bitwise operations on BINARY will change behavior in a future
         version, check the 'Bit functions' section in the manual.
2 rows in set (0.00 sec)

为了避免在升级到 MySQL 8.0 后受影响的语句产生不同的结果,请对其进行重写,以使其不产生位操作警告。为此,请使用投射(...为未签名)将至少一个二进制参数转换为BIGINT。这使得 MySQL 5.7 隐式二进制到整数强制转换是显式的:

mysql> SELECT HEX(CAST(vbin1 AS UNSIGNED) & CAST(vbin2 AS UNSIGNED)) AS op1,
    -> HEX(CAST(vbin1 AS UNSIGNED) | CAST(vbin2 AS UNSIGNED)) AS op2
    -> FROM t;
+------+------+
| op1  | op2  |
+------+------+
| 1    | 3    |
| 2    | 3    |
| 3    | 3    |
+------+------+
3 rows in set (0.01 sec)

mysql> SHOW WARNINGS\G
Empty set (0.00 sec)

如下所示重写语句,MySQL 8.0 尊重将二进制参数视为整数的意图,并产生与 5.7 中相同的结果。同样,将语句从 MySQL 5.7 复制到 8.0 不会在不同服务器上产生不同的结果。

不能重写的受影响的语句在升级和复制方面受到以下潜在问题的困扰:

  • 升级到 MySQL 8.0 后,该语句可能返回不同的结果。

  • 对于基于语句和混合格式的二进制日志记录,从旧版本复制到 MySQL 8.0 可能会失败。对于在 8.0 服务器上重放较旧的二进制日志(例如,使用mysqlbinlog)也是如此。为避免这种情况,请在较旧的主服务器上切换到基于行的二进制日志记录。

下 table 描述了可用的位函数和运算符:

|

Bitwise OR.

结果是一个无符号的 64 位整数。

mysql> SELECT 29 | 15;
        -> 31

&

Bitwise AND.

结果是一个无符号的 64 位整数。

mysql> SELECT 29 & 15;
        -> 13

^

Bitwise XOR.

结果是一个无符号的 64 位整数。

mysql> SELECT 1 ^ 1;
        -> 0
mysql> SELECT 1 ^ 0;
        -> 1
mysql> SELECT 11 ^ 3;
        -> 8

<<

向左移动一个 longlong(BIGINT)数字。

结果是一个无符号的 64 位整数。该值被截断为 64 位。特别是,如果移位计数大于或等于一个无符号 64 位数字的宽度,则结果为零。

mysql> SELECT 1 << 2;
        -> 4

>>

向右移动一个 longlong(BIGINT)数字。

结果是一个无符号的 64 位整数。该值被截断为 64 位。特别是,如果移位计数大于或等于一个无符号 64 位数字的宽度,则结果为零。

mysql> SELECT 4 >> 2;
        -> 1

~

反转所有位。

结果是一个无符号的 64 位整数。

mysql> SELECT 5 & ~1;
        -> 4

BIT_COUNT(N)

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

mysql> SELECT BIT_COUNT(29), BIT_COUNT(b'101010');
        -> 4, 3