diff --git a/executor/executor_test.go b/executor/executor_test.go index 41b66b424ff56..793bc17b58853 100644 --- a/executor/executor_test.go +++ b/executor/executor_test.go @@ -947,8 +947,17 @@ func (s *testSuite) TestUnion(c *C) { tk.MustExec("create table t(a int)") tk.MustExec("insert into t value(0),(0)") tk.MustQuery("select 1 from (select a from t union all select a from t) tmp").Check(testkit.Rows("1", "1", "1", "1")) - tk.MustQuery("select 1 from (select a from t limit 1 union all select a from t limit 1) tmp").Check(testkit.Rows("1", "1")) tk.MustQuery("select count(1) from (select a from t union all select a from t) tmp").Check(testkit.Rows("4")) + + _, err := tk.Exec("select 1 from (select a from t limit 1 union all select a from t limit 1) tmp") + c.Assert(err, NotNil) + terr := errors.Trace(err).(*errors.Err).Cause().(*terror.Error) + c.Assert(terr.Code(), Equals, terror.ErrCode(mysql.ErrWrongUsage)) + + _, err = tk.Exec("select 1 from (select a from t order by a union all select a from t limit 1) tmp") + c.Assert(err, NotNil) + terr = errors.Trace(err).(*errors.Err).Cause().(*terror.Error) + c.Assert(terr.Code(), Equals, terror.ErrCode(mysql.ErrWrongUsage)) } func (s *testSuite) TestIn(c *C) { diff --git a/plan/errors.go b/plan/errors.go new file mode 100644 index 0000000000000..214c44046c0fa --- /dev/null +++ b/plan/errors.go @@ -0,0 +1,35 @@ +// Copyright 2018 PingCAP, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// See the License for the specific language governing permissions and +// limitations under the License. + +package plan + +import ( + "github.com/pingcap/tidb/mysql" + "github.com/pingcap/tidb/terror" +) + +var ( + // ErrWrongUsage is returned when SQL operators are not properly used. + ErrWrongUsage = terror.ClassParser.New(codeWrongUsage, mysql.MySQLErrName[mysql.ErrWrongUsage]) +) + +const ( + codeWrongUsage = terror.ErrCode(mysql.ErrWrongUsage) +) + +func init() { + typesMySQLErrCodes := map[terror.ErrCode]uint16{ + codeWrongUsage: mysql.ErrWrongUsage, + } + terror.ErrClassToMySQLCodes[terror.ClassParser] = typesMySQLErrCodes +} diff --git a/plan/preprocess.go b/plan/preprocess.go index e8d1444ab274a..25b6d9121cc48 100644 --- a/plan/preprocess.go +++ b/plan/preprocess.go @@ -69,6 +69,8 @@ func (p *preprocessor) Enter(in ast.Node) (out ast.Node, skipChildren bool) { p.checkDropDatabaseGrammar(node) case *ast.ShowStmt: p.resolveShowStmt(node) + case *ast.UnionSelectList: + p.checkUnionSelectList(node) case *ast.DeleteTableList: return in, true } @@ -206,6 +208,18 @@ func (p *preprocessor) checkAutoIncrement(stmt *ast.CreateTableStmt) { } } +func (p *preprocessor) checkUnionSelectList(stmt *ast.UnionSelectList) { + for idx, sel := range stmt.Selects { + if idx != len(stmt.Selects)-1 { + if sel.OrderBy != nil { + p.err = ErrWrongUsage.GenByArgs("UNION", "ORDER BY") + } else if sel.Limit != nil { + p.err = ErrWrongUsage.GenByArgs("UNION", "LIMIT") + } + } + } +} + func (p *preprocessor) checkCreateDatabaseGrammar(stmt *ast.CreateDatabaseStmt) { if isIncorrectName(stmt.Name) { p.err = ddl.ErrWrongDBName.GenByArgs(stmt.Name)