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

*: Introduce TemporaryTableDDL to provide unified APIs for temporary table ddl operations #27776

Merged
merged 9 commits into from
Sep 6, 2021
Merged
2 changes: 1 addition & 1 deletion ddl/serial_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -658,7 +658,7 @@ func (s *testSerialSuite) TestCreateTableWithLikeAtTemporaryMode(c *C) {
") ENGINE=memory DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin"))
tk.MustExec("create temporary table if not exists tb12 like tb11;")
c.Assert(tk.Se.(sessionctx.Context).GetSessionVars().StmtCtx.GetWarnings()[0].Err.Error(), Equals,
infoschema.ErrTableExists.GenWithStackByArgs("tb12").Error())
infoschema.ErrTableExists.GenWithStackByArgs("test.tb12").Error())
defer tk.MustExec("drop table if exists tb11, tb12")
// Test from->local temporary, to->local temporary
tk.MustExec("drop table if exists tb13, tb14")
Expand Down
2 changes: 2 additions & 0 deletions executor/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import (
"github.com/pingcap/tidb/statistics"
"github.com/pingcap/tidb/table"
"github.com/pingcap/tidb/table/tables"
"github.com/pingcap/tidb/table/temptable"
"github.com/pingcap/tidb/types"
"github.com/pingcap/tidb/util"
"github.com/pingcap/tidb/util/admin"
Expand Down Expand Up @@ -950,6 +951,7 @@ func (b *executorBuilder) buildDDL(v *plannercore.DDL) Executor {
baseExecutor: newBaseExecutor(b.ctx, v.Schema(), v.ID()),
stmt: v.Statement,
is: b.is,
tempTableDDL: temptable.GetTemporaryTableDDL(b.ctx),
}
return e
}
Expand Down
173 changes: 21 additions & 152 deletions executor/ddl.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
package executor

import (
"bytes"
"context"
"fmt"
"strings"
Expand All @@ -29,20 +28,16 @@ import (
"github.com/pingcap/tidb/ddl"
"github.com/pingcap/tidb/domain"
"github.com/pingcap/tidb/infoschema"
"github.com/pingcap/tidb/kv"
"github.com/pingcap/tidb/meta"
"github.com/pingcap/tidb/meta/autoid"
"github.com/pingcap/tidb/planner/core"
"github.com/pingcap/tidb/sessionctx/variable"
"github.com/pingcap/tidb/table"
"github.com/pingcap/tidb/table/tables"
"github.com/pingcap/tidb/tablecodec"
"github.com/pingcap/tidb/table/temptable"
"github.com/pingcap/tidb/util/admin"
"github.com/pingcap/tidb/util/chunk"
"github.com/pingcap/tidb/util/gcutil"
"github.com/pingcap/tidb/util/logutil"
"github.com/pingcap/tidb/util/sqlexec"
"github.com/tikv/client-go/v2/tikv"
"go.uber.org/zap"
)

Expand All @@ -51,9 +46,10 @@ import (
type DDLExec struct {
baseExecutor

stmt ast.StmtNode
is infoschema.InfoSchema
done bool
stmt ast.StmtNode
is infoschema.InfoSchema
tempTableDDL temptable.TemporaryTableDDL
done bool
}

// toErr converts the error to the ErrInfoSchemaChanged when the schema is outdated.
Expand All @@ -73,47 +69,6 @@ func (e *DDLExec) toErr(err error) error {
return err
}

// deleteTemporaryTableRecords delete temporary table data.
func deleteTemporaryTableRecords(sessionData variable.TemporaryTableData, tblID int64) error {
if sessionData == nil {
return kv.ErrNotExist
}

tblPrefix := tablecodec.EncodeTablePrefix(tblID)
endKey := tablecodec.EncodeTablePrefix(tblID + 1)

iter, err := sessionData.Iter(tblPrefix, endKey)
if err != nil {
return err
}
for iter.Valid() {
key := iter.Key()
if !bytes.HasPrefix(key, tblPrefix) {
break
}

err = sessionData.DeleteTableKey(tblID, key)
if err != nil {
return err
}

err = iter.Next()
if err != nil {
return err
}
}

return nil
}

func (e *DDLExec) getLocalTemporaryTables() *infoschema.LocalTemporaryTables {
tempTables := e.ctx.GetSessionVars().LocalTemporaryTables
if tempTables != nil {
return tempTables.(*infoschema.LocalTemporaryTables)
}
return nil
}

func (e *DDLExec) getLocalTemporaryTable(schema model.CIStr, table model.CIStr) (table.Table, bool) {
tbl, err := e.ctx.GetInfoSchema().(infoschema.InfoSchema).TableByName(schema, table)
if infoschema.ErrTableNotExists.Equal(err) {
Expand Down Expand Up @@ -146,14 +101,9 @@ func (e *DDLExec) Next(ctx context.Context, req *chunk.Chunk) (err error) {
if s.IsView {
break
}
sessVars := e.ctx.GetSessionVars()
sessVarsTempTable := sessVars.LocalTemporaryTables
if sessVarsTempTable == nil {
break
}
localTemporaryTables := sessVarsTempTable.(*infoschema.LocalTemporaryTables)

for tbIdx := len(s.Tables) - 1; tbIdx >= 0; tbIdx-- {
if _, ok := localTemporaryTables.TableByName(s.Tables[tbIdx].Schema, s.Tables[tbIdx].Name); ok {
if _, ok := e.getLocalTemporaryTable(s.Tables[tbIdx].Schema, s.Tables[tbIdx].Name); ok {
localTempTablesToDrop = append(localTempTablesToDrop, s.Tables[tbIdx])
s.Tables = append(s.Tables[:tbIdx], s.Tables[tbIdx+1:]...)
}
Expand Down Expand Up @@ -261,39 +211,12 @@ func (e *DDLExec) Next(ctx context.Context, req *chunk.Chunk) (err error) {
func (e *DDLExec) executeTruncateTable(s *ast.TruncateTableStmt) error {
ident := ast.Ident{Schema: s.Table.Schema, Name: s.Table.Name}
if _, exist := e.getLocalTemporaryTable(s.Table.Schema, s.Table.Name); exist {
return e.executeTruncateLocalTemporaryTable(s)
return e.tempTableDDL.TruncateLocalTemporaryTable(s.Table.Schema, s.Table.Name)
}
err := domain.GetDomain(e.ctx).DDL().TruncateTable(e.ctx, ident)
return err
}

func (e *DDLExec) executeTruncateLocalTemporaryTable(s *ast.TruncateTableStmt) error {
tbl, exists := e.getLocalTemporaryTable(s.Table.Schema, s.Table.Name)
if !exists {
return infoschema.ErrTableNotExists.GenWithStackByArgs(s.Table.Schema, s.Table.Name)
}

tblInfo := tbl.Meta()

newTbl, err := e.newTemporaryTableFromTableInfo(tblInfo.Clone())
if err != nil {
return err
}

localTempTables := e.getLocalTemporaryTables()
localTempTables.RemoveTable(s.Table.Schema, s.Table.Name)
if err := localTempTables.AddTable(s.Table.Schema, newTbl); err != nil {
return err
}

err = deleteTemporaryTableRecords(e.ctx.GetSessionVars().TemporaryTableData, tblInfo.ID)
if err != nil {
return err
}

return nil
}

func (e *DDLExec) executeRenameTable(s *ast.RenameTableStmt) error {
isAlterTable := false
var err error
Expand Down Expand Up @@ -359,70 +282,23 @@ func (e *DDLExec) createSessionTemporaryTable(s *ast.CreateTableStmt) error {
if !ok {
return infoschema.ErrDatabaseNotExists.GenWithStackByArgs(s.Table.Schema.O)
}
tbInfo, err := ddl.BuildSessionTemporaryTableInfo(e.ctx, is, s, dbInfo.Charset, dbInfo.Collate)
if err != nil {
return err
}

tbl, err := e.newTemporaryTableFromTableInfo(tbInfo)
if err != nil {
return err
}

// Store this temporary table to the session.
sessVars := e.ctx.GetSessionVars()
if sessVars.LocalTemporaryTables == nil {
sessVars.LocalTemporaryTables = infoschema.NewLocalTemporaryTables()
}
localTempTables := sessVars.LocalTemporaryTables.(*infoschema.LocalTemporaryTables)

// Init MemBuffer in session
if sessVars.TemporaryTableData == nil {
// Create this txn just for getting a MemBuffer. It's a little tricky
bufferTxn, err := e.ctx.GetStore().BeginWithOption(tikv.DefaultStartTSOption().SetStartTS(0))
if err != nil {
return err
_, exists := e.getLocalTemporaryTable(s.Table.Schema, s.Table.Name)
if exists {
err := infoschema.ErrTableExists.GenWithStackByArgs(ast.Ident{Schema: s.Table.Schema, Name: s.Table.Name})
if s.IfNotExists {
e.ctx.GetSessionVars().StmtCtx.AppendNote(err)
return nil
}

sessVars.TemporaryTableData = variable.NewTemporaryTableData(bufferTxn.GetMemBuffer())
}

err = localTempTables.AddTable(dbInfo.Name, tbl)

if err != nil && s.IfNotExists && infoschema.ErrTableExists.Equal(err) {
e.ctx.GetSessionVars().StmtCtx.AppendNote(err)
return nil
return err
}

return err
}

func (e *DDLExec) newTemporaryTableFromTableInfo(tbInfo *model.TableInfo) (table.Table, error) {
dom := domain.GetDomain(e.ctx)
// Local temporary table uses a real table ID.
// We could mock a table ID, but the mocked ID might be identical to an existing
// real table, and then we'll get into trouble.
err := kv.RunInNewTxn(context.Background(), dom.Store(), true, func(ctx context.Context, txn kv.Transaction) error {
m := meta.NewMeta(txn)
tblID, err := m.GenGlobalID()
if err != nil {
return errors.Trace(err)
}
tbInfo.ID = tblID
tbInfo.State = model.StatePublic
return nil
})
tbInfo, err := ddl.BuildSessionTemporaryTableInfo(e.ctx, is, s, dbInfo.Charset, dbInfo.Collate)
if err != nil {
return nil, err
return err
}

// AutoID is allocated in mocked..
alloc := autoid.NewAllocatorFromTempTblInfo(tbInfo)
allocs := make([]autoid.Allocator, 0, 1)
if alloc != nil {
allocs = append(allocs, alloc)
}
return tables.TableFromMeta(allocs, tbInfo)
return e.tempTableDDL.CreateLocalTemporaryTable(dbInfo.Name, tbInfo)
}

func (e *DDLExec) executeCreateView(s *ast.CreateViewStmt) error {
Expand Down Expand Up @@ -602,21 +478,14 @@ func (e *DDLExec) dropLocalTemporaryTables(localTempTables []*ast.TableName) err
if len(localTempTables) == 0 {
return nil
}
sessVars := e.ctx.GetSessionVars()
sessVarsTempTable := sessVars.LocalTemporaryTables
if sessVarsTempTable == nil {
return nil
}
localTemporaryTables := sessVarsTempTable.(*infoschema.LocalTemporaryTables)
// if all tables are local temporary, directly drop those tables.

for _, tb := range localTempTables {
tableInfo, _ := localTemporaryTables.TableByName(tb.Schema, tb.Name)
localTemporaryTables.RemoveTable(tb.Schema, tb.Name)
err := deleteTemporaryTableRecords(sessVars.TemporaryTableData, tableInfo.Meta().ID)
err := e.tempTableDDL.DropLocalTemporaryTable(tb.Schema, tb.Name)
if err != nil {
return err
}
}

return nil
}

Expand Down
Loading