Skip to content

Commit 10724f0

Browse files
Merge branch 'parse-alter-statement' of https://github.com/openark/gh-ost into parse-alter-statement
2 parents 720182f + ae4dd18 commit 10724f0

File tree

6 files changed

+220
-42
lines changed

6 files changed

+220
-42
lines changed

go/base/context.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,10 @@ func NewThrottleCheckResult(throttle bool, reason string, reasonHint ThrottleRea
7777
type MigrationContext struct {
7878
Uuid string
7979

80-
DatabaseName string
81-
OriginalTableName string
82-
AlterStatement string
80+
DatabaseName string
81+
OriginalTableName string
82+
AlterStatement string
83+
AlterStatementOptions string // anything following the 'ALTER TABLE [schema.]table' from AlterStatement
8384

8485
CountTableRows bool
8586
ConcurrentCountTableRows bool

go/cmd/gh-ost/main.go

Lines changed: 17 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

@@ -173,14 +174,25 @@ func main() {
173174
migrationContext.Log.SetLevel(log.ERROR)
174175
}
175176

177+
if migrationContext.AlterStatement == "" {
178+
log.Fatalf("--alter must be provided and statement must not be empty")
179+
}
180+
parser := sql.NewParserFromAlterStatement(migrationContext.AlterStatement)
181+
migrationContext.AlterStatementOptions = parser.GetAlterStatementOptions()
182+
176183
if migrationContext.DatabaseName == "" {
177-
migrationContext.Log.Fatalf("--database must be provided and database name must not be empty")
184+
if parser.HasExplicitSchema() {
185+
migrationContext.DatabaseName = parser.GetExplicitSchema()
186+
} else {
187+
log.Fatalf("--database must be provided and database name must not be empty, or --alter must specify database name")
188+
}
178189
}
179190
if migrationContext.OriginalTableName == "" {
180-
migrationContext.Log.Fatalf("--table must be provided and table name must not be empty")
181-
}
182-
if migrationContext.AlterStatement == "" {
183-
migrationContext.Log.Fatalf("--alter must be provided and statement must not be empty")
191+
if parser.HasExplicitTable() {
192+
migrationContext.OriginalTableName = parser.GetExplicitTable()
193+
} else {
194+
log.Fatalf("--table must be provided and table name must not be empty, or --alter must specify table name")
195+
}
184196
}
185197
migrationContext.Noop = !(*executeFlag)
186198
if migrationContext.AllowedRunningOnMaster && migrationContext.TestOnReplica {

go/logic/applier.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ func (this *Applier) AlterGhost() error {
190190
query := fmt.Sprintf(`alter /* gh-ost */ table %s.%s %s`,
191191
sql.EscapeName(this.migrationContext.DatabaseName),
192192
sql.EscapeName(this.migrationContext.GetGhostTableName()),
193-
this.migrationContext.AlterStatement,
193+
this.migrationContext.AlterStatementOptions,
194194
)
195195
this.migrationContext.Log.Infof("Altering ghost table %s.%s",
196196
sql.EscapeName(this.migrationContext.DatabaseName),

go/logic/migrator.go

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

6161
// Migrator is the main schema migration flow manager.
6262
type Migrator struct {
63-
parser *sql.Parser
63+
parser *sql.AlterTableParser
6464
inspector *Inspector
6565
applier *Applier
6666
eventsStreamer *EventsStreamer
@@ -88,7 +88,7 @@ type Migrator struct {
8888
func NewMigrator(context *base.MigrationContext) *Migrator {
8989
migrator := &Migrator{
9090
migrationContext: context,
91-
parser: sql.NewParser(),
91+
parser: sql.NewAlterTableParser(),
9292
ghostTableMigrated: make(chan bool),
9393
firstThrottlingCollected: make(chan bool, 3),
9494
rowCopyComplete: make(chan error),

go/sql/parser.go

Lines changed: 81 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,54 @@ 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+
// ALTER TABLE `scm`.`tbl` something
21+
regexp.MustCompile(`(?i)\balter\s+table\s+` + "`" + `([^` + "`" + `]+)` + "`" + `[.]` + "`" + `([^` + "`" + `]+)` + "`" + `\s+(.*$)`),
22+
// ALTER TABLE `scm`.tbl something
23+
regexp.MustCompile(`(?i)\balter\s+table\s+` + "`" + `([^` + "`" + `]+)` + "`" + `[.]([\S]+)\s+(.*$)`),
24+
// ALTER TABLE scm.`tbl` something
25+
regexp.MustCompile(`(?i)\balter\s+table\s+([\S]+)[.]` + "`" + `([^` + "`" + `]+)` + "`" + `\s+(.*$)`),
26+
// ALTER TABLE scm.tbl something
27+
regexp.MustCompile(`(?i)\balter\s+table\s+([\S]+)[.]([\S]+)\s+(.*$)`),
28+
}
29+
alterTableExplicitTableRegexps = []*regexp.Regexp{
30+
// ALTER TABLE `tbl` something
31+
regexp.MustCompile(`(?i)\balter\s+table\s+` + "`" + `([^` + "`" + `]+)` + "`" + `\s+(.*$)`),
32+
// ALTER TABLE tbl something
33+
regexp.MustCompile(`(?i)\balter\s+table\s+([\S]+)\s+(.*$)`),
34+
}
1935
)
2036

21-
type Parser struct {
37+
type AlterTableParser struct {
2238
columnRenameMap map[string]string
2339
droppedColumns map[string]bool
2440
isRenameTable bool
41+
42+
alterStatementOptions string
43+
alterTokens []string
44+
45+
explicitSchema string
46+
explicitTable string
2547
}
2648

27-
func NewParser() *Parser {
28-
return &Parser{
49+
func NewAlterTableParser() *AlterTableParser {
50+
return &AlterTableParser{
2951
columnRenameMap: make(map[string]string),
3052
droppedColumns: make(map[string]bool),
3153
}
3254
}
3355

34-
func (this *Parser) tokenizeAlterStatement(alterStatement string) (tokens []string, err error) {
56+
func NewParserFromAlterStatement(alterStatement string) *AlterTableParser {
57+
parser := NewAlterTableParser()
58+
parser.ParseAlterStatement(alterStatement)
59+
return parser
60+
}
61+
62+
func (this *AlterTableParser) tokenizeAlterStatement(alterStatement string) (tokens []string, err error) {
3563
terminatingQuote := rune(0)
3664
f := func(c rune) bool {
3765
switch {
@@ -58,13 +86,13 @@ func (this *Parser) tokenizeAlterStatement(alterStatement string) (tokens []stri
5886
return tokens, nil
5987
}
6088

61-
func (this *Parser) sanitizeQuotesFromAlterStatement(alterStatement string) (strippedStatement string) {
89+
func (this *AlterTableParser) sanitizeQuotesFromAlterStatement(alterStatement string) (strippedStatement string) {
6290
strippedStatement = alterStatement
6391
strippedStatement = sanitizeQuotesRegexp.ReplaceAllString(strippedStatement, "''")
6492
return strippedStatement
6593
}
6694

67-
func (this *Parser) parseAlterToken(alterToken string) (err error) {
95+
func (this *AlterTableParser) parseAlterToken(alterToken string) (err error) {
6896
{
6997
// rename
7098
allStringSubmatch := renameColumnRegexp.FindAllStringSubmatch(alterToken, -1)
@@ -97,16 +125,34 @@ func (this *Parser) parseAlterToken(alterToken string) (err error) {
97125
return nil
98126
}
99127

100-
func (this *Parser) ParseAlterStatement(alterStatement string) (err error) {
101-
alterTokens, _ := this.tokenizeAlterStatement(alterStatement)
128+
func (this *AlterTableParser) ParseAlterStatement(alterStatement string) (err error) {
129+
130+
this.alterStatementOptions = alterStatement
131+
for _, alterTableRegexp := range alterTableExplicitSchemaTableRegexps {
132+
if submatch := alterTableRegexp.FindStringSubmatch(this.alterStatementOptions); len(submatch) > 0 {
133+
this.explicitSchema = submatch[1]
134+
this.explicitTable = submatch[2]
135+
this.alterStatementOptions = submatch[3]
136+
break
137+
}
138+
}
139+
for _, alterTableRegexp := range alterTableExplicitTableRegexps {
140+
if submatch := alterTableRegexp.FindStringSubmatch(this.alterStatementOptions); len(submatch) > 0 {
141+
this.explicitTable = submatch[1]
142+
this.alterStatementOptions = submatch[2]
143+
break
144+
}
145+
}
146+
alterTokens, _ := this.tokenizeAlterStatement(this.alterStatementOptions)
102147
for _, alterToken := range alterTokens {
103148
alterToken = this.sanitizeQuotesFromAlterStatement(alterToken)
104149
this.parseAlterToken(alterToken)
150+
this.alterTokens = append(this.alterTokens, alterToken)
105151
}
106152
return nil
107153
}
108154

109-
func (this *Parser) GetNonTrivialRenames() map[string]string {
155+
func (this *AlterTableParser) GetNonTrivialRenames() map[string]string {
110156
result := make(map[string]string)
111157
for column, renamed := range this.columnRenameMap {
112158
if column != renamed {
@@ -116,14 +162,33 @@ func (this *Parser) GetNonTrivialRenames() map[string]string {
116162
return result
117163
}
118164

119-
func (this *Parser) HasNonTrivialRenames() bool {
165+
func (this *AlterTableParser) HasNonTrivialRenames() bool {
120166
return len(this.GetNonTrivialRenames()) > 0
121167
}
122168

123-
func (this *Parser) DroppedColumnsMap() map[string]bool {
169+
func (this *AlterTableParser) DroppedColumnsMap() map[string]bool {
124170
return this.droppedColumns
125171
}
126172

127-
func (this *Parser) IsRenameTable() bool {
173+
func (this *AlterTableParser) IsRenameTable() bool {
128174
return this.isRenameTable
129175
}
176+
func (this *AlterTableParser) GetExplicitSchema() string {
177+
return this.explicitSchema
178+
}
179+
180+
func (this *AlterTableParser) HasExplicitSchema() bool {
181+
return this.GetExplicitSchema() != ""
182+
}
183+
184+
func (this *AlterTableParser) GetExplicitTable() string {
185+
return this.explicitTable
186+
}
187+
188+
func (this *AlterTableParser) HasExplicitTable() bool {
189+
return this.GetExplicitTable() != ""
190+
}
191+
192+
func (this *AlterTableParser) GetAlterStatementOptions() string {
193+
return this.alterStatementOptions
194+
}

0 commit comments

Comments
 (0)