Skip to content

Commit 841bf14

Browse files
committed
Fix SETTINGS placement in EXPLAIN AST for FORMAT...SETTINGS syntax
When SETTINGS comes after FORMAT in a query (e.g., "SELECT * FORMAT Null SETTINGS..."), the Set node should only appear at the SelectWithUnionQuery level, not at the SelectQuery level. This matches ClickHouse's EXPLAIN AST behavior. Added SettingsAfterFormat field to SelectQuery AST to track this ordering. This fixes 156+ explain tests that were previously failing.
1 parent 4821721 commit 841bf14

3 files changed

Lines changed: 20 additions & 24 deletions

File tree

ast/ast.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,8 @@ type SelectQuery struct {
7575
LimitBy []Expression `json:"limit_by,omitempty"`
7676
LimitByHasLimit bool `json:"limit_by_has_limit,omitempty"` // true if LIMIT BY was followed by another LIMIT
7777
Offset Expression `json:"offset,omitempty"`
78-
Settings []*SettingExpr `json:"settings,omitempty"`
78+
Settings []*SettingExpr `json:"settings,omitempty"`
79+
SettingsAfterFormat bool `json:"settings_after_format,omitempty"` // true if SETTINGS came after FORMAT
7980
IntoOutfile *IntoOutfileClause `json:"into_outfile,omitempty"`
8081
Format *Identifier `json:"format,omitempty"`
8182
}

internal/explain/select.go

Lines changed: 17 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -36,21 +36,18 @@ func explainSelectWithUnionQuery(sb *strings.Builder, n *ast.SelectWithUnionQuer
3636
}
3737
}
3838
// FORMAT clause - check if any SelectQuery has Format set
39-
var hasFormat bool
4039
for _, sel := range n.Selects {
4140
if sq, ok := sel.(*ast.SelectQuery); ok && sq.Format != nil {
4241
Node(sb, sq.Format, depth+1)
43-
hasFormat = true
4442
break
4543
}
4644
}
47-
// When FORMAT is present, SETTINGS is output at SelectWithUnionQuery level
48-
if hasFormat {
49-
for _, sel := range n.Selects {
50-
if sq, ok := sel.(*ast.SelectQuery); ok && len(sq.Settings) > 0 {
51-
fmt.Fprintf(sb, "%s Set\n", indent)
52-
break
53-
}
45+
// When SETTINGS comes AFTER FORMAT, it is ALSO output at SelectWithUnionQuery level
46+
// (in addition to being at SelectQuery level)
47+
for _, sel := range n.Selects {
48+
if sq, ok := sel.(*ast.SelectQuery); ok && sq.SettingsAfterFormat && len(sq.Settings) > 0 {
49+
fmt.Fprintf(sb, "%s Set\n", indent)
50+
break
5451
}
5552
}
5653
}
@@ -126,8 +123,9 @@ func explainSelectQuery(sb *strings.Builder, n *ast.SelectQuery, indent string,
126123
Node(sb, expr, depth+2)
127124
}
128125
}
129-
// SETTINGS - output here if there's no FORMAT, otherwise it's at SelectWithUnionQuery level
130-
if len(n.Settings) > 0 && n.Format == nil {
126+
// SETTINGS - output at SelectQuery level only if NOT after FORMAT
127+
// When SETTINGS comes after FORMAT, it's only at SelectWithUnionQuery level
128+
if len(n.Settings) > 0 && !n.SettingsAfterFormat {
131129
fmt.Fprintf(sb, "%s Set\n", indent)
132130
}
133131
}
@@ -235,21 +233,17 @@ func countSelectUnionChildren(n *ast.SelectWithUnionQuery) int {
235233
}
236234
}
237235
// Check if any SelectQuery has Format set
238-
var hasFormat bool
239236
for _, sel := range n.Selects {
240237
if sq, ok := sel.(*ast.SelectQuery); ok && sq.Format != nil {
241238
count++
242-
hasFormat = true
243239
break
244240
}
245241
}
246-
// When FORMAT is present, SETTINGS is counted at this level
247-
if hasFormat {
248-
for _, sel := range n.Selects {
249-
if sq, ok := sel.(*ast.SelectQuery); ok && len(sq.Settings) > 0 {
250-
count++
251-
break
252-
}
242+
// When SETTINGS comes AFTER FORMAT, it is ALSO counted at this level
243+
for _, sel := range n.Selects {
244+
if sq, ok := sel.(*ast.SelectQuery); ok && sq.SettingsAfterFormat && len(sq.Settings) > 0 {
245+
count++
246+
break
253247
}
254248
}
255249
return count
@@ -390,9 +384,9 @@ func countSelectQueryChildren(n *ast.SelectQuery) int {
390384
if n.Offset != nil {
391385
count++
392386
}
393-
// SETTINGS is counted here only if there's no FORMAT
394-
// If FORMAT is present, SETTINGS is at SelectWithUnionQuery level
395-
if len(n.Settings) > 0 && n.Format == nil {
387+
// SETTINGS is counted at SelectQuery level only if NOT after FORMAT
388+
// When SETTINGS comes after FORMAT, it's only counted at SelectWithUnionQuery level
389+
if len(n.Settings) > 0 && !n.SettingsAfterFormat {
396390
count++
397391
}
398392
return count

parser/parser.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,7 @@ func (p *Parser) parseSelect() *ast.SelectQuery {
595595
if p.currentIs(token.SETTINGS) {
596596
p.nextToken()
597597
sel.Settings = p.parseSettingsList()
598+
sel.SettingsAfterFormat = true
598599
}
599600

600601
return sel

0 commit comments

Comments
 (0)