Skip to content

Commit c8ab377

Browse files
authored
Merge pull request #2997 from dolthub/angela/escape_comments
Properly escape special characters in comments
2 parents 5701b10 + f722c60 commit c8ab377

File tree

3 files changed

+66
-15
lines changed

3 files changed

+66
-15
lines changed

enginetest/queries/alter_table_queries.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1029,6 +1029,23 @@ var AlterTableScripts = []ScriptTest{
10291029
},
10301030
},
10311031
},
1032+
{
1033+
Name: "alter table comments are escaped",
1034+
SetUpScript: []string{
1035+
"create table t (i int);",
1036+
`alter table t modify column i int comment "newline \n | return \r | backslash \\ | NUL \0 \x00"`,
1037+
`alter table t add column j int comment "newline \n | return \r | backslash \\ | NUL \0 \x00"`,
1038+
},
1039+
Assertions: []ScriptTestAssertion{
1040+
{
1041+
Query: "show create table t",
1042+
Expected: []sql.Row{{
1043+
"t",
1044+
"CREATE TABLE `t` (\n `i` int COMMENT 'newline \\n | return \\r | backslash \\\\ | NUL \\0 x00'," +
1045+
"\n `j` int COMMENT 'newline \\n | return \\r | backslash \\\\ | NUL \\0 x00'\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"}},
1046+
},
1047+
},
1048+
},
10321049
}
10331050

10341051
var RenameTableScripts = []ScriptTest{

enginetest/queries/create_table_queries.go

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,42 @@ var CreateTableQueries = []WriteQueryTest{
4040
SelectQuery: "SHOW CREATE TABLE tableWithComment",
4141
ExpectedSelect: []sql.Row{{"tableWithComment", "CREATE TABLE `tableWithComment` (\n `pk` int\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin COMMENT='~!@ #$ %^ &* ()'"}},
4242
},
43+
{
44+
WriteQuery: `create table tableWithComment (pk int) COMMENT "'"`,
45+
ExpectedWriteResult: []sql.Row{{types.NewOkResult(0)}},
46+
SelectQuery: "SHOW CREATE TABLE tableWithComment",
47+
ExpectedSelect: []sql.Row{{"tableWithComment", "CREATE TABLE `tableWithComment` (\n `pk` int\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin COMMENT=''''"}},
48+
},
49+
{
50+
WriteQuery: `create table tableWithComment (pk int) COMMENT "\'"`,
51+
ExpectedWriteResult: []sql.Row{{types.NewOkResult(0)}},
52+
SelectQuery: "SHOW CREATE TABLE tableWithComment",
53+
ExpectedSelect: []sql.Row{{"tableWithComment", "CREATE TABLE `tableWithComment` (\n `pk` int\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin COMMENT=''''"}},
54+
},
55+
{
56+
WriteQuery: `create table tableWithComment (pk int) COMMENT "newline \n | return \r | backslash \\ | NUL \0 \x00"`,
57+
ExpectedWriteResult: []sql.Row{{types.NewOkResult(0)}},
58+
SelectQuery: "SHOW CREATE TABLE tableWithComment",
59+
ExpectedSelect: []sql.Row{{"tableWithComment", "CREATE TABLE `tableWithComment` (\n `pk` int\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin COMMENT='newline \\n | return \\r | backslash \\\\ | NUL \\0 x00'"}},
60+
},
61+
{
62+
WriteQuery: `create table tableWithColumnComment (pk int COMMENT "'")`,
63+
ExpectedWriteResult: []sql.Row{{types.NewOkResult(0)}},
64+
SelectQuery: "SHOW CREATE TABLE tableWithColumnComment",
65+
ExpectedSelect: []sql.Row{{"tableWithColumnComment", "CREATE TABLE `tableWithColumnComment` (\n `pk` int COMMENT ''''\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"}},
66+
},
67+
{
68+
WriteQuery: `create table tableWithColumnComment (pk int COMMENT "\'")`,
69+
ExpectedWriteResult: []sql.Row{{types.NewOkResult(0)}},
70+
SelectQuery: "SHOW CREATE TABLE tableWithColumnComment",
71+
ExpectedSelect: []sql.Row{{"tableWithColumnComment", "CREATE TABLE `tableWithColumnComment` (\n `pk` int COMMENT ''''\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"}},
72+
},
73+
{
74+
WriteQuery: `create table tableWithColumnComment (pk int COMMENT "newline \n | return \r | backslash \\ | NUL \0 \x00")`,
75+
ExpectedWriteResult: []sql.Row{{types.NewOkResult(0)}},
76+
SelectQuery: "SHOW CREATE TABLE tableWithColumnComment",
77+
ExpectedSelect: []sql.Row{{"tableWithColumnComment", "CREATE TABLE `tableWithColumnComment` (\n `pk` int COMMENT 'newline \\n | return \\r | backslash \\\\ | NUL \\0 x00'\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"}},
78+
},
4379
{
4480
WriteQuery: `create table floattypedefs (a float(10), b float(10, 2), c double(10, 2))`,
4581
ExpectedWriteResult: []sql.Row{{types.NewOkResult(0)}},
@@ -1118,18 +1154,6 @@ var CreateTableAutoIncrementTests = []ScriptTest{
11181154
}
11191155

11201156
var BrokenCreateTableQueries = []WriteQueryTest{
1121-
{
1122-
// TODO: We don't support table comments that contain single quotes due to how table options are parsed.
1123-
// Vitess parses them, but turns any double quotes into single quotes and puts all table options back
1124-
// into a string that GMS has to reparse. This means we can't tell if the single quote is the end of
1125-
// the quoted string, or if it was a single quote inside of double quotes and needs to be escaped.
1126-
// To fix this, Vitess should return the parsed table options as structured data, instead of as a
1127-
// single string.
1128-
WriteQuery: `create table tableWithComment (pk int) COMMENT "'"`,
1129-
ExpectedWriteResult: []sql.Row{{types.NewOkResult(0)}},
1130-
SelectQuery: "SHOW CREATE TABLE tableWithComment",
1131-
ExpectedSelect: []sql.Row{{"tableWithComment", "CREATE TABLE `tableWithComment` (\n `pk` int\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin COMMENT=''''"}},
1132-
},
11331157
{
11341158
WriteQuery: `create table t1 (b blob, primary key(b(1)))`,
11351159
ExpectedWriteResult: []sql.Row{{types.NewOkResult(0)}},

sql/parser.go

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,17 @@ func RemoveSpaceAndDelimiter(query string, d rune) string {
133133
})
134134
}
135135

136+
func EscapeSpecialCharactersInComment(comment string) string {
137+
commentString := comment
138+
commentString = strings.ReplaceAll(commentString, "'", "''")
139+
commentString = strings.ReplaceAll(commentString, "\\", "\\\\")
140+
commentString = strings.ReplaceAll(commentString, "\"", "\\\"")
141+
commentString = strings.ReplaceAll(commentString, "\n", "\\n")
142+
commentString = strings.ReplaceAll(commentString, "\r", "\\r")
143+
commentString = strings.ReplaceAll(commentString, "\x00", "\\0")
144+
return commentString
145+
}
146+
136147
type MySqlSchemaFormatter struct{}
137148

138149
var _ SchemaFormatter = &MySqlSchemaFormatter{}
@@ -141,8 +152,7 @@ var _ SchemaFormatter = &MySqlSchemaFormatter{}
141152
func (m *MySqlSchemaFormatter) GenerateCreateTableStatement(tblName string, colStmts []string, temp, autoInc, tblCharsetName, tblCollName, comment string) string {
142153
if comment != "" {
143154
// Escape any single quotes in the comment and add the COMMENT keyword
144-
comment = strings.ReplaceAll(comment, "'", "''")
145-
comment = fmt.Sprintf(" COMMENT='%s'", comment)
155+
comment = fmt.Sprintf(" COMMENT='%s'", EscapeSpecialCharactersInComment(comment))
146156
}
147157

148158
if autoInc != "" {
@@ -201,7 +211,7 @@ func (m *MySqlSchemaFormatter) GenerateCreateTableColumnDefinition(col *Column,
201211
}
202212

203213
if col.Comment != "" {
204-
stmt = fmt.Sprintf("%s COMMENT '%s'", stmt, col.Comment)
214+
stmt = fmt.Sprintf("%s COMMENT '%s'", stmt, EscapeSpecialCharactersInComment(col.Comment))
205215
}
206216
return stmt
207217
}

0 commit comments

Comments
 (0)