Skip to content

Commit 53f1886

Browse files
authored
Merge pull request #3068 from dolthub/elianddb/9426-enum-string-context
dolthub/dolt#9426 - Support enum string context in functions
2 parents de1be10 + 270a87e commit 53f1886

File tree

5 files changed

+124
-28
lines changed

5 files changed

+124
-28
lines changed

enginetest/queries/script_queries.go

Lines changed: 55 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9085,7 +9085,6 @@ where
90859085
},
90869086
},
90879087
{
9088-
Skip: true,
90899088
Name: "enum conversion to strings",
90909089
Dialect: "mysql",
90919090
SetUpScript: []string{
@@ -9094,21 +9093,72 @@ where
90949093
},
90959094
Assertions: []ScriptTestAssertion{
90969095
{
9097-
// We incorrectly use the numeric values of the enum, resulting in length of 1
90989096
Query: "select e, length(e) from t order by e;",
90999097
Expected: []sql.Row{
91009098
{"abc", 3},
91019099
{"defg", 4},
9102-
{"hijkl", 5},
9100+
{"hjikl", 5},
91039101
},
91049102
},
91059103
{
9106-
// We incorrectly use the numeric values of the enum, resulting in length of 1
91079104
Query: "select e, concat(e, 'test') from t order by e;",
91089105
Expected: []sql.Row{
91099106
{"abc", "abctest"},
91109107
{"defg", "defgtest"},
9111-
{"hijkl", "hijkltest"},
9108+
{"hjikl", "hjikltest"},
9109+
},
9110+
},
9111+
{
9112+
Query: "select e, e like 'a%', e like '%g' from t order by e;",
9113+
Expected: []sql.Row{
9114+
{"abc", true, false},
9115+
{"defg", false, true},
9116+
{"hjikl", false, false},
9117+
},
9118+
},
9119+
{
9120+
Query: "select group_concat(e order by e) as grouped from t;",
9121+
Expected: []sql.Row{
9122+
{"abc,defg,hjikl"},
9123+
},
9124+
},
9125+
{
9126+
Query: "select e from t where e = 'abc';",
9127+
Expected: []sql.Row{
9128+
{"abc"},
9129+
},
9130+
},
9131+
{
9132+
Query: "select count(*) from t where e = 'defg';",
9133+
Expected: []sql.Row{
9134+
{1},
9135+
},
9136+
},
9137+
},
9138+
},
9139+
{
9140+
Name: "enum conversion with system variables",
9141+
Dialect: "mysql",
9142+
SetUpScript: []string{
9143+
"create table t (e enum('ON', 'OFF', 'AUTO'));",
9144+
"set autocommit = 'ON';",
9145+
"insert into t values(@@autocommit), ('OFF'), ('AUTO');",
9146+
},
9147+
Assertions: []ScriptTestAssertion{
9148+
{
9149+
Query: "select e, @@autocommit, e = @@autocommit from t order by e;",
9150+
Expected: []sql.Row{
9151+
{"ON", 1, true},
9152+
{"OFF", 1, false},
9153+
{"AUTO", 1, false},
9154+
},
9155+
},
9156+
{
9157+
Query: "select e, concat(e, @@version_comment) from t order by e;",
9158+
Expected: []sql.Row{
9159+
{"ON", "ONDolt"},
9160+
{"OFF", "OFFDolt"},
9161+
{"AUTO", "AUTODolt"},
91129162
},
91139163
},
91149164
},

sql/expression/function/aggregation/group_concat.go

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -271,16 +271,27 @@ func (g *groupConcatBuffer) Update(ctx *sql.Context, originalRow sql.Row) error
271271
return nil
272272
}
273273
} else {
274-
v, _, err = types.LongText.Convert(ctx, evalRow[0])
275-
if err != nil {
276-
return err
277-
}
278-
if v == nil {
279-
return nil
280-
}
281-
vs, _, err = sql.Unwrap[string](ctx, v)
282-
if err != nil {
283-
return err
274+
// Use type-aware conversion for enum types
275+
if len(g.gc.selectExprs) > 0 {
276+
vs, _, err = types.ConvertToCollatedString(ctx, evalRow[0], g.gc.selectExprs[0].Type())
277+
if err != nil {
278+
return err
279+
}
280+
if vs == "" {
281+
return nil
282+
}
283+
} else {
284+
v, _, err = types.LongText.Convert(ctx, evalRow[0])
285+
if err != nil {
286+
return err
287+
}
288+
if v == nil {
289+
return nil
290+
}
291+
vs, _, err = sql.Unwrap[string](ctx, v)
292+
if err != nil {
293+
return err
294+
}
284295
}
285296
}
286297

sql/expression/function/concat.go

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -123,17 +123,13 @@ func (c *Concat) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) {
123123
return nil, nil
124124
}
125125

126-
val, _, err = types.LongText.Convert(ctx, val)
126+
// Use type-aware conversion for enum types
127+
content, _, err := types.ConvertToCollatedString(ctx, val, arg.Type())
127128
if err != nil {
128129
return nil, err
129130
}
130131

131-
val, _, err = sql.Unwrap[string](ctx, val)
132-
if err != nil {
133-
return nil, err
134-
}
135-
136-
parts = append(parts, val.(string))
132+
parts = append(parts, content)
137133
}
138134

139135
return strings.Join(parts, ""), nil

sql/expression/like.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,12 @@ func (l *Like) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) {
8686
return nil, err
8787
}
8888
if _, ok := left.(string); !ok {
89-
left, _, err = types.LongText.Convert(ctx, left)
89+
// Use type-aware conversion for enum types
90+
leftStr, _, err := types.ConvertToCollatedString(ctx, left, l.Left().Type())
9091
if err != nil {
9192
return nil, err
9293
}
94+
left = leftStr
9395
}
9496

9597
var lm LikeMatcher
@@ -138,10 +140,12 @@ func (l *Like) evalRight(ctx *sql.Context, row sql.Row) (right *string, escape r
138140
return nil, 0, err
139141
}
140142
if _, ok := rightVal.(string); !ok {
141-
rightVal, _, err = types.LongText.Convert(ctx, rightVal)
143+
// Use type-aware conversion for enum types
144+
rightStr, _, err := types.ConvertToCollatedString(ctx, rightVal, l.Right().Type())
142145
if err != nil {
143146
return nil, 0, err
144147
}
148+
rightVal = rightStr
145149
}
146150

147151
var escapeVal interface{}

sql/types/strings.go

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,29 @@ func ConvertToBytes(ctx context.Context, v interface{}, t sql.StringType, dest [
496496
return val, nil
497497
}
498498

499+
// convertToLongTextString safely converts a value to string using LongText.Convert with nil checking
500+
func convertToLongTextString(ctx context.Context, val interface{}) (string, error) {
501+
converted, _, err := LongText.Convert(ctx, val)
502+
if err != nil {
503+
return "", err
504+
}
505+
if converted == nil {
506+
return "", nil
507+
}
508+
return converted.(string), nil
509+
}
510+
511+
// convertEnumToString converts an enum value to its string representation
512+
func convertEnumToString(ctx context.Context, val interface{}, enumType sql.EnumType) (string, error) {
513+
if enumVal, ok := val.(uint16); ok {
514+
if enumStr, exists := enumType.At(int(enumVal)); exists {
515+
return enumStr, nil
516+
}
517+
return "", nil
518+
}
519+
return convertToLongTextString(ctx, val)
520+
}
521+
499522
// ConvertToCollatedString returns the given interface as a string, along with its collation. If the Type possess a
500523
// collation, then that collation is returned. If the Type does not possess a collation (such as an integer), then the
501524
// value is converted to a string and the default collation is used. If the value is already a string then no additional
@@ -516,20 +539,32 @@ func ConvertToCollatedString(ctx context.Context, val interface{}, typ sql.Type)
516539
content = strVal
517540
} else if byteVal, ok := val.([]byte); ok {
518541
content = encodings.BytesToString(byteVal)
542+
} else if enumType, ok := typ.(sql.EnumType); ok {
543+
// Handle enum types in string context - return the string value, not the index
544+
content, err = convertEnumToString(ctx, val, enumType)
545+
if err != nil {
546+
return "", sql.Collation_Unspecified, err
547+
}
519548
} else {
520-
val, _, err = LongText.Convert(ctx, val)
549+
content, err = convertToLongTextString(ctx, val)
521550
if err != nil {
522551
return "", sql.Collation_Unspecified, err
523552
}
524-
content = val.(string)
525553
}
526554
} else {
527555
collation = sql.Collation_Default
528-
val, _, err = LongText.Convert(ctx, val)
556+
// Handle enum types in string context even without collation
557+
if enumType, ok := typ.(sql.EnumType); ok {
558+
content, err = convertEnumToString(ctx, val, enumType)
559+
if err != nil {
560+
return "", sql.Collation_Unspecified, err
561+
}
562+
return content, collation, nil
563+
}
564+
content, err = convertToLongTextString(ctx, val)
529565
if err != nil {
530566
return "", sql.Collation_Unspecified, err
531567
}
532-
content = val.(string)
533568
}
534569
return content, collation, nil
535570
}

0 commit comments

Comments
 (0)