Skip to content

Commit

Permalink
cherry-pick: mannual cherry-pick 49421 back to release 7.1 (#49592)
Browse files Browse the repository at this point in the history
close #49377
  • Loading branch information
AilinKid authored Dec 22, 2023
1 parent 36c74e6 commit 4d53073
Show file tree
Hide file tree
Showing 8 changed files with 191 additions and 4 deletions.
34 changes: 34 additions & 0 deletions executor/explain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -702,3 +702,37 @@ func TestExplainFormatPlanCache(t *testing.T) {
tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("0"))
}
}

func TestIssues49377(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("drop table if exists employee")
tk.MustExec("create table employee (employee_id int, name varchar(20), dept_id int)")
tk.MustExec("insert into employee values (1, 'Furina', 1), (2, 'Klee', 1), (3, 'Eula', 1), (4, 'Diluc', 2), (5, 'Tartaglia', 2)")

tk.MustQuery("select 1,1,1 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 " +
");").Sort().Check(testkit.Rows("1 1 1", "1 Furina 1"))

tk.MustQuery("select 1,1,1 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" +
");").Sort().Check(testkit.Rows("1 1 1", "1 Furina 1", "1 Furina 1", "2 Klee 1", "2 Klee 1", "3 Eula 1", "3 Eula 1"))

tk.MustQuery("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" +
");").Sort().Check(testkit.Rows("1 Furina 1", "1 Furina 1", "1 Furina 1", "2 Klee 1", "2 Klee 1", "3 Eula 1", "3 Eula 1"))
}
2 changes: 2 additions & 0 deletions parser/ast/dml.go
Original file line number Diff line number Diff line change
Expand Up @@ -1550,6 +1550,8 @@ type SetOprSelectList struct {
With *WithClause
AfterSetOperator *SetOprType
Selects []Node
Limit *Limit
OrderBy *OrderByClause
}

// Restore implements Node interface.
Expand Down
8 changes: 7 additions & 1 deletion parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -19364,15 +19364,21 @@ yynewstate:
}
var setOprList2 []ast.Node
var with2 *ast.WithClause
var limit2 *ast.Limit
var orderBy2 *ast.OrderByClause
switch x := yyS[yypt-0].expr.(*ast.SubqueryExpr).Query.(type) {
case *ast.SelectStmt:
setOprList2 = []ast.Node{x}
with2 = x.With
case *ast.SetOprStmt:
// child setOprStmt's limit and order should also make sense
// we should separate it out from other normal SetOprSelectList.
setOprList2 = x.SelectList.Selects
with2 = x.With
limit2 = x.Limit
orderBy2 = x.OrderBy
}
nextSetOprList := &ast.SetOprSelectList{Selects: setOprList2, With: with2}
nextSetOprList := &ast.SetOprSelectList{Selects: setOprList2, With: with2, Limit: limit2, OrderBy: orderBy2}
nextSetOprList.AfterSetOperator = yyS[yypt-1].item.(*ast.SetOprType)
setOprList := append(setOprList1, nextSetOprList)
setOpr := &ast.SetOprStmt{SelectList: &ast.SetOprSelectList{Selects: setOprList}}
Expand Down
8 changes: 7 additions & 1 deletion parser/parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -9994,15 +9994,21 @@ SetOprStmtWoutLimitOrderBy:
}
var setOprList2 []ast.Node
var with2 *ast.WithClause
var limit2 *ast.Limit
var orderBy2 *ast.OrderByClause
switch x := $3.(*ast.SubqueryExpr).Query.(type) {
case *ast.SelectStmt:
setOprList2 = []ast.Node{x}
with2 = x.With
case *ast.SetOprStmt:
// child setOprStmt's limit and order should also make sense
// we should separate it out from other normal SetOprSelectList.
setOprList2 = x.SelectList.Selects
with2 = x.With
limit2 = x.Limit
orderBy2 = x.OrderBy
}
nextSetOprList := &ast.SetOprSelectList{Selects: setOprList2, With: with2}
nextSetOprList := &ast.SetOprSelectList{Selects: setOprList2, With: with2, Limit: limit2, OrderBy: orderBy2}
nextSetOprList.AfterSetOperator = $2.(*ast.SetOprType)
setOprList := append(setOprList1, nextSetOprList)
setOpr := &ast.SetOprStmt{SelectList: &ast.SetOprSelectList{Selects: setOprList}}
Expand Down
26 changes: 26 additions & 0 deletions planner/core/casetest/physical_plan_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2433,6 +2433,32 @@ func TestCountStarForTiFlash(t *testing.T) {
}
}

func TestIssues49377Plan(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("drop table if exists employee")
tk.MustExec("create table employee (employee_id int, name varchar(20), dept_id int)")

var (
input []string
output []struct {
SQL string
Plan []string
Warning []string
}
)
planSuiteData := GetPlanSuiteData()
planSuiteData.LoadTestCases(t, &input, &output)
for i, ts := range input {
testdata.OnRecord(func() {
output[i].SQL = ts
output[i].Plan = testdata.ConvertRowsToStrings(tk.MustQuery("explain format = 'brief' " + ts).Rows())
})
tk.MustQuery("explain format = 'brief' " + ts).Check(testkit.Rows(output[i].Plan...))
}
}

func TestHashAggPushdownToTiFlashCompute(t *testing.T) {
var (
input []string
Expand Down
9 changes: 9 additions & 0 deletions planner/core/casetest/testdata/plan_suite_in.json
Original file line number Diff line number Diff line change
Expand Up @@ -1332,5 +1332,14 @@
"select * from tcommon where (a = 1 and c = 2) or (b = 1) order by c limit 2",
"select * from thash use index(idx_ac, idx_bc) where a = 1 or b = 1 order by c limit 2"
]
},
{
"name": "TestIssues49377Plan",
"cases": [
"select 1,1,1 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 );",
"select 1,1,1 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);",
"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);"
]
}
]
98 changes: 98 additions & 0 deletions planner/core/casetest/testdata/plan_suite_out.json
Original file line number Diff line number Diff line change
Expand Up @@ -8721,5 +8721,103 @@
]
}
]
},
{
"Name": "TestIssues49377Plan",
"Cases": [
{
"SQL": "select 1,1,1 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 );",
"Plan": [
"Union 21.00 root ",
"├─Projection 1.00 root 1->Column#15, 1->Column#16, 1->Column#17",
"│ └─TableDual 1.00 root rows:1",
"└─Projection 20.00 root cast(Column#12, bigint(11) BINARY)->Column#15, Column#13, cast(Column#14, bigint(11) BINARY)->Column#17",
" └─Sort 20.00 root Column#12",
" └─Union 20.00 root ",
" ├─TableReader 10.00 root data:Selection",
" │ └─Selection 10.00 cop[tikv] eq(test.employee.dept_id, 1)",
" │ └─TableFullScan 10000.00 cop[tikv] table:employee keep order:false, stats:pseudo",
" └─Sort 10.00 root test.employee.employee_id",
" └─TableReader 10.00 root data:Selection",
" └─Selection 10.00 cop[tikv] eq(test.employee.dept_id, 1)",
" └─TableFullScan 10000.00 cop[tikv] table:employee keep order:false, stats:pseudo"
],
"Warning": null
},
{
"SQL": "select 1,1,1 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);",
"Plan": [
"Union 2.00 root ",
"├─Projection 1.00 root 1->Column#15, 1->Column#16, 1->Column#17",
"│ └─TableDual 1.00 root rows:1",
"└─Projection 1.00 root cast(Column#12, bigint(11) BINARY)->Column#15, Column#13, cast(Column#14, bigint(11) BINARY)->Column#17",
" └─TopN 1.00 root Column#12, offset:0, count:1",
" └─Union 2.00 root ",
" ├─TopN 1.00 root test.employee.employee_id, offset:0, count:1",
" │ └─TableReader 1.00 root data:TopN",
" │ └─TopN 1.00 cop[tikv] test.employee.employee_id, offset:0, count:1",
" │ └─Selection 10.00 cop[tikv] eq(test.employee.dept_id, 1)",
" │ └─TableFullScan 10000.00 cop[tikv] table:employee keep order:false, stats:pseudo",
" └─TopN 1.00 root test.employee.employee_id, offset:0, count:1",
" └─TableReader 1.00 root data:TopN",
" └─TopN 1.00 cop[tikv] test.employee.employee_id, offset:0, count:1",
" └─Selection 10.00 cop[tikv] eq(test.employee.dept_id, 1)",
" └─TableFullScan 10000.00 cop[tikv] table:employee keep order:false, stats:pseudo"
],
"Warning": null
},
{
"SQL": "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);",
"Plan": [
"Union 21.00 root ",
"├─TableReader 10.00 root data:Selection",
"│ └─Selection 10.00 cop[tikv] eq(test.employee.dept_id, 1)",
"│ └─TableFullScan 10000.00 cop[tikv] table:employee keep order:false, stats:pseudo",
"├─Sort 10.00 root test.employee.employee_id",
"│ └─TableReader 10.00 root data:Selection",
"│ └─Selection 10.00 cop[tikv] eq(test.employee.dept_id, 1)",
"│ └─TableFullScan 10000.00 cop[tikv] table:employee keep order:false, stats:pseudo",
"└─Limit 1.00 root offset:0, count:1",
" └─Union 1.00 root ",
" ├─Limit 1.00 root offset:0, count:1",
" │ └─TableReader 1.00 root data:Limit",
" │ └─Limit 1.00 cop[tikv] offset:0, count:1",
" │ └─Selection 1.00 cop[tikv] eq(test.employee.dept_id, 1)",
" │ └─TableFullScan 1000.00 cop[tikv] table:employee keep order:false, stats:pseudo",
" └─TopN 1.00 root test.employee.employee_id, offset:0, count:1",
" └─TableReader 1.00 root data:TopN",
" └─TopN 1.00 cop[tikv] test.employee.employee_id, offset:0, count:1",
" └─Selection 10.00 cop[tikv] eq(test.employee.dept_id, 1)",
" └─TableFullScan 10000.00 cop[tikv] table:employee keep order:false, stats:pseudo"
],
"Warning": null
},
{
"SQL": "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);",
"Plan": [
"Union 21.00 root ",
"├─TableReader 10.00 root data:Selection",
"│ └─Selection 10.00 cop[tikv] eq(test.employee.dept_id, 1)",
"│ └─TableFullScan 10000.00 cop[tikv] table:employee keep order:false, stats:pseudo",
"├─Sort 10.00 root test.employee.employee_id",
"│ └─TableReader 10.00 root data:Selection",
"│ └─Selection 10.00 cop[tikv] eq(test.employee.dept_id, 1)",
"│ └─TableFullScan 10000.00 cop[tikv] table:employee keep order:false, stats:pseudo",
"└─TopN 1.00 root Column#17, offset:0, count:1",
" └─Union 2.00 root ",
" ├─TopN 1.00 root test.employee.employee_id, offset:0, count:1",
" │ └─TableReader 1.00 root data:TopN",
" │ └─TopN 1.00 cop[tikv] test.employee.employee_id, offset:0, count:1",
" │ └─Selection 10.00 cop[tikv] eq(test.employee.dept_id, 1)",
" │ └─TableFullScan 10000.00 cop[tikv] table:employee keep order:false, stats:pseudo",
" └─TopN 1.00 root test.employee.employee_id, offset:0, count:1",
" └─TableReader 1.00 root data:TopN",
" └─TopN 1.00 cop[tikv] test.employee.employee_id, offset:0, count:1",
" └─Selection 10.00 cop[tikv] eq(test.employee.dept_id, 1)",
" └─TableFullScan 10000.00 cop[tikv] table:employee keep order:false, stats:pseudo"
],
"Warning": null
}
]
}
]
10 changes: 8 additions & 2 deletions planner/core/logical_plan_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -1824,6 +1824,12 @@ func (b *PlanBuilder) buildSetOpr(ctx context.Context, setOpr *ast.SetOprStmt) (
if *x.AfterSetOperator != ast.Intersect && *x.AfterSetOperator != ast.IntersectAll {
breakIteration = true
}
if x.Limit != nil || x.OrderBy != nil {
// when SetOprSelectList's limit and order-by is not nil, it means itself is converted from
// an independent ast.SetOprStmt in parser, its data should be evaluated first, and ordered
// by given items and conduct a limit on it, then it can only be integrated with other brothers.
breakIteration = true
}
}
if breakIteration {
break
Expand Down Expand Up @@ -1922,7 +1928,7 @@ func (b *PlanBuilder) buildIntersect(ctx context.Context, selects []ast.Node) (L
leftPlan, err = b.buildSelect(ctx, x)
case *ast.SetOprSelectList:
afterSetOperator = x.AfterSetOperator
leftPlan, err = b.buildSetOpr(ctx, &ast.SetOprStmt{SelectList: x, With: x.With})
leftPlan, err = b.buildSetOpr(ctx, &ast.SetOprStmt{SelectList: x, With: x.With, Limit: x.Limit, OrderBy: x.OrderBy})
}
if err != nil {
return nil, nil, err
Expand All @@ -1946,7 +1952,7 @@ func (b *PlanBuilder) buildIntersect(ctx context.Context, selects []ast.Node) (L
// TODO: support intersect all
return nil, nil, errors.Errorf("TiDB do not support intersect all")
}
rightPlan, err = b.buildSetOpr(ctx, &ast.SetOprStmt{SelectList: x, With: x.With})
rightPlan, err = b.buildSetOpr(ctx, &ast.SetOprStmt{SelectList: x, With: x.With, Limit: x.Limit, OrderBy: x.OrderBy})
}
if err != nil {
return nil, nil, err
Expand Down

0 comments on commit 4d53073

Please sign in to comment.