Skip to content

Commit 6c7b473

Browse files
committed
Support a complete ALTER TABLE statement in --alter
1 parent 4dab06e commit 6c7b473

File tree

4 files changed

+177
-37
lines changed

4 files changed

+177
-37
lines changed

go/cmd/gh-ost/main.go

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414

1515
"github.com/github/gh-ost/go/base"
1616
"github.com/github/gh-ost/go/logic"
17+
"github.com/github/gh-ost/go/sql"
1718
_ "github.com/go-sql-driver/mysql"
1819
"github.com/outbrain/golib/log"
1920

@@ -172,14 +173,24 @@ func main() {
172173
log.SetLevel(log.ERROR)
173174
}
174175

176+
if migrationContext.AlterStatement == "" {
177+
log.Fatalf("--alter must be provided and statement must not be empty")
178+
}
179+
parser := sql.NewParserFromAlterStatement(migrationContext.AlterStatement)
180+
175181
if migrationContext.DatabaseName == "" {
176-
log.Fatalf("--database must be provided and database name must not be empty")
182+
if parser.HasExplicitSchema() {
183+
migrationContext.DatabaseName = parser.GetExplicitSchema()
184+
} else {
185+
log.Fatalf("--database must be provided and database name must not be empty, or --alter must specify database name")
186+
}
177187
}
178188
if migrationContext.OriginalTableName == "" {
179-
log.Fatalf("--table must be provided and table name must not be empty")
180-
}
181-
if migrationContext.AlterStatement == "" {
182-
log.Fatalf("--alter must be provided and statement must not be empty")
189+
if parser.HasExplicitTable() {
190+
migrationContext.OriginalTableName = parser.GetExplicitTable()
191+
} else {
192+
log.Fatalf("--table must be provided and table name must not be empty, or --alter must specify table name")
193+
}
183194
}
184195
migrationContext.Noop = !(*executeFlag)
185196
if migrationContext.AllowedRunningOnMaster && migrationContext.TestOnReplica {

go/logic/migrator.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ const (
6262

6363
// Migrator is the main schema migration flow manager.
6464
type Migrator struct {
65-
parser *sql.Parser
65+
parser *sql.AlterTableParser
6666
inspector *Inspector
6767
applier *Applier
6868
eventsStreamer *EventsStreamer
@@ -90,7 +90,7 @@ type Migrator struct {
9090
func NewMigrator(context *base.MigrationContext) *Migrator {
9191
migrator := &Migrator{
9292
migrationContext: context,
93-
parser: sql.NewParser(),
93+
parser: sql.NewAlterTableParser(),
9494
ghostTableMigrated: make(chan bool),
9595
firstThrottlingCollected: make(chan bool, 3),
9696
rowCopyComplete: make(chan error),

go/sql/parser.go

Lines changed: 68 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,47 @@ import (
1212
)
1313

1414
var (
15-
sanitizeQuotesRegexp = regexp.MustCompile("('[^']*')")
16-
renameColumnRegexp = regexp.MustCompile(`(?i)\bchange\s+(column\s+|)([\S]+)\s+([\S]+)\s+`)
17-
dropColumnRegexp = regexp.MustCompile(`(?i)\bdrop\s+(column\s+|)([\S]+)$`)
18-
renameTableRegexp = regexp.MustCompile(`(?i)\brename\s+(to|as)\s+`)
15+
sanitizeQuotesRegexp = regexp.MustCompile("('[^']*')")
16+
renameColumnRegexp = regexp.MustCompile(`(?i)\bchange\s+(column\s+|)([\S]+)\s+([\S]+)\s+`)
17+
dropColumnRegexp = regexp.MustCompile(`(?i)\bdrop\s+(column\s+|)([\S]+)$`)
18+
renameTableRegexp = regexp.MustCompile(`(?i)\brename\s+(to|as)\s+`)
19+
alterTableExplicitSchemaTableRegexps = []*regexp.Regexp{
20+
regexp.MustCompile(`(?i)\balter\s+table\s+` + "`" + `([^` + "`" + `]+)` + "`" + `[.]` + "`" + `([^` + "`" + `]+)` + "`" + `\s+(.*$)`),
21+
regexp.MustCompile(`(?i)\balter\s+table\s+` + "`" + `([^` + "`" + `]+)` + "`" + `[.]([\S]+)\s+(.*$)`),
22+
regexp.MustCompile(`(?i)\balter\s+table\s+([\S]+)[.]` + "`" + `([^` + "`" + `]+)` + "`" + `\s+(.*$)`),
23+
regexp.MustCompile(`(?i)\balter\s+table\s+([\S]+)[.]([\S]+)\s+(.*$)`),
24+
}
25+
alterTableExplicitTableRegexps = []*regexp.Regexp{
26+
regexp.MustCompile(`(?i)\balter\s+table\s+` + "`" + `([^` + "`" + `]+)` + "`" + `\s+(.*$)`),
27+
regexp.MustCompile(`(?i)\balter\s+table\s+([\S]+)\s+(.*$)`),
28+
}
1929
)
2030

21-
type Parser struct {
31+
type AlterTableParser struct {
2232
columnRenameMap map[string]string
2333
droppedColumns map[string]bool
2434
isRenameTable bool
35+
36+
alterTokens []string
37+
38+
explicitSchema string
39+
explicitTable string
2540
}
2641

27-
func NewParser() *Parser {
28-
return &Parser{
42+
func NewAlterTableParser() *AlterTableParser {
43+
return &AlterTableParser{
2944
columnRenameMap: make(map[string]string),
3045
droppedColumns: make(map[string]bool),
3146
}
3247
}
3348

34-
func (this *Parser) tokenizeAlterStatement(alterStatement string) (tokens []string, err error) {
49+
func NewParserFromAlterStatement(alterStatement string) *AlterTableParser {
50+
parser := NewAlterTableParser()
51+
parser.ParseAlterStatement(alterStatement)
52+
return parser
53+
}
54+
55+
func (this *AlterTableParser) tokenizeAlterStatement(alterStatement string) (tokens []string, err error) {
3556
terminatingQuote := rune(0)
3657
f := func(c rune) bool {
3758
switch {
@@ -58,13 +79,13 @@ func (this *Parser) tokenizeAlterStatement(alterStatement string) (tokens []stri
5879
return tokens, nil
5980
}
6081

61-
func (this *Parser) sanitizeQuotesFromAlterStatement(alterStatement string) (strippedStatement string) {
82+
func (this *AlterTableParser) sanitizeQuotesFromAlterStatement(alterStatement string) (strippedStatement string) {
6283
strippedStatement = alterStatement
6384
strippedStatement = sanitizeQuotesRegexp.ReplaceAllString(strippedStatement, "''")
6485
return strippedStatement
6586
}
6687

67-
func (this *Parser) parseAlterToken(alterToken string) (err error) {
88+
func (this *AlterTableParser) parseAlterToken(alterToken string) (err error) {
6889
{
6990
// rename
7091
allStringSubmatch := renameColumnRegexp.FindAllStringSubmatch(alterToken, -1)
@@ -97,16 +118,33 @@ func (this *Parser) parseAlterToken(alterToken string) (err error) {
97118
return nil
98119
}
99120

100-
func (this *Parser) ParseAlterStatement(alterStatement string) (err error) {
121+
func (this *AlterTableParser) ParseAlterStatement(alterStatement string) (err error) {
122+
123+
for _, alterTableRegexp := range alterTableExplicitSchemaTableRegexps {
124+
if submatch := alterTableRegexp.FindStringSubmatch(alterStatement); len(submatch) > 0 {
125+
this.explicitSchema = submatch[1]
126+
this.explicitTable = submatch[2]
127+
alterStatement = submatch[3]
128+
break
129+
}
130+
}
131+
for _, alterTableRegexp := range alterTableExplicitTableRegexps {
132+
if submatch := alterTableRegexp.FindStringSubmatch(alterStatement); len(submatch) > 0 {
133+
this.explicitTable = submatch[1]
134+
alterStatement = submatch[2]
135+
break
136+
}
137+
}
101138
alterTokens, _ := this.tokenizeAlterStatement(alterStatement)
102139
for _, alterToken := range alterTokens {
103140
alterToken = this.sanitizeQuotesFromAlterStatement(alterToken)
104141
this.parseAlterToken(alterToken)
142+
this.alterTokens = append(this.alterTokens, alterToken)
105143
}
106144
return nil
107145
}
108146

109-
func (this *Parser) GetNonTrivialRenames() map[string]string {
147+
func (this *AlterTableParser) GetNonTrivialRenames() map[string]string {
110148
result := make(map[string]string)
111149
for column, renamed := range this.columnRenameMap {
112150
if column != renamed {
@@ -116,14 +154,29 @@ func (this *Parser) GetNonTrivialRenames() map[string]string {
116154
return result
117155
}
118156

119-
func (this *Parser) HasNonTrivialRenames() bool {
157+
func (this *AlterTableParser) HasNonTrivialRenames() bool {
120158
return len(this.GetNonTrivialRenames()) > 0
121159
}
122160

123-
func (this *Parser) DroppedColumnsMap() map[string]bool {
161+
func (this *AlterTableParser) DroppedColumnsMap() map[string]bool {
124162
return this.droppedColumns
125163
}
126164

127-
func (this *Parser) IsRenameTable() bool {
165+
func (this *AlterTableParser) IsRenameTable() bool {
128166
return this.isRenameTable
129167
}
168+
func (this *AlterTableParser) GetExplicitSchema() string {
169+
return this.explicitSchema
170+
}
171+
172+
func (this *AlterTableParser) HasExplicitSchema() bool {
173+
return this.GetExplicitSchema() != ""
174+
}
175+
176+
func (this *AlterTableParser) GetExplicitTable() string {
177+
return this.explicitTable
178+
}
179+
180+
func (this *AlterTableParser) HasExplicitTable() bool {
181+
return this.GetExplicitTable() != ""
182+
}

0 commit comments

Comments
 (0)