Skip to content

Commit

Permalink
planner: The length function could not be substitute when collation o…
Browse files Browse the repository at this point in the history
…f mapped column is utfxxx_bin (#54179) (#56994)

close #53730
  • Loading branch information
ti-chi-bot authored Nov 8, 2024
1 parent a87524f commit ba09647
Show file tree
Hide file tree
Showing 7 changed files with 116 additions and 0 deletions.
5 changes: 5 additions & 0 deletions expression/constant_propagation.go
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,11 @@ func (s *propConstSolver) solve(conditions []Expression) []Expression {

// PropagateConstant propagate constant values of deterministic predicates in a condition.
func PropagateConstant(ctx sessionctx.Context, conditions []Expression) []Expression {
sc := ctx.GetSessionVars().StmtCtx
sc.InConstantPropagateCheck = true
defer func() {
sc.InConstantPropagateCheck = false
}()
return newPropConstSolver().PropagateConstant(ctx, conditions)
}

Expand Down
23 changes: 23 additions & 0 deletions expression/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"github.com/pingcap/failpoint"
"github.com/pingcap/tidb/kv"
"github.com/pingcap/tidb/parser/ast"
"github.com/pingcap/tidb/parser/charset"
"github.com/pingcap/tidb/parser/mysql"
"github.com/pingcap/tidb/parser/opcode"
"github.com/pingcap/tidb/parser/terror"
Expand Down Expand Up @@ -461,6 +462,28 @@ func ColumnSubstituteImpl(expr Expression, schema *Schema, newExprs []Expression
}
return false, false, v
}
// If the collation of the column is PAD SPACE,
// we can't propagate the constant to the length function.
// For example, schema = ['name'], newExprs = ['a'], v = length(name).
// We can't substitute name with 'a' in length(name) because the collation of name is PAD SPACE.
// TODO: We will fix it here temporarily, and redesign the logic if we encounter more similar functions or situations later.
// Fixed issue #53730
if v.GetCtx().GetSessionVars().StmtCtx.InConstantPropagateCheck && v.FuncName.L == ast.Length {
arg0, isColumn := v.GetArgs()[0].(*Column)
if isColumn {
id := schema.ColumnIndex(arg0)
if id != -1 {
_, isConstant := newExprs[id].(*Constant)
if isConstant {
mappedNewColumnCollate := schema.Columns[id].GetType().GetCollate()
if mappedNewColumnCollate == charset.CollationUTF8MB4 ||
mappedNewColumnCollate == charset.CollationUTF8 {
return false, false, v
}
}
}
}
}
// cowExprRef is a copy-on-write util, args array allocation happens only
// when expr in args is changed
refExprArr := cowExprRef{v.GetArgs(), nil}
Expand Down
4 changes: 4 additions & 0 deletions planner/core/casetest/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,3 +138,7 @@ func GetDerivedTopNSuiteData() testdata.TestData {
func GetPredicateSimplificationTestData() testdata.TestData {
return testDataMap["predicate_simplification"]
}

func GetPredicatePushdownSuiteData() testdata.TestData {
return testDataMap["predicate_pushdown_suite"]
}
31 changes: 31 additions & 0 deletions planner/core/casetest/physical_plan_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2562,3 +2562,34 @@ func TestIndexMergeOrderPushDown(t *testing.T) {
tk.MustQuery("show warnings").Check(testkit.Rows(output[i].Warning...))
}
}

func TestConstantPropagateWithCollation(t *testing.T) {
var input []string
var output []struct {
SQL string
Plan []string
Warning []string
}
planSuiteData := GetPlanSuiteData()
planSuiteData.LoadTestCases(t, &input, &output)
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
// create table
tk.MustExec("use test")
tk.MustExec("create table t (id int primary key, name varchar(20));")
require.Equal(t, len(input), len(output))

for i := range input {
if strings.Contains(input[i], "set") {
tk.MustExec(input[i])
continue
}
testdata.OnRecord(func() {
output[i].SQL = input[i]
output[i].Plan = testdata.ConvertRowsToStrings(tk.MustQuery("explain format = 'brief' " + input[i]).Rows())
output[i].Warning = testdata.ConvertRowsToStrings(tk.MustQuery("show warnings").Rows())
})
tk.MustQuery("explain format = 'brief' " + input[i]).Check(testkit.Rows(output[i].Plan...))
tk.MustQuery("show warnings").Check(testkit.Rows(output[i].Warning...))
}
}
10 changes: 10 additions & 0 deletions planner/core/casetest/testdata/plan_suite_in.json
Original file line number Diff line number Diff line change
Expand Up @@ -1351,5 +1351,15 @@
"select * from employee where dept_id = 1 union all ( select * from employee where dept_id = 1 order by employee_id) union all ( select * from employee where dept_id = 1 union all ( select * from employee where dept_id = 1 order by employee_id ) limit 1);",
"select * from employee where dept_id = 1 union all ( select * from employee where dept_id = 1 order by employee_id) union all ( select * from employee where dept_id = 1 union all ( select * from employee where dept_id = 1 order by employee_id ) order by 1 limit 1);"
]
},
{
"name": "TestConstantPropagateWithCollation",
"cases": [
"set names utf8",
"select * from t where name='a' and length(name)=1; -- without constant propagated",
"set names utf8mb4",
"select * from t where name='a' and length(name)=1; -- without constant propagated",
"select * from (select 'test' as b from t) n where length(b) > 2; -- can be substituted"
]
}
]
42 changes: 42 additions & 0 deletions planner/core/casetest/testdata/plan_suite_out.json
Original file line number Diff line number Diff line change
Expand Up @@ -8951,5 +8951,47 @@
"Warning": null
}
]
},
{
"Name": "TestConstantPropagateWithCollation",
"Cases": [
{
"SQL": "",
"Plan": null,
"Warning": null
},
{
"SQL": "select * from t where name='a' and length(name)=1; -- without constant propagated",
"Plan": [
"TableReader 8.00 root data:Selection",
"└─Selection 8.00 cop[tikv] eq(length(test.t.name), 1), eq(test.t.name, \"a\")",
" └─TableFullScan 10000.00 cop[tikv] table:t keep order:false, stats:pseudo"
],
"Warning": null
},
{
"SQL": "",
"Plan": null,
"Warning": null
},
{
"SQL": "select * from t where name='a' and length(name)=1; -- without constant propagated",
"Plan": [
"TableReader 8.00 root data:Selection",
"└─Selection 8.00 cop[tikv] eq(length(test.t.name), 1), eq(test.t.name, \"a\")",
" └─TableFullScan 10000.00 cop[tikv] table:t keep order:false, stats:pseudo"
],
"Warning": null
},
{
"SQL": "select * from (select 'test' as b from t) n where length(b) > 2; -- can be substituted",
"Plan": [
"Projection 10000.00 root test->Column#3",
"└─TableReader 10000.00 root data:TableFullScan",
" └─TableFullScan 10000.00 cop[tikv] table:t keep order:false, stats:pseudo"
],
"Warning": null
}
]
}
]
1 change: 1 addition & 0 deletions sessionctx/stmtctx/stmtctx.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ type StatementContext struct {
CacheType PlanCacheType
BatchCheck bool
InNullRejectCheck bool
InConstantPropagateCheck bool
AllowInvalidDate bool
IgnoreNoPartition bool
IgnoreExplainIDSuffix bool
Expand Down

0 comments on commit ba09647

Please sign in to comment.