Skip to content

Commit

Permalink
ddl: clear MDL related tables for create view (#53944)
Browse files Browse the repository at this point in the history
ref #53246
  • Loading branch information
D3Hunter authored Jun 12, 2024
1 parent 3fcf785 commit 7b8c91d
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 1 deletion.
1 change: 1 addition & 0 deletions pkg/ddl/job_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,7 @@ func (s *jobScheduler) startDispatch() error {
if err := s.checkAndUpdateClusterState(false); err != nil {
continue
}
failpoint.InjectCall("beforeAllLoadDDLJobAndRun")
s.loadDDLJobAndRun(se, s.generalDDLWorkerPool, s.getGeneralJob)
s.loadDDLJobAndRun(se, s.reorgWorkerPool, s.getReorgJob)
}
Expand Down
35 changes: 35 additions & 0 deletions pkg/ddl/job_table_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,3 +228,38 @@ func TestUpgradingRelatedJobState(t *testing.T) {
dom.DDL().StateSyncer().UpdateGlobalState(context.Background(), &syncer.StateInfo{State: syncer.StateNormalRunning})
}
}

func TestGeneralDDLWithQuery(t *testing.T) {
store, _ := testkit.CreateMockStoreAndDomain(t)

tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("CREATE TABLE t (id INT NOT NULL);")

var beforeRunCh = make(chan struct{})
testfailpoint.EnableCall(t, "github.com/pingcap/tidb/pkg/ddl/beforeAllLoadDDLJobAndRun", func() {
<-beforeRunCh
})
var ch = make(chan struct{})
testfailpoint.EnableCall(t, "github.com/pingcap/tidb/pkg/ddl/waitJobSubmitted", func() {
<-ch
})
// 2 general DDLs shouldn't be blocked by each other for MDL, i.e. the "create view xx from select xxx"
// should not fill the MDL related tables.
var wg util.WaitGroupWrapper
wg.Run(func() {
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("alter table t add column b int")
})
ch <- struct{}{}
wg.Run(func() {
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("create view v as select * from t")
})
ch <- struct{}{}
tk.MustQuery("select count(1) from mysql.tidb_ddl_job").Check(testkit.Rows("2"))
close(beforeRunCh)
wg.Wait()
}
1 change: 1 addition & 0 deletions pkg/executor/ddl.go
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,7 @@ func (e *DDLExec) executeCreateView(ctx context.Context, s *ast.CreateViewStmt)
return exeerrors.ErrViewInvalid.GenWithStackByArgs(s.ViewName.Schema.L, s.ViewName.Name.L)
}

e.Ctx().GetSessionVars().ClearRelatedTableForMDL()
return domain.GetDomain(e.Ctx()).DDL().CreateView(e.Ctx(), s)
}

Expand Down
6 changes: 5 additions & 1 deletion pkg/planner/core/preprocess.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,9 @@ const (
inPrepare preprocessorFlag = 1 << iota
// inTxnRetry is set when visiting in transaction retry.
inTxnRetry
// inCreateOrDropTable is set when visiting create/drop table statement.
// inCreateOrDropTable is set when visiting create/drop table/view/sequence,
// rename table, alter table add foreign key, and BR restore.
// TODO need a better name to clarify it's meaning
inCreateOrDropTable
// parentIsJoin is set when visiting node's parent is join.
parentIsJoin
Expand Down Expand Up @@ -927,6 +929,8 @@ func (p *preprocessor) checkCreateTableGrammar(stmt *ast.CreateTableStmt) {
}
if stmt.Select != nil {
// FIXME: a temp error noticing 'not implemented' (issue 4754)
// Note: if we implement it later, please clear it's MDL related tables for
// it like what CREATE VIEW does.
p.err = errors.New("'CREATE TABLE ... SELECT' is not implemented yet")
return
} else if len(stmt.Cols) == 0 && stmt.ReferTable == nil {
Expand Down
10 changes: 10 additions & 0 deletions pkg/sessionctx/variable/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -3636,6 +3636,16 @@ func (s *SessionVars) GetRelatedTableForMDL() *sync.Map {
return s.TxnCtx.relatedTableForMDL
}

// ClearRelatedTableForMDL clears the related table for MDL.
// related tables for MDL is filled during build logical plan or Preprocess for all DataSources,
// even for queries inside DDLs like `create view as select xxx` and `create table as select xxx`.
// it should be cleared before we execute the DDL statement.
func (s *SessionVars) ClearRelatedTableForMDL() {
s.TxnCtx.tdmLock.Lock()
defer s.TxnCtx.tdmLock.Unlock()
s.TxnCtx.relatedTableForMDL = nil
}

// EnableForceInlineCTE returns the session variable enableForceInlineCTE
func (s *SessionVars) EnableForceInlineCTE() bool {
return s.enableForceInlineCTE
Expand Down

0 comments on commit 7b8c91d

Please sign in to comment.