关于【CASE WHEN】与【JSON_EXTRACT】结合使用的bug

【 TiDB 使用环境】生产环境
【 TiDB 版本】v6.5
【复现路径】执行以下sql,返回结果中a的类型有问题,本来应该返回0,但java取到的值是[48]。返回的b,c,d都没问题。
此sql在mysql执行没问题,只有在TiDB执行才有问题。

【遇到的问题:问题现象及影响】
详见截图
TiDB问题截图.zip (225.5 KB)
有问题的sql附件:
问题sql.sql (822 字节)

【复现路径2】经多次验证,与IFNULL无关,详见“问题sql2”附件。此sql在mysql环境执行没问题,只有TiDB执行才有问题。
问题sql2.sql (590 字节)

没太看懂,case when 一般返回的类型是根据你then的类型决定的吧?

可以看一下我sql里的注释,只有case when后面用某个表作为条件时才有问题,也就是a有问题。但b,c,d都没问题。

JSON_EXTRACT(‘{}’, ‘$.KEY’)这个字段的类型是什么?

单独执行select JSON_EXTRACT(‘{}’, ‘$.KEY’); 返回的类型是longtext。

我又试了几次,与IFNULL无关,以下sql,e的类型有问题但f没问题。
select
t.v,

CASE
    WHEN t.v > 2 THEN 1
    ELSE JSON_EXTRACT('{"KEY":0}', '$.KEY')
END AS e,

CASE
    WHEN 1 > 2 THEN 1
    ELSE JSON_EXTRACT('{"KEY":0}', '$.KEY')
END AS f

from (select 1 as v) t
;

测试 tidb v6.5.3 和 mysql 5.7.42 结果一致

1 个赞

感谢回复。

如果只看sql返回结果的值,确实都是0。
但如果用可视化客户端工具查看sql执行结果,可以看出返回值的类型是不一样的,“问题sql”里的 a 和“问题sql2”里的 e 返回类型有问题,导致java取到的值是带中括号的[48](是个byte数组);而返回的 b,c,d,f,g 都没问题,都是正常的0。

以上问题只在TiDB6.5有问题,而相同的sql在mysql执行就没有问题。
java连接TiDB取到的结果,a和e是[48],b,c,d,f,g都是0。
java连接mysql取到的结果,a~g 都是0。

明白你意思了,tidb在对同样的casewhen else json函数语句,如果when的条件带的是表字段的话,返回的字符类型和直接用常量返回的字符类型不一样。这个确实有点问题。
我在tidb5.4.3上测试也是一样的问题。

嗯是的,确实是有问题的。

请问这个问题怎么反馈给官方的研发团队呢?

可以到github上提个issue

github上提个issue或者论坛里面提个建议反馈

我直接把这个帖子转移到产品缺陷分类~

感谢关注,我刚才提了个意见反馈

好叻,辛苦啦!

我提的意见反馈,1天了也没啥回复 :sob:

请问具体的 tidb 版本是多少呢。我试了 6.5.0 ~ 6.5.5 所有版本,mysql --column-type-info 中显示 a,c,d,e,f 都是 LONG_BLOB 的数据类型,而通过 DataGrip 查询,他们数据类型都显示未 LONG_TEXT。
另外看看你这个可视化工具使用的 mysql-java-connector driver 是哪个版本的,麻烦换几个版本试试会正常么。

select
    t.v,

    # CASE WHEN 后面的条件使用某个表时,返回a的类型有问题,是longblob
    CASE
        WHEN t.v > 2 THEN 1
        ELSE IFNULL(JSON_EXTRACT('{}', '$.KEY'), 0)
        END AS a,

    # 添加了CONVERT,其它与a相同,此时返回的b的类型没有问题,是decimal
    CASE
        WHEN t.v > 2 THEN 1
        ELSE IFNULL(CONVERT(JSON_EXTRACT('{}', '$.KEY'), unsigned ), 0)
        END AS b,

    # CASE WHEN 后面用不使用表判断,其它与a相同,此时返回的c的类型没有问题,是longtext
    CASE
        WHEN 1 > 2 THEN 1
        ELSE IFNULL(JSON_EXTRACT('{}', '$.KEY'), 0)
        END AS c,

    # 只保留 IFNULL JSON_EXTRACT,此时返回的d的类型没有问题,是longtext
    IFNULL(JSON_EXTRACT('{}', '$.KEY'), 0) AS d,

    # CASE WHEN 后面使用某个表作为条件,返回的e类型有问题,是longblob
    CASE
        WHEN t.v > 2 THEN 1
        ELSE JSON_EXTRACT('{"KEY": 0}', '$.KEY')
        END AS e,

    # CASE WHEN 改成 IF,其它与e相同,返回的f类型没有问题,是longtext
    IF(t.v > 2, 1, JSON_EXTRACT('{"KEY": 0}', '$.KEY'))
            AS f,

    # CASE WHEN 后的条件不使用表,其它与e相同,返回的g类型没有问题,是text
    CASE
        WHEN 1 > 2 THEN 1
        ELSE JSON_EXTRACT('{"KEY": 0}', '$.KEY')
        END AS g

from (select 1 as v) t
;
Field   1:  `v`
Catalog:    `def`
Database:   `test`
Table:      `t`
Org_table:  ``
Type:       LONGLONG
Collation:  binary (63)
Length:     1
Max_length: 1
Decimals:   0
Flags:      NOT_NULL BINARY NUM

Field   2:  `a`
Catalog:    `def`
Database:   ``
Table:      ``
Org_table:  ``
Type:       LONG_BLOB
Collation:  utf8mb4_bin (46)
Length:     67108864
Max_length: 1
Decimals:   31
Flags:      BINARY

Field   3:  `b`
Catalog:    `def`
Database:   ``
Table:      ``
Org_table:  ``
Type:       NEWDECIMAL
Collation:  binary (63)
Length:     24
Max_length: 1
Decimals:   0
Flags:      BINARY NUM

Field   4:  `c`
Catalog:    `def`
Database:   ``
Table:      ``
Org_table:  ``
Type:       LONG_BLOB
Collation:  utf8mb4_bin (46)
Length:     67108864
Max_length: 1
Decimals:   31
Flags:      NOT_NULL

Field   5:  `d`
Catalog:    `def`
Database:   ``
Table:      ``
Org_table:  ``
Type:       LONG_BLOB
Collation:  utf8mb4_bin (46)
Length:     67108864
Max_length: 1
Decimals:   31
Flags:      NOT_NULL

Field   6:  `e`
Catalog:    `def`
Database:   ``
Table:      ``
Org_table:  ``
Type:       LONG_BLOB
Collation:  utf8mb4_bin (46)
Length:     67108864
Max_length: 1
Decimals:   31
Flags:      BINARY

Field   7:  `f`
Catalog:    `def`
Database:   ``
Table:      ``
Org_table:  ``
Type:       LONG_BLOB
Collation:  utf8mb4_bin (46)
Length:     67108864
Max_length: 1
Decimals:   31
Flags:

Field   8:  `g`
Catalog:    `def`
Database:   ``
Table:      ``
Org_table:  ``
Type:       VAR_STRING
Collation:  utf8mb4_bin (46)
Length:     67108864
Max_length: 1
Decimals:   31
Flags:


+---+------+------+---+---+------+------+------+
| v | a    | b    | c | d | e    | f    | g    |
+---+------+------+---+---+------+------+------+
| 1 | 0    |    0 | 0 | 0 | 0    | 0    | 0    |
+---+------+------+---+---+------+------+------+
1 row in set (0.00 sec)
1 个赞

TiDB版本是v6.5.2,mysql-connector-java driver版本是5.1.47,driver换成8.0.25后,之前有问题的a和e的类型是变成longtext了。但我们的java项目里的mysql-connector-java driver版是5.1.44的,连接TiDB执行sql后,java取到的a和e是byte[],而连接mysql执行相同sql是没有问题的。
所以问题出在,相同环境下,mysql没问题,而TiDB有问题。

开了一个 issue:https://github.com/pingcap/tidb/issues/48004 后续在这里跟踪

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