Skip to content

Commit 11447f1

Browse files
Csongclaude
andcommitted
fix: strip trailing semicolon from ALTER statement options
A trailing semicolon in the ALTER statement was carried into alterStatementOptions by the greedy (.*$) capture and never trimmed. When those options are spliced into a larger statement (e.g. appending ", ALGORITHM=INSTANT" in generateInstantDDLQuery) the semicolon lands mid-statement. With multiStatements=true on the applier connection this turns one INSTANT DDL into two statements, silently degrading to a native online DDL and, on error, falling back to the full copy. Trim the trailing terminator once in ParseAlterStatement so the options stay a clean fragment. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent c231272 commit 11447f1

2 files changed

Lines changed: 26 additions & 0 deletions

File tree

go/sql/parser.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,11 @@ func (atp *AlterTableParser) ParseAlterStatement(alterStatement string) (err err
150150
break
151151
}
152152
}
153+
// Strip any trailing statement terminator. A trailing semicolon would
154+
// otherwise be carried into alterStatementOptions and, when the options are
155+
// spliced into a larger statement (e.g. appending ", ALGORITHM=INSTANT"),
156+
// break it into two statements under multiStatements=true.
157+
atp.alterStatementOptions = strings.TrimRight(atp.alterStatementOptions, "; \t\r\n")
153158
for _, alterToken := range atp.tokenizeAlterStatement(atp.alterStatementOptions) {
154159
alterToken = atp.sanitizeQuotesFromAlterStatement(alterToken)
155160
atp.parseAlterToken(alterToken)

go/sql/parser_test.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,27 @@ func TestParseAlterStatement(t *testing.T) {
2626
require.False(t, parser.IsAutoIncrementDefined())
2727
}
2828

29+
func TestParseAlterStatementTrailingSemicolon(t *testing.T) {
30+
statements := []string{
31+
"add column t int;",
32+
"add column t int ;",
33+
"add column t int; \t\r\n",
34+
"ADD KEY idx_username (`username`);",
35+
}
36+
expected := []string{
37+
"add column t int",
38+
"add column t int",
39+
"add column t int",
40+
"ADD KEY idx_username (`username`)",
41+
}
42+
for i, statement := range statements {
43+
parser := NewAlterTableParser()
44+
err := parser.ParseAlterStatement(statement)
45+
require.NoError(t, err)
46+
require.Equal(t, expected[i], parser.alterStatementOptions)
47+
}
48+
}
49+
2950
func TestParseAlterStatementrivialRename(t *testing.T) {
3051
statement := "add column t int, change ts ts timestamp, engine=innodb"
3152
parser := NewAlterTableParser()

0 commit comments

Comments
 (0)