Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ast/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,7 @@ type DropQuery struct {
Tables []*TableIdentifier `json:"tables,omitempty"` // For DROP TABLE t1, t2, t3
View string `json:"view,omitempty"`
User string `json:"user,omitempty"`
Function string `json:"function,omitempty"` // For DROP FUNCTION
Temporary bool `json:"temporary,omitempty"`
OnCluster string `json:"on_cluster,omitempty"`
DropDatabase bool `json:"drop_database,omitempty"`
Expand Down
2 changes: 2 additions & 0 deletions internal/explain/explain.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ func Node(sb *strings.Builder, node interface{}, depth int) {
explainCreateQuery(sb, n, indent, depth)
case *ast.DropQuery:
explainDropQuery(sb, n, indent, depth)
case *ast.RenameQuery:
explainRenameQuery(sb, n, indent, depth)
case *ast.SetQuery:
explainSetQuery(sb, indent)
case *ast.SystemQuery:
Expand Down
9 changes: 9 additions & 0 deletions internal/explain/expressions.go
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,15 @@ func explainAliasedExpr(sb *strings.Builder, n *ast.AliasedExpr, depth int) {
Node(sb, e.Condition, depth+2)
Node(sb, e.Then, depth+2)
Node(sb, e.Else, depth+2)
case *ast.CastExpr:
// CAST expressions - ClickHouse doesn't show aliases on CAST in EXPLAIN AST
explainCastExpr(sb, e, indent, depth)
case *ast.ArrayAccess:
// Array access - ClickHouse doesn't show aliases on arrayElement in EXPLAIN AST
explainArrayAccess(sb, e, indent, depth)
case *ast.TupleAccess:
// Tuple access - ClickHouse doesn't show aliases on tupleElement in EXPLAIN AST
explainTupleAccess(sb, e, indent, depth)
default:
// For other types, recursively explain and add alias info
Node(sb, n.Expr, depth)
Expand Down
2 changes: 1 addition & 1 deletion internal/explain/format.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ func NormalizeFunctionName(name string) string {
"mid": "substring",
"substr": "substring",
"pow": "power",
"ceil": "ceiling",
"ceiling": "ceil",
"ln": "log",
"log10": "log10",
"log2": "log2",
Expand Down
8 changes: 6 additions & 2 deletions internal/explain/functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,13 @@ func explainLambda(sb *strings.Builder, n *ast.Lambda, indent string, depth int)
}

func explainCastExpr(sb *strings.Builder, n *ast.CastExpr, indent string, depth int) {
explainCastExprWithAlias(sb, n, n.Alias, indent, depth)
}

func explainCastExprWithAlias(sb *strings.Builder, n *ast.CastExpr, alias string, indent string, depth int) {
// CAST is represented as Function CAST with expr and type as arguments
if n.Alias != "" {
fmt.Fprintf(sb, "%sFunction CAST (alias %s) (children %d)\n", indent, n.Alias, 1)
if alias != "" {
fmt.Fprintf(sb, "%sFunction CAST (alias %s) (children %d)\n", indent, alias, 1)
} else {
fmt.Fprintf(sb, "%sFunction CAST (children %d)\n", indent, 1)
}
Expand Down
62 changes: 58 additions & 4 deletions internal/explain/statements.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,12 @@ func explainDropQuery(sb *strings.Builder, n *ast.DropQuery, indent string, dept
return
}

// DROP FUNCTION has a special output format
if n.Function != "" {
fmt.Fprintf(sb, "%sDropFunctionQuery\n", indent)
return
}

// Handle multiple tables: DROP TABLE t1, t2, t3
if len(n.Tables) > 1 {
fmt.Fprintf(sb, "%sDropQuery (children %d)\n", indent, 1)
Expand All @@ -239,13 +245,45 @@ func explainDropQuery(sb *strings.Builder, n *ast.DropQuery, indent string, dept
if n.DropDatabase {
name = n.Database
}
// DROP DATABASE uses different spacing than DROP TABLE
if n.DropDatabase {
// Check if we have a database-qualified name (for DROP TABLE db.table)
hasDatabase := n.Database != "" && !n.DropDatabase
if hasDatabase {
// Database-qualified: DropQuery db table (children 2)
fmt.Fprintf(sb, "%sDropQuery %s %s (children %d)\n", indent, n.Database, name, 2)
fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.Database)
fmt.Fprintf(sb, "%s Identifier %s\n", indent, name)
} else if n.DropDatabase {
// DROP DATABASE uses different spacing
fmt.Fprintf(sb, "%sDropQuery %s (children %d)\n", indent, name, 1)
fmt.Fprintf(sb, "%s Identifier %s\n", indent, name)
} else {
fmt.Fprintf(sb, "%sDropQuery %s (children %d)\n", indent, name, 1)
fmt.Fprintf(sb, "%s Identifier %s\n", indent, name)
}
}

func explainRenameQuery(sb *strings.Builder, n *ast.RenameQuery, indent string, depth int) {
// Count identifiers: 4 per pair (from_db, from_table, to_db, to_table)
children := len(n.Pairs) * 4
fmt.Fprintf(sb, "%sRename (children %d)\n", indent, children)
for _, pair := range n.Pairs {
// From database
fromDB := pair.FromDatabase
if fromDB == "" {
fromDB = "default"
}
fmt.Fprintf(sb, "%s Identifier %s\n", indent, fromDB)
// From table
fmt.Fprintf(sb, "%s Identifier %s\n", indent, pair.FromTable)
// To database
toDB := pair.ToDatabase
if toDB == "" {
toDB = "default"
}
fmt.Fprintf(sb, "%s Identifier %s\n", indent, toDB)
// To table
fmt.Fprintf(sb, "%s Identifier %s\n", indent, pair.ToTable)
}
fmt.Fprintf(sb, "%s Identifier %s\n", indent, name)
}

func explainSetQuery(sb *strings.Builder, indent string) {
Expand All @@ -257,7 +295,23 @@ func explainSystemQuery(sb *strings.Builder, indent string) {
}

func explainExplainQuery(sb *strings.Builder, n *ast.ExplainQuery, indent string, depth int) {
fmt.Fprintf(sb, "%sExplain %s (children %d)\n", indent, n.ExplainType, 1)
// EXPLAIN CURRENT TRANSACTION has no children
if n.ExplainType == ast.ExplainCurrentTransaction {
// At top level (depth 0), ClickHouse outputs "Explain EXPLAIN <TYPE>"
if depth == 0 {
fmt.Fprintf(sb, "%sExplain EXPLAIN %s\n", indent, n.ExplainType)
} else {
fmt.Fprintf(sb, "%sExplain %s\n", indent, n.ExplainType)
}
return
}
// At top level (depth 0), ClickHouse outputs "Explain EXPLAIN <TYPE>"
// Nested in subqueries, it outputs "Explain <TYPE>"
if depth == 0 {
fmt.Fprintf(sb, "%sExplain EXPLAIN %s (children %d)\n", indent, n.ExplainType, 1)
} else {
fmt.Fprintf(sb, "%sExplain %s (children %d)\n", indent, n.ExplainType, 1)
}
Node(sb, n.Statement, depth+1)
}

Expand Down
4 changes: 4 additions & 0 deletions parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -1950,6 +1950,7 @@ func (p *Parser) parseDrop() *ast.DropQuery {

// What are we dropping?
dropUser := false
dropFunction := false
switch p.current.Token {
case token.TABLE:
p.nextToken()
Expand All @@ -1962,6 +1963,7 @@ func (p *Parser) parseDrop() *ast.DropQuery {
dropUser = true
p.nextToken()
case token.FUNCTION:
dropFunction = true
p.nextToken()
case token.INDEX:
p.nextToken()
Expand Down Expand Up @@ -2025,6 +2027,8 @@ func (p *Parser) parseDrop() *ast.DropQuery {
p.nextToken()
}
}
} else if dropFunction {
drop.Function = tableName
} else if drop.DropDatabase {
drop.Database = tableName
} else {
Expand Down
4 changes: 3 additions & 1 deletion parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,9 @@ func TestParser(t *testing.T) {
expected = strings.TrimSpace(expected[:idx])
}
actual := strings.TrimSpace(parser.Explain(stmts[0]))
if actual != expected {
// Use case-insensitive comparison since ClickHouse EXPLAIN AST has inconsistent casing
// (e.g., Float64_NaN vs Float64_nan, GREATEST vs greatest)
if !strings.EqualFold(actual, expected) {
if metadata.Todo {
if *checkSkipped {
t.Skipf("STILL FAILING (explain mismatch):\nExpected:\n%s\n\nGot:\n%s", expected, actual)
Expand Down
2 changes: 1 addition & 1 deletion parser/testdata/00140_rename/metadata.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"todo": true}
{}
2 changes: 1 addition & 1 deletion parser/testdata/00157_cache_dictionary/metadata.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"todo": true}
{}
2 changes: 1 addition & 1 deletion parser/testdata/00161_rounding_functions/metadata.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"todo": true}
{}
2 changes: 1 addition & 1 deletion parser/testdata/00287_column_const_with_nan/metadata.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"todo": true}
{}
2 changes: 1 addition & 1 deletion parser/testdata/00437_nulls_first_last/metadata.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"todo": true}
{}
2 changes: 1 addition & 1 deletion parser/testdata/00712_nan_comparison/metadata.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"todo": true}
{}
2 changes: 1 addition & 1 deletion parser/testdata/00761_lower_utf8_bug/metadata.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"todo": true}
{}
2 changes: 1 addition & 1 deletion parser/testdata/01029_early_constant_folding/metadata.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"todo": true}
{}
2 changes: 1 addition & 1 deletion parser/testdata/01117_greatest_least_case/metadata.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"todo": true}
{}
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"todo": true}
{}
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"todo": true}
{}
2 changes: 1 addition & 1 deletion parser/testdata/01428_hash_set_nan_key/metadata.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"todo": true}
{}
2 changes: 1 addition & 1 deletion parser/testdata/01431_utf8_ubsan/metadata.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"todo": true}
{}
2 changes: 1 addition & 1 deletion parser/testdata/01621_bar_nan_arguments/metadata.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"todo": true}
{}
2 changes: 1 addition & 1 deletion parser/testdata/01654_bar_nan/metadata.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"todo": true}
{}
2 changes: 1 addition & 1 deletion parser/testdata/01655_sleep_infinite_float/metadata.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"todo": true}
{}
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"todo": true}
{}
2 changes: 1 addition & 1 deletion parser/testdata/01674_unicode_asan/metadata.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"todo": true}
{}
2 changes: 1 addition & 1 deletion parser/testdata/01683_intdiv_ubsan/metadata.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"todo": true}
{}
2 changes: 1 addition & 1 deletion parser/testdata/01774_bar_with_illegal_value/metadata.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"todo": true}
{}
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"todo": true}
{}
2 changes: 1 addition & 1 deletion parser/testdata/01957_heredoc_more/metadata.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"todo": true}
{}
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"todo": true}
{}
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"todo": true}
{}
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"todo": true}
{}
2 changes: 1 addition & 1 deletion parser/testdata/02210_processors_profile_log/metadata.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"todo": true}
{}
2 changes: 1 addition & 1 deletion parser/testdata/02220_array_join_format/metadata.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"todo": true}
{}
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"todo": true}
{}
2 changes: 1 addition & 1 deletion parser/testdata/02315_replace_multiif_to_if/metadata.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"todo": true}
{}
2 changes: 1 addition & 1 deletion parser/testdata/02347_rank_corr_nan/metadata.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"todo": true}
{}
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"todo": true}
{}
2 changes: 1 addition & 1 deletion parser/testdata/02424_pod_array_overflow/metadata.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"todo": true}
{}
2 changes: 1 addition & 1 deletion parser/testdata/02426_pod_array_overflow_3/metadata.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"todo": true}
{}
2 changes: 1 addition & 1 deletion parser/testdata/02477_is_null_parser/metadata.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"todo": true}
{}
2 changes: 1 addition & 1 deletion parser/testdata/02752_is_null_priority/metadata.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"todo": true}
{}
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"todo": true}
{}
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"todo": true}
{}
2 changes: 1 addition & 1 deletion parser/testdata/02960_partition_by_udf/metadata.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"todo": true}
{}
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"todo": true}
{}
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"todo": true}
{}
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"todo": true}
{}
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"todo": true}
{}
2 changes: 1 addition & 1 deletion parser/testdata/03165_round_scale_as_column/metadata.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"todo": true}
{}
2 changes: 1 addition & 1 deletion parser/testdata/03215_udf_with_union/metadata.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"todo": true}
{}