diff --git a/ddl/error.go b/ddl/error.go index 1e3e7d5d09890..ca78800c33e4c 100644 --- a/ddl/error.go +++ b/ddl/error.go @@ -191,6 +191,8 @@ var ( ErrFunctionalIndexOnField = terror.ClassDDL.New(mysql.ErrFunctionalIndexOnField, mysql.MySQLErrName[mysql.ErrFunctionalIndexOnField]) // ErrInvalidAutoRandom returns when auto_random is used incorrectly. ErrInvalidAutoRandom = terror.ClassDDL.New(mysql.ErrInvalidAutoRandom, mysql.MySQLErrName[mysql.ErrInvalidAutoRandom]) + // ErrDerivedMustHaveAlias returns when a sub select statement does not have a table alias. + ErrDerivedMustHaveAlias = terror.ClassDDL.New(mysql.ErrDerivedMustHaveAlias, mysql.MySQLErrName[mysql.ErrDerivedMustHaveAlias]) // ErrSequenceRunOut returns when the sequence has been run out. ErrSequenceRunOut = terror.ClassDDL.New(mysql.ErrSequenceRunOut, mysql.MySQLErrName[mysql.ErrSequenceRunOut]) diff --git a/errors.toml b/errors.toml index 7a0611015e6ca..ae7aec9aa9cd5 100644 --- a/errors.toml +++ b/errors.toml @@ -121,6 +121,11 @@ error = ''' The used table type doesn't support FULLTEXT indexes ''' +["ddl:1248"] +error = ''' +Every derived table must have its own alias +''' + ["ddl:1253"] error = ''' COLLATION '%s' is not valid for CHARACTER SET '%s' diff --git a/executor/executor_test.go b/executor/executor_test.go index 87ad96db85c8f..ff1266c2fcf7b 100644 --- a/executor/executor_test.go +++ b/executor/executor_test.go @@ -3916,7 +3916,33 @@ func (s *testSuite3) TestDoSubquery(c *C) { c.Assert(r, IsNil, Commentf("result of Do not empty")) } -func (s *testSuite3) TestTSOFail(c *C) { +func (s *testSuite3) TestSubqueryTableAlias(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec(`use test`) + tk.MustExec(`drop table if exists t`) + + tk.MustExec("set sql_mode = ''") + tk.MustGetErrCode("select a, b from (select 1 a) ``, (select 2 b) ``;", mysql.ErrDerivedMustHaveAlias) + tk.MustGetErrCode("select a, b from (select 1 a) `x`, (select 2 b) `x`;", mysql.ErrNonuniqTable) + tk.MustGetErrCode("select a, b from (select 1 a), (select 2 b);", mysql.ErrDerivedMustHaveAlias) + // ambiguous column name + tk.MustGetErrCode("select a from (select 1 a) ``, (select 2 a) ``;", mysql.ErrDerivedMustHaveAlias) + tk.MustGetErrCode("select a from (select 1 a) `x`, (select 2 a) `x`;", mysql.ErrNonuniqTable) + tk.MustGetErrCode("select x.a from (select 1 a) `x`, (select 2 a) `x`;", mysql.ErrNonuniqTable) + tk.MustGetErrCode("select a from (select 1 a), (select 2 a);", mysql.ErrDerivedMustHaveAlias) + + tk.MustExec("set sql_mode = 'oracle';") + tk.MustQuery("select a, b from (select 1 a) ``, (select 2 b) ``;").Check(testkit.Rows("1 2")) + tk.MustQuery("select a, b from (select 1 a) `x`, (select 2 b) `x`;").Check(testkit.Rows("1 2")) + tk.MustQuery("select a, b from (select 1 a), (select 2 b);").Check(testkit.Rows("1 2")) + // ambiguous column name + tk.MustGetErrCode("select a from (select 1 a) ``, (select 2 a) ``;", mysql.ErrNonUniq) + tk.MustGetErrCode("select a from (select 1 a) `x`, (select 2 a) `x`;", mysql.ErrNonUniq) + tk.MustGetErrCode("select x.a from (select 1 a) `x`, (select 2 a) `x`;", mysql.ErrNonUniq) + tk.MustGetErrCode("select a from (select 1 a), (select 2 a);", mysql.ErrNonUniq) +} + +func (s *testSerialSuite1) TestTSOFail(c *C) { tk := testkit.NewTestKit(c, s.store) tk.MustExec(`use test`) tk.MustExec(`drop table if exists t`) diff --git a/planner/core/preprocess.go b/planner/core/preprocess.go index 6cb9905aa64f0..3f4bc1a3b8796 100644 --- a/planner/core/preprocess.go +++ b/planner/core/preprocess.go @@ -188,6 +188,11 @@ func (p *preprocessor) Enter(in ast.Node) (out ast.Node, skipChildren bool) { if node.Kind == ast.BRIEKindRestore { p.flag |= inCreateOrDropTable } + case *ast.TableSource: + isModeOracle := p.ctx.GetSessionVars().SQLMode&mysql.ModeOracle != 0 + if _, ok := node.Source.(*ast.SelectStmt); ok && !isModeOracle && len(node.AsName.L) == 0 { + p.err = ddl.ErrDerivedMustHaveAlias.GenWithStackByArgs() + } default: p.flag &= ^parentIsJoin } @@ -556,13 +561,16 @@ func (p *preprocessor) checkNonUniqTableAlias(stmt *ast.Join) { p.tableAliasInJoin = append(p.tableAliasInJoin, make(map[string]interface{})) } tableAliases := p.tableAliasInJoin[len(p.tableAliasInJoin)-1] - if err := isTableAliasDuplicate(stmt.Left, tableAliases); err != nil { - p.err = err - return - } - if err := isTableAliasDuplicate(stmt.Right, tableAliases); err != nil { - p.err = err - return + isOracleMode := p.ctx.GetSessionVars().SQLMode&mysql.ModeOracle != 0 + if !isOracleMode { + if err := isTableAliasDuplicate(stmt.Left, tableAliases); err != nil { + p.err = err + return + } + if err := isTableAliasDuplicate(stmt.Right, tableAliases); err != nil { + p.err = err + return + } } p.flag |= parentIsJoin }