Skip to content

Commit 09cde5c

Browse files
authored
Merge branch 'dolthub:main' into fix-newserver-readme
2 parents eede8d3 + b7b74d4 commit 09cde5c

File tree

14 files changed

+262
-48
lines changed

14 files changed

+262
-48
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)}},

enginetest/queries/script_queries.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8477,6 +8477,56 @@ where
84778477
},
84788478
},
84798479
},
8480+
{
8481+
// This is a script test here because every table in the harness setup data is in all lowercase
8482+
Name: "case insensitive update with insubqueries and update joins",
8483+
Dialect: "mysql",
8484+
SetUpScript: []string{
8485+
"create table MiXeDcAsE (i int primary key, j int)",
8486+
"insert into mixedcase values (1, 1);",
8487+
"insert into mixedcase values (2, 2);",
8488+
},
8489+
Assertions: []ScriptTestAssertion{
8490+
{
8491+
Query: "update mixedcase set j = 999 where i in (select 1)",
8492+
Expected: []sql.Row{
8493+
{types.OkResult{
8494+
RowsAffected: 1,
8495+
Info: plan.UpdateInfo{
8496+
Matched: 1,
8497+
Updated: 1,
8498+
},
8499+
}},
8500+
},
8501+
},
8502+
{
8503+
Query: "select * from mixedcase;",
8504+
Expected: []sql.Row{
8505+
{1, 999},
8506+
{2, 2},
8507+
},
8508+
},
8509+
{
8510+
Query: " with cte(x) as (select 2) update mixedcase set j = 999 where i in (select x from cte)",
8511+
Expected: []sql.Row{
8512+
{types.OkResult{
8513+
RowsAffected: 1,
8514+
Info: plan.UpdateInfo{
8515+
Matched: 1,
8516+
Updated: 1,
8517+
},
8518+
}},
8519+
},
8520+
},
8521+
{
8522+
Query: "select * from mixedcase;",
8523+
Expected: []sql.Row{
8524+
{1, 999},
8525+
{2, 999},
8526+
},
8527+
},
8528+
},
8529+
},
84808530
}
84818531

84828532
var SpatialScriptTests = []ScriptTest{

enginetest/queries/table_func_scripts.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,4 +222,20 @@ var TableFunctionScriptTests = []ScriptTest{
222222
JoinTypes: []plan.JoinType{plan.JoinTypeLookup},
223223
ExpectedIndexes: []string{"y"},
224224
},
225+
{
226+
SetUpScript: []string{
227+
`
228+
create procedure proc(in x int)
229+
begin
230+
select * from sequence_table('x', x);
231+
end;
232+
`,
233+
},
234+
Query: "call proc(3)",
235+
Expected: []sql.Row{
236+
{0},
237+
{1},
238+
{2},
239+
},
240+
},
225241
}

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ require (
66
github.com/dolthub/go-icu-regex v0.0.0-20250327004329-6799764f2dad
77
github.com/dolthub/jsonpath v0.0.2-0.20240227200619-19675ab05c71
88
github.com/dolthub/sqllogictest/go v0.0.0-20201107003712-816f3ae12d81
9-
github.com/dolthub/vitess v0.0.0-20250523011542-0f6cf9472d1c
9+
github.com/dolthub/vitess v0.0.0-20250530231040-bfd522856394
1010
github.com/go-kit/kit v0.10.0
1111
github.com/go-sql-driver/mysql v1.7.2-0.20231213112541-0004702b931d
1212
github.com/gocraft/dbr/v2 v2.7.2

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ github.com/dolthub/jsonpath v0.0.2-0.20240227200619-19675ab05c71 h1:bMGS25NWAGTE
5858
github.com/dolthub/jsonpath v0.0.2-0.20240227200619-19675ab05c71/go.mod h1:2/2zjLQ/JOOSbbSboojeg+cAwcRV0fDLzIiWch/lhqI=
5959
github.com/dolthub/sqllogictest/go v0.0.0-20201107003712-816f3ae12d81 h1:7/v8q9XGFa6q5Ap4Z/OhNkAMBaK5YeuEzwJt+NZdhiE=
6060
github.com/dolthub/sqllogictest/go v0.0.0-20201107003712-816f3ae12d81/go.mod h1:siLfyv2c92W1eN/R4QqG/+RjjX5W2+gCTRjZxBjI3TY=
61-
github.com/dolthub/vitess v0.0.0-20250523011542-0f6cf9472d1c h1:23KvsBtJk2GmHpXwQ/RkwIkdNpWL8tWdHRCiidhnaUA=
62-
github.com/dolthub/vitess v0.0.0-20250523011542-0f6cf9472d1c/go.mod h1:1gQZs/byeHLMSul3Lvl3MzioMtOW1je79QYGyi2fd70=
61+
github.com/dolthub/vitess v0.0.0-20250530231040-bfd522856394 h1:sMwntvk7O9dttaJLqnOvy8zgk0ah9qnyWkAahfOgnIo=
62+
github.com/dolthub/vitess v0.0.0-20250530231040-bfd522856394/go.mod h1:1gQZs/byeHLMSul3Lvl3MzioMtOW1je79QYGyi2fd70=
6363
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
6464
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
6565
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=

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
}

sql/plan/update_join.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
package plan
1616

1717
import (
18+
"strings"
19+
1820
"github.com/dolthub/go-mysql-server/sql"
1921
)
2022

@@ -232,6 +234,7 @@ func SplitRowIntoTableRowMap(row sql.Row, joinSchema sql.Schema) map[string]sql.
232234
}
233235
}
234236

237+
currentTable = strings.ToLower(currentTable)
235238
ret[currentTable] = currentRow
236239

237240
return ret

sql/planbuilder/aggregates.go

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -492,7 +492,7 @@ func (b *Builder) buildGroupConcat(inScope *scope, e *ast.GroupConcatExpr) sql.E
492492
sortFields = append(sortFields, sf)
493493
}
494494

495-
//TODO: this should be acquired at runtime, not at parse time, so fix this
495+
// TODO: this should be acquired at runtime, not at parse time, so fix this
496496
gcml, err := b.ctx.GetSessionVariable(b.ctx, "group_concat_max_len")
497497
if err != nil {
498498
b.handleErr(err)
@@ -515,6 +515,63 @@ func (b *Builder) buildGroupConcat(inScope *scope, e *ast.GroupConcatExpr) sql.E
515515
return col.scalarGf()
516516
}
517517

518+
// buildOrderedInjectedExpr builds an InjectedExpr with an ORDER BY dependency
519+
func (b *Builder) buildOrderedInjectedExpr(inScope *scope, e *ast.OrderedInjectedExpr) sql.Expression {
520+
inScope.initGroupBy()
521+
gb := inScope.groupBy
522+
523+
var resolvedChildren []any
524+
if len(e.Children) > 0 {
525+
resolvedChildren = make([]any, len(e.Children))
526+
for i, child := range e.Children {
527+
resolvedChildren[i] = b.buildScalar(inScope, child)
528+
}
529+
} else {
530+
resolvedChildren = make([]any, len(e.SelectExprChildren))
531+
for i, child := range e.SelectExprChildren {
532+
resolvedChildren[i] = b.selectExprToExpression(inScope, child)
533+
}
534+
}
535+
536+
orderByScope := b.analyzeOrderBy(inScope, inScope, e.OrderBy)
537+
var sortFields sql.SortFields
538+
for _, c := range orderByScope.cols {
539+
so := sql.Ascending
540+
if c.descending {
541+
so = sql.Descending
542+
}
543+
scalar := c.scalar
544+
if scalar == nil {
545+
scalar = c.scalarGf()
546+
}
547+
sf := sql.SortField{
548+
Column: scalar,
549+
Order: so,
550+
}
551+
sortFields = append(sortFields, sf)
552+
}
553+
554+
resolvedChildren = append(resolvedChildren, sortFields)
555+
556+
expr := b.buildInjectedExpressionFromResolvedChildren(e.InjectedExpr, resolvedChildren)
557+
agg, ok := expr.(sql.Aggregation)
558+
if !ok {
559+
b.handleErr(fmt.Errorf("expected sql.Aggregation, got %T", expr))
560+
}
561+
562+
aggName := strings.ToLower(plan.AliasSubqueryString(agg))
563+
col := scopeColumn{col: aggName, scalar: agg, typ: agg.Type(), nullable: agg.IsNullable()}
564+
id := gb.outScope.newColumn(col)
565+
566+
agg = agg.WithId(sql.ColumnId(id)).(sql.Aggregation)
567+
gb.outScope.cols[len(gb.outScope.cols)-1].scalar = agg
568+
col.scalar = agg
569+
570+
gb.addAggStr(col)
571+
col.id = id
572+
return col.scalarGf()
573+
}
574+
518575
func isWindowFunc(name string) bool {
519576
switch name {
520577
case "first", "last", "count", "sum", "any_value",

0 commit comments

Comments
 (0)