Skip to content

Commit

Permalink
planner: fix cannot binding for deleting multi table with alias (#57255
Browse files Browse the repository at this point in the history
…) (#57420)

close #56726
  • Loading branch information
ti-chi-bot authored Dec 11, 2024
1 parent 152012b commit cf2978a
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 1 deletion.
7 changes: 6 additions & 1 deletion pkg/parser/ast/dml.go
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,11 @@ type TableName struct {
TableSample *TableSample
// AS OF is used to see the data as it was at a specific point in time.
AsOf *AsOfClause
// IsAlias is true if this table name is an alias.
// sometime, we need to distinguish the table name is an alias or not.
// for example ```delete tt1 from t1 tt1,(select max(id) id from t2)tt2 where tt1.id<=tt2.id```
// ```tt1``` is a alias name. so we need to set IsAlias to true and restore the table name without database name.
IsAlias bool
}

func (*TableName) resultSet() {}
Expand All @@ -296,7 +301,7 @@ func (n *TableName) restoreName(ctx *format.RestoreCtx) {
if n.Schema.String() != "" {
ctx.WriteName(n.Schema.String())
ctx.WritePlain(".")
} else if ctx.DefaultDB != "" {
} else if ctx.DefaultDB != "" && !n.IsAlias {
// Try CTE, for a CTE table name, we shouldn't write the database name.
if !ctx.IsCTETableName(n.Name.L) {
ctx.WriteName(ctx.DefaultDB)
Expand Down
59 changes: 59 additions & 0 deletions pkg/planner/core/preprocess.go
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,9 @@ func (p *preprocessor) checkBindGrammar(originNode, hintedNode ast.StmtNode, def
tn.TableInfo = tableInfo
tn.DBInfo = dbInfo
}
aliasChecker := &aliasChecker{}
originNode.Accept(aliasChecker)
hintedNode.Accept(aliasChecker)

originSQL := parser.NormalizeForBinding(utilparser.RestoreWithDefaultDB(originNode, defaultDB, originNode.Text()))
hintedSQL := parser.NormalizeForBinding(utilparser.RestoreWithDefaultDB(hintedNode, defaultDB, hintedNode.Text()))
Expand Down Expand Up @@ -1928,3 +1931,59 @@ func (p *preprocessor) skipLockMDL() bool {
// skip lock mdl for ANALYZE statement.
return p.flag&inImportInto > 0 || p.flag&inAnalyze > 0
}

// aliasChecker is used to check the alias of the table in delete statement.
//
// for example: delete tt1 from t1 tt1,(select max(id) id from t2)tt2 where tt1.id<=tt2.id
// `delete tt1` will be transformed to `delete current_database.t1` by default.
// because `tt1` cannot be used as alias in delete statement.
// so we have to set `tt1` as alias by aliasChecker.
type aliasChecker struct{}

func (*aliasChecker) Enter(in ast.Node) (ast.Node, bool) {
if deleteStmt, ok := in.(*ast.DeleteStmt); ok {
// 1. check the tableRefs of deleteStmt to find the alias
var aliases []*model.CIStr
if deleteStmt.TableRefs != nil && deleteStmt.TableRefs.TableRefs != nil {
tableRefs := deleteStmt.TableRefs.TableRefs
if val := getTableRefsAlias(tableRefs.Left); val != nil {
aliases = append(aliases, val)
}
if val := getTableRefsAlias(tableRefs.Right); val != nil {
aliases = append(aliases, val)
}
}
// 2. check the Tables to tag the alias
if deleteStmt.Tables != nil && deleteStmt.Tables.Tables != nil {
for _, table := range deleteStmt.Tables.Tables {
if table.Schema.String() != "" {
continue
}
for _, alias := range aliases {
if table.Name.L == alias.L {
table.IsAlias = true
break
}
}
}
}
return in, true
}
return in, false
}

func getTableRefsAlias(tableRefs ast.ResultSetNode) *model.CIStr {
switch v := tableRefs.(type) {
case *ast.Join:
if v.Left != nil {
return getTableRefsAlias(v.Left)
}
case *ast.TableSource:
return &v.AsName
}
return nil
}

func (*aliasChecker) Leave(in ast.Node) (ast.Node, bool) {
return in, true
}
11 changes: 11 additions & 0 deletions pkg/planner/core/preprocess_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -408,3 +408,14 @@ func TestPreprocessCTE(t *testing.T) {
require.Equal(t, tc.after, rs.String())
}
}

func TestPreprocessDeleteFromWithAlias(t *testing.T) {
// https://github.com/pingcap/tidb/issues/56726
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("create table t1(id int);")
tk.MustExec(" create table t2(id int);")
tk.MustExec("delete tt1 from t1 tt1,(select max(id) id from t2)tt2 where tt1.id<=tt2.id;")
tk.MustExec("create global binding for delete tt1 from t1 tt1,(select max(id) id from t2)tt2 where tt1.id<=tt2.id using delete /*+ MAX_EXECUTION_TIME(10)*/ tt1 from t1 tt1,(select max(id) id from t2)tt2 where tt1.id<=tt2.id;")
}

0 comments on commit cf2978a

Please sign in to comment.