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

*: only create TemporaryTableAttachedInfoSchema if needed #37196

Merged
merged 11 commits into from
Aug 18, 2022
21 changes: 19 additions & 2 deletions ddl/db_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3801,8 +3801,15 @@ func TestCreateTempTableInTxn(t *testing.T) {
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("begin")
tk.MustExec("create temporary table t1(id int)")
tk.MustQuery("select * from t1")
// new created temporary table should be visible
tk.MustExec("create temporary table t1(id int primary key, v int)")
tk.MustQuery("select * from t1").Check(testkit.Rows())
// new inserted data should be visible
tk.MustExec("insert into t1 values(123, 456)")
tk.MustQuery("select * from t1 where id=123").Check(testkit.Rows("123 456"))
// truncate table will clear data but table still visible
tk.MustExec("truncate table t1")
tk.MustQuery("select * from t1 where id=123").Check(testkit.Rows())
tk.MustExec("commit")

tk1 := testkit.NewTestKit(t, store)
Expand All @@ -3812,6 +3819,16 @@ func TestCreateTempTableInTxn(t *testing.T) {
tk1.MustExec("create temporary table t1(id int)")
tk1.MustExec("insert into tt select * from t1")
tk1.MustExec("drop table tt")

tk2 := testkit.NewTestKit(t, store)
tk2.MustExec("use test")
tk2.MustExec("create table t2(id int primary key, v int)")
tk2.MustExec("insert into t2 values(234, 567)")
tk2.MustExec("begin")
// create a new temporary table with the same name will override physical table
tk2.MustExec("create temporary table t2(id int primary key, v int)")
tk2.MustQuery("select * from t2 where id=234").Check(testkit.Rows())
tk2.MustExec("commit")
}

// See https://github.com/pingcap/tidb/issues/29327
Expand Down
14 changes: 9 additions & 5 deletions domain/domain.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,15 @@ import (
"google.golang.org/grpc/keepalive"
)

// NewMockDomain is only used for test
func NewMockDomain() *Domain {
do := &Domain{
infoCache: infoschema.NewCache(1),
}
do.infoCache.Insert(infoschema.MockInfoSchema(nil), 1)
return do
}

// Domain represents a storage space. Different domains can use the same database name.
// Multiple domains can be used in parallel without synchronization.
type Domain struct {
Expand Down Expand Up @@ -332,11 +341,6 @@ func canSkipSchemaCheckerDDL(tp model.ActionType) bool {

// InfoSchema gets the latest information schema from domain.
func (do *Domain) InfoSchema() infoschema.InfoSchema {
if do.infoCache == nil {
// Return nil is for test purpose where domain is not well initialized in session context.
// In real implementation, the code will not reach here.
return nil
}
return do.infoCache.GetLatest()
}

Expand Down
7 changes: 6 additions & 1 deletion executor/ddl.go
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,12 @@ func (e *DDLExec) createSessionTemporaryTable(s *ast.CreateTableStmt) error {
return err
}

return e.tempTableDDL.CreateLocalTemporaryTable(dbInfo, tbInfo)
if err = e.tempTableDDL.CreateLocalTemporaryTable(dbInfo, tbInfo); err != nil {
return err
}

sessiontxn.GetTxnManager(e.ctx).OnLocalTemporaryTableCreated()
return nil
}

func (e *DDLExec) executeCreateView(s *ast.CreateViewStmt) error {
Expand Down
2 changes: 1 addition & 1 deletion planner/core/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,7 @@ func MockContext() sessionctx.Context {
Client: &mock.Client{},
}
ctx.GetSessionVars().CurrentDB = "test"
do := &domain.Domain{}
do := domain.NewMockDomain()
if err := do.CreateStatsHandle(ctx); err != nil {
panic(fmt.Sprintf("create mock context panic: %+v", err))
}
Expand Down
2 changes: 1 addition & 1 deletion session/schema_amender_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ func TestAmendCollectAndGenMutations(t *testing.T) {
sessionVars: variable.NewSessionVars(),
}
se.mu.values = make(map[fmt.Stringer]interface{})
domain.BindDomain(se, &domain.Domain{})
domain.BindDomain(se, domain.NewMockDomain())
startStates := []model.SchemaState{model.StateNone, model.StateDeleteOnly, model.StateWriteOnly, model.StateWriteReorganization}
for _, startState := range startStates {
endStatMap := ConstOpAddIndex[startState]
Expand Down
8 changes: 8 additions & 0 deletions session/txnmanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,14 @@ func (m *txnManager) OnStmtRetry(ctx context.Context) error {
return m.ctxProvider.OnStmtRetry(ctx)
}

// OnLocalTemporaryTableCreated is the hook that should be called when a temporary table created.
// The provider will update its state then
func (m *txnManager) OnLocalTemporaryTableCreated() {
if m.ctxProvider != nil {
m.ctxProvider.OnLocalTemporaryTableCreated()
}
}

func (m *txnManager) AdviseWarmup() error {
if m.ctxProvider != nil {
return m.ctxProvider.AdviseWarmup()
Expand Down
4 changes: 4 additions & 0 deletions sessiontxn/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ type TxnContextProvider interface {
OnStmtErrorForNextAction(point StmtErrorHandlePoint, err error) (StmtErrorAction, error)
// OnStmtRetry is the hook that should be called when a statement is retried internally.
OnStmtRetry(ctx context.Context) error
// OnLocalTemporaryTableCreated is the hook that should be called when a local temporary table created.
OnLocalTemporaryTableCreated()
// ActivateTxn activates the transaction.
ActivateTxn() (kv.Transaction, error)
}
Expand Down Expand Up @@ -177,6 +179,8 @@ type TxnManager interface {
OnStmtErrorForNextAction(point StmtErrorHandlePoint, err error) (StmtErrorAction, error)
// OnStmtRetry is the hook that should be called when a statement retry
OnStmtRetry(ctx context.Context) error
// OnLocalTemporaryTableCreated is the hook that should be called when a local temporary table created.
OnLocalTemporaryTableCreated()
// ActivateTxn activates the transaction.
ActivateTxn() (kv.Transaction, error)
// GetCurrentStmt returns the current statement node
Expand Down
6 changes: 6 additions & 0 deletions sessiontxn/isolation/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,12 @@ func (p *baseTxnContextProvider) OnStmtRetry(ctx context.Context) error {
return nil
}

// OnLocalTemporaryTableCreated is the hook that should be called when a local temporary table created.
func (p *baseTxnContextProvider) OnLocalTemporaryTableCreated() {
p.infoSchema = temptable.AttachLocalTemporaryTableInfoSchema(p.sctx, p.infoSchema)
p.sctx.GetSessionVars().TxnCtx.InfoSchema = p.infoSchema
}

// OnStmtErrorForNextAction is the hook that should be called when a new statement get an error
func (p *baseTxnContextProvider) OnStmtErrorForNextAction(point sessiontxn.StmtErrorHandlePoint, err error) (sessiontxn.StmtErrorAction, error) {
switch point {
Expand Down
3 changes: 3 additions & 0 deletions sessiontxn/staleread/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,3 +228,6 @@ func (p *StalenessTxnContextProvider) GetSnapshotWithStmtReadTS() (kv.Snapshot,
func (p *StalenessTxnContextProvider) GetSnapshotWithStmtForUpdateTS() (kv.Snapshot, error) {
return nil, errors.New("GetSnapshotWithStmtForUpdateTS not supported for stalenessTxnProvider")
}

// OnLocalTemporaryTableCreated will not be called for StalenessTxnContextProvider
func (p *StalenessTxnContextProvider) OnLocalTemporaryTableCreated() {}
2 changes: 1 addition & 1 deletion table/temptable/ddl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ func TestTruncateLocalTemporaryTable(t *testing.T) {
// truncate when empty
err := ddl.TruncateLocalTemporaryTable(model.NewCIStr("db1"), model.NewCIStr("t1"))
require.True(t, infoschema.ErrTableNotExists.Equal(err))
require.Equal(t, 0, sessVars.LocalTemporaryTables.(*infoschema.LocalTemporaryTables).Count())
require.Nil(t, sessVars.LocalTemporaryTables)
require.Nil(t, sessVars.TemporaryTableData)

// add one table
Expand Down
14 changes: 11 additions & 3 deletions table/temptable/infoschema.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,15 @@ import (

// AttachLocalTemporaryTableInfoSchema attach local temporary table information schema to is
func AttachLocalTemporaryTableInfoSchema(sctx sessionctx.Context, is infoschema.InfoSchema) infoschema.InfoSchema {
localTemporaryTables := getLocalTemporaryTables(sctx)
if localTemporaryTables == nil {
return is
}

if _, ok := is.(*infoschema.TemporaryTableAttachedInfoSchema); ok {
return is
}

localTemporaryTables := getLocalTemporaryTables(sctx)
return &infoschema.TemporaryTableAttachedInfoSchema{
InfoSchema: is,
LocalTemporaryTables: localTemporaryTables,
Expand All @@ -42,8 +46,12 @@ func DetachLocalTemporaryTableInfoSchema(is infoschema.InfoSchema) infoschema.In
}

func getLocalTemporaryTables(sctx sessionctx.Context) *infoschema.LocalTemporaryTables {
// Do not return nil so that new created tables can always be visited through the returned object.
return ensureLocalTemporaryTables(sctx)
localTemporaryTables := sctx.GetSessionVars().LocalTemporaryTables
if localTemporaryTables == nil {
return nil
}

return localTemporaryTables.(*infoschema.LocalTemporaryTables)
}

func ensureLocalTemporaryTables(sctx sessionctx.Context) *infoschema.LocalTemporaryTables {
Expand Down