Skip to content

Commit 3142456

Browse files
committed
Fix nested tuple literal formatting in EXPLAIN output
When a tuple contains only primitive literals (including nested tuples with primitive literals), it should be rendered as a single Literal Tuple_(...) rather than Function tuple with children. Add containsOnlyPrimitiveLiteralsWithUnary helper that checks if a tuple contains only primitive literals, including handling unary negation of numeric literals (e.g., -0., -123). Fixes 17 statements across 11 tests.
1 parent 0d45aba commit 3142456

13 files changed

Lines changed: 58 additions & 47 deletions

File tree

internal/explain/expressions.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,16 @@ func explainLiteral(sb *strings.Builder, n *ast.Literal, indent string, depth in
6565
for _, e := range exprs {
6666
// Simple literals (numbers, strings, etc.) are OK
6767
if lit, isLit := e.(*ast.Literal); isLit {
68-
// Nested tuples/arrays are complex
69-
if lit.Type == ast.LiteralTuple || lit.Type == ast.LiteralArray {
68+
// Nested tuples that contain only primitive literals are OK
69+
if lit.Type == ast.LiteralTuple {
70+
if !containsOnlyPrimitiveLiteralsWithUnary(lit) {
71+
hasComplexExpr = true
72+
break
73+
}
74+
continue
75+
}
76+
// Arrays are always complex in tuple context
77+
if lit.Type == ast.LiteralArray {
7078
hasComplexExpr = true
7179
break
7280
}

internal/explain/functions.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,46 @@ func containsOnlyPrimitiveLiterals(lit *ast.Literal) bool {
322322
return true
323323
}
324324

325+
// containsOnlyPrimitiveLiteralsWithUnary is like containsOnlyPrimitiveLiterals but also handles
326+
// unary negation of numeric literals (e.g., -0., -123)
327+
func containsOnlyPrimitiveLiteralsWithUnary(lit *ast.Literal) bool {
328+
if lit.Type != ast.LiteralTuple {
329+
// Non-tuple literals are primitive
330+
return true
331+
}
332+
exprs, ok := lit.Value.([]ast.Expression)
333+
if !ok {
334+
return false
335+
}
336+
for _, e := range exprs {
337+
// Direct literal
338+
if innerLit, ok := e.(*ast.Literal); ok {
339+
// Recursively check nested tuples
340+
if innerLit.Type == ast.LiteralTuple {
341+
if !containsOnlyPrimitiveLiteralsWithUnary(innerLit) {
342+
return false
343+
}
344+
}
345+
// Arrays inside tuples make it complex
346+
if innerLit.Type == ast.LiteralArray {
347+
return false
348+
}
349+
continue
350+
}
351+
// Unary negation of numeric literal is also primitive
352+
if unary, ok := e.(*ast.UnaryExpr); ok && unary.Op == "-" {
353+
if innerLit, ok := unary.Operand.(*ast.Literal); ok {
354+
if innerLit.Type == ast.LiteralInteger || innerLit.Type == ast.LiteralFloat {
355+
continue
356+
}
357+
}
358+
}
359+
// Non-literal expression in tuple
360+
return false
361+
}
362+
return true
363+
}
364+
325365
// exprToLiteral converts a numeric expression to a literal (handles unary minus)
326366
func exprToLiteral(expr ast.Expression) *ast.Literal {
327367
if lit, ok := expr.(*ast.Literal); ok {

parser/testdata/00132_sets/metadata.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
{
22
"explain_todo": {
3-
"stmt11": true,
43
"stmt12": true,
54
"stmt6": true,
65
"stmt9": true
Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1 @@
1-
{
2-
"explain_todo": {
3-
"stmt3": true,
4-
"stmt4": true,
5-
"stmt5": true,
6-
"stmt6": true
7-
}
8-
}
1+
{}

parser/testdata/00945_bloom_filter_index/metadata.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
{
22
"explain_todo": {
3-
"stmt10": true,
43
"stmt152": true,
54
"stmt19": true,
65
"stmt20": true,
Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1 @@
1-
{
2-
"explain_todo": {
3-
"stmt13": true
4-
}
5-
}
1+
{}
Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1 @@
1-
{
2-
"explain_todo": {
3-
"stmt16": true,
4-
"stmt17": true,
5-
"stmt18": true
6-
}
7-
}
1+
{}
Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1 @@
1-
{
2-
"explain_todo": {
3-
"stmt1": true
4-
}
5-
}
1+
{}
Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1 @@
1-
{
2-
"explain_todo": {
3-
"stmt90": true
4-
}
5-
}
1+
{}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"explain_todo":{"stmt10":true,"stmt11":true,"stmt13":true}}
1+
{}

0 commit comments

Comments
 (0)