schematracker: treat TableInfo as immutable (#39103)

ref pingcap/tidb#35933
This commit is contained in:
lance6716
2022-11-14 18:21:55 +08:00
committed by GitHub
parent d734cc8e8e
commit bdcb85031e
3 changed files with 156 additions and 51 deletions

View File

@ -49,6 +49,9 @@ var _ ddl.DDL = SchemaTracker{}
// SchemaTracker is used to track schema changes by DM. It implements DDL interface and by applying DDL, it updates the
// table structure to keep tracked with upstream changes.
// It embeds an InfoStore which stores DBInfo and TableInfo. The DBInfo and TableInfo can be treated as immutable, so
// after reading them by SchemaByName or TableByName, later modifications made by SchemaTracker will not change them.
// SchemaTracker is not thread-safe.
type SchemaTracker struct {
*InfoStore
}
@ -108,16 +111,22 @@ func (d SchemaTracker) CreateSchemaWithInfo(ctx sessionctx.Context, dbInfo *mode
}
// AlterSchema implements the DDL interface.
func (d SchemaTracker) AlterSchema(ctx sessionctx.Context, stmt *ast.AlterDatabaseStmt) error {
func (d SchemaTracker) AlterSchema(ctx sessionctx.Context, stmt *ast.AlterDatabaseStmt) (err error) {
dbInfo := d.SchemaByName(stmt.Name)
if dbInfo == nil {
return infoschema.ErrDatabaseNotExists.GenWithStackByArgs(stmt.Name.O)
}
dbInfo = dbInfo.Clone()
defer func() {
if err == nil {
d.PutSchema(dbInfo)
}
}()
// Resolve target charset and collation from options.
var (
toCharset, toCollate string
err error
)
for _, val := range stmt.Options {
@ -173,9 +182,15 @@ func (d SchemaTracker) CreateTable(ctx sessionctx.Context, s *ast.CreateTableStm
return infoschema.ErrDatabaseNotExists.GenWithStackByArgs(ident.Schema)
}
// suppress ErrTooLongKey
strictSQLModeBackup := ctx.GetSessionVars().StrictSQLMode
ctx.GetSessionVars().StrictSQLMode = false
// support drop PK
enableClusteredIndexBackup := ctx.GetSessionVars().EnableClusteredIndex
ctx.GetSessionVars().EnableClusteredIndex = variable.ClusteredIndexDefModeOff
defer func() {
ctx.GetSessionVars().StrictSQLMode = strictSQLModeBackup
ctx.GetSessionVars().EnableClusteredIndex = enableClusteredIndexBackup
}()
var (
referTbl *model.TableInfo
@ -354,6 +369,13 @@ func (d SchemaTracker) CreateIndex(ctx sessionctx.Context, stmt *ast.CreateIndex
stmt.IndexPartSpecifications, stmt.IndexOption, stmt.IfNotExists)
}
func (d SchemaTracker) putTableIfNoError(err error, dbName model.CIStr, tbInfo *model.TableInfo) {
if err != nil {
return
}
_ = d.PutTable(dbName, tbInfo)
}
// createIndex is shared by CreateIndex and AlterTable.
func (d SchemaTracker) createIndex(
ctx sessionctx.Context,
@ -363,12 +385,15 @@ func (d SchemaTracker) createIndex(
indexPartSpecifications []*ast.IndexPartSpecification,
indexOption *ast.IndexOption,
ifNotExists bool,
) error {
) (err error) {
unique := keyType == ast.IndexKeyTypeUnique
tblInfo, err := d.TableByName(ti.Schema, ti.Name)
tblInfo, err := d.TableClonedByName(ti.Schema, ti.Name)
if err != nil {
return err
}
defer d.putTableIfNoError(err, ti.Schema, tblInfo)
t := tables.MockTableFromMeta(tblInfo)
// Deal with anonymous index.
@ -432,12 +457,14 @@ func (d SchemaTracker) DropIndex(ctx sessionctx.Context, stmt *ast.DropIndexStmt
}
// dropIndex is shared by DropIndex and AlterTable.
func (d SchemaTracker) dropIndex(ctx sessionctx.Context, ti ast.Ident, indexName model.CIStr, ifExists bool) error {
tblInfo, err := d.TableByName(ti.Schema, ti.Name)
func (d SchemaTracker) dropIndex(ctx sessionctx.Context, ti ast.Ident, indexName model.CIStr, ifExists bool) (err error) {
tblInfo, err := d.TableClonedByName(ti.Schema, ti.Name)
if err != nil {
return infoschema.ErrTableNotExists.GenWithStackByArgs(ti.Schema, ti.Name)
}
defer d.putTableIfNoError(err, ti.Schema, tblInfo)
indexInfo := tblInfo.FindIndexByName(indexName.L)
if indexInfo == nil {
if ifExists {
@ -464,16 +491,19 @@ func (d SchemaTracker) dropIndex(ctx sessionctx.Context, ti ast.Ident, indexName
}
// addColumn is used by AlterTable.
func (d SchemaTracker) addColumn(ctx sessionctx.Context, ti ast.Ident, spec *ast.AlterTableSpec) error {
func (d SchemaTracker) addColumn(ctx sessionctx.Context, ti ast.Ident, spec *ast.AlterTableSpec) (err error) {
specNewColumn := spec.NewColumns[0]
schema := d.SchemaByName(ti.Schema)
if schema == nil {
return infoschema.ErrDatabaseNotExists.GenWithStackByArgs(ti.Schema)
}
tblInfo, err := d.TableByName(ti.Schema, ti.Name)
tblInfo, err := d.TableClonedByName(ti.Schema, ti.Name)
if err != nil {
return err
}
defer d.putTableIfNoError(err, ti.Schema, tblInfo)
t := tables.MockTableFromMeta(tblInfo)
colName := specNewColumn.Name.Name.O
@ -504,12 +534,14 @@ func (d SchemaTracker) addColumn(ctx sessionctx.Context, ti ast.Ident, spec *ast
}
// dropColumn is used by AlterTable.
func (d *SchemaTracker) dropColumn(ctx sessionctx.Context, ti ast.Ident, spec *ast.AlterTableSpec) error {
tblInfo, err := d.TableByName(ti.Schema, ti.Name)
func (d *SchemaTracker) dropColumn(ctx sessionctx.Context, ti ast.Ident, spec *ast.AlterTableSpec) (err error) {
tblInfo, err := d.TableClonedByName(ti.Schema, ti.Name)
if err != nil {
return err
}
defer d.putTableIfNoError(err, ti.Schema, tblInfo)
colName := spec.OldColumnName.Name
colInfo := tblInfo.FindPublicColumnByName(colName.L)
if colInfo == nil {
@ -546,14 +578,17 @@ func (d *SchemaTracker) dropColumn(ctx sessionctx.Context, ti ast.Ident, spec *a
}
// renameColumn is used by AlterTable.
func (d SchemaTracker) renameColumn(ctx sessionctx.Context, ident ast.Ident, spec *ast.AlterTableSpec) error {
func (d SchemaTracker) renameColumn(ctx sessionctx.Context, ident ast.Ident, spec *ast.AlterTableSpec) (err error) {
oldColName := spec.OldColumnName.Name
newColName := spec.NewColumnName.Name
tblInfo, err := d.TableByName(ident.Schema, ident.Name)
tblInfo, err := d.TableClonedByName(ident.Schema, ident.Name)
if err != nil {
return err
}
defer d.putTableIfNoError(err, ident.Schema, tblInfo)
tbl := tables.MockTableFromMeta(tblInfo)
oldCol := table.FindCol(tbl.VisibleCols(), oldColName.L)
@ -595,12 +630,15 @@ func (d SchemaTracker) renameColumn(ctx sessionctx.Context, ident ast.Ident, spe
}
// alterColumn is used by AlterTable.
func (d SchemaTracker) alterColumn(ctx sessionctx.Context, ident ast.Ident, spec *ast.AlterTableSpec) error {
func (d SchemaTracker) alterColumn(ctx sessionctx.Context, ident ast.Ident, spec *ast.AlterTableSpec) (err error) {
specNewColumn := spec.NewColumns[0]
tblInfo, err := d.TableByName(ident.Schema, ident.Name)
tblInfo, err := d.TableClonedByName(ident.Schema, ident.Name)
if err != nil {
return err
}
defer d.putTableIfNoError(err, ident.Schema, tblInfo)
t := tables.MockTableFromMeta(tblInfo)
colName := specNewColumn.Name.Name
@ -664,11 +702,14 @@ func (d SchemaTracker) handleModifyColumn(
ident ast.Ident,
originalColName model.CIStr,
spec *ast.AlterTableSpec,
) error {
tblInfo, err := d.TableByName(ident.Schema, ident.Name)
) (err error) {
tblInfo, err := d.TableClonedByName(ident.Schema, ident.Name)
if err != nil {
return err
}
defer d.putTableIfNoError(err, ident.Schema, tblInfo)
schema := d.SchemaByName(ident.Schema)
t := tables.MockTableFromMeta(tblInfo)
job, err := ddl.GetModifiableColumnJob(ctx, sctx, nil, ident, originalColName, schema, t, spec)
@ -714,11 +755,14 @@ func (d SchemaTracker) handleModifyColumn(
}
// renameIndex is used by AlterTable.
func (d SchemaTracker) renameIndex(ctx sessionctx.Context, ident ast.Ident, spec *ast.AlterTableSpec) error {
tblInfo, err := d.TableByName(ident.Schema, ident.Name)
func (d SchemaTracker) renameIndex(ctx sessionctx.Context, ident ast.Ident, spec *ast.AlterTableSpec) (err error) {
tblInfo, err := d.TableClonedByName(ident.Schema, ident.Name)
if err != nil {
return err
}
defer d.putTableIfNoError(err, ident.Schema, tblInfo)
duplicate, err := ddl.ValidateRenameIndex(spec.FromKey, spec.ToKey, tblInfo)
if duplicate {
return nil
@ -732,12 +776,14 @@ func (d SchemaTracker) renameIndex(ctx sessionctx.Context, ident ast.Ident, spec
}
// addTablePartitions is used by AlterTable.
func (d SchemaTracker) addTablePartitions(ctx sessionctx.Context, ident ast.Ident, spec *ast.AlterTableSpec) error {
tblInfo, err := d.TableByName(ident.Schema, ident.Name)
func (d SchemaTracker) addTablePartitions(ctx sessionctx.Context, ident ast.Ident, spec *ast.AlterTableSpec) (err error) {
tblInfo, err := d.TableClonedByName(ident.Schema, ident.Name)
if err != nil {
return errors.Trace(err)
}
defer d.putTableIfNoError(err, ident.Schema, tblInfo)
pi := tblInfo.GetPartitionInfo()
if pi == nil {
return errors.Trace(dbterror.ErrPartitionMgmtOnNonpartitioned)
@ -752,12 +798,14 @@ func (d SchemaTracker) addTablePartitions(ctx sessionctx.Context, ident ast.Iden
}
// dropTablePartitions is used by AlterTable.
func (d SchemaTracker) dropTablePartition(ctx sessionctx.Context, ident ast.Ident, spec *ast.AlterTableSpec) error {
tblInfo, err := d.TableByName(ident.Schema, ident.Name)
func (d SchemaTracker) dropTablePartitions(ctx sessionctx.Context, ident ast.Ident, spec *ast.AlterTableSpec) (err error) {
tblInfo, err := d.TableClonedByName(ident.Schema, ident.Name)
if err != nil {
return errors.Trace(err)
}
defer d.putTableIfNoError(err, ident.Schema, tblInfo)
pi := tblInfo.GetPartitionInfo()
if pi == nil {
return errors.Trace(dbterror.ErrPartitionMgmtOnNonpartitioned)
@ -799,12 +847,14 @@ func (d SchemaTracker) createPrimaryKey(
indexName model.CIStr,
indexPartSpecifications []*ast.IndexPartSpecification,
indexOption *ast.IndexOption,
) error {
tblInfo, err := d.TableByName(ti.Schema, ti.Name)
) (err error) {
tblInfo, err := d.TableClonedByName(ti.Schema, ti.Name)
if err != nil {
return errors.Trace(err)
}
defer d.putTableIfNoError(err, ti.Schema, tblInfo)
indexName = model.NewCIStr(mysql.PrimaryKeyName)
if indexInfo := tblInfo.FindIndexByName(indexName.L); indexInfo != nil ||
// If the table's PKIsHandle is true, it also means that this table has a primary key.
@ -888,7 +938,7 @@ func (d SchemaTracker) AlterTable(ctx context.Context, sctx sessionctx.Context,
case ast.AlterTableRenameIndex:
err = d.renameIndex(sctx, ident, spec)
case ast.AlterTableDropPartition:
err = d.dropTablePartition(sctx, ident, spec)
err = d.dropTablePartitions(sctx, ident, spec)
case ast.AlterTableAddConstraint:
constr := spec.Constraint
switch spec.Constraint.Tp {
@ -925,7 +975,9 @@ func (d SchemaTracker) AlterTable(ctx context.Context, sctx sessionctx.Context,
case ast.TableOptionAutoIdCache:
case ast.TableOptionAutoRandomBase:
case ast.TableOptionComment:
tblInfo = tblInfo.Clone()
tblInfo.Comment = opt.StrValue
_ = d.PutTable(ident.Schema, tblInfo)
case ast.TableOptionCharset, ast.TableOptionCollate:
// getCharsetAndCollateInTableOption will get the last charset and collate in the options,
// so it should be handled only once.
@ -939,6 +991,7 @@ func (d SchemaTracker) AlterTable(ctx context.Context, sctx sessionctx.Context,
}
needsOverwriteCols := ddl.NeedToOverwriteColCharset(spec.Options)
tblInfo = tblInfo.Clone()
if toCharset != "" {
tblInfo.Charset = toCharset
}
@ -957,6 +1010,7 @@ func (d SchemaTracker) AlterTable(ctx context.Context, sctx sessionctx.Context,
}
}
}
_ = d.PutTable(ident.Schema, tblInfo)
handledCharsetOrCollate = true
case ast.TableOptionPlacementPolicy:
@ -970,11 +1024,13 @@ func (d SchemaTracker) AlterTable(ctx context.Context, sctx sessionctx.Context,
}
}
case ast.AlterTableIndexInvisible:
tblInfo = tblInfo.Clone()
idx := tblInfo.FindIndexByName(spec.IndexName.L)
if idx == nil {
return errors.Trace(infoschema.ErrKeyNotExists.GenWithStackByArgs(spec.IndexName.O, ident.Name))
}
idx.Invisible = spec.Visibility == ast.IndexVisibilityInvisible
_ = d.PutTable(ident.Schema, tblInfo)
case ast.AlterTablePartitionOptions,
ast.AlterTableDropForeignKey,
ast.AlterTableCoalescePartitions,

View File

@ -98,6 +98,12 @@ func execAlter(t *testing.T, tracker schematracker.SchemaTracker, sql string) {
require.NoError(t, err)
}
func mustTableByName(t *testing.T, tracker schematracker.SchemaTracker, schema, table string) *model.TableInfo {
tblInfo, err := tracker.TableByName(model.NewCIStr(schema), model.NewCIStr(table))
require.NoError(t, err)
return tblInfo
}
func TestAlterPK(t *testing.T) {
sql := "create table test.t (c1 int primary key, c2 blob);"
@ -105,20 +111,24 @@ func TestAlterPK(t *testing.T) {
tracker.CreateTestDB()
execCreate(t, tracker, sql)
tblInfo, err := tracker.TableByName(model.NewCIStr("test"), model.NewCIStr("t"))
require.NoError(t, err)
tblInfo := mustTableByName(t, tracker, "test", "t")
require.Equal(t, 1, len(tblInfo.Indices))
sql = "alter table test.t drop primary key;"
execAlter(t, tracker, sql)
// TableInfo should be immutable.
require.Equal(t, 1, len(tblInfo.Indices))
tblInfo = mustTableByName(t, tracker, "test", "t")
require.Equal(t, 0, len(tblInfo.Indices))
sql = "alter table test.t add primary key(c1);"
execAlter(t, tracker, sql)
tblInfo = mustTableByName(t, tracker, "test", "t")
require.Equal(t, 1, len(tblInfo.Indices))
sql = "alter table test.t drop primary key;"
execAlter(t, tracker, sql)
tblInfo = mustTableByName(t, tracker, "test", "t")
require.Equal(t, 0, len(tblInfo.Indices))
}
@ -129,20 +139,22 @@ func TestDropColumn(t *testing.T) {
tracker.CreateTestDB()
execCreate(t, tracker, sql)
tblInfo, err := tracker.TableByName(model.NewCIStr("test"), model.NewCIStr("t"))
require.NoError(t, err)
tblInfo := mustTableByName(t, tracker, "test", "t")
require.Equal(t, 1, len(tblInfo.Indices))
sql = "alter table test.t drop column b"
execAlter(t, tracker, sql)
tblInfo = mustTableByName(t, tracker, "test", "t")
require.Equal(t, 0, len(tblInfo.Indices))
sql = "alter table test.t add index idx_2_col(a, c)"
execAlter(t, tracker, sql)
tblInfo = mustTableByName(t, tracker, "test", "t")
require.Equal(t, 1, len(tblInfo.Indices))
sql = "alter table test.t drop column c"
execAlter(t, tracker, sql)
tblInfo = mustTableByName(t, tracker, "test", "t")
require.Equal(t, 1, len(tblInfo.Indices))
require.Equal(t, 1, len(tblInfo.Columns))
}
@ -172,8 +184,7 @@ func TestIndexLength(t *testing.T) {
tracker.CreateTestDB()
execCreate(t, tracker, sql)
tblInfo, err := tracker.TableByName(model.NewCIStr("test"), model.NewCIStr("t"))
require.NoError(t, err)
tblInfo := mustTableByName(t, tracker, "test", "t")
expected := "CREATE TABLE `t` (\n" +
" `a` text DEFAULT NULL,\n" +
@ -185,7 +196,7 @@ func TestIndexLength(t *testing.T) {
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin"
checkShowCreateTable(t, tblInfo, expected)
err = tracker.DeleteTable(model.NewCIStr("test"), model.NewCIStr("t"))
err := tracker.DeleteTable(model.NewCIStr("test"), model.NewCIStr("t"))
require.NoError(t, err)
sql = "create table test.t(a text, b text charset ascii, c blob);"
@ -198,9 +209,7 @@ func TestIndexLength(t *testing.T) {
sql = "alter table test.t add index (c(3072))"
execAlter(t, tracker, sql)
tblInfo, err = tracker.TableByName(model.NewCIStr("test"), model.NewCIStr("t"))
require.NoError(t, err)
tblInfo = mustTableByName(t, tracker, "test", "t")
checkShowCreateTable(t, tblInfo, expected)
}
@ -225,8 +234,7 @@ func TestIssue5092(t *testing.T) {
sql = "alter table test.t add column b2 int after b1, add column c2 int first"
execAlter(t, tracker, sql)
tblInfo, err := tracker.TableByName(model.NewCIStr("test"), model.NewCIStr("t"))
require.NoError(t, err)
tblInfo := mustTableByName(t, tracker, "test", "t")
expected := "CREATE TABLE `t` (\n" +
" `c2` int(11) DEFAULT NULL,\n" +
@ -303,8 +311,7 @@ func TestAddExpressionIndex(t *testing.T) {
sql = "alter table test.t add index idx_multi((a+b),(a+1), b);"
execAlter(t, tracker, sql)
tblInfo, err := tracker.TableByName(model.NewCIStr("test"), model.NewCIStr("t"))
require.NoError(t, err)
tblInfo := mustTableByName(t, tracker, "test", "t")
expected := "CREATE TABLE `t` (\n" +
" `a` int(11) DEFAULT NULL,\n" +
@ -319,6 +326,8 @@ func TestAddExpressionIndex(t *testing.T) {
sql = "alter table test.t drop index idx_multi;"
execAlter(t, tracker, sql)
tblInfo = mustTableByName(t, tracker, "test", "t")
expected = "CREATE TABLE `t` (\n" +
" `a` int(11) DEFAULT NULL,\n" +
" `b` double DEFAULT NULL\n" +
@ -330,8 +339,7 @@ func TestAddExpressionIndex(t *testing.T) {
sql = "alter table test.t2 add unique index ei_ab ((concat(a, b)));"
execAlter(t, tracker, sql)
tblInfo, err = tracker.TableByName(model.NewCIStr("test"), model.NewCIStr("t2"))
require.NoError(t, err)
tblInfo = mustTableByName(t, tracker, "test", "t2")
expected = "CREATE TABLE `t2` (\n" +
" `a` varchar(10) DEFAULT NULL,\n" +
@ -343,6 +351,8 @@ func TestAddExpressionIndex(t *testing.T) {
sql = "alter table test.t2 alter index ei_ab invisible;"
execAlter(t, tracker, sql)
tblInfo = mustTableByName(t, tracker, "test", "t2")
expected = "CREATE TABLE `t2` (\n" +
" `a` varchar(10) DEFAULT NULL,\n" +
" `b` varchar(10) DEFAULT NULL,\n" +
@ -353,8 +363,7 @@ func TestAddExpressionIndex(t *testing.T) {
sql = "create table test.t3(a int, key((a+1)), key((a+2)), key idx((a+3)), key((a+4)), UNIQUE KEY ((a * 2)));"
execCreate(t, tracker, sql)
tblInfo, err = tracker.TableByName(model.NewCIStr("test"), model.NewCIStr("t3"))
require.NoError(t, err)
tblInfo = mustTableByName(t, tracker, "test", "t3")
expected = "CREATE TABLE `t3` (\n" +
" `a` int(11) DEFAULT NULL,\n" +
@ -381,8 +390,7 @@ func TestAddExpressionIndex(t *testing.T) {
sql = "alter table test.t4 add index idx((a+c));"
execAlter(t, tracker, sql)
tblInfo, err = tracker.TableByName(model.NewCIStr("test"), model.NewCIStr("t4"))
require.NoError(t, err)
tblInfo = mustTableByName(t, tracker, "test", "t4")
expected = "CREATE TABLE `t4` (\n" +
" `a` int(11) DEFAULT NULL,\n" +
@ -408,8 +416,7 @@ func TestAtomicMultiSchemaChange(t *testing.T) {
sql = "alter table test.t add b int, add c int;"
execAlter(t, tracker, sql)
tblInfo, err := tracker.TableByName(model.NewCIStr("test"), model.NewCIStr("t"))
require.NoError(t, err)
tblInfo := mustTableByName(t, tracker, "test", "t")
require.Len(t, tblInfo.Columns, 3)
sql = "alter table test.t add d int, add a int;"
@ -422,11 +429,45 @@ func TestAtomicMultiSchemaChange(t *testing.T) {
err = tracker.AlterTable(ctx, sctx, stmt.(*ast.AlterTableStmt))
require.True(t, infoschema.ErrColumnExists.Equal(err))
tblInfo, err = tracker.TableByName(model.NewCIStr("test"), model.NewCIStr("t"))
require.NoError(t, err)
tblInfo = mustTableByName(t, tracker, "test", "t")
require.Len(t, tblInfo.Columns, 3)
}
func TestImmutableTableInfo(t *testing.T) {
sql := "create table test.t (a varchar(20)) charset latin1;"
tracker := schematracker.NewSchemaTracker(2)
tracker.CreateTestDB()
execCreate(t, tracker, sql)
tblInfo := mustTableByName(t, tracker, "test", "t")
require.Equal(t, "", tblInfo.Comment)
sql = "alter table test.t comment = '123';"
execAlter(t, tracker, sql)
require.Equal(t, "", tblInfo.Comment)
tblInfo = mustTableByName(t, tracker, "test", "t")
require.Equal(t, "123", tblInfo.Comment)
require.Equal(t, "latin1", tblInfo.Charset)
require.Equal(t, "latin1_bin", tblInfo.Collate)
require.Equal(t, "latin1", tblInfo.Columns[0].GetCharset())
require.Equal(t, "latin1_bin", tblInfo.Columns[0].GetCollate())
sql = "alter table test.t convert to character set utf8mb4 collate utf8mb4_general_ci;"
execAlter(t, tracker, sql)
require.Equal(t, "latin1", tblInfo.Charset)
require.Equal(t, "latin1_bin", tblInfo.Collate)
require.Equal(t, "latin1", tblInfo.Columns[0].GetCharset())
require.Equal(t, "latin1_bin", tblInfo.Columns[0].GetCollate())
tblInfo = mustTableByName(t, tracker, "test", "t")
require.Equal(t, "utf8mb4", tblInfo.Charset)
require.Equal(t, "utf8mb4_general_ci", tblInfo.Collate)
require.Equal(t, "utf8mb4", tblInfo.Columns[0].GetCharset())
require.Equal(t, "utf8mb4_general_ci", tblInfo.Columns[0].GetCollate())
}
var _ sqlexec.RestrictedSQLExecutor = (*mockRestrictedSQLExecutor)(nil)
type mockRestrictedSQLExecutor struct {
@ -462,7 +503,6 @@ func TestModifyFromNullToNotNull(t *testing.T) {
err = tracker.AlterTable(ctx, executorCtx, stmt.(*ast.AlterTableStmt))
require.NoError(t, err)
tblInfo, err := tracker.TableByName(model.NewCIStr("test"), model.NewCIStr("t"))
require.NoError(t, err)
tblInfo := mustTableByName(t, tracker, "test", "t")
require.Len(t, tblInfo.Columns, 2)
}

View File

@ -88,6 +88,15 @@ func (i *InfoStore) TableByName(schema, table model.CIStr) (*model.TableInfo, er
return tbl, nil
}
// TableClonedByName is like TableByName, plus it will clone the TableInfo.
func (i *InfoStore) TableClonedByName(schema, table model.CIStr) (*model.TableInfo, error) {
tbl, err := i.TableByName(schema, table)
if err != nil {
return nil, err
}
return tbl.Clone(), nil
}
// PutTable puts a TableInfo, it will overwrite the old one. If the schema doesn't exist, it will return ErrDatabaseNotExists.
func (i *InfoStore) PutTable(schemaName model.CIStr, tblInfo *model.TableInfo) error {
schemaKey := i.ciStr2Key(schemaName)