Skip to content

Commit 8fb7119

Browse files
committed
Fix 25 todo tests: CAST alias, inf/nan formatting, subquery alias, named tuples
Key fixes: - Add UsedASSyntax field to CastExpr to distinguish CAST(x AS Type) from CAST(x, 'Type') - Fix inf/nan float formatting to use lowercase (inf, -inf, nan) matching ClickHouse - Add NameTypePair support in FormatDataType for named tuple fields like Tuple(a UInt32) - Display Subquery alias when present - Update 03601 golden file for inf formatting change Tests now passing: - 00503_cast_const_nullable - 00516_is_inf_nan - 00525_aggregate_functions_of_nullable_that_return_non_nullable - 00547_named_tuples - 01351_geohash_assert - 01581_to_int_inf_nan - 01602_modified_julian_day_msan - 01611_constant_folding_subqueries - 01642_if_nullable_regression - 01664_decimal_ubsan - 01677_bit_float - 01679_format_readable_time_delta_inf - 01773_datetime64_add_ubsan - 01852_cast_operator - 02007_ipv4_and_ipv6_to_and_from_string - 02136_scalar_subquery_metrics - 02148_cast_type_parsing - 02313_avro_records_and_maps - 02366_union_decimal_conversion - 02416_input_json_formats - 02795_full_join_assert_cast - 02832_transform_fixed_string_no_default - 02921_bit_hamming_distance_big_int - 03237_get_subcolumn_low_cardinality_column - 03261_json_hints_types_check
1 parent 21bc015 commit 8fb7119

32 files changed

Lines changed: 144 additions & 101 deletions

File tree

ast/ast.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -911,6 +911,7 @@ type CastExpr struct {
911911
TypeExpr Expression `json:"type_expr,omitempty"` // For dynamic type like CAST(x, if(cond, 'Type1', 'Type2'))
912912
Alias string `json:"alias,omitempty"`
913913
OperatorSyntax bool `json:"operator_syntax,omitempty"` // true if using :: syntax
914+
UsedASSyntax bool `json:"-"` // true if CAST(x AS Type) syntax used (not CAST(x, 'Type'))
914915
}
915916

916917
func (c *CastExpr) Pos() token.Position { return c.Position }

internal/explain/expressions.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,11 @@ func explainUnaryExpr(sb *strings.Builder, n *ast.UnaryExpr, indent string, dept
198198

199199
func explainSubquery(sb *strings.Builder, n *ast.Subquery, indent string, depth int) {
200200
children := 1
201-
fmt.Fprintf(sb, "%sSubquery (children %d)\n", indent, children)
201+
if n.Alias != "" {
202+
fmt.Fprintf(sb, "%sSubquery (alias %s) (children %d)\n", indent, n.Alias, children)
203+
} else {
204+
fmt.Fprintf(sb, "%sSubquery (children %d)\n", indent, children)
205+
}
202206
Node(sb, n.Query, depth+1)
203207
}
204208

@@ -270,8 +274,12 @@ func explainAliasedExpr(sb *strings.Builder, n *ast.AliasedExpr, depth int) {
270274
Node(sb, e.Then, depth+2)
271275
Node(sb, e.Else, depth+2)
272276
case *ast.CastExpr:
273-
// CAST expressions - ClickHouse doesn't show aliases on CAST in EXPLAIN AST
274-
explainCastExpr(sb, e, indent, depth)
277+
// CAST expressions - show alias only for CAST(x AS Type) syntax, not CAST(x, 'Type')
278+
if e.UsedASSyntax {
279+
explainCastExprWithAlias(sb, e, n.Alias, indent, depth)
280+
} else {
281+
explainCastExpr(sb, e, indent, depth)
282+
}
275283
case *ast.ArrayAccess:
276284
// Array access - ClickHouse doesn't show aliases on arrayElement in EXPLAIN AST
277285
explainArrayAccess(sb, e, indent, depth)

internal/explain/format.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package explain
22

33
import (
44
"fmt"
5+
"math"
56
"strconv"
67
"strings"
78

@@ -10,6 +11,16 @@ import (
1011

1112
// FormatFloat formats a float value for EXPLAIN AST output
1213
func FormatFloat(val float64) string {
14+
// Handle special float values - ClickHouse uses lowercase
15+
if math.IsInf(val, 1) {
16+
return "inf"
17+
}
18+
if math.IsInf(val, -1) {
19+
return "-inf"
20+
}
21+
if math.IsNaN(val) {
22+
return "nan"
23+
}
1324
// Use 'f' format to avoid scientific notation, -1 precision for smallest representation
1425
return strconv.FormatFloat(val, 'f', -1, 64)
1526
}
@@ -161,6 +172,9 @@ func FormatDataType(dt *ast.DataType) string {
161172
}
162173
} else if nested, ok := p.(*ast.DataType); ok {
163174
params = append(params, FormatDataType(nested))
175+
} else if ntp, ok := p.(*ast.NameTypePair); ok {
176+
// Named tuple field: "name Type"
177+
params = append(params, ntp.Name+" "+FormatDataType(ntp.Type))
164178
} else {
165179
params = append(params, fmt.Sprintf("%v", p))
166180
}

internal/explain/functions.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,19 @@ func explainCastExpr(sb *strings.Builder, n *ast.CastExpr, indent string, depth
8383
}
8484

8585
func explainCastExprWithAlias(sb *strings.Builder, n *ast.CastExpr, alias string, indent string, depth int) {
86+
// For :: operator syntax, ClickHouse hides alias only when expression is
87+
// an array/tuple with complex content that gets formatted as string
88+
hideAlias := false
89+
if n.OperatorSyntax {
90+
if lit, ok := n.Expr.(*ast.Literal); ok {
91+
if lit.Type == ast.LiteralArray || lit.Type == ast.LiteralTuple {
92+
hideAlias = !containsOnlyPrimitives(lit)
93+
}
94+
}
95+
}
96+
8697
// CAST is represented as Function CAST with expr and type as arguments
87-
if alias != "" {
98+
if alias != "" && !hideAlias {
8899
fmt.Fprintf(sb, "%sFunction CAST (alias %s) (children %d)\n", indent, alias, 1)
89100
} else {
90101
fmt.Fprintf(sb, "%sFunction CAST (children %d)\n", indent, 1)

parser/expression.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -958,6 +958,7 @@ func (p *Parser) parseCast() ast.Expression {
958958
if p.currentIs(token.AS) {
959959
p.nextToken()
960960
expr.Type = p.parseDataType()
961+
expr.UsedASSyntax = true
961962
} else if p.currentIs(token.COMMA) {
962963
p.nextToken()
963964
// Type can be given as a string literal or an expression (e.g., if(cond, 'Type1', 'Type2'))
@@ -1564,6 +1565,18 @@ func (p *Parser) parseAlias(left ast.Expression) ast.Expression {
15641565
case *ast.Subquery:
15651566
e.Alias = alias
15661567
return e
1568+
case *ast.CastExpr:
1569+
// For :: operator syntax, set alias directly on CastExpr
1570+
// For function-style CAST(), wrap in AliasedExpr
1571+
if e.OperatorSyntax {
1572+
e.Alias = alias
1573+
return e
1574+
}
1575+
return &ast.AliasedExpr{
1576+
Position: left.Pos(),
1577+
Expr: left,
1578+
Alias: alias,
1579+
}
15671580
case *ast.CaseExpr:
15681581
e.Alias = alias
15691582
return e
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"todo": true}
1+
{}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"todo": true}
1+
{}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"todo": true}
1+
{}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"todo": true}
1+
{}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"todo": true}
1+
{}

0 commit comments

Comments
 (0)