diff --git a/br/pkg/restore/db_test.go b/br/pkg/restore/db_test.go index 24abf08dc24b6..21a468a399a69 100644 --- a/br/pkg/restore/db_test.go +++ b/br/pkg/restore/db_test.go @@ -406,7 +406,7 @@ func TestGetExistedUserDBs(t *testing.T) { {Name: model.NewCIStr("d1")}, { Name: model.NewCIStr("test"), - Tables: []*model.TableInfo{{Name: model.NewCIStr("t1"), State: model.StatePublic}}, + Tables: []*model.TableInfo{{ID: 1, Name: model.NewCIStr("t1"), State: model.StatePublic}}, State: model.StatePublic, }, }, diff --git a/pkg/infoschema/builder.go b/pkg/infoschema/builder.go index 7fcf54ab59ebf..1b3644be5879f 100644 --- a/pkg/infoschema/builder.go +++ b/pkg/infoschema/builder.go @@ -35,6 +35,7 @@ import ( "github.com/pingcap/tidb/pkg/table" "github.com/pingcap/tidb/pkg/table/tables" "github.com/pingcap/tidb/pkg/util/domainutil" + "github.com/pingcap/tidb/pkg/util/intest" ) // Builder builds a new InfoSchema. @@ -970,9 +971,10 @@ func NewBuilder(r autoid.Requirement, factory func() (pools.Resource, error), in } func tableBucketIdx(tableID int64) int { + intest.Assert(tableID > 0) return int(tableID % bucketCount) } func tableIDIsValid(tableID int64) bool { - return tableID != 0 + return tableID > 0 } diff --git a/pkg/infoschema/infoschema.go b/pkg/infoschema/infoschema.go index 3aa845de721b3..352fb3051f8f5 100644 --- a/pkg/infoschema/infoschema.go +++ b/pkg/infoschema/infoschema.go @@ -104,7 +104,17 @@ func MockInfoSchema(tbList []*model.TableInfo) InfoSchema { tables: make(map[string]table.Table), } result.schemaMap["test"] = tableNames + var tableIDs map[int64]struct{} for _, tb := range tbList { + intest.AssertFunc(func() bool { + if tableIDs == nil { + tableIDs = make(map[int64]struct{}) + } + _, ok := tableIDs[tb.ID] + intest.Assert(!ok) + tableIDs[tb.ID] = struct{}{} + return true + }) tb.DBID = dbInfo.ID tbl := table.MockTableFromMeta(tb) tableNames.tables[tb.Name.L] = tbl @@ -238,6 +248,10 @@ func SchemaByTable(is InfoSchema, tableInfo *model.TableInfo) (val *model.DBInfo } func (is *infoSchema) TableByID(id int64) (val table.Table, ok bool) { + if !tableIDIsValid(id) { + return nil, false + } + slice := is.sortedTablesBuckets[tableBucketIdx(id)] idx := slice.searchTable(id) if idx == -1 { @@ -713,6 +727,10 @@ func (ts *SessionExtendedInfoSchema) FindTableInfoByPartitionID( // TableByID implements InfoSchema.TableByID func (ts *SessionExtendedInfoSchema) TableByID(id int64) (table.Table, bool) { + if !tableIDIsValid(id) { + return nil, false + } + if ts.LocalTemporaryTables != nil { if tbl, ok := ts.LocalTemporaryTables.TableByID(id); ok { return tbl, true diff --git a/pkg/infoschema/infoschema_test.go b/pkg/infoschema/infoschema_test.go index d697011d5ebd7..09d508b8e63b8 100644 --- a/pkg/infoschema/infoschema_test.go +++ b/pkg/infoschema/infoschema_test.go @@ -172,6 +172,14 @@ func TestBasic(t *testing.T) { require.False(t, ok) require.Nil(t, gotTblInfo) + tb, ok = is.TableByID(-12345) + require.False(t, ok) + require.Nil(t, tb) + + gotTblInfo, ok = is.TableInfoByID(-12345) + require.False(t, ok) + require.Nil(t, gotTblInfo) + tb, err = is.TableByName(dbName, tbName) require.NoError(t, err) require.NotNil(t, tb) @@ -187,6 +195,17 @@ func TestBasic(t *testing.T) { require.Error(t, err) require.Nil(t, gotTblInfo) + // negative id should always be seen as not exists + tb, ok = is.TableByID(-1) + require.False(t, ok) + require.Nil(t, tb) + schema, ok = is.SchemaByID(-1) + require.False(t, ok) + require.Nil(t, schema) + gotTblInfo, ok = is.TableInfoByID(-1) + require.Nil(t, gotTblInfo) + require.False(t, ok) + tbs := is.SchemaTables(dbName) require.Len(t, tbs, 1) @@ -855,6 +874,14 @@ func TestLocalTemporaryTables(t *testing.T) { info, ok = is.SchemaByID(tb22.Meta().DBID) require.False(t, ok) require.Nil(t, info) + + // negative id should always be seen as not exists + tbl, ok = is.TableByID(-1) + require.False(t, ok) + require.Nil(t, tbl) + info, ok = is.SchemaByID(-1) + require.False(t, ok) + require.Nil(t, info) } // TestInfoSchemaCreateTableLike tests the table's column ID and index ID for memory database. diff --git a/pkg/infoschema/infoschema_v2.go b/pkg/infoschema/infoschema_v2.go index 9e66f2eb1b609..859adfe83b6a0 100644 --- a/pkg/infoschema/infoschema_v2.go +++ b/pkg/infoschema/infoschema_v2.go @@ -278,6 +278,10 @@ func (is *infoschemaV2) base() *infoSchema { } func (is *infoschemaV2) TableByID(id int64) (val table.Table, ok bool) { + if !tableIDIsValid(id) { + return + } + // Get from the cache. key := tableCacheKey{id, is.infoSchema.schemaMetaVersion} tbl, found := is.tableCache.Get(key) diff --git a/pkg/infoschema/infoschema_v2_test.go b/pkg/infoschema/infoschema_v2_test.go index afd09afd8f43d..31a412ffcf748 100644 --- a/pkg/infoschema/infoschema_v2_test.go +++ b/pkg/infoschema/infoschema_v2_test.go @@ -81,6 +81,17 @@ func TestV2Basic(t *testing.T) { require.True(t, ok) require.Same(t, gotTblInfo, getTableInfo.Meta()) + // negative id should always be seen as not exists + getTableInfo, ok = is.TableByID(-1) + require.False(t, ok) + require.Nil(t, getTableInfo) + gotTblInfo, ok = is.TableInfoByID(-1) + require.False(t, ok) + require.Nil(t, gotTblInfo) + getDBInfo, ok = is.SchemaByID(-1) + require.False(t, ok) + require.Nil(t, getDBInfo) + gotTblInfo, ok = is.TableInfoByID(1234567) require.False(t, ok) require.Nil(t, gotTblInfo) diff --git a/pkg/planner/core/logical_plans_test.go b/pkg/planner/core/logical_plans_test.go index 6f39f13cef347..2511b5d8c30b7 100644 --- a/pkg/planner/core/logical_plans_test.go +++ b/pkg/planner/core/logical_plans_test.go @@ -83,7 +83,7 @@ func createPlannerSuite() (s *plannerSuite) { MockListPartitionTable(), MockStateNoneColumnTable(), } - id := int64(0) + id := int64(1) for _, tblInfo := range tblInfos { tblInfo.ID = id id += 1 diff --git a/pkg/planner/core/mock.go b/pkg/planner/core/mock.go index cbe24ce6b179a..8cc2b8d33853a 100644 --- a/pkg/planner/core/mock.go +++ b/pkg/planner/core/mock.go @@ -267,6 +267,7 @@ func MockSignedTable() *model.TableInfo { col5.SetFlag(mysql.NotNullFlag) col6.SetFlag(mysql.NoDefaultValueFlag) table := &model.TableInfo{ + ID: 1, Columns: []*model.ColumnInfo{pkColumn, col0, col1, col2, col3, colStr1, colStr2, colStr3, col4, col5, col6, col7}, Indices: indices, Name: model.NewCIStr("t"), @@ -336,6 +337,7 @@ func MockUnsignedTable() *model.TableInfo { col0.SetFlag(mysql.NotNullFlag) col1.SetFlag(mysql.UnsignedFlag) table := &model.TableInfo{ + ID: 2, Columns: []*model.ColumnInfo{pkColumn, col0, col1}, Indices: indices, Name: model.NewCIStr("t2"), @@ -365,6 +367,7 @@ func MockNoPKTable() *model.TableInfo { col0.SetFlag(mysql.NotNullFlag) col1.SetFlag(mysql.UnsignedFlag) table := &model.TableInfo{ + ID: 3, Columns: []*model.ColumnInfo{col0, col1}, Name: model.NewCIStr("t3"), PKIsHandle: true, @@ -395,6 +398,7 @@ func MockView() *model.TableInfo { } view := &model.ViewInfo{SelectStmt: selectStmt, Security: model.SecurityDefiner, Definer: &auth.UserIdentity{Username: "root", Hostname: ""}, Cols: []model.CIStr{col0.Name, col1.Name, col2.Name}} table := &model.TableInfo{ + ID: 4, Name: model.NewCIStr("v"), Columns: []*model.ColumnInfo{col0, col1, col2}, View: view, @@ -462,6 +466,7 @@ func MockRangePartitionTable() *model.TableInfo { }, } tableInfo := MockSignedTable() + tableInfo.ID = 5 tableInfo.Name = model.NewCIStr("pt1") cols := make([]*model.ColumnInfo, 0, len(tableInfo.Columns)) cols = append(cols, tableInfo.Columns...) @@ -497,6 +502,7 @@ func MockHashPartitionTable() *model.TableInfo { }, } tableInfo := MockSignedTable() + tableInfo.ID = 6 tableInfo.Name = model.NewCIStr("pt2") cols := make([]*model.ColumnInfo, 0, len(tableInfo.Columns)) cols = append(cols, tableInfo.Columns...) @@ -543,6 +549,7 @@ func MockListPartitionTable() *model.TableInfo { }, } tableInfo := MockSignedTable() + tableInfo.ID = 7 tableInfo.Name = model.NewCIStr("pt3") cols := make([]*model.ColumnInfo, 0, len(tableInfo.Columns)) cols = append(cols, tableInfo.Columns...) @@ -610,6 +617,7 @@ func MockStateNoneColumnTable() *model.TableInfo { col0.SetFlag(mysql.NotNullFlag) col1.SetFlag(mysql.UnsignedFlag) table := &model.TableInfo{ + ID: 8, Columns: []*model.ColumnInfo{pkColumn, col0, col1}, Indices: indices, Name: model.NewCIStr("T_StateNoneColumn"), diff --git a/pkg/ttl/ttlworker/job_manager_test.go b/pkg/ttl/ttlworker/job_manager_test.go index 4c9aa6c0dae06..61c74683602d9 100644 --- a/pkg/ttl/ttlworker/job_manager_test.go +++ b/pkg/ttl/ttlworker/job_manager_test.go @@ -260,8 +260,8 @@ func TestReadyForLockHBTimeoutJobTables(t *testing.T) { tables := m.readyForLockHBTimeoutJobTables(se.Now()) if c.shouldSchedule { assert.Len(t, tables, 1) - assert.Equal(t, int64(0), tables[0].ID) - assert.Equal(t, int64(0), tables[0].TableInfo.ID) + assert.Equal(t, tbl.ID, tables[0].ID) + assert.Equal(t, tbl.ID, tables[0].TableInfo.ID) } else { assert.Len(t, tables, 0) } diff --git a/pkg/ttl/ttlworker/session_test.go b/pkg/ttl/ttlworker/session_test.go index 9ba47f7bf4494..56c018005c6c0 100644 --- a/pkg/ttl/ttlworker/session_test.go +++ b/pkg/ttl/ttlworker/session_test.go @@ -18,6 +18,7 @@ import ( "context" "errors" "strings" + "sync/atomic" "testing" "time" @@ -36,8 +37,11 @@ import ( "github.com/stretchr/testify/require" ) +var idAllocator atomic.Int64 + func newMockTTLTbl(t *testing.T, name string) *cache.PhysicalTable { tblInfo := &model.TableInfo{ + ID: idAllocator.Add(1), Name: model.NewCIStr(name), Columns: []*model.ColumnInfo{ {