From 0f3776622df1e2d319a61560c23ef861c92a3da4 Mon Sep 17 00:00:00 2001 From: Ti Chi Robot Date: Thu, 16 May 2024 12:46:12 +0800 Subject: [PATCH] meta,ddl: fix duplicate entry error when insert after drop and recover table (#52761) (#53187) close pingcap/tidb#52680 --- pkg/ddl/db_integration_test.go | 62 ++++++++++++++++++++++++++++++++++ pkg/ddl/table.go | 2 +- pkg/meta/meta.go | 12 +++++-- pkg/meta/meta_test.go | 2 +- 4 files changed, 73 insertions(+), 5 deletions(-) diff --git a/pkg/ddl/db_integration_test.go b/pkg/ddl/db_integration_test.go index 9933063aa51d7..76ce362de0d41 100644 --- a/pkg/ddl/db_integration_test.go +++ b/pkg/ddl/db_integration_test.go @@ -29,6 +29,7 @@ import ( _ "github.com/pingcap/tidb/pkg/autoid_service" "github.com/pingcap/tidb/pkg/config" "github.com/pingcap/tidb/pkg/ddl/schematracker" + ddlutil "github.com/pingcap/tidb/pkg/ddl/util" "github.com/pingcap/tidb/pkg/ddl/util/callback" "github.com/pingcap/tidb/pkg/domain" "github.com/pingcap/tidb/pkg/errno" @@ -3020,3 +3021,64 @@ func TestOptimizeTable(t *testing.T) { tk := testkit.NewTestKit(t, store) tk.MustGetErrMsg("optimize table t", "[ddl:8200]OPTIMIZE TABLE is not supported") } + +func TestIssue52680(t *testing.T) { + store, dom := testkit.CreateMockStoreAndDomain(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec("use test;") + tk.MustExec("create table issue52680 (id bigint primary key auto_increment) auto_id_cache=1;") + tk.MustExec("insert into issue52680 values(default),(default);") + tk.MustQuery("select * from issue52680").Check(testkit.Rows("1", "2")) + + is := dom.InfoSchema() + ti, err := is.TableInfoByName(model.NewCIStr("test"), model.NewCIStr("issue52680")) + require.NoError(t, err) + + ddlutil.EmulatorGCDisable() + defer ddlutil.EmulatorGCEnable() + + // For mocktikv, safe point is not initialized, we manually insert it for snapshot to use. + safePointName := "tikv_gc_safe_point" + safePointValue := "20060102-15:04:05 -0700" + safePointComment := "All versions after safe point can be accessed. (DO NOT EDIT)" + updateSafePoint := fmt.Sprintf(`INSERT INTO mysql.tidb VALUES ('%[1]s', '%[2]s', '%[3]s') + ON DUPLICATE KEY + UPDATE variable_value = '%[2]s', comment = '%[3]s'`, safePointName, safePointValue, safePointComment) + tk.MustExec(updateSafePoint) + + testSteps := []struct { + sql string + expect meta.AutoIDGroup + }{ + {sql: "", expect: meta.AutoIDGroup{RowID: 0, IncrementID: 4000, RandomID: 0}}, + {sql: "drop table issue52680", expect: meta.AutoIDGroup{RowID: 0, IncrementID: 0, RandomID: 0}}, + {sql: "recover table issue52680", expect: meta.AutoIDGroup{RowID: 0, IncrementID: 4000, RandomID: 0}}, + } + for _, step := range testSteps { + if step.sql != "" { + tk.MustExec(step.sql) + } + + txn, err := store.Begin() + require.NoError(t, err) + m := meta.NewMeta(txn) + idAcc := m.GetAutoIDAccessors(ti.DBID, ti.ID) + ids, err := idAcc.Get() + require.NoError(t, err) + require.Equal(t, ids, step.expect) + txn.Rollback() + } + + tk.MustQuery("show table issue52680 next_row_id").Check(testkit.Rows( + "test issue52680 id 1 _TIDB_ROWID", + "test issue52680 id 3 AUTO_INCREMENT", + )) + + is = dom.InfoSchema() + ti1, err := is.TableInfoByName(model.NewCIStr("test"), model.NewCIStr("issue52680")) + require.NoError(t, err) + require.Equal(t, ti1.ID, ti.ID) + + tk.MustExec("insert into issue52680 values(default);") + tk.MustQuery("select * from issue52680").Check(testkit.Rows("1", "2", "3")) +} diff --git a/pkg/ddl/table.go b/pkg/ddl/table.go index f8184e634cd17..63523481509dd 100644 --- a/pkg/ddl/table.go +++ b/pkg/ddl/table.go @@ -560,7 +560,7 @@ func (w *worker) recoverTable(t *meta.Meta, job *model.Job, recoverInfo *Recover tableInfo := recoverInfo.TableInfo.Clone() tableInfo.State = model.StatePublic tableInfo.UpdateTS = t.StartTS - err = t.CreateTableAndSetAutoID(recoverInfo.SchemaID, recoverInfo.OldSchemaName, tableInfo, recoverInfo.AutoIDs.RowID, recoverInfo.AutoIDs.RandomID) + err = t.CreateTableAndSetAutoID(recoverInfo.SchemaID, recoverInfo.OldSchemaName, tableInfo, recoverInfo.AutoIDs) if err != nil { return ver, errors.Trace(err) } diff --git a/pkg/meta/meta.go b/pkg/meta/meta.go index 9d176d51f32d9..05adae04f982f 100644 --- a/pkg/meta/meta.go +++ b/pkg/meta/meta.go @@ -813,17 +813,23 @@ func (m *Meta) GetMetadataLock() (enable bool, isNull bool, err error) { // CreateTableAndSetAutoID creates a table with tableInfo in database, // and rebases the table autoID. -func (m *Meta) CreateTableAndSetAutoID(dbID int64, dbName string, tableInfo *model.TableInfo, autoIncID, autoRandID int64) error { +func (m *Meta) CreateTableAndSetAutoID(dbID int64, dbName string, tableInfo *model.TableInfo, autoIDs AutoIDGroup) error { err := m.CreateTableOrView(dbID, dbName, tableInfo) if err != nil { return errors.Trace(err) } - _, err = m.txn.HInc(m.dbKey(dbID), m.autoTableIDKey(tableInfo.ID), autoIncID) + _, err = m.txn.HInc(m.dbKey(dbID), m.autoTableIDKey(tableInfo.ID), autoIDs.RowID) if err != nil { return errors.Trace(err) } if tableInfo.AutoRandomBits > 0 { - _, err = m.txn.HInc(m.dbKey(dbID), m.autoRandomTableIDKey(tableInfo.ID), autoRandID) + _, err = m.txn.HInc(m.dbKey(dbID), m.autoRandomTableIDKey(tableInfo.ID), autoIDs.RandomID) + if err != nil { + return errors.Trace(err) + } + } + if tableInfo.SepAutoInc() && tableInfo.GetAutoIncrementColInfo() != nil { + _, err = m.txn.HInc(m.dbKey(dbID), m.autoIncrementIDKey(tableInfo.ID), autoIDs.IncrementID) if err != nil { return errors.Trace(err) } diff --git a/pkg/meta/meta_test.go b/pkg/meta/meta_test.go index 3d46085e685bc..31abb03fe7c66 100644 --- a/pkg/meta/meta_test.go +++ b/pkg/meta/meta_test.go @@ -360,7 +360,7 @@ func TestMeta(t *testing.T) { ID: 3, Name: model.NewCIStr("tbl3"), } - err = m.CreateTableAndSetAutoID(1, dbInfo.Name.L, tbInfo3, 123, 0) + err = m.CreateTableAndSetAutoID(1, dbInfo.Name.L, tbInfo3, meta.AutoIDGroup{RowID: 123, IncrementID: 0}) require.NoError(t, err) id, err := m.GetAutoIDAccessors(1, tbInfo3.ID).RowID().Get() require.NoError(t, err)