Skip to content

Commit c26d7ae

Browse files
hawkingreiti-chi-bot
authored andcommitted
This is an automated cherry-pick of pingcap#60702
Signed-off-by: ti-chi-bot <[email protected]>
1 parent b29954e commit c26d7ae

File tree

5 files changed

+132
-1
lines changed

5 files changed

+132
-1
lines changed

pkg/planner/core/expression_rewriter.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -698,13 +698,18 @@ func (er *expressionRewriter) handleCompareSubquery(ctx context.Context, planCtx
698698
er.err = err
699699
return v, true
700700
}
701+
<<<<<<< HEAD
701702

702703
noDecorrelate := hintFlags&hint.HintFlagNoDecorrelate > 0
703704
if noDecorrelate && len(extractCorColumnsBySchema4LogicalPlan(np, planCtx.plan.Schema())) == 0 {
704705
b.ctx.GetSessionVars().StmtCtx.SetHintWarning(
705706
"NO_DECORRELATE() is inapplicable because there are no correlated columns.")
706707
noDecorrelate = false
707708
}
709+
=======
710+
corCols := coreusage.ExtractCorColumnsBySchema4LogicalPlan(np, planCtx.plan.Schema())
711+
noDecorrelate := isNoDecorrelate(planCtx, corCols, hintFlags)
712+
>>>>>>> 9331aeab088 (collate: latin1_bin has the same collate with utf8mb4_bin,utf8_bin (#60702))
708713

709714
// Only (a,b,c) = any (...) and (a,b,c) != all (...) can use row expression.
710715
canMultiCol := (!v.All && v.Op == opcode.EQ) || (v.All && v.Op == opcode.NE)
@@ -1007,13 +1012,18 @@ func (er *expressionRewriter) handleExistSubquery(ctx context.Context, planCtx *
10071012
return v, true
10081013
}
10091014
np = er.popExistsSubPlan(planCtx, np)
1015+
<<<<<<< HEAD
10101016

10111017
noDecorrelate := hintFlags&hint.HintFlagNoDecorrelate > 0
10121018
if noDecorrelate && len(extractCorColumnsBySchema4LogicalPlan(np, planCtx.plan.Schema())) == 0 {
10131019
b.ctx.GetSessionVars().StmtCtx.SetHintWarning(
10141020
"NO_DECORRELATE() is inapplicable because there are no correlated columns.")
10151021
noDecorrelate = false
10161022
}
1023+
=======
1024+
corCols := coreusage.ExtractCorColumnsBySchema4LogicalPlan(np, planCtx.plan.Schema())
1025+
noDecorrelate := isNoDecorrelate(planCtx, corCols, hintFlags)
1026+
>>>>>>> 9331aeab088 (collate: latin1_bin has the same collate with utf8mb4_bin,utf8_bin (#60702))
10171027
semiJoinRewrite := hintFlags&hint.HintFlagSemiJoinRewrite > 0
10181028
if semiJoinRewrite && noDecorrelate {
10191029
b.ctx.GetSessionVars().StmtCtx.SetHintWarning(
@@ -1180,6 +1190,7 @@ func (er *expressionRewriter) handleInSubquery(ctx context.Context, planCtx *exp
11801190
// If the leftKey and the rightKey have different collations, don't convert the sub-query to an inner-join
11811191
// since when converting we will add a distinct-agg upon the right child and this distinct-agg doesn't have the right collation.
11821192
// To keep it simple, we forbid this converting if they have different collations.
1193+
<<<<<<< HEAD
11831194
lt, rt := lexpr.GetType(), rexpr.GetType()
11841195
collFlag := collate.CompatibleCollate(lt.GetCollate(), rt.GetCollate())
11851196

@@ -1190,6 +1201,13 @@ func (er *expressionRewriter) handleInSubquery(ctx context.Context, planCtx *exp
11901201
"NO_DECORRELATE() is inapplicable because there are no correlated columns.")
11911202
noDecorrelate = false
11921203
}
1204+
=======
1205+
// tested by TestCollateSubQuery.
1206+
lt, rt := lexpr.GetType(er.sctx.GetEvalCtx()), rexpr.GetType(er.sctx.GetEvalCtx())
1207+
collFlag := collate.CompatibleCollate(lt.GetCollate(), rt.GetCollate())
1208+
corCols := coreusage.ExtractCorColumnsBySchema4LogicalPlan(np, planCtx.plan.Schema())
1209+
noDecorrelate := isNoDecorrelate(planCtx, corCols, hintFlags)
1210+
>>>>>>> 9331aeab088 (collate: latin1_bin has the same collate with utf8mb4_bin,utf8_bin (#60702))
11931211

11941212
// If it's not the form of `not in (SUBQUERY)`,
11951213
// and has no correlated column from the current level plan(if the correlated column is from upper level,
@@ -1234,6 +1252,16 @@ func (er *expressionRewriter) handleInSubquery(ctx context.Context, planCtx *exp
12341252
return v, true
12351253
}
12361254

1255+
func isNoDecorrelate(planCtx *exprRewriterPlanCtx, corCols []*expression.CorrelatedColumn, hintFlags uint64) bool {
1256+
noDecorrelate := hintFlags&hint.HintFlagNoDecorrelate > 0
1257+
if noDecorrelate && len(corCols) == 0 {
1258+
planCtx.builder.ctx.GetSessionVars().StmtCtx.SetHintWarning(
1259+
"NO_DECORRELATE() is inapplicable because there are no correlated columns.")
1260+
noDecorrelate = false
1261+
}
1262+
return noDecorrelate
1263+
}
1264+
12371265
func (er *expressionRewriter) handleScalarSubquery(ctx context.Context, planCtx *exprRewriterPlanCtx, v *ast.SubqueryExpr) (ast.Node, bool) {
12381266
intest.AssertNotNil(planCtx)
12391267
ci := planCtx.builder.prepareCTECheckForSubQuery()
@@ -1244,13 +1272,18 @@ func (er *expressionRewriter) handleScalarSubquery(ctx context.Context, planCtx
12441272
return v, true
12451273
}
12461274
np = planCtx.builder.buildMaxOneRow(np)
1275+
<<<<<<< HEAD
12471276

12481277
noDecorrelate := hintFlags&hint.HintFlagNoDecorrelate > 0
12491278
if noDecorrelate && len(extractCorColumnsBySchema4LogicalPlan(np, planCtx.plan.Schema())) == 0 {
12501279
planCtx.builder.ctx.GetSessionVars().StmtCtx.SetHintWarning(
12511280
"NO_DECORRELATE() is inapplicable because there are no correlated columns.")
12521281
noDecorrelate = false
12531282
}
1283+
=======
1284+
correlatedColumn := coreusage.ExtractCorColumnsBySchema4LogicalPlan(np, planCtx.plan.Schema())
1285+
noDecorrelate := isNoDecorrelate(planCtx, correlatedColumn, hintFlags)
1286+
>>>>>>> 9331aeab088 (collate: latin1_bin has the same collate with utf8mb4_bin,utf8_bin (#60702))
12541287

12551288
if planCtx.builder.disableSubQueryPreprocessing || len(ExtractCorrelatedCols4LogicalPlan(np)) > 0 || hasCTEConsumerInSubPlan(np) {
12561289
planCtx.plan = planCtx.builder.buildApplyWithJoinType(planCtx.plan, np, LeftOuterJoin, noDecorrelate)
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
load("@io_bazel_rules_go//go:def.bzl", "go_test")
2+
3+
go_test(
4+
name = "subquery_test",
5+
timeout = "short",
6+
srcs = [
7+
"main_test.go",
8+
"subquery_test.go",
9+
],
10+
flaky = True,
11+
deps = [
12+
"//pkg/testkit",
13+
"//pkg/testkit/testsetup",
14+
"@org_uber_go_goleak//:goleak",
15+
],
16+
)
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright 2025 PingCAP, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package subquery
16+
17+
import (
18+
"flag"
19+
"testing"
20+
21+
"github.com/pingcap/tidb/pkg/testkit/testsetup"
22+
"go.uber.org/goleak"
23+
)
24+
25+
func TestMain(m *testing.M) {
26+
testsetup.SetupForCommonTest()
27+
flag.Parse()
28+
opts := []goleak.Option{
29+
goleak.IgnoreTopFunction("github.com/golang/glog.(*fileSink).flushDaemon"),
30+
goleak.IgnoreTopFunction("github.com/bazelbuild/rules_go/go/tools/bzltestutil.RegisterTimeoutHandler.func1"),
31+
goleak.IgnoreTopFunction("github.com/lestrrat-go/httprc.runFetchWorker"),
32+
}
33+
goleak.VerifyTestMain(m, opts...)
34+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// Copyright 2025 PingCAP, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package subquery
16+
17+
import (
18+
"testing"
19+
20+
"github.com/pingcap/tidb/pkg/testkit"
21+
)
22+
23+
func TestCollateSubQuery(t *testing.T) {
24+
store := testkit.CreateMockStore(t)
25+
tk := testkit.NewTestKit(t, store)
26+
tk.MustExec("use test")
27+
tk.MustExec("create table t(id int, col varchar(100), key ix(col)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;")
28+
tk.MustExec("create table t1(id varchar(100)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;")
29+
samePlan := testkit.Rows(
30+
"IndexHashJoin 8000.00 root inner join, inner:IndexLookUp, outer key:Column#6, inner key:test.t.col, equal cond:eq(Column#6, test.t.col)",
31+
"├─HashAgg(Build) 6400.00 root group by:Column#12, funcs:firstrow(Column#12)->Column#6",
32+
"│ └─TableReader 6400.00 root data:HashAgg",
33+
"│ └─HashAgg 6400.00 cop[tikv] group by:cast(test.t1.id, var_string(5)), ",
34+
"│ └─Selection 8000.00 cop[tikv] not(isnull(cast(test.t1.id, var_string(5))))",
35+
"│ └─TableFullScan 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo",
36+
"└─IndexLookUp(Probe) 8000.00 root ",
37+
" ├─Selection(Build) 8000.00 cop[tikv] not(isnull(test.t.col))",
38+
" │ └─IndexRangeScan 8008.01 cop[tikv] table:t, index:ix(col) range: decided by [eq(test.t.col, Column#6)], keep order:false, stats:pseudo",
39+
" └─TableRowIDScan(Probe) 8000.00 cop[tikv] table:t keep order:false, stats:pseudo")
40+
tk.MustQuery(`explain format="brief" select * from t use index(ix) where col in (select cast(id as char) from t1);`).
41+
Check(samePlan)
42+
tk.MustExec(`set collation_connection='utf8_bin';`)
43+
tk.MustQuery(`explain format="brief" select * from t use index(ix) where col in (select cast(id as char) from t1);`).
44+
Check(samePlan)
45+
tk.MustExec(`set collation_connection='latin1_bin';`)
46+
tk.MustQuery(`explain format="brief" select * from t use index(ix) where col in (select cast(id as char) from t1);`).
47+
Check(samePlan)
48+
}

pkg/util/collate/collate.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ func NewCollationEnabled() bool {
102102
func CompatibleCollate(collate1, collate2 string) bool {
103103
if (collate1 == "utf8mb4_general_ci" || collate1 == "utf8_general_ci") && (collate2 == "utf8mb4_general_ci" || collate2 == "utf8_general_ci") {
104104
return true
105-
} else if (collate1 == "utf8mb4_bin" || collate1 == "utf8_bin" || collate1 == "latin1_bin") && (collate2 == "utf8mb4_bin" || collate2 == "utf8_bin") {
105+
} else if (collate1 == "utf8mb4_bin" || collate1 == "utf8_bin" || collate1 == "latin1_bin") && (collate2 == "utf8mb4_bin" || collate2 == "utf8_bin" || collate2 == "latin1_bin") {
106106
return true
107107
} else if (collate1 == "utf8mb4_unicode_ci" || collate1 == "utf8_unicode_ci") && (collate2 == "utf8mb4_unicode_ci" || collate2 == "utf8_unicode_ci") {
108108
return true

0 commit comments

Comments
 (0)