diff --git a/ast/ast.go b/ast/ast.go index c724583cf4..f1f9f1a0a8 100644 --- a/ast/ast.go +++ b/ast/ast.go @@ -637,6 +637,7 @@ func (p *Projection) End() token.Position { return p.Position } // ProjectionSelectQuery represents the SELECT part of a projection. type ProjectionSelectQuery struct { Position token.Position `json:"-"` + With []Expression `json:"with,omitempty"` // WITH clause expressions Columns []Expression `json:"columns"` GroupBy []Expression `json:"group_by,omitempty"` OrderBy []Expression `json:"order_by,omitempty"` // ORDER BY columns @@ -700,6 +701,7 @@ const ( AlterModifyOrderBy AlterCommandType = "MODIFY_ORDER_BY" AlterModifySampleBy AlterCommandType = "MODIFY_SAMPLE_BY" AlterRemoveSampleBy AlterCommandType = "REMOVE_SAMPLE_BY" + AlterApplyDeletedMask AlterCommandType = "APPLY_DELETED_MASK" ) // TruncateQuery represents a TRUNCATE statement. @@ -983,6 +985,7 @@ type RenameQuery struct { To string `json:"to,omitempty"` // Deprecated: for backward compat OnCluster string `json:"on_cluster,omitempty"` Settings []*SettingExpr `json:"settings,omitempty"` + IfExists bool `json:"if_exists,omitempty"` // IF EXISTS modifier } func (r *RenameQuery) Pos() token.Position { return r.Position } diff --git a/internal/explain/expressions.go b/internal/explain/expressions.go index 43a87b1765..67e9bd7f26 100644 --- a/internal/explain/expressions.go +++ b/internal/explain/expressions.go @@ -211,6 +211,31 @@ func isSimpleLiteralOrNegation(e ast.Expression) bool { return false } +// isSimpleLiteralOrNestedLiteral checks if an expression is a literal (including nested tuples/arrays of literals) +// Returns false for complex expressions like subqueries, function calls, identifiers, etc. +func isSimpleLiteralOrNestedLiteral(e ast.Expression) bool { + if lit, ok := e.(*ast.Literal); ok { + // For nested arrays/tuples, recursively check if all elements are also literals + if lit.Type == ast.LiteralArray || lit.Type == ast.LiteralTuple { + if exprs, ok := lit.Value.([]ast.Expression); ok { + for _, elem := range exprs { + if !isSimpleLiteralOrNestedLiteral(elem) { + return false + } + } + } + } + return true + } + // Unary minus of a literal integer/float is also simple (negative number) + if unary, ok := e.(*ast.UnaryExpr); ok && unary.Op == "-" { + if lit, ok := unary.Operand.(*ast.Literal); ok { + return lit.Type == ast.LiteralInteger || lit.Type == ast.LiteralFloat + } + } + return false +} + // containsOnlyArraysOrTuples checks if a slice of expressions contains // only array or tuple literals (including empty arrays). // Returns true if the slice is empty or contains only arrays/tuples. @@ -952,16 +977,39 @@ func explainWithElement(sb *strings.Builder, n *ast.WithElement, indent string, // When name is empty, don't show the alias part switch e := n.Query.(type) { case *ast.Literal: - // Empty tuples should be rendered as Function tuple, not Literal + // Tuples containing complex expressions (subqueries, function calls, etc) should be rendered as Function tuple + // But tuples of simple literals (including nested tuples of literals) stay as Literal if e.Type == ast.LiteralTuple { - if exprs, ok := e.Value.([]ast.Expression); ok && len(exprs) == 0 { - if n.Name != "" { - fmt.Fprintf(sb, "%sFunction tuple (alias %s) (children %d)\n", indent, n.Name, 1) + if exprs, ok := e.Value.([]ast.Expression); ok { + needsFunctionFormat := false + // Empty tuples always use Function tuple format + if len(exprs) == 0 { + needsFunctionFormat = true } else { - fmt.Fprintf(sb, "%sFunction tuple (children %d)\n", indent, 1) + for _, expr := range exprs { + // Check if any element is a truly complex expression (not just a literal) + if !isSimpleLiteralOrNestedLiteral(expr) { + needsFunctionFormat = true + break + } + } + } + if needsFunctionFormat { + if n.Name != "" { + fmt.Fprintf(sb, "%sFunction tuple (alias %s) (children %d)\n", indent, n.Name, 1) + } else { + fmt.Fprintf(sb, "%sFunction tuple (children %d)\n", indent, 1) + } + if len(exprs) > 0 { + fmt.Fprintf(sb, "%s ExpressionList (children %d)\n", indent, len(exprs)) + } else { + fmt.Fprintf(sb, "%s ExpressionList\n", indent) + } + for _, expr := range exprs { + Node(sb, expr, depth+2) + } + return } - fmt.Fprintf(sb, "%s ExpressionList\n", indent) - return } } // Arrays containing non-literal expressions should be rendered as Function array @@ -1064,6 +1112,36 @@ func explainWithElement(sb *strings.Builder, n *ast.WithElement, indent string, explainArrayAccessWithAlias(sb, e, n.Name, indent, depth) case *ast.BetweenExpr: explainBetweenExprWithAlias(sb, e, n.Name, indent, depth) + case *ast.UnaryExpr: + // For unary minus with numeric literal, output as negative literal with alias + if e.Op == "-" { + if lit, ok := e.Operand.(*ast.Literal); ok && (lit.Type == ast.LiteralInteger || lit.Type == ast.LiteralFloat) { + // Format as negative literal + negLit := &ast.Literal{ + Position: lit.Position, + Type: lit.Type, + Value: lit.Value, + } + if n.Name != "" { + fmt.Fprintf(sb, "%sLiteral %s (alias %s)\n", indent, formatNegativeLiteral(negLit), n.Name) + } else { + fmt.Fprintf(sb, "%sLiteral %s\n", indent, formatNegativeLiteral(negLit)) + } + return + } + } + // For other unary expressions, output as function + fnName := "negate" + if e.Op == "NOT" { + fnName = "not" + } + if n.Name != "" { + fmt.Fprintf(sb, "%sFunction %s (alias %s) (children %d)\n", indent, fnName, n.Name, 1) + } else { + fmt.Fprintf(sb, "%sFunction %s (children %d)\n", indent, fnName, 1) + } + fmt.Fprintf(sb, "%s ExpressionList (children %d)\n", indent, 1) + Node(sb, e.Operand, depth+2) default: // For other types, just output the expression (alias may be lost) Node(sb, n.Query, depth) diff --git a/internal/explain/format.go b/internal/explain/format.go index e9e5711611..1cb9efa886 100644 --- a/internal/explain/format.go +++ b/internal/explain/format.go @@ -144,6 +144,26 @@ func FormatLiteral(lit *ast.Literal) string { } } +// formatNegativeLiteral formats a numeric literal with a negative sign prepended +func formatNegativeLiteral(lit *ast.Literal) string { + switch lit.Type { + case ast.LiteralInteger: + switch val := lit.Value.(type) { + case int64: + return fmt.Sprintf("Int64_-%d", val) + case uint64: + return fmt.Sprintf("Int64_-%d", val) + default: + return fmt.Sprintf("Int64_-%v", lit.Value) + } + case ast.LiteralFloat: + val := lit.Value.(float64) + return fmt.Sprintf("Float64_-%s", FormatFloat(val)) + default: + return fmt.Sprintf("-%v", lit.Value) + } +} + // formatArrayLiteral formats an array literal for EXPLAIN AST output func formatArrayLiteral(val interface{}) string { exprs, ok := val.([]ast.Expression) diff --git a/internal/explain/functions.go b/internal/explain/functions.go index 53870ed619..c0cd00fcde 100644 --- a/internal/explain/functions.go +++ b/internal/explain/functions.go @@ -1133,7 +1133,12 @@ func explainInExpr(sb *strings.Builder, n *ast.InExpr, indent string, depth int) fmt.Fprintf(sb, "%s Function tuple (children %d)\n", indent, 1) if allParenthesizedPrimitives { // Expand the elements - fmt.Fprintf(sb, "%s ExpressionList (children %d)\n", indent, len(elems)) + // For empty tuples, don't include children count + if len(elems) == 0 { + fmt.Fprintf(sb, "%s ExpressionList\n", indent) + } else { + fmt.Fprintf(sb, "%s ExpressionList (children %d)\n", indent, len(elems)) + } for _, elem := range elems { Node(sb, elem, depth+4) } diff --git a/internal/explain/select.go b/internal/explain/select.go index 4adc1023a4..543a6e855f 100644 --- a/internal/explain/select.go +++ b/internal/explain/select.go @@ -298,8 +298,13 @@ func explainSelectWithUnionQuery(sb *strings.Builder, n *ast.SelectWithUnionQuer // ClickHouse optimizes UNION ALL when selects have identical expressions but different aliases. // In that case, only the first SELECT is shown since column names come from the first SELECT anyway. selects := simplifyUnionSelects(n.Selects) + + // Check if we need to group selects due to mode changes + // e.g., A UNION DISTINCT B UNION ALL C -> (A UNION DISTINCT B) UNION ALL C + groupedSelects := groupSelectsByUnionMode(selects, n.UnionModes) + // Wrap selects in ExpressionList - fmt.Fprintf(sb, "%s ExpressionList (children %d)\n", indent, len(selects)) + fmt.Fprintf(sb, "%s ExpressionList (children %d)\n", indent, len(groupedSelects)) // Check if first operand has a WITH clause to be inherited by subsequent operands var inheritedWith []ast.Expression @@ -307,7 +312,7 @@ func explainSelectWithUnionQuery(sb *strings.Builder, n *ast.SelectWithUnionQuer inheritedWith = extractWithClause(selects[0]) } - for i, sel := range selects { + for i, sel := range groupedSelects { if i > 0 && len(inheritedWith) > 0 { // Subsequent operands inherit the WITH clause from the first operand explainSelectQueryWithInheritedWith(sb, sel, inheritedWith, depth+2) @@ -620,6 +625,62 @@ func simplifyUnionSelects(selects []ast.Statement) []ast.Statement { return selects } +// groupSelectsByUnionMode groups selects when union modes change from DISTINCT to ALL. +// For example, A UNION DISTINCT B UNION ALL C becomes (A UNION DISTINCT B) UNION ALL C. +// This matches ClickHouse's EXPLAIN AST output which nests DISTINCT groups before ALL. +// Note: The reverse (ALL followed by DISTINCT) does NOT trigger nesting. +func groupSelectsByUnionMode(selects []ast.Statement, unionModes []string) []ast.Statement { + if len(selects) < 3 || len(unionModes) < 2 { + return selects + } + + // Normalize union modes (strip "UNION " prefix if present) + normalizeMode := func(mode string) string { + if len(mode) > 6 && mode[:6] == "UNION " { + return mode[6:] + } + return mode + } + + // Only group when DISTINCT transitions to ALL + // Find first DISTINCT mode, then check if it's followed by ALL + firstMode := normalizeMode(unionModes[0]) + if firstMode != "DISTINCT" { + return selects + } + + // Find where DISTINCT ends and ALL begins + modeChangeIdx := -1 + for i := 1; i < len(unionModes); i++ { + if normalizeMode(unionModes[i]) == "ALL" { + modeChangeIdx = i + break + } + } + + // If no DISTINCT->ALL transition found, return as-is + if modeChangeIdx == -1 { + return selects + } + + // Create a nested SelectWithUnionQuery for selects 0..modeChangeIdx (inclusive) + // modeChangeIdx is the index of the union operator, so we include selects[0] through selects[modeChangeIdx] + nestedSelects := selects[:modeChangeIdx+1] + nestedModes := unionModes[:modeChangeIdx] + + nested := &ast.SelectWithUnionQuery{ + Selects: nestedSelects, + UnionModes: nestedModes, + } + + // Result is [nested, selects[modeChangeIdx+1], ...] + result := make([]ast.Statement, 0, len(selects)-modeChangeIdx) + result = append(result, nested) + result = append(result, selects[modeChangeIdx+1:]...) + + return result +} + func countSelectQueryChildren(n *ast.SelectQuery) int { count := 1 // columns ExpressionList // WITH clause diff --git a/internal/explain/statements.go b/internal/explain/statements.go index 93c582e590..ed66b7c4cc 100644 --- a/internal/explain/statements.go +++ b/internal/explain/statements.go @@ -446,7 +446,13 @@ func explainCreateQuery(sb *strings.Builder, n *ast.CreateQuery, indent string, if len(n.OrderBy) > 0 { if len(n.OrderBy) == 1 { if ident, ok := n.OrderBy[0].(*ast.Identifier); ok { - fmt.Fprintf(sb, "%s Identifier %s\n", storageIndent, ident.Name()) + // When ORDER BY has modifiers (ASC/DESC), wrap in StorageOrderByElement + if n.OrderByHasModifiers { + fmt.Fprintf(sb, "%s StorageOrderByElement (children %d)\n", storageIndent, 1) + fmt.Fprintf(sb, "%s Identifier %s\n", storageIndent, ident.Name()) + } else { + fmt.Fprintf(sb, "%s Identifier %s\n", storageIndent, ident.Name()) + } } else if lit, ok := n.OrderBy[0].(*ast.Literal); ok && lit.Type == ast.LiteralTuple { // Handle tuple literal - for ORDER BY with modifiers (DESC/ASC), // ClickHouse outputs just "Function tuple" without children @@ -1620,6 +1626,10 @@ func explainAlterCommand(sb *strings.Builder, cmd *ast.AlterCommand, indent stri if cmdType == ast.AlterClearStatistics { cmdType = ast.AlterDropStatistics } + // ATTACH PARTITION ... FROM table is shown as REPLACE_PARTITION in EXPLAIN AST + if cmdType == ast.AlterAttachPartition && cmd.FromTable != "" { + cmdType = ast.AlterReplacePartition + } // DETACH_PARTITION is shown as DROP_PARTITION in EXPLAIN AST if cmdType == ast.AlterDetachPartition { cmdType = ast.AlterDropPartition @@ -1802,7 +1812,7 @@ func explainAlterCommand(sb *strings.Builder, cmd *ast.AlterCommand, indent stri case ast.AlterModifySetting: fmt.Fprintf(sb, "%s Set\n", indent) case ast.AlterDropPartition, ast.AlterDetachPartition, ast.AlterAttachPartition, - ast.AlterReplacePartition, ast.AlterFetchPartition, ast.AlterMovePartition, ast.AlterFreezePartition, ast.AlterApplyPatches: + ast.AlterReplacePartition, ast.AlterFetchPartition, ast.AlterMovePartition, ast.AlterFreezePartition, ast.AlterApplyPatches, ast.AlterApplyDeletedMask: if cmd.Partition != nil { // PARTITION ALL is shown as Partition_ID (empty) in EXPLAIN AST if ident, ok := cmd.Partition.(*ast.Identifier); ok && strings.ToUpper(ident.Name()) == "ALL" { @@ -1910,6 +1920,9 @@ func explainProjection(sb *strings.Builder, p *ast.Projection, indent string, de func explainProjectionSelectQuery(sb *strings.Builder, q *ast.ProjectionSelectQuery, indent string, depth int) { children := 0 + if len(q.With) > 0 { + children++ + } if len(q.Columns) > 0 { children++ } @@ -1920,6 +1933,13 @@ func explainProjectionSelectQuery(sb *strings.Builder, q *ast.ProjectionSelectQu children++ } fmt.Fprintf(sb, "%sProjectionSelectQuery (children %d)\n", indent, children) + // Output WITH clause first + if len(q.With) > 0 { + fmt.Fprintf(sb, "%s ExpressionList (children %d)\n", indent, len(q.With)) + for _, w := range q.With { + Node(sb, w, depth+2) + } + } if len(q.Columns) > 0 { fmt.Fprintf(sb, "%s ExpressionList (children %d)\n", indent, len(q.Columns)) for _, col := range q.Columns { @@ -2085,7 +2105,7 @@ func countAlterCommandChildren(cmd *ast.AlterCommand) int { case ast.AlterModifySetting: children = 1 case ast.AlterDropPartition, ast.AlterDetachPartition, ast.AlterAttachPartition, - ast.AlterReplacePartition, ast.AlterFetchPartition, ast.AlterMovePartition, ast.AlterFreezePartition, ast.AlterApplyPatches: + ast.AlterReplacePartition, ast.AlterFetchPartition, ast.AlterMovePartition, ast.AlterFreezePartition, ast.AlterApplyPatches, ast.AlterApplyDeletedMask: if cmd.Partition != nil { children++ } diff --git a/parser/parser.go b/parser/parser.go index a4affacc8e..fd6636e927 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -2626,7 +2626,13 @@ func (p *Parser) parseTableOptions(create *ast.CreateQuery) { } } else { // Use ALIAS_PREC to avoid consuming AS keyword (for AS SELECT) - create.OrderBy = []ast.Expression{p.parseExpression(ALIAS_PREC)} + expr := p.parseExpression(ALIAS_PREC) + create.OrderBy = []ast.Expression{expr} + // Handle ASC/DESC modifier after single non-parenthesized ORDER BY expression + if p.currentIs(token.ASC) || p.currentIs(token.DESC) { + create.OrderByHasModifiers = true + p.nextToken() + } } } case p.currentIs(token.PRIMARY): @@ -5817,6 +5823,14 @@ func (p *Parser) parseAlterCommand() *ast.AlterCommand { cmd.PartitionIsID = true } cmd.Partition = p.parseExpression(LOWEST) + // Handle FROM table (ATTACH PARTITION ... FROM table) + if p.currentIs(token.FROM) { + p.nextToken() + if p.currentIs(token.IDENT) || p.current.Token.IsKeyword() { + cmd.FromTable = p.current.Value + p.nextToken() + } + } } else if p.currentIs(token.IDENT) && strings.ToUpper(p.current.Value) == "PART" { // ATTACH PART uses ATTACH_PARTITION type in ClickHouse EXPLAIN cmd.Type = ast.AlterAttachPartition @@ -5879,6 +5893,7 @@ func (p *Parser) parseAlterCommand() *ast.AlterCommand { } case token.APPLY: // APPLY PATCHES IN PARTITION expr + // APPLY DELETED MASK [IN PARTITION expr] p.nextToken() // skip APPLY if p.currentIs(token.IDENT) && strings.ToUpper(p.current.Value) == "PATCHES" { p.nextToken() // skip PATCHES @@ -5890,6 +5905,19 @@ func (p *Parser) parseAlterCommand() *ast.AlterCommand { cmd.Partition = p.parseExpression(LOWEST) } } + } else if p.currentIs(token.IDENT) && strings.ToUpper(p.current.Value) == "DELETED" { + p.nextToken() // skip DELETED + if p.currentIs(token.IDENT) && strings.ToUpper(p.current.Value) == "MASK" { + p.nextToken() // skip MASK + cmd.Type = ast.AlterApplyDeletedMask + if p.currentIs(token.IN) { + p.nextToken() // skip IN + if p.currentIs(token.PARTITION) { + p.nextToken() // skip PARTITION + cmd.Partition = p.parseExpression(LOWEST) + } + } + } } case token.DELETE: // DELETE WHERE condition - mutation to delete rows @@ -6367,6 +6395,13 @@ func (p *Parser) parseShow() ast.Statement { case token.SETTINGS: show.ShowType = ast.ShowSettings p.nextToken() + case token.FULL: + // SHOW FULL COLUMNS/FIELDS FROM table - treat as ShowColumns + p.nextToken() + if p.currentIs(token.COLUMNS) || (p.currentIs(token.IDENT) && strings.ToUpper(p.current.Value) == "FIELDS") { + p.nextToken() + } + show.ShowType = ast.ShowColumns default: // Handle SHOW PROCESSLIST, SHOW DICTIONARIES, SHOW FUNCTIONS, etc. if p.currentIs(token.IDENT) { @@ -6380,9 +6415,18 @@ func (p *Parser) parseShow() ast.Statement { show.ShowType = ast.ShowFunctions case "SETTING": show.ShowType = ast.ShowSetting - case "INDEXES", "INDICES", "KEYS": - // SHOW INDEXES/INDICES/KEYS FROM table - treat as ShowColumns + case "INDEXES", "INDICES", "KEYS", "FIELDS": + // SHOW INDEXES/INDICES/KEYS/FIELDS FROM table - treat as ShowColumns + show.ShowType = ast.ShowColumns + case "FULL": + // SHOW FULL COLUMNS/FIELDS FROM table - treat as ShowColumns + p.nextToken() + if p.currentIs(token.COLUMNS) || (p.currentIs(token.IDENT) && strings.ToUpper(p.current.Value) == "FIELDS") { + p.nextToken() + } show.ShowType = ast.ShowColumns + // Don't consume another token, fall through to FROM parsing + goto parseFrom case "EXTENDED": // SHOW EXTENDED INDEX FROM table - treat as ShowColumns p.nextToken() @@ -6771,6 +6815,7 @@ func (p *Parser) parseSystem() *ast.SystemQuery { upperCmd := strings.ToUpper(sys.Command) if strings.Contains(upperCmd, "RELOAD DICTIONARY") || strings.Contains(upperCmd, "DROP REPLICA") || + strings.Contains(upperCmd, "RESTORE REPLICA") || strings.Contains(upperCmd, "STOP DISTRIBUTED SENDS") || strings.Contains(upperCmd, "START DISTRIBUTED SENDS") || strings.Contains(upperCmd, "FLUSH DISTRIBUTED") { @@ -6803,7 +6848,7 @@ func (p *Parser) parseSystem() *ast.SystemQuery { func (p *Parser) isSystemCommandKeyword() bool { switch p.current.Token { case token.TTL, token.SYNC, token.DROP, token.FORMAT, token.FOR, token.INDEX, token.INSERT, - token.PRIMARY, token.KEY, token.DISTRIBUTED: + token.PRIMARY, token.KEY, token.DISTRIBUTED, token.RESTORE: return true } // Handle identifiers that are part of SYSTEM commands (not table names) @@ -6848,6 +6893,13 @@ func (p *Parser) parseRename() *ast.RenameQuery { return nil } + // Handle IF EXISTS after TABLE/DICTIONARY + if p.currentIs(token.IF) && p.peekIs(token.EXISTS) { + p.nextToken() // skip IF + p.nextToken() // skip EXISTS + rename.IfExists = true + } + // Parse rename pairs (can have multiple: t1 TO t2, t3 TO t4, ...) for { pair := &ast.RenamePair{} @@ -7762,6 +7814,12 @@ func (p *Parser) parseProjection() *ast.Projection { Position: p.current.Pos, } + // Parse WITH clause if present + if p.currentIs(token.WITH) { + p.nextToken() // skip WITH + proj.Select.With = p.parseWithClause() + } + // Parse SELECT keyword (optional in projection) if p.currentIs(token.SELECT) { p.nextToken() diff --git a/parser/testdata/00626_replace_partition_from_table/metadata.json b/parser/testdata/00626_replace_partition_from_table/metadata.json index cc4446e67a..0967ef424b 100644 --- a/parser/testdata/00626_replace_partition_from_table/metadata.json +++ b/parser/testdata/00626_replace_partition_from_table/metadata.json @@ -1,6 +1 @@ -{ - "explain_todo": { - "stmt44": true, - "stmt46": true - } -} +{} diff --git a/parser/testdata/01055_compact_parts_1/metadata.json b/parser/testdata/01055_compact_parts_1/metadata.json index dbdbb76d4f..0967ef424b 100644 --- a/parser/testdata/01055_compact_parts_1/metadata.json +++ b/parser/testdata/01055_compact_parts_1/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt6": true - } -} +{} diff --git a/parser/testdata/01109_exchange_tables/metadata.json b/parser/testdata/01109_exchange_tables/metadata.json index 6599b4f20b..9e26dfeeb6 100644 --- a/parser/testdata/01109_exchange_tables/metadata.json +++ b/parser/testdata/01109_exchange_tables/metadata.json @@ -1,6 +1 @@ -{ - "explain_todo": { - "stmt43": true, - "stmt44": true - } -} +{} \ No newline at end of file diff --git a/parser/testdata/01277_fromUnixTimestamp64/metadata.json b/parser/testdata/01277_fromUnixTimestamp64/metadata.json index 02d3e5a7c6..9e26dfeeb6 100644 --- a/parser/testdata/01277_fromUnixTimestamp64/metadata.json +++ b/parser/testdata/01277_fromUnixTimestamp64/metadata.json @@ -1 +1 @@ -{"explain_todo":{"stmt21":true}} +{} \ No newline at end of file diff --git a/parser/testdata/01461_query_start_time_microseconds/metadata.json b/parser/testdata/01461_query_start_time_microseconds/metadata.json index 05aa6dfc72..0967ef424b 100644 --- a/parser/testdata/01461_query_start_time_microseconds/metadata.json +++ b/parser/testdata/01461_query_start_time_microseconds/metadata.json @@ -1,6 +1 @@ -{ - "explain_todo": { - "stmt4": true, - "stmt8": true - } -} +{} diff --git a/parser/testdata/01651_bugs_from_15889/metadata.json b/parser/testdata/01651_bugs_from_15889/metadata.json index bfbd10f0e3..0967ef424b 100644 --- a/parser/testdata/01651_bugs_from_15889/metadata.json +++ b/parser/testdata/01651_bugs_from_15889/metadata.json @@ -1,6 +1 @@ -{ - "explain_todo": { - "stmt21": true, - "stmt22": true - } -} +{} diff --git a/parser/testdata/01710_minmax_count_projection/metadata.json b/parser/testdata/01710_minmax_count_projection/metadata.json index af0aabc403..7bf4b04abe 100644 --- a/parser/testdata/01710_minmax_count_projection/metadata.json +++ b/parser/testdata/01710_minmax_count_projection/metadata.json @@ -1,6 +1,5 @@ { "explain_todo": { - "stmt20": true, "stmt33": true } } diff --git a/parser/testdata/01901_test_attach_partition_from/metadata.json b/parser/testdata/01901_test_attach_partition_from/metadata.json index dbdbb76d4f..0967ef424b 100644 --- a/parser/testdata/01901_test_attach_partition_from/metadata.json +++ b/parser/testdata/01901_test_attach_partition_from/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt6": true - } -} +{} diff --git a/parser/testdata/02008_test_union_distinct_in_subquery/metadata.json b/parser/testdata/02008_test_union_distinct_in_subquery/metadata.json index ccc75f74d5..0967ef424b 100644 --- a/parser/testdata/02008_test_union_distinct_in_subquery/metadata.json +++ b/parser/testdata/02008_test_union_distinct_in_subquery/metadata.json @@ -1,6 +1 @@ -{ - "explain_todo": { - "stmt15": true, - "stmt9": true - } -} +{} diff --git a/parser/testdata/02706_show_columns/metadata.json b/parser/testdata/02706_show_columns/metadata.json index 25122ac4f4..9e26dfeeb6 100644 --- a/parser/testdata/02706_show_columns/metadata.json +++ b/parser/testdata/02706_show_columns/metadata.json @@ -1,6 +1 @@ -{ - "explain_todo": { - "stmt5": true, - "stmt9": true - } -} +{} \ No newline at end of file diff --git a/parser/testdata/02731_replace_partition_from_temporary_table/metadata.json b/parser/testdata/02731_replace_partition_from_temporary_table/metadata.json index c52ae2d780..0967ef424b 100644 --- a/parser/testdata/02731_replace_partition_from_temporary_table/metadata.json +++ b/parser/testdata/02731_replace_partition_from_temporary_table/metadata.json @@ -1,6 +1 @@ -{ - "explain_todo": { - "stmt31": true, - "stmt34": true - } -} +{} diff --git a/parser/testdata/02932_apply_deleted_mask/metadata.json b/parser/testdata/02932_apply_deleted_mask/metadata.json index 49a71d5123..0967ef424b 100644 --- a/parser/testdata/02932_apply_deleted_mask/metadata.json +++ b/parser/testdata/02932_apply_deleted_mask/metadata.json @@ -1,6 +1 @@ -{ - "explain_todo": { - "stmt13": true, - "stmt21": true - } -} +{} diff --git a/parser/testdata/02932_lwd_and_mutations/metadata.json b/parser/testdata/02932_lwd_and_mutations/metadata.json index 983800a6c0..0967ef424b 100644 --- a/parser/testdata/02932_lwd_and_mutations/metadata.json +++ b/parser/testdata/02932_lwd_and_mutations/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt23": true - } -} +{} diff --git a/parser/testdata/02998_projection_after_attach_partition/metadata.json b/parser/testdata/02998_projection_after_attach_partition/metadata.json index ab9202e88e..0967ef424b 100644 --- a/parser/testdata/02998_projection_after_attach_partition/metadata.json +++ b/parser/testdata/02998_projection_after_attach_partition/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt11": true - } -} +{} diff --git a/parser/testdata/03168_attach_as_replicated_materialized_view/metadata.json b/parser/testdata/03168_attach_as_replicated_materialized_view/metadata.json index ec09c7e10e..0967ef424b 100644 --- a/parser/testdata/03168_attach_as_replicated_materialized_view/metadata.json +++ b/parser/testdata/03168_attach_as_replicated_materialized_view/metadata.json @@ -1,6 +1 @@ -{ - "explain_todo": { - "stmt11": true, - "stmt12": true - } -} +{} diff --git a/parser/testdata/03257_reverse_sorting_key/metadata.json b/parser/testdata/03257_reverse_sorting_key/metadata.json index 3a06a4a1ac..0967ef424b 100644 --- a/parser/testdata/03257_reverse_sorting_key/metadata.json +++ b/parser/testdata/03257_reverse_sorting_key/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt5": true - } -} +{} diff --git a/parser/testdata/03257_reverse_sorting_key_simple/metadata.json b/parser/testdata/03257_reverse_sorting_key_simple/metadata.json index 3a06a4a1ac..0967ef424b 100644 --- a/parser/testdata/03257_reverse_sorting_key_simple/metadata.json +++ b/parser/testdata/03257_reverse_sorting_key_simple/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt5": true - } -} +{} diff --git a/parser/testdata/03257_reverse_sorting_key_zookeeper/metadata.json b/parser/testdata/03257_reverse_sorting_key_zookeeper/metadata.json index 1295a45747..0967ef424b 100644 --- a/parser/testdata/03257_reverse_sorting_key_zookeeper/metadata.json +++ b/parser/testdata/03257_reverse_sorting_key_zookeeper/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt3": true - } -} +{} diff --git a/parser/testdata/03340_projections_formatting/metadata.json b/parser/testdata/03340_projections_formatting/metadata.json index aeb01f1428..0967ef424b 100644 --- a/parser/testdata/03340_projections_formatting/metadata.json +++ b/parser/testdata/03340_projections_formatting/metadata.json @@ -1,6 +1 @@ -{ - "explain_todo": { - "stmt1": true, - "stmt4": true - } -} +{} diff --git a/parser/testdata/03362_reverse_sorting_key_explicit_primary_key/metadata.json b/parser/testdata/03362_reverse_sorting_key_explicit_primary_key/metadata.json index ef58f80315..0967ef424b 100644 --- a/parser/testdata/03362_reverse_sorting_key_explicit_primary_key/metadata.json +++ b/parser/testdata/03362_reverse_sorting_key_explicit_primary_key/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt2": true - } -} +{} diff --git a/parser/testdata/03404_json_tables/metadata.json b/parser/testdata/03404_json_tables/metadata.json index ab9202e88e..0967ef424b 100644 --- a/parser/testdata/03404_json_tables/metadata.json +++ b/parser/testdata/03404_json_tables/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt11": true - } -} +{} diff --git a/parser/testdata/03459-reverse-sorting-key-stable-result/metadata.json b/parser/testdata/03459-reverse-sorting-key-stable-result/metadata.json index ef58f80315..0967ef424b 100644 --- a/parser/testdata/03459-reverse-sorting-key-stable-result/metadata.json +++ b/parser/testdata/03459-reverse-sorting-key-stable-result/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt2": true - } -} +{} diff --git a/parser/testdata/03513_read_in_order_nullable/metadata.json b/parser/testdata/03513_read_in_order_nullable/metadata.json index cdfe9ecd52..9e26dfeeb6 100644 --- a/parser/testdata/03513_read_in_order_nullable/metadata.json +++ b/parser/testdata/03513_read_in_order_nullable/metadata.json @@ -1,6 +1 @@ -{ - "explain_todo": { - "stmt14": true, - "stmt36": true - } -} +{} \ No newline at end of file diff --git a/parser/testdata/03710_empty_tuple_lhs_in_function/metadata.json b/parser/testdata/03710_empty_tuple_lhs_in_function/metadata.json index 85329699d6..9e26dfeeb6 100644 --- a/parser/testdata/03710_empty_tuple_lhs_in_function/metadata.json +++ b/parser/testdata/03710_empty_tuple_lhs_in_function/metadata.json @@ -1,6 +1 @@ -{ - "explain_todo": { - "stmt31": true, - "stmt7": true - } -} +{} \ No newline at end of file