将数据库列从 UNSIGNED 更改为 BINARY 而无需转换为字符串

Change a Database Column from UNSIGNED to BINARY without converting to string

我有一个 table 在 UNSIGNED INTEGER 列中包含 IPv4 地址。我现在将其更改为支持 IPv6 地址,由 INET6_ATON() 返回,需要 VARBINARY(16) 列类型。

https://mariadb.com/kb/en/mariadb/inet6_aton/

如何更改现有列以保留其内容?

ALTER TABLE hitcounts CHANGE ip ip BINARY(16);

上面的命令似乎将无符号整数值转换为等效的字符串,这不是我想要的。

示范[​​=27=]
CREATE TEMPORARY TABLE hitcounts (ip INTEGER UNSIGNED);
INSERT INTO hitcounts VALUES (INET_ATON('78.156.181.3')),(INET_ATON('64.255.180.66')),(INET_ATON('31.126.241.81'));
SELECT * FROM hitcounts;
+------------+
| ip         |
+------------+
| 1318892803 |
| 1090499650 |
|  528413009 |
+------------+
3 rows in set (0.00 sec)

ALTER TABLE hitcounts MODIFY COLUMN ip VARBINARY(16);
SELECT * FROM hitcounts;
+------------+
| ip         |
+------------+
| 1318892803 |
| 1090499650 |
| 528413009  |
+------------+
3 rows in set (0.00 sec)

虽然转换后的ip值看起来已经被保留了,但实际上它们已经被转换成ASCII字符串(注意第三行的左对齐与它是真实数字时使用的右对齐相比) .尝试获取 IP 地址将失败:

SELECT INET6_NTOA(ip) FROM hitcounts;
+----------------+
| INET6_NTOA(ip) |
+----------------+
| NULL           |
| NULL           |
| NULL           |
+----------------+
3 rows in set (0.01 sec)

简单的解决方案是按照所述更改列,然后更新列以转换为由 INET6_ATON() 生成的二进制字符串:

UPDATE hitcounts SET ip = INET6_ATON(INET_NTOA(ip));

由于 INET6 函数处理 IPv4 的 4 字节二进制和 IPv6 的 16 字节二进制,我认为这更接近 'correct':

ALTER TABLE hitcounts MODIFY COLUMN ip VARBINARY(16) NOT NULL;

VAR是因为INET6_ATON('1.2.3.4')生成了一个BINARY(4)字符串。

我尚未验证仅将 UNSIGNED 转换为 VARBINARY(16) 是否会正确保留 IPv4 值。

MySQL 需要 5.6.3 或 MariaDB 10.0.12。 (在早些时候,我认为 MariaDB 使用了不同的拼写:INET6_NTOP()INET6_PTON())。