timestamp默认零值查询的问题

tidb时区和mariadb时区设置的都是根据系统时间,格式为 timestamp,表中数据为零值’0000-00-00 00:00:00’的数据,用go-sql-driver scan出来的时候,mariadb库中的结果就是默认的时间零值0001-01-01 00:00:00,但是tidb scan出来的结果是-0001-11-30T00:00:00+08:05.有大佬们解答一下吗,很疑惑啊

  1. 您好,能否麻烦帮忙验证下 mysql 5.7 版本查询是什么结果?
  2. mariadb 和 tidb 的 sql_mode 是否一致?
  3. 客户端时区是否一致/

1:mysql 5.7本地没有环境,详细看第二条,里面有mariadb的版本
2:tidb的数据库信息:
tidb
mariadb的数据库信息:


3:查询mariadb和tidb的客户端时区是一致的

另外我把mariadb和tidb scan出来的值用golang time.Time对象接的时候,再打印time.Unix()值,发现两个的时间戳是不一样的

@TYDSC

  1. 我还想再确认一下数据库的时区设置,还请提供一下 TiDB 和 MariaDB 的以下查询结果:show variables like '%time_zone%';

  2. 另外我把mariadb和tidb scan出来的值用golang time.Time对象接的时候,再打印time.Unix()值,发现两个的时间戳是不一样的

    这一点我没理解,还请更具体一些说明,最好能给一个例子,谢谢!

1: mariadb show 结果:
time_zone: SYSTEM
system_time_zone:CST
tidb 结果: time_zone:SYSTEM;
system_time_zone:Asia/Shanghai

2:就是说比如我要查询一个id=1的时间,时间这一列叫a,select a from table where id = 1,然后这个a的值我用一个time.Time{}对象去承接,然后再打印出 a.Unix()的值

我用的驱动是 github.com/go-sql-driver/mysql v1.5.0

我们抓了一下包,发现如果是先 prepare 再 execute,tidb 返回的 response 好像跟 mysql 的不兼容,导致 go 在解析的时候得到一个负数时间。如果不 prepare 直接查询,返回的结果又是正常的。

收到,非常感谢,我们再具体看一下

老哥,你们这边有结论了麻烦反馈一下,谢谢

无法复现你的问题
Mariadb 默认 0 值在 CST 和 GTM+8 下都是 0000-00-00 00:00:00(scan 结果 0001-01-01 00:00:00 +0000 UTC)
create table s(a datetime default 0)
TiDB 同上
你的场景在单纯的 mysql client 上扫出来有问题吗?
还是只有在这个驱动下才有问题?

PS: 这个驱动的 DSN 参数都加了吗 &parseTime=true&loc=Local

dsn 参数加了,我说的直白一点,你用 golang 代码去查询的时候,select 一个时间列(timestamp 或者 datetime 都可以),当你用占位符去查询的时候,扫出来的时间就会有问题,即 select time from table where id = ?,如果不是这种就没有问题,我们抓包发现带占位符的时候,会有一个 prepare stat 和 exec 的过程,所以猜测是这个过程出了问题

好的,原来是 prepare 语句,我们再细看一下
问题已经复现了,多谢

您好,该问题是 prepare 语句结果上的 encode 不对。对于0 时,
MySQL 表示时间的 integer 的编码长度首字节应该是 0 不为空,驱动这边才正确识别它是个 0 时。
TiDB 表示时间的 integer 的编码长度首字节是 11 (dumpBinaryRow,应该使用 dumpLengthEncodedString)不为空,因此在时间的 decode 解析上才产生了差异。

我们后续会讨论处理,这边方便可以使用非 prepare 的查询语句绕过嘛

不太方便,有sql注入的可能,我们现在主要是在业务上避免了这个0时,但是写的很难受:joy:

https://github.com/pingcap/tidb/issues/18824 您好,可以关注这个issue,多谢。

此话题已在最后回复的 1 分钟后被自动关闭。不再允许新回复。