From 0336d3bc4ad1e87f98d55db5b41854e0e923b081 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 30 Dec 2025 08:17:54 +0000 Subject: [PATCH] Add DESCRIBE subquery support for DESCRIBE (SELECT ...) statements Add support for parsing DESCRIBE queries with subqueries, like `DESCRIBE (SELECT 1, 'Value')`. This required: - Adding TableExpr field to DescribeQuery struct in ast/ast.go - Updating parseDescribe() in parser/parser.go to detect and parse subqueries using the existing parseTableExpression() function - Updating explainDescribeQuery() in internal/explain/statements.go to output the TableExpression properly for subqueries This fixes 84 pending statements across multiple test files, including: - 02378_analyzer_projection_names (major fix) - 00515_shard_desc_table_functions_and_subqueries - 01549_low_cardinality_materialized_view - 01937_nested_chinese - 02096_sql_user_defined_function_alias - 02337_analyzer_columns_basic - 02338_analyzer_constants_basic - 02339_analyzer_matcher_basic - 02340_analyzer_functions - 02342_analyzer_compound_types - 03108_describe_union_all --- ast/ast.go | 13 +-- internal/explain/explain.go | 2 +- internal/explain/statements.go | 15 +++- parser/parser.go | 9 +- .../metadata.json | 8 +- .../metadata.json | 3 +- .../01937_nested_chinese/metadata.json | 8 +- .../metadata.json | 6 +- .../metadata.json | 15 +--- .../metadata.json | 14 +-- .../metadata.json | 10 --- .../02340_analyzer_functions/metadata.json | 9 +- .../metadata.json | 16 ---- .../metadata.json | 86 ------------------- .../03108_describe_union_all/metadata.json | 6 +- 15 files changed, 35 insertions(+), 185 deletions(-) diff --git a/ast/ast.go b/ast/ast.go index a0531fed64..525e7ad672 100644 --- a/ast/ast.go +++ b/ast/ast.go @@ -623,12 +623,13 @@ func (a *AttachQuery) statementNode() {} // DescribeQuery represents a DESCRIBE statement. type DescribeQuery struct { - Position token.Position `json:"-"` - Database string `json:"database,omitempty"` - Table string `json:"table,omitempty"` - TableFunction *FunctionCall `json:"table_function,omitempty"` - Settings []*SettingExpr `json:"settings,omitempty"` - Format string `json:"format,omitempty"` + Position token.Position `json:"-"` + Database string `json:"database,omitempty"` + Table string `json:"table,omitempty"` + TableFunction *FunctionCall `json:"table_function,omitempty"` + TableExpr *TableExpression `json:"table_expr,omitempty"` // For DESCRIBE (SELECT ...) + Settings []*SettingExpr `json:"settings,omitempty"` + Format string `json:"format,omitempty"` } func (d *DescribeQuery) Pos() token.Position { return d.Position } diff --git a/internal/explain/explain.go b/internal/explain/explain.go index 6275a5e4f4..2fd7d609d2 100644 --- a/internal/explain/explain.go +++ b/internal/explain/explain.go @@ -134,7 +134,7 @@ func Node(sb *strings.Builder, node interface{}, depth int) { case *ast.UseQuery: explainUseQuery(sb, n, indent) case *ast.DescribeQuery: - explainDescribeQuery(sb, n, indent) + explainDescribeQuery(sb, n, indent, depth) case *ast.ExistsQuery: explainExistsTableQuery(sb, n, indent) case *ast.DetachQuery: diff --git a/internal/explain/statements.go b/internal/explain/statements.go index 4622b2ec5f..00ef1a27a2 100644 --- a/internal/explain/statements.go +++ b/internal/explain/statements.go @@ -577,8 +577,19 @@ func explainUseQuery(sb *strings.Builder, n *ast.UseQuery, indent string) { fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.Database) } -func explainDescribeQuery(sb *strings.Builder, n *ast.DescribeQuery, indent string) { - if n.TableFunction != nil { +func explainDescribeQuery(sb *strings.Builder, n *ast.DescribeQuery, indent string, depth int) { + if n.TableExpr != nil { + // DESCRIBE on a subquery - TableExpr contains a TableExpression with a Subquery + children := 1 + if len(n.Settings) > 0 { + children++ + } + fmt.Fprintf(sb, "%sDescribeQuery (children %d)\n", indent, children) + Node(sb, n.TableExpr, depth+1) + if len(n.Settings) > 0 { + fmt.Fprintf(sb, "%s Set\n", indent) + } + } else if n.TableFunction != nil { // DESCRIBE on a table function - wrap in TableExpression children := 1 if len(n.Settings) > 0 { diff --git a/parser/parser.go b/parser/parser.go index bce7c7c26b..c09df4a5f7 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -3253,9 +3253,12 @@ func (p *Parser) parseDescribe() *ast.DescribeQuery { p.nextToken() } - // Parse table name or table function - // Table functions look like: format(CSV, '...'), url('...'), s3Cluster(...) - if p.currentIs(token.IDENT) || p.current.Token.IsKeyword() { + // Check for subquery: DESCRIBE (SELECT ...) + if p.currentIs(token.LPAREN) { + desc.TableExpr = p.parseTableExpression() + } else if p.currentIs(token.IDENT) || p.current.Token.IsKeyword() { + // Parse table name or table function + // Table functions look like: format(CSV, '...'), url('...'), s3Cluster(...) pos := p.current.Pos tableName := p.current.Value p.nextToken() diff --git a/parser/testdata/00515_shard_desc_table_functions_and_subqueries/metadata.json b/parser/testdata/00515_shard_desc_table_functions_and_subqueries/metadata.json index 23aecdaa08..0967ef424b 100644 --- a/parser/testdata/00515_shard_desc_table_functions_and_subqueries/metadata.json +++ b/parser/testdata/00515_shard_desc_table_functions_and_subqueries/metadata.json @@ -1,7 +1 @@ -{ - "explain_todo": { - "stmt12": true, - "stmt14": true, - "stmt16": true - } -} +{} diff --git a/parser/testdata/01549_low_cardinality_materialized_view/metadata.json b/parser/testdata/01549_low_cardinality_materialized_view/metadata.json index 8b0256d0ad..b65b07d7a6 100644 --- a/parser/testdata/01549_low_cardinality_materialized_view/metadata.json +++ b/parser/testdata/01549_low_cardinality_materialized_view/metadata.json @@ -1,6 +1,5 @@ { "explain_todo": { - "stmt4": true, - "stmt7": true + "stmt4": true } } diff --git a/parser/testdata/01937_nested_chinese/metadata.json b/parser/testdata/01937_nested_chinese/metadata.json index a4f8773303..0967ef424b 100644 --- a/parser/testdata/01937_nested_chinese/metadata.json +++ b/parser/testdata/01937_nested_chinese/metadata.json @@ -1,7 +1 @@ -{ - "explain_todo": { - "stmt3": true, - "stmt4": true, - "stmt5": true - } -} +{} diff --git a/parser/testdata/02096_sql_user_defined_function_alias/metadata.json b/parser/testdata/02096_sql_user_defined_function_alias/metadata.json index ef58f80315..0967ef424b 100644 --- a/parser/testdata/02096_sql_user_defined_function_alias/metadata.json +++ b/parser/testdata/02096_sql_user_defined_function_alias/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt2": true - } -} +{} diff --git a/parser/testdata/02337_analyzer_columns_basic/metadata.json b/parser/testdata/02337_analyzer_columns_basic/metadata.json index d7de92e31a..f505bca475 100644 --- a/parser/testdata/02337_analyzer_columns_basic/metadata.json +++ b/parser/testdata/02337_analyzer_columns_basic/metadata.json @@ -1,19 +1,6 @@ { "explain_todo": { - "stmt17": true, - "stmt20": true, - "stmt23": true, - "stmt26": true, - "stmt29": true, - "stmt3": true, - "stmt32": true, - "stmt35": true, "stmt42": true, - "stmt43": true, - "stmt45": true, - "stmt48": true, - "stmt51": true, - "stmt6": true, - "stmt9": true + "stmt43": true } } diff --git a/parser/testdata/02338_analyzer_constants_basic/metadata.json b/parser/testdata/02338_analyzer_constants_basic/metadata.json index b791443cfa..0967ef424b 100644 --- a/parser/testdata/02338_analyzer_constants_basic/metadata.json +++ b/parser/testdata/02338_analyzer_constants_basic/metadata.json @@ -1,13 +1 @@ -{ - "explain_todo": { - "stmt11": true, - "stmt14": true, - "stmt17": true, - "stmt2": true, - "stmt20": true, - "stmt23": true, - "stmt25": true, - "stmt5": true, - "stmt8": true - } -} +{} diff --git a/parser/testdata/02339_analyzer_matcher_basic/metadata.json b/parser/testdata/02339_analyzer_matcher_basic/metadata.json index 69cf8faf21..2295ed2cc2 100644 --- a/parser/testdata/02339_analyzer_matcher_basic/metadata.json +++ b/parser/testdata/02339_analyzer_matcher_basic/metadata.json @@ -4,14 +4,10 @@ "stmt103": true, "stmt105": true, "stmt106": true, - "stmt15": true, "stmt18": true, "stmt19": true, "stmt21": true, "stmt22": true, - "stmt24": true, - "stmt27": true, - "stmt3": true, "stmt30": true, "stmt31": true, "stmt33": true, @@ -20,7 +16,6 @@ "stmt37": true, "stmt42": true, "stmt43": true, - "stmt45": true, "stmt48": true, "stmt49": true, "stmt51": true, @@ -37,19 +32,14 @@ "stmt69": true, "stmt7": true, "stmt70": true, - "stmt72": true, - "stmt76": true, "stmt79": true, "stmt80": true, "stmt82": true, "stmt83": true, "stmt85": true, "stmt86": true, - "stmt89": true, - "stmt9": true, "stmt92": true, "stmt93": true, - "stmt95": true, "stmt98": true, "stmt99": true } diff --git a/parser/testdata/02340_analyzer_functions/metadata.json b/parser/testdata/02340_analyzer_functions/metadata.json index bcb9974e9e..0967ef424b 100644 --- a/parser/testdata/02340_analyzer_functions/metadata.json +++ b/parser/testdata/02340_analyzer_functions/metadata.json @@ -1,8 +1 @@ -{ - "explain_todo": { - "stmt11": true, - "stmt14": true, - "stmt2": true, - "stmt5": true - } -} +{} diff --git a/parser/testdata/02342_analyzer_compound_types/metadata.json b/parser/testdata/02342_analyzer_compound_types/metadata.json index 912daafa0d..3bb42e5f91 100644 --- a/parser/testdata/02342_analyzer_compound_types/metadata.json +++ b/parser/testdata/02342_analyzer_compound_types/metadata.json @@ -1,35 +1,19 @@ { "explain_todo": { - "stmt14": true, - "stmt17": true, - "stmt20": true, - "stmt23": true, - "stmt26": true, "stmt29": true, "stmt30": true, - "stmt32": true, "stmt35": true, "stmt36": true, - "stmt38": true, "stmt4": true, - "stmt41": true, - "stmt44": true, "stmt47": true, "stmt48": true, "stmt5": true, - "stmt50": true, "stmt53": true, "stmt54": true, "stmt6": true, - "stmt60": true, - "stmt63": true, - "stmt66": true, - "stmt69": true, "stmt7": true, - "stmt72": true, "stmt75": true, "stmt76": true, - "stmt78": true, "stmt8": true, "stmt81": true, "stmt82": true diff --git a/parser/testdata/02378_analyzer_projection_names/metadata.json b/parser/testdata/02378_analyzer_projection_names/metadata.json index 9b4055d3e5..a2a84ebabd 100644 --- a/parser/testdata/02378_analyzer_projection_names/metadata.json +++ b/parser/testdata/02378_analyzer_projection_names/metadata.json @@ -1,122 +1,36 @@ { "explain_todo": { "stmt101": true, - "stmt103": true, "stmt105": true, "stmt107": true, "stmt109": true, - "stmt111": true, "stmt113": true, - "stmt115": true, "stmt117": true, "stmt119": true, "stmt121": true, - "stmt123": true, "stmt125": true, - "stmt127": true, - "stmt129": true, - "stmt131": true, "stmt133": true, - "stmt135": true, - "stmt137": true, - "stmt139": true, "stmt141": true, - "stmt143": true, - "stmt145": true, - "stmt147": true, - "stmt149": true, - "stmt151": true, - "stmt153": true, - "stmt155": true, - "stmt157": true, - "stmt159": true, - "stmt161": true, - "stmt163": true, - "stmt165": true, - "stmt167": true, - "stmt169": true, - "stmt171": true, - "stmt173": true, - "stmt175": true, - "stmt177": true, - "stmt179": true, - "stmt181": true, - "stmt183": true, "stmt185": true, - "stmt187": true, - "stmt189": true, - "stmt191": true, - "stmt193": true, - "stmt195": true, - "stmt197": true, - "stmt199": true, - "stmt201": true, - "stmt203": true, "stmt205": true, "stmt207": true, - "stmt209": true, - "stmt21": true, - "stmt211": true, "stmt213": true, "stmt215": true, - "stmt217": true, - "stmt219": true, - "stmt221": true, - "stmt223": true, "stmt225": true, "stmt227": true, - "stmt229": true, - "stmt23": true, - "stmt231": true, "stmt233": true, "stmt235": true, - "stmt237": true, - "stmt239": true, - "stmt241": true, - "stmt243": true, - "stmt245": true, - "stmt247": true, - "stmt25": true, - "stmt250": true, - "stmt252": true, - "stmt254": true, - "stmt256": true, - "stmt258": true, - "stmt27": true, - "stmt29": true, "stmt31": true, "stmt33": true, - "stmt35": true, "stmt37": true, "stmt39": true, "stmt41": true, - "stmt43": true, - "stmt45": true, - "stmt47": true, - "stmt49": true, - "stmt51": true, - "stmt53": true, "stmt55": true, "stmt57": true, - "stmt59": true, - "stmt61": true, - "stmt63": true, - "stmt65": true, "stmt67": true, - "stmt69": true, - "stmt71": true, - "stmt73": true, - "stmt75": true, - "stmt77": true, - "stmt79": true, - "stmt81": true, - "stmt83": true, - "stmt85": true, - "stmt87": true, "stmt89": true, "stmt91": true, "stmt93": true, - "stmt95": true, "stmt97": true, "stmt99": true } diff --git a/parser/testdata/03108_describe_union_all/metadata.json b/parser/testdata/03108_describe_union_all/metadata.json index ef58f80315..0967ef424b 100644 --- a/parser/testdata/03108_describe_union_all/metadata.json +++ b/parser/testdata/03108_describe_union_all/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt2": true - } -} +{}