parsing AUTO_INCREMENT from alter query, reading AUTO_INCREMENT from original table, applying AUTO_INCREMENT value onto ghost table if applicable and user has not specified AUTO_INCREMENT in alter statement
This commit is contained in:
parent
2d0281f29b
commit
af20211629
@ -203,6 +203,7 @@ type MigrationContext struct {
|
|||||||
OriginalTableColumns *sql.ColumnList
|
OriginalTableColumns *sql.ColumnList
|
||||||
OriginalTableVirtualColumns *sql.ColumnList
|
OriginalTableVirtualColumns *sql.ColumnList
|
||||||
OriginalTableUniqueKeys [](*sql.UniqueKey)
|
OriginalTableUniqueKeys [](*sql.UniqueKey)
|
||||||
|
OriginalTableAutoIncrement uint64
|
||||||
GhostTableColumns *sql.ColumnList
|
GhostTableColumns *sql.ColumnList
|
||||||
GhostTableVirtualColumns *sql.ColumnList
|
GhostTableVirtualColumns *sql.ColumnList
|
||||||
GhostTableUniqueKeys [](*sql.UniqueKey)
|
GhostTableUniqueKeys [](*sql.UniqueKey)
|
||||||
|
@ -204,6 +204,25 @@ func (this *Applier) AlterGhost() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AlterGhost applies `alter` statement on ghost table
|
||||||
|
func (this *Applier) AlterGhostAutoIncrement() error {
|
||||||
|
query := fmt.Sprintf(`alter /* gh-ost */ table %s.%s AUTO_INCREMENT=%d`,
|
||||||
|
sql.EscapeName(this.migrationContext.DatabaseName),
|
||||||
|
sql.EscapeName(this.migrationContext.GetGhostTableName()),
|
||||||
|
this.migrationContext.OriginalTableAutoIncrement,
|
||||||
|
)
|
||||||
|
this.migrationContext.Log.Infof("Altering ghost table AUTO_INCREMENT value %s.%s",
|
||||||
|
sql.EscapeName(this.migrationContext.DatabaseName),
|
||||||
|
sql.EscapeName(this.migrationContext.GetGhostTableName()),
|
||||||
|
)
|
||||||
|
this.migrationContext.Log.Debugf("AUTO_INCREMENT ALTER statement: %s", query)
|
||||||
|
if _, err := sqlutils.ExecNoPrepare(this.db, query); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
this.migrationContext.Log.Infof("Ghost table AUTO_INCREMENT altered")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// CreateChangelogTable creates the changelog table on the applier host
|
// CreateChangelogTable creates the changelog table on the applier host
|
||||||
func (this *Applier) CreateChangelogTable() error {
|
func (this *Applier) CreateChangelogTable() error {
|
||||||
if err := this.DropChangelogTable(); err != nil {
|
if err := this.DropChangelogTable(); err != nil {
|
||||||
|
@ -109,6 +109,10 @@ func (this *Inspector) InspectOriginalTable() (err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
this.migrationContext.OriginalTableAutoIncrement, err = this.getAutoIncrementValue(this.migrationContext.OriginalTableName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -589,6 +593,24 @@ func (this *Inspector) applyColumnTypes(databaseName, tableName string, columnsL
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getAutoIncrementValue get's the original table's AUTO_INCREMENT value, if exists (0 value if not exists)
|
||||||
|
func (this *Inspector) getAutoIncrementValue(tableName string) (autoIncrement uint64, err error) {
|
||||||
|
query := `
|
||||||
|
SELECT
|
||||||
|
AUTO_INCREMENT
|
||||||
|
FROM INFORMATION_SCHEMA.TABLES
|
||||||
|
WHERE
|
||||||
|
TABLES.TABLE_SCHEMA = ?
|
||||||
|
AND TABLES.TABLE_NAME = ?
|
||||||
|
AND AUTO_INCREMENT IS NOT NULL
|
||||||
|
`
|
||||||
|
err = sqlutils.QueryRowsMap(this.db, query, func(m sqlutils.RowMap) error {
|
||||||
|
autoIncrement = m.GetUint64("AUTO_INCREMENT")
|
||||||
|
return nil
|
||||||
|
}, this.migrationContext.DatabaseName, tableName)
|
||||||
|
return autoIncrement, err
|
||||||
|
}
|
||||||
|
|
||||||
// getCandidateUniqueKeys investigates a table and returns the list of unique keys
|
// getCandidateUniqueKeys investigates a table and returns the list of unique keys
|
||||||
// candidate for chunking
|
// candidate for chunking
|
||||||
func (this *Inspector) getCandidateUniqueKeys(tableName string) (uniqueKeys [](*sql.UniqueKey), err error) {
|
func (this *Inspector) getCandidateUniqueKeys(tableName string) (uniqueKeys [](*sql.UniqueKey), err error) {
|
||||||
|
@ -1068,6 +1068,14 @@ func (this *Migrator) initiateApplier() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if this.migrationContext.OriginalTableAutoIncrement > 0 && !this.parser.IsAutoIncrementDefined() {
|
||||||
|
// Original table has AUTO_INCREMENT value and the -alter statement does not indicate any override,
|
||||||
|
// so we should copy AUTO_INCREMENT value onto our ghost table.
|
||||||
|
if err := this.applier.AlterGhostAutoIncrement(); err != nil {
|
||||||
|
this.migrationContext.Log.Errorf("Unable to ALTER ghost table AUTO_INCREMENT value, see further error details. Bailing out")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
this.applier.WriteChangelogState(string(GhostTableMigrated))
|
this.applier.WriteChangelogState(string(GhostTableMigrated))
|
||||||
go this.applier.InitiateHeartbeat()
|
go this.applier.InitiateHeartbeat()
|
||||||
return nil
|
return nil
|
||||||
|
@ -16,6 +16,7 @@ var (
|
|||||||
renameColumnRegexp = regexp.MustCompile(`(?i)\bchange\s+(column\s+|)([\S]+)\s+([\S]+)\s+`)
|
renameColumnRegexp = regexp.MustCompile(`(?i)\bchange\s+(column\s+|)([\S]+)\s+([\S]+)\s+`)
|
||||||
dropColumnRegexp = regexp.MustCompile(`(?i)\bdrop\s+(column\s+|)([\S]+)$`)
|
dropColumnRegexp = regexp.MustCompile(`(?i)\bdrop\s+(column\s+|)([\S]+)$`)
|
||||||
renameTableRegexp = regexp.MustCompile(`(?i)\brename\s+(to|as)\s+`)
|
renameTableRegexp = regexp.MustCompile(`(?i)\brename\s+(to|as)\s+`)
|
||||||
|
autoIncrementRegexp = regexp.MustCompile(`(?i)\bauto_increment[\s]*=[\s]*([0-9]+)`)
|
||||||
alterTableExplicitSchemaTableRegexps = []*regexp.Regexp{
|
alterTableExplicitSchemaTableRegexps = []*regexp.Regexp{
|
||||||
// ALTER TABLE `scm`.`tbl` something
|
// ALTER TABLE `scm`.`tbl` something
|
||||||
regexp.MustCompile(`(?i)\balter\s+table\s+` + "`" + `([^` + "`" + `]+)` + "`" + `[.]` + "`" + `([^` + "`" + `]+)` + "`" + `\s+(.*$)`),
|
regexp.MustCompile(`(?i)\balter\s+table\s+` + "`" + `([^` + "`" + `]+)` + "`" + `[.]` + "`" + `([^` + "`" + `]+)` + "`" + `\s+(.*$)`),
|
||||||
@ -35,9 +36,10 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type AlterTableParser struct {
|
type AlterTableParser struct {
|
||||||
columnRenameMap map[string]string
|
columnRenameMap map[string]string
|
||||||
droppedColumns map[string]bool
|
droppedColumns map[string]bool
|
||||||
isRenameTable bool
|
isRenameTable bool
|
||||||
|
isAutoIncrementDefined bool
|
||||||
|
|
||||||
alterStatementOptions string
|
alterStatementOptions string
|
||||||
alterTokens []string
|
alterTokens []string
|
||||||
@ -122,6 +124,12 @@ func (this *AlterTableParser) parseAlterToken(alterToken string) (err error) {
|
|||||||
this.isRenameTable = true
|
this.isRenameTable = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
// auto_increment
|
||||||
|
if autoIncrementRegexp.MatchString(alterToken) {
|
||||||
|
this.isAutoIncrementDefined = true
|
||||||
|
}
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,6 +181,11 @@ func (this *AlterTableParser) DroppedColumnsMap() map[string]bool {
|
|||||||
func (this *AlterTableParser) IsRenameTable() bool {
|
func (this *AlterTableParser) IsRenameTable() bool {
|
||||||
return this.isRenameTable
|
return this.isRenameTable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *AlterTableParser) IsAutoIncrementDefined() bool {
|
||||||
|
return this.isAutoIncrementDefined
|
||||||
|
}
|
||||||
|
|
||||||
func (this *AlterTableParser) GetExplicitSchema() string {
|
func (this *AlterTableParser) GetExplicitSchema() string {
|
||||||
return this.explicitSchema
|
return this.explicitSchema
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ func TestParseAlterStatement(t *testing.T) {
|
|||||||
test.S(t).ExpectNil(err)
|
test.S(t).ExpectNil(err)
|
||||||
test.S(t).ExpectEquals(parser.alterStatementOptions, statement)
|
test.S(t).ExpectEquals(parser.alterStatementOptions, statement)
|
||||||
test.S(t).ExpectFalse(parser.HasNonTrivialRenames())
|
test.S(t).ExpectFalse(parser.HasNonTrivialRenames())
|
||||||
|
test.S(t).ExpectFalse(parser.IsAutoIncrementDefined())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParseAlterStatementTrivialRename(t *testing.T) {
|
func TestParseAlterStatementTrivialRename(t *testing.T) {
|
||||||
@ -33,10 +34,31 @@ func TestParseAlterStatementTrivialRename(t *testing.T) {
|
|||||||
test.S(t).ExpectNil(err)
|
test.S(t).ExpectNil(err)
|
||||||
test.S(t).ExpectEquals(parser.alterStatementOptions, statement)
|
test.S(t).ExpectEquals(parser.alterStatementOptions, statement)
|
||||||
test.S(t).ExpectFalse(parser.HasNonTrivialRenames())
|
test.S(t).ExpectFalse(parser.HasNonTrivialRenames())
|
||||||
|
test.S(t).ExpectFalse(parser.IsAutoIncrementDefined())
|
||||||
test.S(t).ExpectEquals(len(parser.columnRenameMap), 1)
|
test.S(t).ExpectEquals(len(parser.columnRenameMap), 1)
|
||||||
test.S(t).ExpectEquals(parser.columnRenameMap["ts"], "ts")
|
test.S(t).ExpectEquals(parser.columnRenameMap["ts"], "ts")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestParseAlterStatementWithAutoIncrement(t *testing.T) {
|
||||||
|
|
||||||
|
statements := []string{
|
||||||
|
"auto_increment=7",
|
||||||
|
"auto_increment = 7",
|
||||||
|
"AUTO_INCREMENT = 71",
|
||||||
|
"add column t int, change ts ts timestamp, auto_increment=7 engine=innodb",
|
||||||
|
"add column t int, change ts ts timestamp, auto_increment =7 engine=innodb",
|
||||||
|
"add column t int, change ts ts timestamp, AUTO_INCREMENT = 7 engine=innodb",
|
||||||
|
"add column t int, change ts ts timestamp, engine=innodb auto_increment=73425",
|
||||||
|
}
|
||||||
|
for _, statement := range statements {
|
||||||
|
parser := NewAlterTableParser()
|
||||||
|
err := parser.ParseAlterStatement(statement)
|
||||||
|
test.S(t).ExpectNil(err)
|
||||||
|
test.S(t).ExpectEquals(parser.alterStatementOptions, statement)
|
||||||
|
test.S(t).ExpectTrue(parser.IsAutoIncrementDefined())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestParseAlterStatementTrivialRenames(t *testing.T) {
|
func TestParseAlterStatementTrivialRenames(t *testing.T) {
|
||||||
statement := "add column t int, change ts ts timestamp, CHANGE f `f` float, engine=innodb"
|
statement := "add column t int, change ts ts timestamp, CHANGE f `f` float, engine=innodb"
|
||||||
parser := NewAlterTableParser()
|
parser := NewAlterTableParser()
|
||||||
@ -44,6 +66,7 @@ func TestParseAlterStatementTrivialRenames(t *testing.T) {
|
|||||||
test.S(t).ExpectNil(err)
|
test.S(t).ExpectNil(err)
|
||||||
test.S(t).ExpectEquals(parser.alterStatementOptions, statement)
|
test.S(t).ExpectEquals(parser.alterStatementOptions, statement)
|
||||||
test.S(t).ExpectFalse(parser.HasNonTrivialRenames())
|
test.S(t).ExpectFalse(parser.HasNonTrivialRenames())
|
||||||
|
test.S(t).ExpectFalse(parser.IsAutoIncrementDefined())
|
||||||
test.S(t).ExpectEquals(len(parser.columnRenameMap), 2)
|
test.S(t).ExpectEquals(len(parser.columnRenameMap), 2)
|
||||||
test.S(t).ExpectEquals(parser.columnRenameMap["ts"], "ts")
|
test.S(t).ExpectEquals(parser.columnRenameMap["ts"], "ts")
|
||||||
test.S(t).ExpectEquals(parser.columnRenameMap["f"], "f")
|
test.S(t).ExpectEquals(parser.columnRenameMap["f"], "f")
|
||||||
@ -64,6 +87,7 @@ func TestParseAlterStatementNonTrivial(t *testing.T) {
|
|||||||
parser := NewAlterTableParser()
|
parser := NewAlterTableParser()
|
||||||
err := parser.ParseAlterStatement(statement)
|
err := parser.ParseAlterStatement(statement)
|
||||||
test.S(t).ExpectNil(err)
|
test.S(t).ExpectNil(err)
|
||||||
|
test.S(t).ExpectFalse(parser.IsAutoIncrementDefined())
|
||||||
test.S(t).ExpectEquals(parser.alterStatementOptions, statement)
|
test.S(t).ExpectEquals(parser.alterStatementOptions, statement)
|
||||||
renames := parser.GetNonTrivialRenames()
|
renames := parser.GetNonTrivialRenames()
|
||||||
test.S(t).ExpectEquals(len(renames), 2)
|
test.S(t).ExpectEquals(len(renames), 2)
|
||||||
|
Loading…
Reference in New Issue
Block a user