From f7cea6c08acdfd01b533f5f0f6e7c2628032b794 Mon Sep 17 00:00:00 2001 From: tangenta Date: Tue, 28 May 2024 12:02:56 +0800 Subject: [PATCH] ddl: support create sequences with `BatchCreateTableWithInfo` (#53465) close pingcap/tidb#53374 --- .../restore/internal/prealloc_db/BUILD.bazel | 2 +- .../restore/internal/prealloc_db/db_test.go | 100 ++++++++++++++++++ pkg/ddl/ddl_api.go | 2 +- pkg/ddl/sequence.go | 43 ++++---- pkg/ddl/table.go | 18 +++- 5 files changed, 136 insertions(+), 29 deletions(-) diff --git a/br/pkg/restore/internal/prealloc_db/BUILD.bazel b/br/pkg/restore/internal/prealloc_db/BUILD.bazel index c7b209b70661e..c5205aea23179 100644 --- a/br/pkg/restore/internal/prealloc_db/BUILD.bazel +++ b/br/pkg/restore/internal/prealloc_db/BUILD.bazel @@ -27,7 +27,7 @@ go_test( timeout = "short", srcs = ["db_test.go"], flaky = True, - shard_count = 3, + shard_count = 4, deps = [ ":prealloc_db", "//br/pkg/gluetidb", diff --git a/br/pkg/restore/internal/prealloc_db/db_test.go b/br/pkg/restore/internal/prealloc_db/db_test.go index d45799862e3d9..7b2f11dd21ef7 100644 --- a/br/pkg/restore/internal/prealloc_db/db_test.go +++ b/br/pkg/restore/internal/prealloc_db/db_test.go @@ -161,3 +161,103 @@ func TestDB_ExecDDL(t *testing.T) { assert.NoError(t, err) } } + +func TestCreateTableConsistent(t *testing.T) { + ctx := context.Background() + s := utiltest.CreateRestoreSchemaSuite(t) + tk := testkit.NewTestKit(t, s.Mock.Storage) + tk.MustExec("use test") + tk.MustExec("set @@sql_mode=''") + + db, supportPolicy, err := preallocdb.NewDB(gluetidb.New(), s.Mock.Storage, "STRICT") + require.NoError(t, err) + require.True(t, supportPolicy) + defer db.Close() + + getTableInfo := func(name string) (*model.DBInfo, *model.TableInfo) { + info, err := s.Mock.Domain.GetSnapshotInfoSchema(math.MaxUint64) + require.NoError(t, err) + dbInfo, exists := info.SchemaByName(model.NewCIStr("test")) + require.True(t, exists) + tableInfo, err := info.TableByName(model.NewCIStr("test"), model.NewCIStr(name)) + require.NoError(t, err) + return dbInfo, tableInfo.Meta() + } + tk.MustExec("create sequence test.s increment by 1 minvalue = 10;") + dbInfo, seqInfo := getTableInfo("s") + tk.MustExec("drop sequence test.s;") + + newSeqInfo := seqInfo.Clone() + newSeqInfo.ID += 100 + newTables := []*metautil.Table{ + { + DB: dbInfo.Clone(), + Info: newSeqInfo, + }, + } + err = db.CreateTables(ctx, newTables, nil, false, nil) + require.NoError(t, err) + r11 := tk.MustQuery("select nextval(s)").Rows() + r12 := tk.MustQuery("show create table test.s").Rows() + + tk.MustExec("drop sequence test.s;") + + newSeqInfo = seqInfo.Clone() + newSeqInfo.ID += 100 + newTable := &metautil.Table{DB: dbInfo.Clone(), Info: newSeqInfo} + err = db.CreateTable(ctx, newTable, nil, false, nil) + require.NoError(t, err) + r21 := tk.MustQuery("select nextval(s)").Rows() + r22 := tk.MustQuery("show create table test.s").Rows() + + require.Equal(t, r11, r21) + require.Equal(t, r12, r22) + + tk.MustExec("drop sequence test.s;") + tk.MustExec("create table t (a int);") + tk.MustExec("create view v as select * from t;") + + _, tblInfo := getTableInfo("t") + _, viewInfo := getTableInfo("v") + tk.MustExec("drop table t;") + tk.MustExec("drop view v;") + + newTblInfo := tblInfo.Clone() + newTblInfo.ID += 100 + newViewInfo := viewInfo.Clone() + newViewInfo.ID += 100 + newTables = []*metautil.Table{ + { + DB: dbInfo.Clone(), + Info: newTblInfo, + }, + { + DB: dbInfo.Clone(), + Info: newViewInfo, + }, + } + err = db.CreateTables(ctx, newTables, nil, false, nil) + require.NoError(t, err) + r11 = tk.MustQuery("show create table t;").Rows() + r12 = tk.MustQuery("show create view v;").Rows() + + tk.MustExec("drop table t;") + tk.MustExec("drop view v;") + + newTblInfo = tblInfo.Clone() + newTblInfo.ID += 200 + newTable = &metautil.Table{DB: dbInfo.Clone(), Info: newTblInfo} + err = db.CreateTable(ctx, newTable, nil, false, nil) + require.NoError(t, err) + newViewInfo = viewInfo.Clone() + newViewInfo.ID += 200 + newTable = &metautil.Table{DB: dbInfo.Clone(), Info: newViewInfo} + err = db.CreateTable(ctx, newTable, nil, false, nil) + require.NoError(t, err) + + r21 = tk.MustQuery("show create table t;").Rows() + r22 = tk.MustQuery("show create view v;").Rows() + + require.Equal(t, r11, r21) + require.Equal(t, r12, r22) +} diff --git a/pkg/ddl/ddl_api.go b/pkg/ddl/ddl_api.go index 839c19487eaf9..f1dd371e31ec2 100644 --- a/pkg/ddl/ddl_api.go +++ b/pkg/ddl/ddl_api.go @@ -3007,7 +3007,7 @@ func (d *ddl) BatchCreateTableWithInfo(ctx sessionctx.Context, } } - return nil + return d.callHookOnChanged(jobs, err) } // BatchCreateTableWithJobs combine CreateTableJobs to BatchCreateTableJob. diff --git a/pkg/ddl/sequence.go b/pkg/ddl/sequence.go index efd0b698fada0..341cdd94e1552 100644 --- a/pkg/ddl/sequence.go +++ b/pkg/ddl/sequence.go @@ -45,41 +45,40 @@ func onCreateSequence(d *ddlCtx, t *meta.Meta, job *model.Job) (ver int64, _ err return ver, errors.Trace(err) } + err = createSequenceWithCheck(t, job, tbInfo) + if err != nil { + return ver, errors.Trace(err) + } + ver, err = updateSchemaVersion(d, t, job) if err != nil { return ver, errors.Trace(err) } + job.FinishTableJob(model.JobStateDone, model.StatePublic, ver, tbInfo) + return ver, nil +} +func createSequenceWithCheck(t *meta.Meta, job *model.Job, tbInfo *model.TableInfo) error { switch tbInfo.State { - case model.StateNone: + case model.StateNone, model.StatePublic: // none -> public tbInfo.State = model.StatePublic tbInfo.UpdateTS = t.StartTS - err = createSequenceWithCheck(t, job, schemaID, tbInfo) + err := checkTableInfoValid(tbInfo) if err != nil { - return ver, errors.Trace(err) + job.State = model.JobStateCancelled + return errors.Trace(err) + } + var sequenceBase int64 + if tbInfo.Sequence.Increment >= 0 { + sequenceBase = tbInfo.Sequence.Start - 1 + } else { + sequenceBase = tbInfo.Sequence.Start + 1 } - // Finish this job. - job.FinishTableJob(model.JobStateDone, model.StatePublic, ver, tbInfo) - return ver, nil + return t.CreateSequenceAndSetSeqValue(job.SchemaID, job.SchemaName, tbInfo, sequenceBase) default: - return ver, dbterror.ErrInvalidDDLState.GenWithStackByArgs("sequence", tbInfo.State) - } -} - -func createSequenceWithCheck(t *meta.Meta, job *model.Job, schemaID int64, tbInfo *model.TableInfo) error { - err := checkTableInfoValid(tbInfo) - if err != nil { - job.State = model.JobStateCancelled - return errors.Trace(err) - } - var sequenceBase int64 - if tbInfo.Sequence.Increment >= 0 { - sequenceBase = tbInfo.Sequence.Start - 1 - } else { - sequenceBase = tbInfo.Sequence.Start + 1 + return dbterror.ErrInvalidDDLState.GenWithStackByArgs("sequence", tbInfo.State) } - return t.CreateSequenceAndSetSeqValue(schemaID, job.SchemaName, tbInfo, sequenceBase) } func handleSequenceOptions(seqOptions []*ast.SequenceOption, sequenceInfo *model.SequenceInfo) { diff --git a/pkg/ddl/table.go b/pkg/ddl/table.go index f61775834ef3e..d750191359f8f 100644 --- a/pkg/ddl/table.go +++ b/pkg/ddl/table.go @@ -245,12 +245,20 @@ func onCreateTables(d *ddlCtx, t *meta.Meta, job *model.Job) (int64, error) { for i := range args { stubJob.TableID = args[i].ID stubJob.Args[0] = args[i] - tbInfo, err := createTable(d, t, stubJob, fkCheck) - if err != nil { - job.State = model.JobStateCancelled - return ver, errors.Trace(err) + if args[i].Sequence != nil { + err := createSequenceWithCheck(t, stubJob, args[i]) + if err != nil { + job.State = model.JobStateCancelled + return ver, errors.Trace(err) + } + } else { + tbInfo, err := createTable(d, t, stubJob, fkCheck) + if err != nil { + job.State = model.JobStateCancelled + return ver, errors.Trace(err) + } + args[i] = tbInfo } - args[i] = tbInfo } ver, err = updateSchemaVersion(d, t, job)