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: skip restoring schema name of CTE table columns (#33991) #34081

Merged
merged 5 commits into from
Jun 23, 2022
Merged
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
20 changes: 20 additions & 0 deletions executor/cte_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -440,3 +440,23 @@ func TestCTEExecError(t *testing.T) {
require.True(t, terror.ErrorEqual(err, types.ErrOverflow))
}
}

// https://github.com/pingcap/tidb/issues/33965.
func TestCTEsInView(t *testing.T) {
store, clean := testkit.CreateMockStore(t)
defer clean()
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test;")

tk.MustExec("create database if not exists test1;")
tk.MustExec("create table test.t (a int);")
tk.MustExec("create table test1.t (a int);")
tk.MustExec("insert into test.t values (1);")
tk.MustExec("insert into test1.t values (2);")

tk.MustExec("use test;")
tk.MustExec("create definer='root'@'localhost' view test.v as with tt as (select * from t) select * from tt;")
tk.MustQuery("select * from test.v;").Check(testkit.Rows("1"))
tk.MustExec("use test1;")
tk.MustQuery("select * from test.v;").Check(testkit.Rows("1"))
}
40 changes: 8 additions & 32 deletions parser/ast/dml.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@
package ast

import (
"strings"

"github.com/pingcap/errors"
"github.com/pingcap/tidb/parser/auth"
"github.com/pingcap/tidb/parser/format"
Expand Down Expand Up @@ -286,14 +284,7 @@ func (n *TableName) restoreName(ctx *format.RestoreCtx) {
ctx.WritePlain(".")
} else if ctx.DefaultDB != "" {
// Try CTE, for a CTE table name, we shouldn't write the database name.
ok := false
for _, name := range ctx.CTENames {
if strings.EqualFold(name, n.Name.String()) {
ok = true
break
}
}
if !ok {
if !ctx.IsCTETableName(n.Name.L) {
ctx.WriteName(ctx.DefaultDB)
ctx.WritePlain(".")
}
Expand Down Expand Up @@ -1119,7 +1110,7 @@ func (n *WithClause) Restore(ctx *format.RestoreCtx) error {
if n.IsRecursive {
// If the CTE is recursive, we should make it visible for the CTE's query.
// Otherwise, we should put it to stack after building the CTE's query.
ctx.CTENames = append(ctx.CTENames, cte.Name.L)
ctx.RecordCTEName(cte.Name.L)
}
if len(cte.ColNameList) > 0 {
ctx.WritePlain(" (")
Expand All @@ -1137,7 +1128,7 @@ func (n *WithClause) Restore(ctx *format.RestoreCtx) error {
return err
}
if !n.IsRecursive {
ctx.CTENames = append(ctx.CTENames, cte.Name.L)
ctx.RecordCTEName(cte.Name.L)
}
}
ctx.WritePlain(" ")
Expand All @@ -1163,10 +1154,7 @@ func (n *WithClause) Accept(v Visitor) (Node, bool) {
// Restore implements Node interface.
func (n *SelectStmt) Restore(ctx *format.RestoreCtx) error {
if n.WithBeforeBraces {
l := len(ctx.CTENames)
defer func() {
ctx.CTENames = ctx.CTENames[:l]
}()
defer ctx.RestoreCTEFunc()()
err := n.With.Restore(ctx)
if err != nil {
return err
Expand Down Expand Up @@ -1514,10 +1502,7 @@ type SetOprSelectList struct {
// Restore implements Node interface.
func (n *SetOprSelectList) Restore(ctx *format.RestoreCtx) error {
if n.With != nil {
l := len(ctx.CTENames)
defer func() {
ctx.CTENames = ctx.CTENames[:l]
}()
defer ctx.RestoreCTEFunc()()
if err := n.With.Restore(ctx); err != nil {
return errors.Annotate(err, "An error occurred while restore SetOprSelectList.With")
}
Expand Down Expand Up @@ -1618,10 +1603,7 @@ func (*SetOprStmt) resultSet() {}
// Restore implements Node interface.
func (n *SetOprStmt) Restore(ctx *format.RestoreCtx) error {
if n.With != nil {
l := len(ctx.CTENames)
defer func() {
ctx.CTENames = ctx.CTENames[:l]
}()
defer ctx.RestoreCTEFunc()()
if err := n.With.Restore(ctx); err != nil {
return errors.Annotate(err, "An error occurred while restore UnionStmt.With")
}
Expand Down Expand Up @@ -2203,10 +2185,7 @@ type DeleteStmt struct {
// Restore implements Node interface.
func (n *DeleteStmt) Restore(ctx *format.RestoreCtx) error {
if n.With != nil {
l := len(ctx.CTENames)
defer func() {
ctx.CTENames = ctx.CTENames[:l]
}()
defer ctx.RestoreCTEFunc()()
err := n.With.Restore(ctx)
if err != nil {
return err
Expand Down Expand Up @@ -2367,10 +2346,7 @@ type UpdateStmt struct {
// Restore implements Node interface.
func (n *UpdateStmt) Restore(ctx *format.RestoreCtx) error {
if n.With != nil {
l := len(ctx.CTENames)
defer func() {
ctx.CTENames = ctx.CTENames[:l]
}()
defer ctx.RestoreCTEFunc()()
err := n.With.Restore(ctx)
if err != nil {
return err
Expand Down
2 changes: 1 addition & 1 deletion parser/ast/expressions.go
Original file line number Diff line number Diff line change
Expand Up @@ -512,7 +512,7 @@ type ColumnName struct {

// Restore implements Node interface.
func (n *ColumnName) Restore(ctx *format.RestoreCtx) error {
if n.Schema.O != "" {
if n.Schema.O != "" && !ctx.IsCTETableName(n.Table.L) {
ctx.WriteName(n.Schema.O)
ctx.WritePlain(".")
}
Expand Down
34 changes: 32 additions & 2 deletions parser/format/format.go
Original file line number Diff line number Diff line change
Expand Up @@ -305,12 +305,12 @@ type RestoreCtx struct {
Flags RestoreFlags
In io.Writer
DefaultDB string
CTENames []string
CTERestorer
}

// NewRestoreCtx returns a new `RestoreCtx`.
func NewRestoreCtx(flags RestoreFlags, in io.Writer) *RestoreCtx {
return &RestoreCtx{flags, in, "", make([]string, 0)}
return &RestoreCtx{Flags: flags, In: in, DefaultDB: ""}
}

// WriteKeyWord writes the `keyWord` into writer.
Expand Down Expand Up @@ -387,3 +387,33 @@ func (ctx *RestoreCtx) WritePlain(plainText string) {
func (ctx *RestoreCtx) WritePlainf(format string, a ...interface{}) {
fmt.Fprintf(ctx.In, format, a...)
}

// CTERestorer is used by WithClause related nodes restore.
type CTERestorer struct {
CTENames []string
}

// IsCTETableName returns true if the given tableName comes from CTE.
func (c *CTERestorer) IsCTETableName(nameL string) bool {
for _, n := range c.CTENames {
if n == nameL {
return true
}
}
return false
}

func (c *CTERestorer) RecordCTEName(nameL string) {
c.CTENames = append(c.CTENames, nameL)
}

func (c *CTERestorer) RestoreCTEFunc() func() {
l := len(c.CTENames)
return func() {
if l == 0 {
c.CTENames = nil
} else {
c.CTENames = c.CTENames[:l]
}
}
}