-
Notifications
You must be signed in to change notification settings - Fork 5.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
TiDB incorrectly converts update statement to point get #47445
Comments
It works on mysql> explain UPDATE golang1 a
-> SET procst =(
-> CASE WHEN
-> ( SELECT levlid FROM golang2 b WHERE b.sysgrp = 'COMMON' AND b.procst = 'ACSC' )
-> >
-> ( SELECT levlid FROM golang2 c WHERE c.sysgrp = 'COMMON' AND c.procst = a.procst )
-> THEN 'ACSC' ELSE a.procst END
-> ) ,
-> cipstx = 'CI010000',
-> cipsst = 'ACSC',
-> dyngtg = 'EAYT',
-> blncdt= '20230925'
-> WHERE
-> fcbpdt = '20230925'
-> AND fcbpsq = '12023092502158016';
+------------------------------------+---------+-----------+----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------+
| id | estRows | task | access object | operator info |
+------------------------------------+---------+-----------+----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Update_17 | N/A | root | | N/A |
| └─IndexJoin_23 | 1.25 | root | | left outer join, inner:IndexLookUp_22, outer key:test.golang1.procst, inner key:test.golang2.procst, equal cond:eq(test.golang1.procst, test.golang2.procst) |
| ├─Point_Get_36(Build) | 1.00 | root | table:golang1, index:PRIMARY(fcbpdt, fcbpsq) | |
| └─IndexLookUp_22(Probe) | 1.00 | root | | |
| ├─IndexRangeScan_19(Build) | 1.00 | cop[tikv] | table:c, index:PRIMARY(procst) | range: decided by [eq(test.golang2.procst, test.golang1.procst)], keep order:false, stats:pseudo |
| └─Selection_21(Probe) | 1.00 | cop[tikv] | | eq(test.golang2.sysgrp, "COMMON") |
| └─TableRowIDScan_20 | 1.00 | cop[tikv] | table:c | keep order:false, stats:pseudo |
+------------------------------------+---------+-----------+----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------+
7 rows in set (0.01 sec) But on mysql> explain UPDATE golang1 a
-> SET procst =(
-> CASE WHEN
-> ( SELECT levlid FROM golang2 b WHERE b.sysgrp = 'COMMON' AND b.procst = 'ACSC' )
-> >
-> ( SELECT levlid FROM golang2 c WHERE c.sysgrp = 'COMMON' AND c.procst = a.procst )
-> THEN 'ACSC' ELSE a.procst END
-> ) ,
-> cipstx = 'CI010000',
-> cipsst = 'ACSC',
-> dyngtg = 'EAYT',
-> blncdt= '20230925'
-> WHERE
-> fcbpdt = '20230925'
-> AND fcbpsq = '12023092502158016';
+-------------------+---------+------+--------------------------------------------------------+---------------+
| id | estRows | task | access object | operator info |
+-------------------+---------+------+--------------------------------------------------------+---------------+
| Update_20 | N/A | root | | N/A |
| └─Point_Get_1 | 1.00 | root | table:golang1, clustered index:PRIMARY(fcbpdt, fcbpsq) | |
+-------------------+---------+------+--------------------------------------------------------+---------------+
2 rows in set (0.00 sec) |
The main difference is the v6.5.1 TiDB converted the update statement to a point-get operation. I first checked which commit introduced this bug, and I found after this commit c6e1982 the plan changed. Then I dug into the code, and I found that we have different results when we call this code on different versions. tidb/planner/core/point_get_plan.go Line 1026 in 350e1c2
So both v6.3.0 and v6.5.1 all have bugs. We should return from here: tidb/planner/core/point_get_plan.go Line 1026 in 350e1c2
Then we don't need to try to convert to a point get. |
/type regression |
It happened in v5.4.1, I think it may also affect release-6.1. |
I tested it on v6.1. It worked on v6.1. mysql> UPDATE golang1 a
-> SET procst =(
-> CASE WHEN
-> ( SELECT levlid FROM golang2 b WHERE b.sysgrp = 'COMMON' AND b.procst = 'ACSC' )
-> >
-> ( SELECT levlid FROM golang2 c WHERE c.sysgrp = 'COMMON' AND c.procst = a.procst )
-> THEN 'ACSC' ELSE a.procst END
-> ) ,
-> cipstx = 'CI010000',
-> cipsst = 'ACSC',
-> dyngtg = 'EAYT',
-> blncdt= '20230925'
-> WHERE
-> fcbpdt = '20230925'
-> AND fcbpsq = '12023092502158016';
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0 I think the bug was only triggered after we enabled the index of the cluster. To fully resolve this issue, we need to cherry-pick it. Because in version 6.1, I believe other reasons have obscured this problem. |
Regression Analysis |
I don't believe that is the root cause. The problem has existed for a long time. This only triggered the bug but did not introduce it. |
I agree with you for the long existing root cause and the configuration change exposed the issue. However, the change broke an existing function per user point of view, which meant a functional regression. |
Bug Report
Please answer these questions before submitting your issue. Thanks!
1. Minimal reproduce step (Required)
2. What did you expect to see? (Required)
Update success.
3. What did you see instead (Required)
Panic:
ERROR 1105 (HY000): runtime error: index out of range [0] with length 0
4. What is your TiDB version? (Required)
The text was updated successfully, but these errors were encountered: