diff --git a/parser/ast/dml.go b/parser/ast/dml.go index d1bf9bfb64152..3264d318e843a 100644 --- a/parser/ast/dml.go +++ b/parser/ast/dml.go @@ -1562,6 +1562,7 @@ func (n *SetOprSelectList) Restore(ctx *format.RestoreCtx) error { return errors.Annotate(err, "An error occurred while restore SetOprSelectList.With") } } + for i, stmt := range n.Selects { switch selectStmt := stmt.(type) { case *SelectStmt: @@ -1583,6 +1584,20 @@ func (n *SetOprSelectList) Restore(ctx *format.RestoreCtx) error { ctx.WritePlain(")") } } + + if n.OrderBy != nil { + ctx.WritePlain(" ") + if err := n.OrderBy.Restore(ctx); err != nil { + return errors.Annotate(err, "An error occurred while restore SetOprSelectList.OrderBy") + } + } + + if n.Limit != nil { + ctx.WritePlain(" ") + if err := n.Limit.Restore(ctx); err != nil { + return errors.Annotate(err, "An error occurred while restore SetOprSelectList.Limit") + } + } return nil } @@ -1607,6 +1622,20 @@ func (n *SetOprSelectList) Accept(v Visitor) (Node, bool) { } n.Selects[i] = node } + if n.OrderBy != nil { + node, ok := n.OrderBy.Accept(v) + if !ok { + return n, false + } + n.OrderBy = node.(*OrderByClause) + } + if n.Limit != nil { + node, ok := n.Limit.Accept(v) + if !ok { + return n, false + } + n.Limit = node.(*Limit) + } return v.Leave(n) } diff --git a/parser/parser.go b/parser/parser.go index fc1bd4cfcfe70..dc0bb606fa22c 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -19393,6 +19393,8 @@ yynewstate: } var setOprList2 []ast.Node var with2 *ast.WithClause + var limit2 *ast.Limit + var orderBy2 *ast.OrderByClause switch x := yyS[yypt-1].expr.(*ast.SubqueryExpr).Query.(type) { case *ast.SelectStmt: setOprList2 = []ast.Node{x} @@ -19400,8 +19402,10 @@ yynewstate: case *ast.SetOprStmt: 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-2].item.(*ast.SetOprType) setOprList := append(setOprList1, nextSetOprList) setOpr := &ast.SetOprStmt{SelectList: &ast.SetOprSelectList{Selects: setOprList}} @@ -19417,6 +19421,8 @@ yynewstate: } var setOprList2 []ast.Node var with2 *ast.WithClause + var limit2 *ast.Limit + var orderBy2 *ast.OrderByClause switch x := yyS[yypt-1].expr.(*ast.SubqueryExpr).Query.(type) { case *ast.SelectStmt: setOprList2 = []ast.Node{x} @@ -19424,8 +19430,10 @@ yynewstate: case *ast.SetOprStmt: 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-2].item.(*ast.SetOprType) setOprList := append(setOprList1, nextSetOprList) setOpr := &ast.SetOprStmt{SelectList: &ast.SetOprSelectList{Selects: setOprList}} @@ -19441,6 +19449,8 @@ yynewstate: } var setOprList2 []ast.Node var with2 *ast.WithClause + var limit2 *ast.Limit + var orderBy2 *ast.OrderByClause switch x := yyS[yypt-2].expr.(*ast.SubqueryExpr).Query.(type) { case *ast.SelectStmt: setOprList2 = []ast.Node{x} @@ -19448,8 +19458,10 @@ yynewstate: case *ast.SetOprStmt: 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-3].item.(*ast.SetOprType) setOprList := append(setOprList1, nextSetOprList) setOpr := &ast.SetOprStmt{SelectList: &ast.SetOprSelectList{Selects: setOprList}} @@ -19460,48 +19472,39 @@ yynewstate: case 1793: { var setOprList []ast.Node - var with *ast.WithClause switch x := yyS[yypt-1].expr.(*ast.SubqueryExpr).Query.(type) { case *ast.SelectStmt: - setOprList = []ast.Node{x} - with = x.With + setOprList = []ast.Node{&ast.SetOprSelectList{Selects: []ast.Node{x}, With: x.With}} case *ast.SetOprStmt: - setOprList = x.SelectList.Selects - with = x.With + setOprList = []ast.Node{&ast.SetOprSelectList{Selects: x.SelectList.Selects, With: x.With, Limit: x.Limit, OrderBy: x.OrderBy}} } - setOpr := &ast.SetOprStmt{SelectList: &ast.SetOprSelectList{Selects: setOprList}, With: with} + setOpr := &ast.SetOprStmt{SelectList: &ast.SetOprSelectList{Selects: setOprList}} setOpr.OrderBy = yyS[yypt-0].item.(*ast.OrderByClause) parser.yyVAL.statement = setOpr } case 1794: { var setOprList []ast.Node - var with *ast.WithClause switch x := yyS[yypt-1].expr.(*ast.SubqueryExpr).Query.(type) { case *ast.SelectStmt: - setOprList = []ast.Node{x} - with = x.With + setOprList = []ast.Node{&ast.SetOprSelectList{Selects: []ast.Node{x}, With: x.With}} case *ast.SetOprStmt: - setOprList = x.SelectList.Selects - with = x.With + setOprList = []ast.Node{&ast.SetOprSelectList{Selects: x.SelectList.Selects, With: x.With, Limit: x.Limit, OrderBy: x.OrderBy}} } - setOpr := &ast.SetOprStmt{SelectList: &ast.SetOprSelectList{Selects: setOprList}, With: with} + setOpr := &ast.SetOprStmt{SelectList: &ast.SetOprSelectList{Selects: setOprList}} setOpr.Limit = yyS[yypt-0].item.(*ast.Limit) parser.yyVAL.statement = setOpr } case 1795: { var setOprList []ast.Node - var with *ast.WithClause switch x := yyS[yypt-2].expr.(*ast.SubqueryExpr).Query.(type) { case *ast.SelectStmt: - setOprList = []ast.Node{x} - with = x.With + setOprList = []ast.Node{&ast.SetOprSelectList{Selects: []ast.Node{x}, With: x.With}} case *ast.SetOprStmt: - setOprList = x.SelectList.Selects - with = x.With + setOprList = []ast.Node{&ast.SetOprSelectList{Selects: x.SelectList.Selects, With: x.With, Limit: x.Limit, OrderBy: x.OrderBy}} } - setOpr := &ast.SetOprStmt{SelectList: &ast.SetOprSelectList{Selects: setOprList}, With: with} + setOpr := &ast.SetOprStmt{SelectList: &ast.SetOprSelectList{Selects: setOprList}} setOpr.OrderBy = yyS[yypt-1].item.(*ast.OrderByClause) setOpr.Limit = yyS[yypt-0].item.(*ast.Limit) parser.yyVAL.statement = setOpr @@ -19533,7 +19536,7 @@ yynewstate: case *ast.SelectStmt: setOprList = []ast.Node{&ast.SetOprSelectList{Selects: []ast.Node{x}}} case *ast.SetOprStmt: - setOprList = []ast.Node{&ast.SetOprSelectList{Selects: x.SelectList.Selects, With: x.With}} + setOprList = []ast.Node{&ast.SetOprSelectList{Selects: x.SelectList.Selects, With: x.With, Limit: x.Limit, OrderBy: x.OrderBy}} } parser.yyVAL.item = setOprList } diff --git a/parser/parser.y b/parser/parser.y index 6d881c6e16d2b..4a16704053d5e 100644 --- a/parser/parser.y +++ b/parser/parser.y @@ -57,6 +57,7 @@ import ( memberof "MEMBER OF" optionallyEnclosedBy "OPTIONALLY ENCLOSED BY" toTSO "TO TSO" + /*yy:token "_%c" */ underscoreCS "UNDERSCORE_CHARSET" @@ -2782,23 +2783,23 @@ FlashbackToTimestampStmt: "FLASHBACK" "CLUSTER" toTimestamp stringLit { $$ = &ast.FlashBackToTimestampStmt{ - FlashbackTS: ast.NewValueExpr($4, "", ""), + FlashbackTS: ast.NewValueExpr($4, "", ""), FlashbackTSO: 0, } } | "FLASHBACK" "TABLE" TableNameList toTimestamp stringLit { $$ = &ast.FlashBackToTimestampStmt{ - Tables: $3.([]*ast.TableName), - FlashbackTS: ast.NewValueExpr($5, "", ""), + Tables: $3.([]*ast.TableName), + FlashbackTS: ast.NewValueExpr($5, "", ""), FlashbackTSO: 0, } } | "FLASHBACK" DatabaseSym DBName toTimestamp stringLit { $$ = &ast.FlashBackToTimestampStmt{ - DBName: model.NewCIStr($3), - FlashbackTS: ast.NewValueExpr($5, "", ""), + DBName: model.NewCIStr($3), + FlashbackTS: ast.NewValueExpr($5, "", ""), FlashbackTSO: 0, } } @@ -2806,20 +2807,20 @@ FlashbackToTimestampStmt: { if tsoValue, ok := $4.(uint64); ok && tsoValue > 0 { $$ = &ast.FlashBackToTimestampStmt{ - FlashbackTSO: tsoValue, - } + FlashbackTSO: tsoValue, + } } else { - yylex.AppendError(yylex.Errorf("Invalid TSO value provided: %d", $4)) - return 1 + yylex.AppendError(yylex.Errorf("Invalid TSO value provided: %d", $4)) + return 1 } } | "FLASHBACK" "TABLE" TableNameList toTSO LengthNum { if tsoValue, ok := $5.(uint64); ok && tsoValue > 0 { $$ = &ast.FlashBackToTimestampStmt{ - Tables: $3.([]*ast.TableName), - FlashbackTSO: tsoValue, - } + Tables: $3.([]*ast.TableName), + FlashbackTSO: tsoValue, + } } else { yylex.AppendError(yylex.Errorf("Invalid TSO value provided: %d", $5)) return 1 @@ -2829,8 +2830,8 @@ FlashbackToTimestampStmt: { if tsoValue, ok := $5.(uint64); ok && tsoValue > 0 { $$ = &ast.FlashBackToTimestampStmt{ - DBName: model.NewCIStr($3), - FlashbackTSO: tsoValue, + DBName: model.NewCIStr($3), + FlashbackTSO: tsoValue, } } else { yylex.AppendError(yylex.Errorf("Invalid TSO value provided: %d", $5)) @@ -2838,7 +2839,6 @@ FlashbackToTimestampStmt: } } - /******************************************************************* * * Flush Back Table Statement @@ -10001,8 +10001,8 @@ SetOprStmtWoutLimitOrderBy: 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. + // 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 @@ -10025,6 +10025,8 @@ SetOprStmtWithLimitOrderBy: } 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} @@ -10032,8 +10034,10 @@ SetOprStmtWithLimitOrderBy: case *ast.SetOprStmt: 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}} @@ -10049,6 +10053,8 @@ SetOprStmtWithLimitOrderBy: } 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} @@ -10056,8 +10062,10 @@ SetOprStmtWithLimitOrderBy: case *ast.SetOprStmt: 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}} @@ -10073,6 +10081,8 @@ SetOprStmtWithLimitOrderBy: } 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} @@ -10080,8 +10090,10 @@ SetOprStmtWithLimitOrderBy: case *ast.SetOprStmt: 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}} @@ -10092,48 +10104,39 @@ SetOprStmtWithLimitOrderBy: | SubSelect OrderBy { var setOprList []ast.Node - var with *ast.WithClause switch x := $1.(*ast.SubqueryExpr).Query.(type) { case *ast.SelectStmt: - setOprList = []ast.Node{x} - with = x.With + setOprList = []ast.Node{&ast.SetOprSelectList{Selects: []ast.Node{x}, With: x.With}} case *ast.SetOprStmt: - setOprList = x.SelectList.Selects - with = x.With + setOprList = []ast.Node{&ast.SetOprSelectList{Selects: x.SelectList.Selects, With: x.With, Limit: x.Limit, OrderBy: x.OrderBy}} } - setOpr := &ast.SetOprStmt{SelectList: &ast.SetOprSelectList{Selects: setOprList}, With: with} + setOpr := &ast.SetOprStmt{SelectList: &ast.SetOprSelectList{Selects: setOprList}} setOpr.OrderBy = $2.(*ast.OrderByClause) $$ = setOpr } | SubSelect SelectStmtLimit { var setOprList []ast.Node - var with *ast.WithClause switch x := $1.(*ast.SubqueryExpr).Query.(type) { case *ast.SelectStmt: - setOprList = []ast.Node{x} - with = x.With + setOprList = []ast.Node{&ast.SetOprSelectList{Selects: []ast.Node{x}, With: x.With}} case *ast.SetOprStmt: - setOprList = x.SelectList.Selects - with = x.With + setOprList = []ast.Node{&ast.SetOprSelectList{Selects: x.SelectList.Selects, With: x.With, Limit: x.Limit, OrderBy: x.OrderBy}} } - setOpr := &ast.SetOprStmt{SelectList: &ast.SetOprSelectList{Selects: setOprList}, With: with} + setOpr := &ast.SetOprStmt{SelectList: &ast.SetOprSelectList{Selects: setOprList}} setOpr.Limit = $2.(*ast.Limit) $$ = setOpr } | SubSelect OrderBy SelectStmtLimit { var setOprList []ast.Node - var with *ast.WithClause switch x := $1.(*ast.SubqueryExpr).Query.(type) { case *ast.SelectStmt: - setOprList = []ast.Node{x} - with = x.With + setOprList = []ast.Node{&ast.SetOprSelectList{Selects: []ast.Node{x}, With: x.With}} case *ast.SetOprStmt: - setOprList = x.SelectList.Selects - with = x.With + setOprList = []ast.Node{&ast.SetOprSelectList{Selects: x.SelectList.Selects, With: x.With, Limit: x.Limit, OrderBy: x.OrderBy}} } - setOpr := &ast.SetOprStmt{SelectList: &ast.SetOprSelectList{Selects: setOprList}, With: with} + setOpr := &ast.SetOprStmt{SelectList: &ast.SetOprSelectList{Selects: setOprList}} setOpr.OrderBy = $2.(*ast.OrderByClause) setOpr.Limit = $3.(*ast.Limit) $$ = setOpr @@ -10170,7 +10173,7 @@ SetOprClause: case *ast.SelectStmt: setOprList = []ast.Node{&ast.SetOprSelectList{Selects: []ast.Node{x}}} case *ast.SetOprStmt: - setOprList = []ast.Node{&ast.SetOprSelectList{Selects: x.SelectList.Selects, With: x.With}} + setOprList = []ast.Node{&ast.SetOprSelectList{Selects: x.SelectList.Selects, With: x.With, Limit: x.Limit, OrderBy: x.OrderBy}} } $$ = setOprList } diff --git a/parser/parser_test.go b/parser/parser_test.go index 80ccd762cabe0..53052ed0d45f2 100644 --- a/parser/parser_test.go +++ b/parser/parser_test.go @@ -5023,6 +5023,16 @@ func TestSetOperator(t *testing.T) { {"(select c1 from t1) union all (select c2 from t2 except select c3 from t3) order by c1 limit 1", true, "(SELECT `c1` FROM `t1`) UNION ALL (SELECT `c2` FROM `t2` EXCEPT SELECT `c3` FROM `t3`) ORDER BY `c1` LIMIT 1"}, {"((select c1 from t1) except select c2 from t2) intersect all (select c3 from t3) order by c1 limit 1", true, "((SELECT `c1` FROM `t1`) EXCEPT SELECT `c2` FROM `t2`) INTERSECT ALL (SELECT `c3` FROM `t3`) ORDER BY `c1` LIMIT 1"}, {"select 1 union distinct (select 1 except all select 1 intersect select 1)", true, "SELECT 1 UNION (SELECT 1 EXCEPT ALL SELECT 1 INTERSECT SELECT 1)"}, + + // https://github.com/pingcap/tidb/issues/49874 + {"select * from a where PK = 0 union all (select * from b where PK = 0 union all (select * from b where PK != 0) order by pk limit 1)", true, + "SELECT * FROM `a` WHERE `PK`=0 UNION ALL (SELECT * FROM `b` WHERE `PK`=0 UNION ALL (SELECT * FROM `b` WHERE `PK`!=0) ORDER BY `pk` LIMIT 1)"}, + {"select * from a where PK = 0 union all (select * from b where PK = 0 union all (select * from b where PK != 0) order by pk limit 1) order by pk limit 2", true, + "SELECT * FROM `a` WHERE `PK`=0 UNION ALL (SELECT * FROM `b` WHERE `PK`=0 UNION ALL (SELECT * FROM `b` WHERE `PK`!=0) ORDER BY `pk` LIMIT 1) ORDER BY `pk` LIMIT 2"}, + {"(select * from b where pk= 0 union all (select * from b where pk !=0) order by pk limit 1) order by pk limit 2", true, + "(SELECT * FROM `b` WHERE `pk`=0 UNION ALL (SELECT * FROM `b` WHERE `pk`!=0) ORDER BY `pk` LIMIT 1) ORDER BY `pk` LIMIT 2"}, + {"(select * from b where pk= 0 union all (select * from b where pk !=0) order by pk limit 1) order by pk", true, + "(SELECT * FROM `b` WHERE `pk`=0 UNION ALL (SELECT * FROM `b` WHERE `pk`!=0) ORDER BY `pk` LIMIT 1) ORDER BY `pk`"}, } RunTest(t, table, false) }