Skip to content

Commit f632188

Browse files
elianddbclaude
andcommitted
Fix SET type casting to CHAR and BINARY
This commit fixes an issue where SET types were not properly converted to their string representation when casting to CHAR or BINARY types. The problem was that SET types use internal uint64 values to represent bit fields, but when casting to CHAR or BINARY, the string representation of the SET should be used instead. Changes: - Added special handling in convertValue() for SET types in both CHAR and BINARY conversion cases - Convert SET uint64 bit field to string representation before passing to LongText/LongBlob converters - Removed Skip flags from previously failing tests in script_queries.go - Updated test expectations to include all SET values (including "defg") Fixes dolthub/dolt#9511 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent e4d9d0a commit f632188

File tree

2 files changed

+32
-9
lines changed

2 files changed

+32
-9
lines changed

enginetest/queries/script_queries.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9911,21 +9911,19 @@ where
99119911
},
99129912
},
99139913
{
9914-
// https://github.com/dolthub/dolt/issues/9511
9915-
Skip: true,
99169914
Query: "select s, cast(s as char) from t order by s;",
99179915
Expected: []sql.Row{
99189916
{"abc", "abc"},
9917+
{"defg", "defg"},
99199918
{"abc,defg", "abc,defg"},
99209919
{"abc,defg,hijkl", "abc,defg,hijkl"},
99219920
},
99229921
},
99239922
{
9924-
// https://github.com/dolthub/dolt/issues/9511
9925-
Skip: true,
99269923
Query: "select s, cast(s as binary) from t order by s;",
99279924
Expected: []sql.Row{
99289925
{"abc", []uint8("abc")},
9926+
{"defg", []uint8("defg")},
99299927
{"abc,defg", []uint8("abc,defg")},
99309928
{"abc,defg,hijkl", []uint8("abc,defg,hijkl")},
99319929
},

sql/expression/convert.go

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -278,17 +278,27 @@ func (c *Convert) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) {
278278
return casted, nil
279279
}
280280

281-
// convertValue only returns an error if converting to JSON, Date, and Datetime;
282-
// the zero value is returned for float types. Nil is returned in all other cases.
283-
// If |typeLength| and |typeScale| are 0, they are ignored, otherwise they are used as constraints on the
284-
// converted type where applicable (e.g. Char conversion supports only |typeLength|, Decimal conversion supports
285-
// |typeLength| and |typeScale|).
281+
// convertValue converts a value from its current type to the specified target type for CAST/CONVERT operations.
282+
// It handles type-specific conversion logic and applies length/scale constraints where applicable.
283+
//
284+
// Parameters:
285+
// - val: the value to convert
286+
// - castTo: target type name (e.g., "char", "binary", "decimal", "json")
287+
// - originType: the original SQL type of the value (used for type-specific conversion logic)
288+
// - typeLength: optional length constraint for the target type (0 if not specified)
289+
// - typeScale: optional scale constraint for decimal types (0 if not specified)
290+
//
291+
// Special handling:
292+
// - SET types: converts uint64 bit field values to their string representation for CHAR/BINARY targets
293+
// - BLOB types: converts hex values to decimals for numeric targets
294+
// - Only returns errors for JSON, Date, and Datetime conversions; returns zero/nil for other failed conversions
286295
func convertValue(ctx *sql.Context, val interface{}, castTo string, originType sql.Type, typeLength, typeScale int) (interface{}, error) {
287296
if val == nil {
288297
return nil, nil
289298
}
290299
switch strings.ToLower(castTo) {
291300
case ConvertToBinary:
301+
val = convertSetToStringForStringContext(val, originType)
292302
b, _, err := types.LongBlob.Convert(ctx, val)
293303
if err != nil {
294304
return nil, nil
@@ -307,6 +317,7 @@ func convertValue(ctx *sql.Context, val interface{}, castTo string, originType s
307317
}
308318
return truncateConvertedValue(b, typeLength)
309319
case ConvertToChar, ConvertToNChar:
320+
val = convertSetToStringForStringContext(val, originType)
310321
s, _, err := types.LongText.Convert(ctx, val)
311322
if err != nil {
312323
return nil, nil
@@ -468,6 +479,20 @@ func createConvertedDecimalType(length, scale int, logErrors bool) sql.DecimalTy
468479
return types.InternalDecimalType
469480
}
470481

482+
// convertSetToStringForStringContext converts SET type bit field values to their string representation
483+
// when converting to string-based types (CHAR, BINARY, etc.). This ensures that SET types are properly
484+
// represented as their comma-separated string values rather than their internal uint64 bit field values.
485+
func convertSetToStringForStringContext(val interface{}, originType sql.Type) interface{} {
486+
if setType, ok := originType.(sql.SetType); ok {
487+
if bitField, ok := val.(uint64); ok {
488+
if stringVal, err := setType.BitsToString(bitField); err == nil {
489+
return stringVal
490+
}
491+
}
492+
}
493+
return val
494+
}
495+
471496
// convertHexBlobToDecimalForNumericContext converts byte array value to unsigned int value if originType is BLOB type.
472497
// This function is called when convertTo type is number type only. The hex literal values are parsed into blobs as
473498
// binary string as default, but for numeric context, the value should be a number.

0 commit comments

Comments
 (0)