From ff4e01dfaeaf996aea8eda3b77ee12c17c5872db Mon Sep 17 00:00:00 2001 From: Arenatlx <314806019@qq.com> Date: Fri, 30 May 2025 14:55:52 +0800 Subject: [PATCH] planner, executor: clone the field type for correlated column when setting the EnumSetAsIntFlag flag. (#61412) close pingcap/tidb#61389 --- pkg/expression/builtin_cast.go | 7 ++ pkg/planner/core/casetest/cbotest/BUILD.bazel | 2 +- pkg/planner/core/casetest/cbotest/cbo_test.go | 29 +++++++ .../cbotest/testdata/analyze_suite_in.json | 7 ++ .../cbotest/testdata/analyze_suite_out.json | 31 +++++++ .../cbotest/testdata/test.t0da79f8d.json | 78 ++++++++++++++++++ .../cbotest/testdata/test.t19f3e4f1.json | 82 +++++++++++++++++++ 7 files changed, 235 insertions(+), 1 deletion(-) create mode 100644 pkg/planner/core/casetest/cbotest/testdata/test.t0da79f8d.json create mode 100644 pkg/planner/core/casetest/cbotest/testdata/test.t19f3e4f1.json diff --git a/pkg/expression/builtin_cast.go b/pkg/expression/builtin_cast.go index 838cacf3d5..fd97e591c6 100644 --- a/pkg/expression/builtin_cast.go +++ b/pkg/expression/builtin_cast.go @@ -2534,11 +2534,18 @@ func BuildCastFunctionWithCheck(ctx BuildContext, expr Expression, tp *types.Fie // type int, otherwise, returns `expr` directly. func WrapWithCastAsInt(ctx BuildContext, expr Expression, targetType *types.FieldType) Expression { if expr.GetType(ctx.GetEvalCtx()).GetType() == mysql.TypeEnum { + // since column and correlated column may be referred in other places, deep + // clone the one out with its field type as well before change the flag inside. if col, ok := expr.(*Column); ok { col = col.Clone().(*Column) col.RetType = col.RetType.Clone() expr = col } + if col, ok := expr.(*CorrelatedColumn); ok { + col = col.Clone().(*CorrelatedColumn) + col.RetType = col.RetType.Clone() + expr = col + } expr.GetType(ctx.GetEvalCtx()).AddFlag(mysql.EnumSetAsIntFlag) } if expr.GetType(ctx.GetEvalCtx()).EvalType() == types.ETInt { diff --git a/pkg/planner/core/casetest/cbotest/BUILD.bazel b/pkg/planner/core/casetest/cbotest/BUILD.bazel index 8f81bb647e..fcf244c3ea 100644 --- a/pkg/planner/core/casetest/cbotest/BUILD.bazel +++ b/pkg/planner/core/casetest/cbotest/BUILD.bazel @@ -10,7 +10,7 @@ go_test( data = glob(["testdata/**"]), flaky = True, race = "on", - shard_count = 18, + shard_count = 19, deps = [ "//pkg/executor", "//pkg/meta/model", diff --git a/pkg/planner/core/casetest/cbotest/cbo_test.go b/pkg/planner/core/casetest/cbotest/cbo_test.go index e846aef2c0..343e2134dc 100644 --- a/pkg/planner/core/casetest/cbotest/cbo_test.go +++ b/pkg/planner/core/casetest/cbotest/cbo_test.go @@ -157,6 +157,35 @@ func TestEstimation(t *testing.T) { } } +func TestIssue61389(t *testing.T) { + store, dom := testkit.CreateMockStoreAndDomain(t) + testKit := testkit.NewTestKit(t, store) + testKit.MustExec("set tidb_cost_model_version=2") + testKit.MustExec("use test;") + testKit.MustExec("CREATE TABLE `t19f3e4f1` (\n `colc864` enum('d9','dt5w4','wsg','i','3','5ur3','s0m4','mmhw6','rh','ge9d','nm') DEFAULT 'dt5w4',\n `colaadb` smallint DEFAULT '7697',\n UNIQUE KEY `ee56e6aa` (`colc864`)\n);") + testKit.MustExec("CREATE TABLE `t0da79f8d` (\n `colf2af` enum('xrsg','go9yf','mj4','u1l','8c','at','o','e9','bh','r','yah') DEFAULT 'r'\n);") + require.NoError(t, testkit.LoadTableStats("test.t0da79f8d.json", dom)) + require.NoError(t, testkit.LoadTableStats("test.t19f3e4f1.json", dom)) + + var input []string + var output []struct { + SQL string + Plan []string + Warn []string + } + analyzeSuiteData := GetAnalyzeSuiteData() + analyzeSuiteData.LoadTestCases(t, &input, &output) + for i, tt := range input { + testdata.OnRecord(func() { + output[i].SQL = tt + output[i].Plan = testdata.ConvertRowsToStrings(testKit.MustQuery(tt).Rows()) + output[i].Warn = testdata.ConvertRowsToStrings(testKit.MustQuery("show warnings").Rows()) + }) + testKit.MustQuery(tt).Check(testkit.Rows(output[i].Plan...)) + testKit.MustQuery("show warnings").Check(testkit.Rows(output[i].Warn...)) + } +} + func TestIssue59563(t *testing.T) { store, dom := testkit.CreateMockStoreAndDomain(t) testKit := testkit.NewTestKit(t, store) diff --git a/pkg/planner/core/casetest/cbotest/testdata/analyze_suite_in.json b/pkg/planner/core/casetest/cbotest/testdata/analyze_suite_in.json index 235b873615..e72deae098 100644 --- a/pkg/planner/core/casetest/cbotest/testdata/analyze_suite_in.json +++ b/pkg/planner/core/casetest/cbotest/testdata/analyze_suite_in.json @@ -261,5 +261,12 @@ "cases": [ "EXPLAIN format = 'verbose' SELECT * FROM `tbl_cardcore_transaction` `transactio0_` WHERE `transactio0_`.`period` = '202502' AND `transactio0_`.`account_number` = '1901040107462200' ORDER BY `transactio0_`.`transaction_status`, `transactio0_`.`account_number`, `transactio0_`.`entry_date` ASC, `transactio0_`.`id` ASC;" ] + }, + { + "name": "TestIssue61389", + "cases": [ + "EXPLAIN format=brief select /*+ nth_plan(5) */ * from `t19f3e4f1` where `colc864` in ( select `colc864` from `t19f3e4f1` where `colaadb` in ( select `colf2af`\n from `t0da79f8d` where not ( `t19f3e4f1`.`colc864` <> null ) ) ) limit 2837;", + "select /*+ nth_plan(5) */ * from `t19f3e4f1` where `colc864` in ( select `colc864` from `t19f3e4f1` where `colaadb` in ( select `colf2af`\n from `t0da79f8d` where not ( `t19f3e4f1`.`colc864` <> null ) ) ) limit 2837;" + ] } ] diff --git a/pkg/planner/core/casetest/cbotest/testdata/analyze_suite_out.json b/pkg/planner/core/casetest/cbotest/testdata/analyze_suite_out.json index fec2b65a30..09c8f35acb 100644 --- a/pkg/planner/core/casetest/cbotest/testdata/analyze_suite_out.json +++ b/pkg/planner/core/casetest/cbotest/testdata/analyze_suite_out.json @@ -534,5 +534,36 @@ "Warn": null } ] + }, + { + "Name": "TestIssue61389", + "Cases": [ + { + "SQL": "EXPLAIN format=brief select /*+ nth_plan(5) */ * from `t19f3e4f1` where `colc864` in ( select `colc864` from `t19f3e4f1` where `colaadb` in ( select `colf2af`\n from `t0da79f8d` where not ( `t19f3e4f1`.`colc864` <> null ) ) ) limit 2837;", + "Plan": [ + "Limit 2.00 root offset:0, count:2837", + "└─HashJoin 2.00 root inner join, equal:[eq(test.t19f3e4f1.colc864, test.t19f3e4f1.colc864)]", + " ├─StreamAgg(Build) 1.60 root group by:test.t19f3e4f1.colc864, funcs:firstrow(test.t19f3e4f1.colc864)->test.t19f3e4f1.colc864", + " │ └─Apply 2.00 root semi join, left side:Projection, equal:[eq(test.t19f3e4f1.colaadb, test.t0da79f8d.colf2af)]", + " │ ├─Projection(Build) 2.00 root test.t19f3e4f1.colc864, test.t19f3e4f1.colaadb", + " │ │ └─IndexLookUp 2.00 root ", + " │ │ ├─IndexFullScan(Build) 2.00 cop[tikv] table:t19f3e4f1, index:ee56e6aa(colc864) keep order:true, stats:pseudo", + " │ │ └─Selection(Probe) 2.00 cop[tikv] not(isnull(test.t19f3e4f1.colaadb))", + " │ │ └─TableRowIDScan 2.00 cop[tikv] table:t19f3e4f1 keep order:false, stats:pseudo", + " │ └─TableReader(Probe) 2.00 root data:Selection", + " │ └─Selection 2.00 cop[tikv] eq(test.t19f3e4f1.colc864, NULL), not(isnull(test.t0da79f8d.colf2af))", + " │ └─TableFullScan 2.00 cop[tikv] table:t0da79f8d keep order:false, stats:pseudo", + " └─IndexLookUp(Probe) 2.00 root ", + " ├─IndexFullScan(Build) 2.00 cop[tikv] table:t19f3e4f1, index:ee56e6aa(colc864) keep order:false, stats:pseudo", + " └─TableRowIDScan(Probe) 2.00 cop[tikv] table:t19f3e4f1 keep order:false, stats:pseudo" + ], + "Warn": null + }, + { + "SQL": "select /*+ nth_plan(5) */ * from `t19f3e4f1` where `colc864` in ( select `colc864` from `t19f3e4f1` where `colaadb` in ( select `colf2af`\n from `t0da79f8d` where not ( `t19f3e4f1`.`colc864` <> null ) ) ) limit 2837;", + "Plan": null, + "Warn": null + } + ] } ] diff --git a/pkg/planner/core/casetest/cbotest/testdata/test.t0da79f8d.json b/pkg/planner/core/casetest/cbotest/testdata/test.t0da79f8d.json new file mode 100644 index 0000000000..d371812b2d --- /dev/null +++ b/pkg/planner/core/casetest/cbotest/testdata/test.t0da79f8d.json @@ -0,0 +1,78 @@ +{ + "columns": { + "colf2af": { + "histogram": { + "ndv": 0 + }, + "cm_sketch": null, + "fm_sketch": null, + "stats_ver": 0, + "null_count": 0, + "tot_col_size": 0, + "last_update_version": 458318142516494382, + "correlation": 0 + } + }, + "indices": { + }, + "partitions": null, + "database_name": "test", + "table_name": "t0da79f8d", + "ext_stats": null, + "predicate_columns": [ + { + "last_used_at": "2025-05-27 11:23:04", + "last_analyzed_at": null, + "id": 3 + }, + { + "last_used_at": "2025-05-27 11:23:04", + "last_analyzed_at": null, + "id": 6 + }, + { + "last_used_at": "2025-05-27 11:23:04", + "last_analyzed_at": null, + "id": 14 + }, + { + "last_used_at": "2025-05-27 11:23:03", + "last_analyzed_at": null, + "id": 15 + }, + { + "last_used_at": "2025-05-27 11:23:03", + "last_analyzed_at": null, + "id": 4 + }, + { + "last_used_at": "2025-05-27 11:23:04", + "last_analyzed_at": null, + "id": 5 + }, + { + "last_used_at": "2025-05-27 11:23:04", + "last_analyzed_at": null, + "id": 9 + }, + { + "last_used_at": "2025-05-27 11:23:03", + "last_analyzed_at": null, + "id": 10 + }, + { + "last_used_at": "2025-05-27 11:23:04", + "last_analyzed_at": null, + "id": 11 + }, + { + "last_used_at": "2025-05-28 03:27:54", + "last_analyzed_at": null, + "id": 13 + } + ], + "count": 1, + "modify_count": 1, + "version": 458318960366452737, + "is_historical_stats": false +} \ No newline at end of file diff --git a/pkg/planner/core/casetest/cbotest/testdata/test.t19f3e4f1.json b/pkg/planner/core/casetest/cbotest/testdata/test.t19f3e4f1.json new file mode 100644 index 0000000000..9a65492163 --- /dev/null +++ b/pkg/planner/core/casetest/cbotest/testdata/test.t19f3e4f1.json @@ -0,0 +1,82 @@ +{ + "columns": { + "colaadb": { + "histogram": { + "ndv": 0 + }, + "cm_sketch": null, + "fm_sketch": null, + "stats_ver": 0, + "null_count": 0, + "tot_col_size": 0, + "last_update_version": 458317529623822463, + "correlation": 0 + }, + "colc864": { + "histogram": { + "ndv": 0 + }, + "cm_sketch": null, + "fm_sketch": null, + "stats_ver": 0, + "null_count": 0, + "tot_col_size": 0, + "last_update_version": 458317529623822463, + "correlation": 0 + } + }, + "indices": { + "ee56e6aa": { + "histogram": { + "ndv": 0 + }, + "cm_sketch": null, + "fm_sketch": null, + "stats_ver": 0, + "null_count": 0, + "tot_col_size": 0, + "last_update_version": 458317529623822463, + "correlation": 0 + } + }, + "partitions": null, + "database_name": "test", + "table_name": "t19f3e4f1", + "ext_stats": null, + "predicate_columns": [ + { + "last_used_at": "2025-05-27 11:23:04", + "last_analyzed_at": null, + "id": 2 + }, + { + "last_used_at": "2025-05-28 03:27:54", + "last_analyzed_at": null, + "id": 3 + }, + { + "last_used_at": "2025-05-27 11:23:04", + "last_analyzed_at": null, + "id": 4 + }, + { + "last_used_at": "2025-05-27 12:21:28", + "last_analyzed_at": null, + "id": 5 + }, + { + "last_used_at": "2025-05-28 03:27:54", + "last_analyzed_at": null, + "id": 6 + }, + { + "last_used_at": "2025-05-27 11:23:04", + "last_analyzed_at": null, + "id": 1 + } + ], + "count": 2, + "modify_count": 3, + "version": 458319478323675137, + "is_historical_stats": false +}