Skip to content

Commit 6aaa618

Browse files
committed
Fix empty tuple and WITH clause expression parsing
1. Fix WITH clause to only treat ( as subquery when followed by SELECT/WITH Previously (SELECT...) AS name was parsed even for empty () or expressions 2. Fix empty tuple EXPLAIN output to use Function tuple format Empty tuples should output "Function tuple (children 1)" with ExpressionList rather than "Literal Tuple_()" Fixes 41 tests including materialized views and WITH clause tests.
1 parent cf878e5 commit 6aaa618

41 files changed

Lines changed: 55 additions & 199 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

internal/explain/expressions.go

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -422,14 +422,18 @@ func explainAliasedExpr(sb *strings.Builder, n *ast.AliasedExpr, depth int) {
422422
// Check if this is a tuple with complex expressions that should be rendered as Function tuple
423423
if e.Type == ast.LiteralTuple {
424424
if exprs, ok := e.Value.([]ast.Expression); ok {
425-
hasComplexExpr := false
425+
needsFunctionFormat := false
426+
// Empty tuples always use Function tuple format
427+
if len(exprs) == 0 {
428+
needsFunctionFormat = true
429+
}
426430
for _, expr := range exprs {
427431
if _, isLit := expr.(*ast.Literal); !isLit {
428-
hasComplexExpr = true
432+
needsFunctionFormat = true
429433
break
430434
}
431435
}
432-
if hasComplexExpr {
436+
if needsFunctionFormat {
433437
// Render as Function tuple with alias
434438
fmt.Fprintf(sb, "%sFunction tuple (alias %s) (children %d)\n", indent, escapeAlias(n.Alias), 1)
435439
fmt.Fprintf(sb, "%s ExpressionList (children %d)\n", indent, len(exprs))
@@ -683,6 +687,18 @@ func explainWithElement(sb *strings.Builder, n *ast.WithElement, indent string,
683687
// When name is empty, don't show the alias part
684688
switch e := n.Query.(type) {
685689
case *ast.Literal:
690+
// Empty tuples should be rendered as Function tuple, not Literal
691+
if e.Type == ast.LiteralTuple {
692+
if exprs, ok := e.Value.([]ast.Expression); ok && len(exprs) == 0 {
693+
if n.Name != "" {
694+
fmt.Fprintf(sb, "%sFunction tuple (alias %s) (children %d)\n", indent, n.Name, 1)
695+
} else {
696+
fmt.Fprintf(sb, "%sFunction tuple (children %d)\n", indent, 1)
697+
}
698+
fmt.Fprintf(sb, "%s ExpressionList\n", indent)
699+
return
700+
}
701+
}
686702
if n.Name != "" {
687703
fmt.Fprintf(sb, "%sLiteral %s (alias %s)\n", indent, FormatLiteral(e), n.Name)
688704
} else {

parser/parser.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -819,8 +819,8 @@ func (p *Parser) parseWithClause() []ast.Expression {
819819
elem.Name = name
820820
elem.Query = &ast.Identifier{Position: pos, Parts: []string{name}}
821821
}
822-
} else if p.currentIs(token.LPAREN) {
823-
// Subquery: (SELECT ...) AS name
822+
} else if p.currentIs(token.LPAREN) && (p.peekIs(token.SELECT) || p.peekIs(token.WITH)) {
823+
// Subquery: (SELECT ...) AS name or (WITH ... SELECT ...) AS name
824824
// In this syntax, the alias goes on the Subquery, not on WithElement
825825
p.nextToken()
826826
subquery := p.parseSelectWithUnion()

parser/testdata/00101_materialized_views_and_insert_without_explicit_database/metadata.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
"stmt35": true,
44
"stmt36": true,
55
"stmt37": true,
6-
"stmt38": true,
7-
"stmt6": true,
8-
"stmt7": true
6+
"stmt38": true
97
}
108
}
Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1 @@
1-
{
2-
"explain_todo": {
3-
"stmt78": true
4-
}
5-
}
1+
{}
Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1 @@
1-
{
2-
"explain_todo": {
3-
"stmt10": true,
4-
"stmt16": true
5-
}
6-
}
1+
{}
Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1 @@
1-
{
2-
"explain_todo": {
3-
"stmt7": true
4-
}
5-
}
1+
{}
Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1 @@
1-
{
2-
"explain_todo": {
3-
"stmt5": true,
4-
"stmt6": true
5-
}
6-
}
1+
{}
Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1 @@
1-
{
2-
"explain_todo": {
3-
"stmt6": 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-
"stmt5": 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-
"stmt6": true,
4-
"stmt7": true,
5-
"stmt8": true
6-
}
7-
}
1+
{}

0 commit comments

Comments
 (0)