Skip to content
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

parser, planner: fix embedded setOprStmt will be seen as SetOprSelectList item and lost its orderBy and Limit (#49421) #49503

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions executor/executor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6511,3 +6511,38 @@ func TestProcessInfoOfSubQuery(t *testing.T) {
tk2.MustQuery("select 1 from information_schema.processlist where TxnStart != '' and info like 'select%sleep% from t%'").Check(testkit.Rows("1"))
wg.Wait()
}

func TestIssues49377(t *testing.T) {
t.Skip()
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"))
}
6 changes: 6 additions & 0 deletions executor/explain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,10 @@ func TestCheckActRowsWithUnistore(t *testing.T) {
// testSuite1 use default mockstore which is unistore
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
// set up general log for debugging.
tk.MustExec("set global tidb_general_log=1")
defer tk.MustExec("set global tidb_general_log=0")

tk.MustExec("set tidb_cost_model_version=2")
tk.MustExec("drop table if exists t_unistore_act_rows")
tk.MustExec("create table t_unistore_act_rows(a int, b int, index(a, b))")
Expand All @@ -335,6 +339,8 @@ func TestCheckActRowsWithUnistore(t *testing.T) {
sql string
expected []string
}
tk.MustQuery("select * from t_unistore_act_rows").Sort().Check(testkit.Rows("1 0", "1 0",
"2 0", "2 1"))

tests := []testStruct{
{
Expand Down
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
7 changes: 7 additions & 0 deletions parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -19364,14 +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, Limit: limit2, OrderBy: orderBy2}
nextSetOprList := &ast.SetOprSelectList{Selects: setOprList2, With: with2}
nextSetOprList.AfterSetOperator = yyS[yypt-1].item.(*ast.SetOprType)
setOprList := append(setOprList1, nextSetOprList)
Expand Down
7 changes: 7 additions & 0 deletions parser/parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -9994,14 +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, Limit: limit2, OrderBy: orderBy2}
nextSetOprList := &ast.SetOprSelectList{Selects: setOprList2, With: with2}
nextSetOprList.AfterSetOperator = $2.(*ast.SetOprType)
setOprList := append(setOprList1, nextSetOprList)
Expand Down
27 changes: 27 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,33 @@ func TestCountStarForTiFlash(t *testing.T) {
}
}

func TestIssues49377Plan(t *testing.T) {
t.Skip()
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
}
]
}
]
6 changes: 6 additions & 0 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