DateTime(6)类型修改为DateTime的BUG

创建表并插入数据:

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
DROP TABLE IF EXISTS `aaa`;
CREATE TABLE `aaa`  (
  `Id` int NOT NULL AUTO_INCREMENT,
  `DataA` datetime(6) NOT NULL,
  PRIMARY KEY (`Id`) USING BTREE
) AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

INSERT INTO `aaa` VALUES (1, '2026-05-15 11:17:08.000000');
INSERT INTO `aaa` VALUES (2, '2026-05-15 11:17:08.999999');
INSERT INTO `aaa` VALUES (3, '9999-12-31 23:59:59.999999');
SET FOREIGN_KEY_CHECKS = 1;

修改列类型:

ALTER TABLE `aaa` 
MODIFY COLUMN `DataA` datetime NOT NULL AFTER `Id`;

MySQL执行结果:

1441 - Datetime function: datetime field overflow

Oceanbase结果

执行成功,查询数据:

+------+---------------------+
| Id   | DataA               |
+------+---------------------+
|    1 | 2026-05-15 11:17:08 |
|    2 | 2026-05-15 11:17:09 |
|    3 | NULL                |
+------+---------------------+

诡异的是

select * from `aaa` where DataA is null;

竟然查不出结果,明明看到了null

UPDATE `aaa` SET `DataA` = '2026-05-15 11:30:56' WHERE `Id` = 3;

执行结果:

这个比较奇怪,我有两个集群,版本都是4.3.5.1,但是一个两副本集群执行结果为:

4377 - fatal internal error in [check_datum_row_nullable_value]
另外一个执行就成功,能够正常更新,这个很奇怪,为什么呢?

总结

在datetime(6)转到datetime的时候,时间会进行四舍五入,但是对于9999-12-31 23:59:59.999999,再入的话就成为一个非法值了。MySQL的策略是不让你改,Oceanbase的策略是你只管改,但是数据给你破坏掉。 把它设置null(虽然表结果规定了该列不可为null),我觉得还是应该安全一些。这种情况不让你改比较好,否则在不知情的情况下业务挂掉是很危险的事情。数据库最重要的就是数据了,溢出了应该不让你改才对,设置null也要看列能不能为null

1 个赞

签到!!!!

SHOW VARIABLES like ‘version_comment’;具体的版本查一下

a. 登录系统租户,打开enable_rich_error_msg 参数
alter system set enable_rich_error_msg=true;
b. 登录业务租户,执行报错 SQL 语句,会直接返回执行节点 IP 和 trace_id 信息。
obclient [test]> select count(*) from t2;
ERROR 1146 (42S02): Table ‘test.t2’ doesn’t exist
[xx.xx.xx.1:2882] [2024-04-13 20:10:20.292087] [YB420BA1CC68-000615A0A8EA5E38-0-0]
c. 去 xx.xx.xx.1 节点过滤日志,如果最新日志无法过滤到,可以正则匹配多个日志进行过滤
[root@x.x.x.1 ~]$ grep “YB420BA1CC68-000615A0A8EA5E38-0-0” rootservice.log
[root@x.x.x.1 ~]$ grep “YB420BA1CC68-000615A0A8EA5E38-0-0” observer.log
d. 获取完日志信息后,关闭enable_rich_error_msg参数
alter system set enable_rich_error_msg=false;

指正:
OceanBase_CE 4.3.5.2 (r102000112025051418-f481a33c42054b0944ae0e9926651b550157e467) (Built May 14 2025 18:44:28)

从4.3.5.2开始不会再出现check_datum_row_nullable_value错误了。这个版本之前好几个版本都有这个update异常问题。

最终要的是时间溢出把不可为null的时间字段弄成了null,用is null却又查不出。 这个一直到4.3.5.5都有问题(之后的版本不知道是不是一样),这种问题又不是报错,中间的SQL执行一切正常,就是把数据破坏了。 这个怎么查日志呢?

或者你用我的脚本试一下,我描述的结果应该是恒定必现的。

好的 我们也测试一下