MySQL 函数和运算符:位函数和运算符

来自Wikioe
跳到导航 跳到搜索


位函数和运算符:

Name Description
& 位运算“AND”
mysql> SELECT 29 & 15;
        -> 13

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

>> 右移
mysql> SELECT 4 >> 2;
        -> 1

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

<< 左移
mysql> SELECT 1 << 2;
        -> 4

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

^ 位运算“XOR”
mysql> SELECT 1 ^ 1;
        -> 0
mysql> SELECT 1 ^ 0;
        -> 1
mysql> SELECT 11 ^ 3;
        -> 8

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

BIT_COUNT() 返回设置的位数
mysql> SELECT BIT_COUNT(29), BIT_COUNT(b'101010');
        -> 4, 3

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

| 位运算“OR”
mysql> SELECT 29 | 15;
        -> 31

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

~ 位运算“取反”
mysql> SELECT 5 & ~1;
        -> 4

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

当前,位函数和运算符需要“BIGINT”(64 位整数)个参数并返回“BIGINT”值,因此它们的最大范围为 64 位。其他类型的参数将转换为“BIGINT”,并且可能会发生截断。【???】

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


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

  1. “nonliteral_binary { & | ^ } binary”:
  2. “binary { & | ^ } nonliteral_binary”:
  3. “nonliteral_binary { << >> } anything”:
  4. “~ nonliteral_binary”:
  5. “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> 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 后受影响的语句产生不同的结果,请对其进行重写,以使其不产生位操作警告。为此,请使用“CAST(... AS UNSIGNED)”将至少一个二进制参数转换为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 不会在不同服务器上产生不同的结果。

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

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