diff --git a/ast/ast.go b/ast/ast.go index c69df6f960..7330196296 100644 --- a/ast/ast.go +++ b/ast/ast.go @@ -64,6 +64,7 @@ type SelectQuery struct { PreWhere Expression `json:"prewhere,omitempty"` Where Expression `json:"where,omitempty"` GroupBy []Expression `json:"group_by,omitempty"` + GroupByAll bool `json:"group_by_all,omitempty"` // true if GROUP BY ALL was used GroupingSets bool `json:"grouping_sets,omitempty"` // true if GROUP BY uses GROUPING SETS WithRollup bool `json:"with_rollup,omitempty"` WithCube bool `json:"with_cube,omitempty"` @@ -253,8 +254,9 @@ type CreateQuery struct { Table string `json:"table,omitempty"` View string `json:"view,omitempty"` Materialized bool `json:"materialized,omitempty"` - To string `json:"to,omitempty"` // Target table for materialized views - Populate bool `json:"populate,omitempty"` // POPULATE for materialized views + ToDatabase string `json:"to_database,omitempty"` // Target database for materialized views + To string `json:"to,omitempty"` // Target table for materialized views + Populate bool `json:"populate,omitempty"` // POPULATE for materialized views Columns []*ColumnDeclaration `json:"columns,omitempty"` Indexes []*IndexDefinition `json:"indexes,omitempty"` Projections []*Projection `json:"projections,omitempty"` @@ -497,6 +499,19 @@ func (d *DropQuery) Pos() token.Position { return d.Position } func (d *DropQuery) End() token.Position { return d.Position } func (d *DropQuery) statementNode() {} +// UndropQuery represents an UNDROP TABLE statement. +type UndropQuery struct { + Position token.Position `json:"-"` + Database string `json:"database,omitempty"` + Table string `json:"table"` + OnCluster string `json:"on_cluster,omitempty"` + UUID string `json:"uuid,omitempty"` +} + +func (u *UndropQuery) Pos() token.Position { return u.Position } +func (u *UndropQuery) End() token.Position { return u.Position } +func (u *UndropQuery) statementNode() {} + // AlterQuery represents an ALTER statement. type AlterQuery struct { Position token.Position `json:"-"` @@ -529,6 +544,7 @@ type AlterCommand struct { ConstraintName string `json:"constraint_name,omitempty"` Partition Expression `json:"partition,omitempty"` FromTable string `json:"from_table,omitempty"` + FromPath string `json:"from_path,omitempty"` // For FETCH PARTITION FROM TTL *TTLClause `json:"ttl,omitempty"` Settings []*SettingExpr `json:"settings,omitempty"` Where Expression `json:"where,omitempty"` // For DELETE WHERE @@ -593,6 +609,8 @@ const ( AlterDetachPartition AlterCommandType = "DETACH_PARTITION" AlterAttachPartition AlterCommandType = "ATTACH_PARTITION" AlterReplacePartition AlterCommandType = "REPLACE_PARTITION" + AlterFetchPartition AlterCommandType = "FETCH_PARTITION" + AlterMovePartition AlterCommandType = "MOVE_PARTITION" AlterFreezePartition AlterCommandType = "FREEZE_PARTITION" AlterFreeze AlterCommandType = "FREEZE" AlterDeleteWhere AlterCommandType = "DELETE_WHERE" @@ -689,18 +707,24 @@ func (s *ShowQuery) statementNode() {} type ShowType string const ( - ShowTables ShowType = "TABLES" - ShowDatabases ShowType = "DATABASES" - ShowProcesses ShowType = "PROCESSLIST" - ShowCreate ShowType = "CREATE" - ShowCreateDB ShowType = "CREATE_DATABASE" - ShowCreateDictionary ShowType = "CREATE_DICTIONARY" - ShowCreateView ShowType = "CREATE_VIEW" - ShowCreateUser ShowType = "CREATE_USER" - ShowColumns ShowType = "COLUMNS" - ShowDictionaries ShowType = "DICTIONARIES" - ShowFunctions ShowType = "FUNCTIONS" - ShowSettings ShowType = "SETTINGS" + ShowTables ShowType = "TABLES" + ShowDatabases ShowType = "DATABASES" + ShowProcesses ShowType = "PROCESSLIST" + ShowCreate ShowType = "CREATE" + ShowCreateDB ShowType = "CREATE_DATABASE" + ShowCreateDictionary ShowType = "CREATE_DICTIONARY" + ShowCreateView ShowType = "CREATE_VIEW" + ShowCreateUser ShowType = "CREATE_USER" + ShowCreateRole ShowType = "CREATE_ROLE" + ShowCreatePolicy ShowType = "CREATE_POLICY" + ShowCreateRowPolicy ShowType = "CREATE_ROW_POLICY" + ShowCreateQuota ShowType = "CREATE_QUOTA" + ShowCreateSettingsProfile ShowType = "CREATE_SETTINGS_PROFILE" + ShowColumns ShowType = "COLUMNS" + ShowDictionaries ShowType = "DICTIONARIES" + ShowFunctions ShowType = "FUNCTIONS" + ShowSettings ShowType = "SETTINGS" + ShowGrants ShowType = "GRANTS" ) // ExplainQuery represents an EXPLAIN statement. @@ -862,6 +886,7 @@ func (g *GrantQuery) statementNode() {} // ShowGrantsQuery represents a SHOW GRANTS statement. type ShowGrantsQuery struct { Position token.Position `json:"-"` + Format string `json:"format,omitempty"` } func (s *ShowGrantsQuery) Pos() token.Position { return s.Position } @@ -881,12 +906,23 @@ func (s *ShowPrivilegesQuery) statementNode() {} type ShowCreateQuotaQuery struct { Position token.Position `json:"-"` Name string `json:"name,omitempty"` + Format string `json:"format,omitempty"` } func (s *ShowCreateQuotaQuery) Pos() token.Position { return s.Position } func (s *ShowCreateQuotaQuery) End() token.Position { return s.Position } func (s *ShowCreateQuotaQuery) statementNode() {} +// CreateQuotaQuery represents a CREATE QUOTA statement. +type CreateQuotaQuery struct { + Position token.Position `json:"-"` + Name string `json:"name,omitempty"` +} + +func (c *CreateQuotaQuery) Pos() token.Position { return c.Position } +func (c *CreateQuotaQuery) End() token.Position { return c.Position } +func (c *CreateQuotaQuery) statementNode() {} + // CreateSettingsProfileQuery represents a CREATE SETTINGS PROFILE statement. type CreateSettingsProfileQuery struct { Position token.Position `json:"-"` @@ -922,6 +958,7 @@ func (d *DropSettingsProfileQuery) statementNode() {} type ShowCreateSettingsProfileQuery struct { Position token.Position `json:"-"` Names []string `json:"names,omitempty"` + Format string `json:"format,omitempty"` } func (s *ShowCreateSettingsProfileQuery) Pos() token.Position { return s.Position } @@ -951,6 +988,7 @@ func (d *DropRowPolicyQuery) statementNode() {} // ShowCreateRowPolicyQuery represents a SHOW CREATE ROW POLICY statement. type ShowCreateRowPolicyQuery struct { Position token.Position `json:"-"` + Format string `json:"format,omitempty"` } func (s *ShowCreateRowPolicyQuery) Pos() token.Position { return s.Position } @@ -981,12 +1019,22 @@ func (d *DropRoleQuery) statementNode() {} type ShowCreateRoleQuery struct { Position token.Position `json:"-"` RoleCount int `json:"role_count,omitempty"` // Number of roles specified + Format string `json:"format,omitempty"` } func (s *ShowCreateRoleQuery) Pos() token.Position { return s.Position } func (s *ShowCreateRoleQuery) End() token.Position { return s.Position } func (s *ShowCreateRoleQuery) statementNode() {} +// SetRoleQuery represents a SET DEFAULT ROLE statement. +type SetRoleQuery struct { + Position token.Position `json:"-"` +} + +func (s *SetRoleQuery) Pos() token.Position { return s.Position } +func (s *SetRoleQuery) End() token.Position { return s.Position } +func (s *SetRoleQuery) statementNode() {} + // CreateResourceQuery represents a CREATE RESOURCE statement. type CreateResourceQuery struct { Position token.Position `json:"-"` @@ -1143,11 +1191,12 @@ const ( // Asterisk represents a *. type Asterisk struct { - Position token.Position `json:"-"` - Table string `json:"table,omitempty"` // for table.* - Except []string `json:"except,omitempty"` // for * EXCEPT (col1, col2) - Replace []*ReplaceExpr `json:"replace,omitempty"` // for * REPLACE (expr AS col) - Apply []string `json:"apply,omitempty"` // for * APPLY (func1) APPLY(func2) + Position token.Position `json:"-"` + Table string `json:"table,omitempty"` // for table.* + Except []string `json:"except,omitempty"` // for * EXCEPT (col1, col2) - deprecated, use Transformers + Replace []*ReplaceExpr `json:"replace,omitempty"` // for * REPLACE (expr AS col) - deprecated, use Transformers + Apply []string `json:"apply,omitempty"` // for * APPLY (func1) APPLY(func2) - deprecated, use Transformers + Transformers []*ColumnTransformer `json:"transformers,omitempty"` // ordered list of transformers } func (a *Asterisk) Pos() token.Position { return a.Position } @@ -1164,15 +1213,28 @@ type ReplaceExpr struct { func (r *ReplaceExpr) Pos() token.Position { return r.Position } func (r *ReplaceExpr) End() token.Position { return r.Position } +// ColumnTransformer represents a single transformer (APPLY, EXCEPT, or REPLACE) in order. +type ColumnTransformer struct { + Position token.Position `json:"-"` + Type string `json:"type"` // "apply", "except", "replace" + Apply string `json:"apply,omitempty"` // function name for APPLY + ApplyLambda Expression `json:"apply_lambda,omitempty"` // lambda expression for APPLY x -> expr + Except []string `json:"except,omitempty"` // column names for EXCEPT + Replaces []*ReplaceExpr `json:"replaces,omitempty"` // replacement expressions for REPLACE +} + // ColumnsMatcher represents COLUMNS('pattern') or COLUMNS(col1, col2) expression. // When Pattern is set, it's a regex matcher (ColumnsRegexpMatcher in explain). // When Columns is set, it's a list matcher (ColumnsListMatcher in explain). type ColumnsMatcher struct { - Position token.Position `json:"-"` - Pattern string `json:"pattern,omitempty"` - Columns []Expression `json:"columns,omitempty"` // For COLUMNS(id, name) syntax - Except []string `json:"except,omitempty"` - Qualifier string `json:"qualifier,omitempty"` // For qualified matchers like table.COLUMNS(...) + Position token.Position `json:"-"` + Pattern string `json:"pattern,omitempty"` + Columns []Expression `json:"columns,omitempty"` // For COLUMNS(id, name) syntax + Except []string `json:"except,omitempty"` // for EXCEPT (col1, col2) - deprecated, use Transformers + Replace []*ReplaceExpr `json:"replace,omitempty"` // for REPLACE (expr AS col) - deprecated, use Transformers + Apply []string `json:"apply,omitempty"` // for APPLY (func1) APPLY(func2) - deprecated, use Transformers + Qualifier string `json:"qualifier,omitempty"` // For qualified matchers like table.COLUMNS(...) + Transformers []*ColumnTransformer `json:"transformers,omitempty"` // ordered list of transformers } func (c *ColumnsMatcher) Pos() token.Position { return c.Position } @@ -1392,9 +1454,10 @@ func (t *TupleAccess) expressionNode() {} // Lambda represents a lambda expression. type Lambda struct { - Position token.Position `json:"-"` - Parameters []string `json:"parameters"` - Body Expression `json:"body"` + Position token.Position `json:"-"` + Parameters []string `json:"parameters"` + Body Expression `json:"body"` + Parenthesized bool `json:"-"` // True if wrapped in explicit parentheses } func (l *Lambda) Pos() token.Position { return l.Position } diff --git a/internal/explain/explain.go b/internal/explain/explain.go index 9cf2b8414d..561fdb6329 100644 --- a/internal/explain/explain.go +++ b/internal/explain/explain.go @@ -113,12 +113,16 @@ func Node(sb *strings.Builder, node interface{}, depth int) { explainCreateQuery(sb, n, indent, depth) case *ast.DropQuery: explainDropQuery(sb, n, indent, depth) + case *ast.UndropQuery: + explainUndropQuery(sb, n, indent, depth) case *ast.RenameQuery: explainRenameQuery(sb, n, indent, depth) case *ast.ExchangeQuery: explainExchangeQuery(sb, n, indent) case *ast.SetQuery: explainSetQuery(sb, indent) + case *ast.SetRoleQuery: + fmt.Fprintf(sb, "%sSetRoleQuery\n", indent) case *ast.SystemQuery: explainSystemQuery(sb, n, indent) case *ast.TransactionControlQuery: @@ -130,7 +134,14 @@ func Node(sb *strings.Builder, node interface{}, depth int) { case *ast.ShowPrivilegesQuery: fmt.Fprintf(sb, "%sShowPrivilegesQuery\n", indent) case *ast.ShowCreateQuotaQuery: - fmt.Fprintf(sb, "%sSHOW CREATE QUOTA query\n", indent) + if n.Format != "" { + fmt.Fprintf(sb, "%sSHOW CREATE QUOTA query (children 1)\n", indent) + fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.Format) + } else { + fmt.Fprintf(sb, "%sSHOW CREATE QUOTA query\n", indent) + } + case *ast.CreateQuotaQuery: + fmt.Fprintf(sb, "%sCreateQuotaQuery\n", indent) case *ast.CreateSettingsProfileQuery: fmt.Fprintf(sb, "%sCreateSettingsProfileQuery\n", indent) case *ast.AlterSettingsProfileQuery: @@ -140,27 +151,43 @@ func Node(sb *strings.Builder, node interface{}, depth int) { fmt.Fprintf(sb, "%sDROP SETTINGS PROFILE query\n", indent) case *ast.ShowCreateSettingsProfileQuery: // Use PROFILES (plural) when multiple profiles are specified + queryName := "SHOW CREATE SETTINGS PROFILE query" if len(n.Names) > 1 { - fmt.Fprintf(sb, "%sSHOW CREATE SETTINGS PROFILES query\n", indent) + queryName = "SHOW CREATE SETTINGS PROFILES query" + } + if n.Format != "" { + fmt.Fprintf(sb, "%s%s (children 1)\n", indent, queryName) + fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.Format) } else { - fmt.Fprintf(sb, "%sSHOW CREATE SETTINGS PROFILE query\n", indent) + fmt.Fprintf(sb, "%s%s\n", indent, queryName) } case *ast.CreateRowPolicyQuery: fmt.Fprintf(sb, "%sCREATE ROW POLICY or ALTER ROW POLICY query\n", indent) case *ast.DropRowPolicyQuery: fmt.Fprintf(sb, "%sDROP ROW POLICY query\n", indent) case *ast.ShowCreateRowPolicyQuery: - fmt.Fprintf(sb, "%sSHOW CREATE ROW POLICY query\n", indent) + // ClickHouse uses "ROW POLICIES" (plural) when FORMAT is present + if n.Format != "" { + fmt.Fprintf(sb, "%sSHOW CREATE ROW POLICIES query (children 1)\n", indent) + fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.Format) + } else { + fmt.Fprintf(sb, "%sSHOW CREATE ROW POLICY query\n", indent) + } case *ast.CreateRoleQuery: fmt.Fprintf(sb, "%sCreateRoleQuery\n", indent) case *ast.DropRoleQuery: fmt.Fprintf(sb, "%sDROP ROLE query\n", indent) case *ast.ShowCreateRoleQuery: // Use ROLES (plural) when multiple roles are specified + queryName := "SHOW CREATE ROLE query" if n.RoleCount > 1 { - fmt.Fprintf(sb, "%sSHOW CREATE ROLES query\n", indent) + queryName = "SHOW CREATE ROLES query" + } + if n.Format != "" { + fmt.Fprintf(sb, "%s%s (children 1)\n", indent, queryName) + fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.Format) } else { - fmt.Fprintf(sb, "%sSHOW CREATE ROLE query\n", indent) + fmt.Fprintf(sb, "%s%s\n", indent, queryName) } case *ast.CreateResourceQuery: fmt.Fprintf(sb, "%sCreateResourceQuery %s (children 1)\n", indent, n.Name) @@ -181,7 +208,12 @@ func Node(sb *strings.Builder, node interface{}, depth int) { case *ast.DropWorkloadQuery: fmt.Fprintf(sb, "%sDropWorkloadQuery\n", indent) case *ast.ShowGrantsQuery: - fmt.Fprintf(sb, "%sShowGrantsQuery\n", indent) + if n.Format != "" { + fmt.Fprintf(sb, "%sShowGrantsQuery (children 1)\n", indent) + fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.Format) + } else { + fmt.Fprintf(sb, "%sShowGrantsQuery\n", indent) + } case *ast.GrantQuery: fmt.Fprintf(sb, "%sGrantQuery\n", indent) case *ast.UseQuery: @@ -285,7 +317,11 @@ func Column(sb *strings.Builder, col *ast.ColumnDeclaration, depth int) { if col.Codec != nil { children++ } - fmt.Fprintf(sb, "%sColumnDeclaration %s (children %d)\n", indent, col.Name, children) + if children > 0 { + fmt.Fprintf(sb, "%sColumnDeclaration %s (children %d)\n", indent, col.Name, children) + } else { + fmt.Fprintf(sb, "%sColumnDeclaration %s\n", indent, col.Name) + } if col.Type != nil { Node(sb, col.Type, depth+1) } diff --git a/internal/explain/expressions.go b/internal/explain/expressions.go index 3d96a1e78a..a2717b38fc 100644 --- a/internal/explain/expressions.go +++ b/internal/explain/expressions.go @@ -585,7 +585,7 @@ func explainAliasedExpr(sb *strings.Builder, n *ast.AliasedExpr, depth int) { func explainAsterisk(sb *strings.Builder, n *ast.Asterisk, indent string, depth int) { // Check if there are any column transformers (EXCEPT, REPLACE, APPLY) - hasTransformers := len(n.Except) > 0 || len(n.Replace) > 0 || len(n.Apply) > 0 + hasTransformers := len(n.Transformers) > 0 || len(n.Except) > 0 || len(n.Replace) > 0 || len(n.Apply) > 0 if n.Table != "" { if hasTransformers { @@ -607,6 +607,16 @@ func explainAsterisk(sb *strings.Builder, n *ast.Asterisk, indent string, depth } func explainColumnsTransformers(sb *strings.Builder, n *ast.Asterisk, indent string, depth int) { + // Use Transformers if available (preserves order), otherwise fall back to legacy arrays + if len(n.Transformers) > 0 { + fmt.Fprintf(sb, "%sColumnsTransformerList (children %d)\n", indent, len(n.Transformers)) + for _, t := range n.Transformers { + explainSingleTransformer(sb, t, indent, depth) + } + return + } + + // Legacy: use separate arrays (doesn't preserve order) transformerCount := 0 if len(n.Except) > 0 { transformerCount++ @@ -647,7 +657,34 @@ func explainColumnsTransformers(sb *strings.Builder, n *ast.Asterisk, indent str } } +func explainSingleTransformer(sb *strings.Builder, t *ast.ColumnTransformer, indent string, depth int) { + switch t.Type { + case "apply": + fmt.Fprintf(sb, "%s ColumnsApplyTransformer\n", indent) + case "except": + fmt.Fprintf(sb, "%s ColumnsExceptTransformer (children %d)\n", indent, len(t.Except)) + for _, col := range t.Except { + fmt.Fprintf(sb, "%s Identifier %s\n", indent, col) + } + case "replace": + fmt.Fprintf(sb, "%s ColumnsReplaceTransformer (children %d)\n", indent, len(t.Replaces)) + for _, replace := range t.Replaces { + children := 0 + if replace.Expr != nil { + children = 1 + } + fmt.Fprintf(sb, "%s ColumnsReplaceTransformer::Replacement (children %d)\n", indent, children) + if replace.Expr != nil { + Node(sb, replace.Expr, depth+3) + } + } + } +} + func explainColumnsMatcher(sb *strings.Builder, n *ast.ColumnsMatcher, indent string, depth int) { + // Check if there are any column transformers (EXCEPT, REPLACE, APPLY) + hasTransformers := len(n.Transformers) > 0 || len(n.Except) > 0 || len(n.Replace) > 0 || len(n.Apply) > 0 + // Determine the matcher type based on whether it's a pattern or a list if len(n.Columns) > 0 { // ColumnsListMatcher for COLUMNS(col1, col2, ...) @@ -655,18 +692,25 @@ func explainColumnsMatcher(sb *strings.Builder, n *ast.ColumnsMatcher, indent st if n.Qualifier != "" { typeName = "QualifiedColumnsListMatcher" } + childCount := 1 // ExpressionList of columns + if n.Qualifier != "" { + childCount++ + } + if hasTransformers { + childCount++ // for ColumnsTransformerList + } + fmt.Fprintf(sb, "%s%s (children %d)\n", indent, typeName, childCount) if n.Qualifier != "" { - // QualifiedColumnsListMatcher has qualifier as a child - fmt.Fprintf(sb, "%s%s (children %d)\n", indent, typeName, 2) fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.Qualifier) - } else { - fmt.Fprintf(sb, "%s%s (children %d)\n", indent, typeName, 1) } // Output the columns as ExpressionList fmt.Fprintf(sb, "%s ExpressionList (children %d)\n", indent, len(n.Columns)) for _, col := range n.Columns { Node(sb, col, depth+2) } + if hasTransformers { + explainColumnsMatcherTransformers(sb, n, indent+" ", depth+1) + } } else { // ColumnsRegexpMatcher for COLUMNS('pattern') typeName := "ColumnsRegexpMatcher" @@ -674,12 +718,75 @@ func explainColumnsMatcher(sb *strings.Builder, n *ast.ColumnsMatcher, indent st typeName = "QualifiedColumnsRegexpMatcher" } if n.Qualifier != "" { - fmt.Fprintf(sb, "%s%s (children %d)\n", indent, typeName, 1) + childCount := 1 // Identifier + if hasTransformers { + childCount++ + } + fmt.Fprintf(sb, "%s%s (children %d)\n", indent, typeName, childCount) fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.Qualifier) + if hasTransformers { + explainColumnsMatcherTransformers(sb, n, indent+" ", depth+1) + } } else { - fmt.Fprintf(sb, "%s%s\n", indent, typeName) + if hasTransformers { + fmt.Fprintf(sb, "%s%s (children %d)\n", indent, typeName, 1) + explainColumnsMatcherTransformers(sb, n, indent+" ", depth+1) + } else { + fmt.Fprintf(sb, "%s%s\n", indent, typeName) + } + } + } +} + +func explainColumnsMatcherTransformers(sb *strings.Builder, n *ast.ColumnsMatcher, indent string, depth int) { + // Use Transformers if available (preserves order), otherwise fall back to legacy arrays + if len(n.Transformers) > 0 { + fmt.Fprintf(sb, "%sColumnsTransformerList (children %d)\n", indent, len(n.Transformers)) + for _, t := range n.Transformers { + explainSingleTransformer(sb, t, indent, depth) + } + return + } + + // Legacy: use separate arrays (doesn't preserve order) + transformerCount := 0 + if len(n.Except) > 0 { + transformerCount++ + } + if len(n.Replace) > 0 { + transformerCount++ + } + // Each APPLY adds one transformer + transformerCount += len(n.Apply) + + fmt.Fprintf(sb, "%sColumnsTransformerList (children %d)\n", indent, transformerCount) + + if len(n.Except) > 0 { + fmt.Fprintf(sb, "%s ColumnsExceptTransformer (children %d)\n", indent, len(n.Except)) + for _, col := range n.Except { + fmt.Fprintf(sb, "%s Identifier %s\n", indent, col) + } + } + + if len(n.Replace) > 0 { + fmt.Fprintf(sb, "%s ColumnsReplaceTransformer (children %d)\n", indent, len(n.Replace)) + for _, replace := range n.Replace { + children := 0 + if replace.Expr != nil { + children = 1 + } + fmt.Fprintf(sb, "%s ColumnsReplaceTransformer::Replacement (children %d)\n", indent, children) + if replace.Expr != nil { + // Output the expression without alias - the replacement name is implied + Node(sb, replace.Expr, depth+3) + } } } + + // Each APPLY function gets its own ColumnsApplyTransformer + for range n.Apply { + fmt.Fprintf(sb, "%s ColumnsApplyTransformer\n", indent) + } } func explainWithElement(sb *strings.Builder, n *ast.WithElement, indent string, depth int) { diff --git a/internal/explain/format.go b/internal/explain/format.go index 1ab3eb49ad..751418d804 100644 --- a/internal/explain/format.go +++ b/internal/explain/format.go @@ -37,6 +37,12 @@ func FormatFloat(val float64) string { return strconv.FormatFloat(val, 'f', -1, 64) } +// EscapeIdentifier escapes single quotes in identifiers for EXPLAIN AST output +// ClickHouse escapes ' as \' in identifier names +func EscapeIdentifier(s string) string { + return strings.ReplaceAll(s, "'", "\\'") +} + // escapeStringLiteral escapes special characters in a string for EXPLAIN AST output // Uses double-escaping as ClickHouse EXPLAIN AST displays strings // Iterates over bytes to preserve raw bytes (including invalid UTF-8) @@ -237,6 +243,19 @@ func FormatDataType(dt *ast.DataType) string { } else if binExpr, ok := p.(*ast.BinaryExpr); ok { // Binary expression (e.g., 'hello' = 1 for Enum types) params = append(params, formatBinaryExprForType(binExpr)) + } else if fn, ok := p.(*ast.FunctionCall); ok { + // Function call (e.g., SKIP for JSON types) + if fn.Name == "SKIP" && len(fn.Arguments) > 0 { + if ident, ok := fn.Arguments[0].(*ast.Identifier); ok { + params = append(params, "SKIP "+ident.Name()) + } + } else if fn.Name == "SKIP REGEXP" && len(fn.Arguments) > 0 { + if lit, ok := fn.Arguments[0].(*ast.Literal); ok { + params = append(params, fmt.Sprintf("SKIP REGEXP \\\\\\'%s\\\\\\'", lit.Value)) + } + } else { + params = append(params, fmt.Sprintf("%v", p)) + } } else { params = append(params, fmt.Sprintf("%v", p)) } @@ -294,6 +313,10 @@ func NormalizeFunctionName(name string) string { "greatest": "greatest", "least": "least", "concat_ws": "concat", + "position": "position", + // SQL standard ANY/ALL subquery operators + "anymatch": "in", + "allmatch": "notIn", } if n, ok := normalized[strings.ToLower(name)]; ok { return n diff --git a/internal/explain/functions.go b/internal/explain/functions.go index c4cbea74d5..2ca9ed3475 100644 --- a/internal/explain/functions.go +++ b/internal/explain/functions.go @@ -7,11 +7,31 @@ import ( "github.com/sqlc-dev/doubleclick/ast" ) +// normalizeIntervalUnit converts interval units to title-cased singular form +// e.g., "years" -> "Year", "MONTH" -> "Month", "days" -> "Day" +func normalizeIntervalUnit(unit string) string { + if len(unit) == 0 { + return "" + } + u := strings.ToLower(unit) + // Remove trailing 's' for plural forms + if strings.HasSuffix(u, "s") && len(u) > 1 { + u = u[:len(u)-1] + } + // Title-case + return strings.ToUpper(u[:1]) + u[1:] +} + func explainFunctionCall(sb *strings.Builder, n *ast.FunctionCall, indent string, depth int) { explainFunctionCallWithAlias(sb, n, n.Alias, indent, depth) } func explainFunctionCallWithAlias(sb *strings.Builder, n *ast.FunctionCall, alias string, indent string, depth int) { + // Handle special function transformations that ClickHouse does internally + if handled := handleSpecialFunction(sb, n, alias, indent, depth); handled { + return + } + children := 1 // arguments ExpressionList if len(n.Parameters) > 0 { children++ // parameters ExpressionList @@ -84,6 +104,172 @@ func windowSpecHasContent(w *ast.WindowSpec) bool { return false } +// handleSpecialFunction handles special function transformations that ClickHouse does internally. +// Returns true if the function was handled, false otherwise. +func handleSpecialFunction(sb *strings.Builder, n *ast.FunctionCall, alias string, indent string, depth int) bool { + fnName := strings.ToUpper(n.Name) + + // POSITION('ll' IN 'Hello') -> position('Hello', 'll') + if fnName == "POSITION" && len(n.Arguments) == 1 { + if inExpr, ok := n.Arguments[0].(*ast.InExpr); ok { + // Transform: POSITION(needle IN haystack) -> position(haystack, needle) + explainPositionWithIn(sb, inExpr.Expr, inExpr.List[0], alias, indent, depth) + return true + } + } + + // DATE_ADD/DATEADD/TIMESTAMP_ADD/TIMESTAMPADD + if fnName == "DATE_ADD" || fnName == "DATEADD" || fnName == "TIMESTAMP_ADD" || fnName == "TIMESTAMPADD" { + return handleDateAddSub(sb, n, alias, indent, depth, "plus") + } + + // DATE_SUB/DATESUB/TIMESTAMP_SUB/TIMESTAMPSUB + if fnName == "DATE_SUB" || fnName == "DATESUB" || fnName == "TIMESTAMP_SUB" || fnName == "TIMESTAMPSUB" { + return handleDateAddSub(sb, n, alias, indent, depth, "minus") + } + + // DATE_DIFF/DATEDIFF + if fnName == "DATE_DIFF" || fnName == "DATEDIFF" { + return handleDateDiff(sb, n, alias, indent, depth) + } + + return false +} + +// explainPositionWithIn outputs POSITION(needle IN haystack) as position(haystack, needle) +func explainPositionWithIn(sb *strings.Builder, needle, haystack ast.Expression, alias string, indent string, depth int) { + if alias != "" { + fmt.Fprintf(sb, "%sFunction position (alias %s) (children %d)\n", indent, alias, 1) + } else { + fmt.Fprintf(sb, "%sFunction position (children %d)\n", indent, 1) + } + fmt.Fprintf(sb, "%s ExpressionList (children %d)\n", indent, 2) + // Arguments are swapped: haystack first, then needle + Node(sb, haystack, depth+2) + Node(sb, needle, depth+2) +} + +// handleDateAddSub handles DATE_ADD/DATE_SUB and variants +// opFunc is "plus" for ADD or "minus" for SUB +func handleDateAddSub(sb *strings.Builder, n *ast.FunctionCall, alias string, indent string, depth int, opFunc string) bool { + if len(n.Arguments) == 3 { + // DATE_ADD(unit, n, date) -> plus/minus(date, toIntervalUnit(n)) + unitArg := n.Arguments[0] + valueArg := n.Arguments[1] + dateArg := n.Arguments[2] + + // Extract unit from identifier + unitName := "" + if ident, ok := unitArg.(*ast.Identifier); ok { + unitName = ident.Name() + } + + if unitName != "" { + explainDateAddSubResult(sb, opFunc, dateArg, valueArg, unitName, alias, indent, depth) + return true + } + } else if len(n.Arguments) == 2 { + // DATE_ADD(interval, date) -> plus(interval, date) + // DATE_SUB(date, interval) -> minus(date, interval) + intervalArg := n.Arguments[0] + dateArg := n.Arguments[1] + + // Check which argument is the interval + if _, ok := intervalArg.(*ast.IntervalExpr); ok { + // Interval first: plus(interval, date) + explainDateAddSubWithInterval(sb, opFunc, intervalArg, dateArg, alias, indent, depth) + return true + } + // Check if first arg is already a toInterval function (from parser) + if fc, ok := intervalArg.(*ast.FunctionCall); ok && strings.HasPrefix(strings.ToLower(fc.Name), "tointerval") { + // Interval first: plus(interval, date) + explainDateAddSubWithInterval(sb, opFunc, intervalArg, dateArg, alias, indent, depth) + return true + } + + // DATE_SUB(date, interval) -> minus(date, interval) + if _, ok := dateArg.(*ast.IntervalExpr); ok { + explainDateAddSubWithInterval(sb, opFunc, intervalArg, dateArg, alias, indent, depth) + return true + } + if fc, ok := dateArg.(*ast.FunctionCall); ok && strings.HasPrefix(strings.ToLower(fc.Name), "tointerval") { + explainDateAddSubWithInterval(sb, opFunc, intervalArg, dateArg, alias, indent, depth) + return true + } + } + + return false +} + +// explainDateAddSubResult outputs the transformed DATE_ADD/SUB with unit syntax +func explainDateAddSubResult(sb *strings.Builder, opFunc string, dateArg, valueArg ast.Expression, unit string, alias string, indent string, depth int) { + if alias != "" { + fmt.Fprintf(sb, "%sFunction %s (alias %s) (children %d)\n", indent, opFunc, alias, 1) + } else { + fmt.Fprintf(sb, "%sFunction %s (children %d)\n", indent, opFunc, 1) + } + fmt.Fprintf(sb, "%s ExpressionList (children %d)\n", indent, 2) + + // First arg: date + Node(sb, dateArg, depth+2) + + // Second arg: toIntervalUnit(value) + unitNorm := normalizeIntervalUnit(unit) + fmt.Fprintf(sb, "%s Function toInterval%s (children %d)\n", indent, unitNorm, 1) + fmt.Fprintf(sb, "%s ExpressionList (children %d)\n", indent, 1) + Node(sb, valueArg, depth+4) +} + +// explainDateAddSubWithInterval outputs the transformed DATE_ADD/SUB with INTERVAL syntax +func explainDateAddSubWithInterval(sb *strings.Builder, opFunc string, arg1, arg2 ast.Expression, alias string, indent string, depth int) { + if alias != "" { + fmt.Fprintf(sb, "%sFunction %s (alias %s) (children %d)\n", indent, opFunc, alias, 1) + } else { + fmt.Fprintf(sb, "%sFunction %s (children %d)\n", indent, opFunc, 1) + } + fmt.Fprintf(sb, "%s ExpressionList (children %d)\n", indent, 2) + Node(sb, arg1, depth+2) + Node(sb, arg2, depth+2) +} + +// handleDateDiff handles DATE_DIFF/DATEDIFF +// DATE_DIFF(unit, date1, date2) -> dateDiff('unit', date1, date2) +func handleDateDiff(sb *strings.Builder, n *ast.FunctionCall, alias string, indent string, depth int) bool { + if len(n.Arguments) != 3 { + return false + } + + unitArg := n.Arguments[0] + date1Arg := n.Arguments[1] + date2Arg := n.Arguments[2] + + // Extract unit from identifier + unitName := "" + if ident, ok := unitArg.(*ast.Identifier); ok { + unitName = ident.Name() + } + + if unitName == "" { + return false + } + + if alias != "" { + fmt.Fprintf(sb, "%sFunction dateDiff (alias %s) (children %d)\n", indent, alias, 1) + } else { + fmt.Fprintf(sb, "%sFunction dateDiff (children %d)\n", indent, 1) + } + fmt.Fprintf(sb, "%s ExpressionList (children %d)\n", indent, 3) + + // First arg: unit as lowercase string literal + fmt.Fprintf(sb, "%s Literal \\'%s\\'\n", indent, strings.ToLower(unitName)) + + // Second and third args: dates + Node(sb, date1Arg, depth+2) + Node(sb, date2Arg, depth+2) + + return true +} + func explainLambda(sb *strings.Builder, n *ast.Lambda, indent string, depth int) { explainLambdaWithAlias(sb, n, "", indent, depth) } @@ -116,19 +302,18 @@ func explainCastExpr(sb *strings.Builder, n *ast.CastExpr, indent string, depth } func explainCastExprWithAlias(sb *strings.Builder, n *ast.CastExpr, alias string, indent string, depth int) { - // For :: operator syntax, ClickHouse hides alias only when expression is - // an array/tuple with complex content that gets formatted as string - hideAlias := false + // For :: operator syntax with arrays/tuples, determine formatting based on content useArrayFormat := false if n.OperatorSyntax { if lit, ok := n.Expr.(*ast.Literal); ok { if lit.Type == ast.LiteralArray || lit.Type == ast.LiteralTuple { // Determine format based on both content and target type useArrayFormat = shouldUseArrayFormat(lit, n.Type) - hideAlias = !useArrayFormat } } } + // Alias is always shown for :: cast syntax with arrays/tuples + hideAlias := false // CAST is represented as Function CAST with expr and type as arguments if alias != "" && !hideAlias { @@ -151,6 +336,9 @@ func explainCastExprWithAlias(sb *strings.Builder, n *ast.CastExpr, alias string exprStr := formatExprAsString(lit) fmt.Fprintf(sb, "%s Literal \\'%s\\'\n", indent, exprStr) } + } else if lit.Type == ast.LiteralNull { + // NULL stays as Literal NULL, not formatted as a string + fmt.Fprintf(sb, "%s Literal NULL\n", indent) } else { // Simple literal - format as string exprStr := formatExprAsString(lit) @@ -183,31 +371,97 @@ func explainCastExprWithAlias(sb *strings.Builder, n *ast.CastExpr, alias string // shouldUseArrayFormat determines whether to use Array_[...] format or string format // for array/tuple literals in :: cast expressions. -// This depends on both the literal content and the target type. +// ClickHouse uses different formats depending on element types: +// - Boolean arrays: Array_[Bool_0, Bool_1] format +// - Numeric arrays: '[1, 2, 3]' string format func shouldUseArrayFormat(lit *ast.Literal, targetType *ast.DataType) bool { // First check if the literal contains only primitive literals (not expressions) if !containsOnlyLiterals(lit) { return false } - // For arrays of strings, check the target type to determine format + // Check if array contains boolean elements - these use Array_ format + if containsBooleanElements(lit) { + return true + } + + // Check if array contains NULL elements - these use Array_ format + if containsNullElements(lit) { + return true + } + + // For arrays of strings, always use string format in :: casts + // This applies to all target types including Array(String) if lit.Type == ast.LiteralArray && hasStringElements(lit) { - // Only use Array_ format when casting to Array(String) specifically - // For other types like Array(JSON), Array(LowCardinality(String)), etc., use string format - if targetType != nil && strings.ToLower(targetType.Name) == "array" && len(targetType.Parameters) > 0 { - if innerType, ok := targetType.Parameters[0].(*ast.DataType); ok { - // Only use Array_ format if inner type is exactly "String" with no parameters - if strings.ToLower(innerType.Name) == "string" && len(innerType.Parameters) == 0 { - return true - } + return false + } + + // For numeric primitives, use string format in :: casts + return false +} + +// containsNullElements checks if a literal array/tuple contains NULL elements +func containsNullElements(lit *ast.Literal) bool { + var exprs []ast.Expression + switch lit.Type { + case ast.LiteralArray, ast.LiteralTuple: + var ok bool + exprs, ok = lit.Value.([]ast.Expression) + if !ok { + return false + } + default: + return false + } + + for _, e := range exprs { + innerLit, ok := e.(*ast.Literal) + if !ok { + continue + } + if innerLit.Type == ast.LiteralNull { + return true + } + // Check nested arrays/tuples + if innerLit.Type == ast.LiteralArray || innerLit.Type == ast.LiteralTuple { + if containsNullElements(innerLit) { + return true } } - // For any other type (JSON, LowCardinality, etc.), use string format + } + return false +} + +// containsBooleanElements checks if a literal array/tuple contains boolean elements +func containsBooleanElements(lit *ast.Literal) bool { + var exprs []ast.Expression + switch lit.Type { + case ast.LiteralArray, ast.LiteralTuple: + var ok bool + exprs, ok = lit.Value.([]ast.Expression) + if !ok { + return false + } + default: return false } - // For non-string primitives, always use Array_ format - return true + for _, e := range exprs { + innerLit, ok := e.(*ast.Literal) + if !ok { + continue + } + if innerLit.Type == ast.LiteralBoolean { + return true + } + // Check nested arrays/tuples + if innerLit.Type == ast.LiteralArray || innerLit.Type == ast.LiteralTuple { + if containsBooleanElements(innerLit) { + return true + } + } + } + return false } // containsOnlyLiterals checks if a literal array/tuple contains only literal values (no expressions) @@ -423,22 +677,28 @@ func explainInExpr(sb *strings.Builder, n *ast.InExpr, indent string, depth int) // Determine if the IN list should be combined into a single tuple literal // This happens when we have multiple literals of compatible types: - // - All numeric literals/expressions (integers/floats, including unary minus) - // - All string literals + // - All numeric literals/expressions (integers/floats, including unary minus) + NULLs + // - All string literals + NULLs // - All tuple literals that contain only primitive literals (recursively) canBeTupleLiteral := false if n.Query == nil && len(n.List) > 1 { - allNumeric := true - allStrings := true + allNumericOrNull := true + allStringsOrNull := true allTuples := true allTuplesArePrimitive := true + hasNonNull := false // Need at least one non-null value for _, item := range n.List { if lit, ok := item.(*ast.Literal); ok { + if lit.Type == ast.LiteralNull { + // NULL is compatible with both numeric and string lists + continue + } + hasNonNull = true if lit.Type != ast.LiteralInteger && lit.Type != ast.LiteralFloat { - allNumeric = false + allNumericOrNull = false } if lit.Type != ast.LiteralString { - allStrings = false + allStringsOrNull = false } if lit.Type != ast.LiteralTuple { allTuples = false @@ -450,17 +710,18 @@ func explainInExpr(sb *strings.Builder, n *ast.InExpr, indent string, depth int) } } else if isNumericExpr(item) { // Unary minus of numeric is still numeric - allStrings = false + hasNonNull = true + allStringsOrNull = false allTuples = false } else { - allNumeric = false - allStrings = false + allNumericOrNull = false + allStringsOrNull = false allTuples = false break } } // For tuples, only combine if all contain primitive literals - canBeTupleLiteral = allNumeric || allStrings || (allTuples && allTuplesArePrimitive) + canBeTupleLiteral = hasNonNull && (allNumericOrNull || allStringsOrNull || (allTuples && allTuplesArePrimitive)) } // Count arguments: expr + list items or subquery @@ -578,17 +839,23 @@ func explainInExprWithAlias(sb *strings.Builder, n *ast.InExpr, alias string, in const maxStringTupleSizeWithAlias = 10 canBeTupleLiteral := false if n.Query == nil && len(n.List) > 1 { - allNumeric := true - allStrings := true + allNumericOrNull := true + allStringsOrNull := true allTuples := true allTuplesArePrimitive := true + hasNonNull := false // Need at least one non-null value for _, item := range n.List { if lit, ok := item.(*ast.Literal); ok { + if lit.Type == ast.LiteralNull { + // NULL is compatible with both numeric and string lists + continue + } + hasNonNull = true if lit.Type != ast.LiteralInteger && lit.Type != ast.LiteralFloat { - allNumeric = false + allNumericOrNull = false } if lit.Type != ast.LiteralString { - allStrings = false + allStringsOrNull = false } if lit.Type != ast.LiteralTuple { allTuples = false @@ -598,16 +865,17 @@ func explainInExprWithAlias(sb *strings.Builder, n *ast.InExpr, alias string, in } } } else if isNumericExpr(item) { - allStrings = false + hasNonNull = true + allStringsOrNull = false allTuples = false } else { - allNumeric = false - allStrings = false + allNumericOrNull = false + allStringsOrNull = false allTuples = false break } } - canBeTupleLiteral = allNumeric || (allStrings && len(n.List) <= maxStringTupleSizeWithAlias) || (allTuples && allTuplesArePrimitive) + canBeTupleLiteral = hasNonNull && (allNumericOrNull || (allStringsOrNull && len(n.List) <= maxStringTupleSizeWithAlias) || (allTuples && allTuplesArePrimitive)) } // Count arguments @@ -857,19 +1125,50 @@ func explainCaseExprWithAlias(sb *strings.Builder, n *ast.CaseExpr, alias string func explainIntervalExpr(sb *strings.Builder, n *ast.IntervalExpr, alias string, indent string, depth int) { // INTERVAL is represented as Function toInterval - // Unit needs to be title-cased (e.g., YEAR -> Year) + // Unit needs to be title-cased and singular (e.g., YEAR -> Year, YEARS -> Year) unit := n.Unit - if len(unit) > 0 { - unit = strings.ToUpper(unit[:1]) + strings.ToLower(unit[1:]) + value := n.Value + + // Handle string literals like INTERVAL '2 years' - extract value and unit + if unit == "" { + if lit, ok := n.Value.(*ast.Literal); ok && lit.Type == ast.LiteralString { + if strVal, ok := lit.Value.(string); ok { + val, u := parseIntervalString(strVal) + if u != "" { + unit = u + // Create a numeric literal for the value + value = &ast.Literal{ + Type: ast.LiteralInteger, + Value: val, + } + } + } + } } - fnName := "toInterval" + unit + + unitNorm := normalizeIntervalUnit(unit) + fnName := "toInterval" + unitNorm if alias != "" { fmt.Fprintf(sb, "%sFunction %s (alias %s) (children %d)\n", indent, fnName, alias, 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, n.Value, depth+2) + Node(sb, value, depth+2) +} + +// parseIntervalString parses a string like "2 years" into value and unit +func parseIntervalString(s string) (value string, unit string) { + // Trim surrounding quotes if present + s = strings.Trim(s, "'\"") + s = strings.TrimSpace(s) + + // Find the split between number and unit + parts := strings.Fields(s) + if len(parts) >= 2 { + return parts[0], parts[1] + } + return s, "" } func explainExistsExpr(sb *strings.Builder, n *ast.ExistsExpr, indent string, depth int) { diff --git a/internal/explain/select.go b/internal/explain/select.go index 06651fa6d3..3c30c111aa 100644 --- a/internal/explain/select.go +++ b/internal/explain/select.go @@ -96,8 +96,8 @@ func explainSelectQuery(sb *strings.Builder, n *ast.SelectQuery, indent string, if n.Where != nil { Node(sb, n.Where, depth+1) } - // GROUP BY - if len(n.GroupBy) > 0 { + // GROUP BY (skip for GROUP BY ALL which doesn't output an expression list) + if len(n.GroupBy) > 0 && !n.GroupByAll { fmt.Fprintf(sb, "%s ExpressionList (children %d)\n", indent, len(n.GroupBy)) for _, g := range n.GroupBy { if n.GroupingSets { @@ -327,7 +327,7 @@ func countSelectQueryChildren(n *ast.SelectQuery) int { if n.Where != nil { count++ } - if len(n.GroupBy) > 0 { + if len(n.GroupBy) > 0 && !n.GroupByAll { count++ } if n.Having != nil { diff --git a/internal/explain/statements.go b/internal/explain/statements.go index cf7b187357..273d7cd098 100644 --- a/internal/explain/statements.go +++ b/internal/explain/statements.go @@ -179,16 +179,16 @@ func explainCreateQuery(sb *strings.Builder, n *ast.CreateQuery, indent string, } // ClickHouse adds an extra space before (children N) for CREATE DATABASE if n.CreateDatabase { - fmt.Fprintf(sb, "%sCreateQuery %s (children %d)\n", indent, name, children) - fmt.Fprintf(sb, "%s Identifier %s\n", indent, name) + fmt.Fprintf(sb, "%sCreateQuery %s (children %d)\n", indent, EscapeIdentifier(name), children) + fmt.Fprintf(sb, "%s Identifier %s\n", indent, EscapeIdentifier(name)) } else if hasDatabase { // Database-qualified: CreateQuery db table (children N) - fmt.Fprintf(sb, "%sCreateQuery %s %s (children %d)\n", indent, n.Database, name, children) - fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.Database) - fmt.Fprintf(sb, "%s Identifier %s\n", indent, name) + fmt.Fprintf(sb, "%sCreateQuery %s %s (children %d)\n", indent, EscapeIdentifier(n.Database), EscapeIdentifier(name), children) + fmt.Fprintf(sb, "%s Identifier %s\n", indent, EscapeIdentifier(n.Database)) + fmt.Fprintf(sb, "%s Identifier %s\n", indent, EscapeIdentifier(name)) } else { - fmt.Fprintf(sb, "%sCreateQuery %s (children %d)\n", indent, name, children) - fmt.Fprintf(sb, "%s Identifier %s\n", indent, name) + fmt.Fprintf(sb, "%sCreateQuery %s (children %d)\n", indent, EscapeIdentifier(name), children) + fmt.Fprintf(sb, "%s Identifier %s\n", indent, EscapeIdentifier(name)) } if len(n.Columns) > 0 || len(n.Indexes) > 0 || len(n.Projections) > 0 || len(n.Constraints) > 0 { childrenCount := 0 @@ -492,16 +492,31 @@ func explainDropQuery(sb *strings.Builder, n *ast.DropQuery, indent string, dept 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) + fmt.Fprintf(sb, "%sDropQuery %s %s (children %d)\n", indent, EscapeIdentifier(n.Database), EscapeIdentifier(name), 2) + fmt.Fprintf(sb, "%s Identifier %s\n", indent, EscapeIdentifier(n.Database)) + fmt.Fprintf(sb, "%s Identifier %s\n", indent, EscapeIdentifier(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) + fmt.Fprintf(sb, "%sDropQuery %s (children %d)\n", indent, EscapeIdentifier(name), 1) + fmt.Fprintf(sb, "%s Identifier %s\n", indent, EscapeIdentifier(name)) } else { - fmt.Fprintf(sb, "%sDropQuery %s (children %d)\n", indent, name, 1) - fmt.Fprintf(sb, "%s Identifier %s\n", indent, name) + fmt.Fprintf(sb, "%sDropQuery %s (children %d)\n", indent, EscapeIdentifier(name), 1) + fmt.Fprintf(sb, "%s Identifier %s\n", indent, EscapeIdentifier(name)) + } +} + +func explainUndropQuery(sb *strings.Builder, n *ast.UndropQuery, indent string, depth int) { + name := n.Table + // Check if we have a database-qualified name (for UNDROP TABLE db.table) + hasDatabase := n.Database != "" + if hasDatabase { + // Database-qualified: UndropQuery db table (children 2) + fmt.Fprintf(sb, "%sUndropQuery %s %s (children %d)\n", indent, EscapeIdentifier(n.Database), EscapeIdentifier(name), 2) + fmt.Fprintf(sb, "%s Identifier %s\n", indent, EscapeIdentifier(n.Database)) + fmt.Fprintf(sb, "%s Identifier %s\n", indent, EscapeIdentifier(name)) + } else { + fmt.Fprintf(sb, "%sUndropQuery %s (children %d)\n", indent, EscapeIdentifier(name), 1) + fmt.Fprintf(sb, "%s Identifier %s\n", indent, EscapeIdentifier(name)) } } @@ -672,32 +687,50 @@ func explainShowQuery(sb *strings.Builder, n *ast.ShowQuery, indent string) { if n.ShowType == ast.ShowCreateDictionary && (n.Database != "" || n.From != "") { if n.Database != "" && n.From != "" { children := 2 + if n.Format != "" { + children++ + } if n.HasSettings { children++ } fmt.Fprintf(sb, "%sShowCreateDictionaryQuery %s %s (children %d)\n", indent, n.Database, n.From, children) fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.Database) fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.From) + if n.Format != "" { + fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.Format) + } if n.HasSettings { fmt.Fprintf(sb, "%s Set\n", indent) } } else if n.From != "" { children := 1 + if n.Format != "" { + children++ + } if n.HasSettings { children++ } fmt.Fprintf(sb, "%sShowCreateDictionaryQuery %s (children %d)\n", indent, n.From, children) fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.From) + if n.Format != "" { + fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.Format) + } if n.HasSettings { fmt.Fprintf(sb, "%s Set\n", indent) } } else if n.Database != "" { children := 1 + if n.Format != "" { + children++ + } if n.HasSettings { children++ } fmt.Fprintf(sb, "%sShowCreateDictionaryQuery %s (children %d)\n", indent, n.Database, children) fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.Database) + if n.Format != "" { + fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.Format) + } if n.HasSettings { fmt.Fprintf(sb, "%s Set\n", indent) } @@ -803,14 +836,41 @@ func explainShowQuery(sb *strings.Builder, n *ast.ShowQuery, indent string) { // SHOW CREATE USER has special output format if n.ShowType == ast.ShowCreateUser { - fmt.Fprintf(sb, "%sSHOW CREATE USER query\n", indent) + if n.Format != "" { + fmt.Fprintf(sb, "%sSHOW CREATE USER query (children 1)\n", indent) + fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.Format) + } else { + fmt.Fprintf(sb, "%sSHOW CREATE USER query\n", indent) + } return } - // SHOW TABLES FROM database - include database as child - if n.ShowType == ast.ShowTables && n.From != "" { - fmt.Fprintf(sb, "%sShowTables (children 1)\n", indent) - fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.From) + // SHOW TABLES/DATABASES/DICTIONARIES - include FROM and FORMAT as children + if n.ShowType == ast.ShowTables || n.ShowType == ast.ShowDatabases || n.ShowType == ast.ShowDictionaries { + children := 0 + if n.From != "" { + children++ + } + if n.Format != "" { + children++ + } + if n.HasSettings { + children++ + } + if children > 0 { + fmt.Fprintf(sb, "%sShowTables (children %d)\n", indent, children) + if n.From != "" { + fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.From) + } + if n.Format != "" { + fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.Format) + } + if n.HasSettings { + fmt.Fprintf(sb, "%s Set\n", indent) + } + } else { + fmt.Fprintf(sb, "%sShowTables\n", indent) + } return } @@ -826,23 +886,35 @@ func explainDescribeQuery(sb *strings.Builder, n *ast.DescribeQuery, indent stri if n.TableExpr != nil { // DESCRIBE on a subquery - TableExpr contains a TableExpression with a Subquery children := 1 + if n.Format != "" { + children++ + } if len(n.Settings) > 0 { children++ } fmt.Fprintf(sb, "%sDescribeQuery (children %d)\n", indent, children) Node(sb, n.TableExpr, depth+1) + if n.Format != "" { + fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.Format) + } 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 n.Format != "" { + children++ + } if len(n.Settings) > 0 { children++ } fmt.Fprintf(sb, "%sDescribeQuery (children %d)\n", indent, children) fmt.Fprintf(sb, "%s TableExpression (children 1)\n", indent) explainFunctionCall(sb, n.TableFunction, indent+" ", 2) + if n.Format != "" { + fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.Format) + } if len(n.Settings) > 0 { fmt.Fprintf(sb, "%s Set\n", indent) } @@ -853,12 +925,18 @@ func explainDescribeQuery(sb *strings.Builder, n *ast.DescribeQuery, indent stri name = n.Database + "." + n.Table } children := 1 + if n.Format != "" { + children++ + } if len(n.Settings) > 0 { children++ } fmt.Fprintf(sb, "%sDescribeQuery (children %d)\n", indent, children) fmt.Fprintf(sb, "%s TableExpression (children 1)\n", indent) fmt.Fprintf(sb, "%s TableIdentifier %s\n", indent, name) + if n.Format != "" { + fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.Format) + } if len(n.Settings) > 0 { fmt.Fprintf(sb, "%s Set\n", indent) } @@ -1027,6 +1105,14 @@ func explainAlterCommand(sb *strings.Builder, cmd *ast.AlterCommand, indent stri if cmdType == ast.AlterDetachPartition { cmdType = ast.AlterDropPartition } + // CLEAR_COLUMN is shown as DROP_COLUMN in EXPLAIN AST + if cmdType == ast.AlterClearColumn { + cmdType = ast.AlterDropColumn + } + // DELETE_WHERE is shown as DELETE in EXPLAIN AST + if cmdType == ast.AlterDeleteWhere { + cmdType = "DELETE" + } fmt.Fprintf(sb, "%sAlterCommand %s (children %d)\n", indent, cmdType, children) switch cmd.Type { @@ -1091,7 +1177,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.AlterFreezePartition: + ast.AlterReplacePartition, ast.AlterFetchPartition, ast.AlterMovePartition, ast.AlterFreezePartition: 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" { @@ -1284,12 +1370,9 @@ func countAlterCommandChildren(cmd *ast.AlterCommand) int { case ast.AlterModifySetting: children = 1 case ast.AlterDropPartition, ast.AlterDetachPartition, ast.AlterAttachPartition, - ast.AlterReplacePartition, ast.AlterFreezePartition: + ast.AlterReplacePartition, ast.AlterFetchPartition, ast.AlterMovePartition, ast.AlterFreezePartition: if cmd.Partition != nil { - // PARTITION ALL doesn't count as a child (shown as Partition_ID empty) - if ident, ok := cmd.Partition.(*ast.Identifier); !ok || strings.ToUpper(ident.Name()) != "ALL" { - children++ - } + children++ } case ast.AlterFreeze: // No children @@ -1363,13 +1446,15 @@ func explainTruncateQuery(sb *strings.Builder, n *ast.TruncateQuery, indent stri return } - name := n.Table if n.Database != "" { - name = n.Database + "." + n.Table + // Database-qualified: TruncateQuery db table (children 2) + fmt.Fprintf(sb, "%sTruncateQuery %s %s (children 2)\n", indent, n.Database, n.Table) + fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.Database) + fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.Table) + } else { + fmt.Fprintf(sb, "%sTruncateQuery %s (children 1)\n", indent, n.Table) + fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.Table) } - - fmt.Fprintf(sb, "%sTruncateQuery %s (children %d)\n", indent, name, 1) - fmt.Fprintf(sb, "%s Identifier %s\n", indent, name) } func explainCheckQuery(sb *strings.Builder, n *ast.CheckQuery, indent string) { @@ -1378,26 +1463,40 @@ func explainCheckQuery(sb *strings.Builder, n *ast.CheckQuery, indent string) { return } - name := n.Table if n.Database != "" { - name = n.Database + "." + n.Table - } - - children := 1 // identifier - if n.Format != "" { - children++ - } - if len(n.Settings) > 0 { - children++ - } - - fmt.Fprintf(sb, "%sCheckQuery %s (children %d)\n", indent, name, children) - fmt.Fprintf(sb, "%s Identifier %s\n", indent, name) - if n.Format != "" { - fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.Format) - } - if len(n.Settings) > 0 { - fmt.Fprintf(sb, "%s Set\n", indent) + // Database-qualified: CheckQuery db table (children N) + children := 2 // database + table identifiers + if n.Format != "" { + children++ + } + if len(n.Settings) > 0 { + children++ + } + fmt.Fprintf(sb, "%sCheckQuery %s %s (children %d)\n", indent, n.Database, n.Table, children) + fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.Database) + fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.Table) + if n.Format != "" { + fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.Format) + } + if len(n.Settings) > 0 { + fmt.Fprintf(sb, "%s Set\n", indent) + } + } else { + children := 1 // table identifier + if n.Format != "" { + children++ + } + if len(n.Settings) > 0 { + children++ + } + fmt.Fprintf(sb, "%sCheckQuery %s (children %d)\n", indent, n.Table, children) + fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.Table) + if n.Format != "" { + fmt.Fprintf(sb, "%s Identifier %s\n", indent, n.Format) + } + if len(n.Settings) > 0 { + fmt.Fprintf(sb, "%s Set\n", indent) + } } } diff --git a/lexer/lexer.go b/lexer/lexer.go index 7335396657..1265e3849e 100644 --- a/lexer/lexer.go +++ b/lexer/lexer.go @@ -80,6 +80,55 @@ func (l *Lexer) skipWhitespace() { } } +// isIdentifierAfterDot checks if what follows the DOT looks like an identifier pattern. +// This handles cases like db.03711_table where 03711_table should be treated as an identifier. +// We look ahead to see if we have: digits followed by underscore followed by letter/digit +func (l *Lexer) isIdentifierAfterDot() bool { + // We're currently at '.', peek ahead to check the pattern + // Save current reader position by peeking + bytes, _ := l.reader.Peek(32) // peek enough to see the pattern, ignore EOF error + if len(bytes) == 0 { + return false + } + + idx := 0 + // Skip initial digits + for idx < len(bytes) && bytes[idx] >= '0' && bytes[idx] <= '9' { + idx++ + } + // If no digits found, it's not our pattern + if idx == 0 { + return false + } + // Check for underscore followed by letter/digit (identifier pattern) + if idx < len(bytes) && bytes[idx] == '_' { + idx++ + if idx < len(bytes) && isIdentContinueByte(bytes[idx]) { + return true + } + } + // Also check for letter directly after digits (like 1abc) + if idx < len(bytes) { + ch, _ := utf8.DecodeRune(bytes[idx:]) + // Check it's a letter but not exponent (e/E followed by digit/+/-) + if unicode.IsLetter(ch) { + if (ch == 'e' || ch == 'E') && idx+1 < len(bytes) { + next := bytes[idx+1] + if next >= '0' && next <= '9' || next == '+' || next == '-' { + return false // This is a scientific notation number + } + } + return true + } + } + return false +} + +// isIdentContinueByte checks if a byte is a valid identifier continuation character +func isIdentContinueByte(b byte) bool { + return (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') || (b >= '0' && b <= '9') || b == '_' +} + // isClickHouseWhitespace returns true for characters ClickHouse treats as whitespace // but Go's unicode.IsSpace does not recognize. func isClickHouseWhitespace(ch rune) bool { @@ -226,6 +275,12 @@ func (l *Lexer) NextToken() Item { return Item{Token: token.COMMA, Value: ",", Pos: pos} case '.': if unicode.IsDigit(l.peekChar()) { + // Before treating .digits as a number, check if it's part of an identifier pattern + // For example, db.03711_table should be DOT + IDENT, not DOT + NUMBER + IDENT + if l.isIdentifierAfterDot() { + l.readChar() + return Item{Token: token.DOT, Value: ".", Pos: pos} + } return l.readNumber() } l.readChar() diff --git a/parser/expression.go b/parser/expression.go index 636d38983e..1320ebefc5 100644 --- a/parser/expression.go +++ b/parser/expression.go @@ -158,6 +158,58 @@ func (p *Parser) parseFunctionArgumentList() []ast.Expression { } } + // Post-process: merge consecutive identifiers followed by a lambda into a multi-param lambda + // Pattern: [Ident("acc"), Lambda(["x"], body)] -> [Lambda(["acc", "x"], body)] + exprs = mergeMultiParamLambdas(exprs) + + return exprs +} + +// mergeMultiParamLambdas looks for pattern [Ident, Ident, ..., Lambda] at the START +// of the expression list and merges them into a single multi-param lambda. +// This handles ClickHouse's syntax: acc,x -> body (multi-param lambda without parentheses) +// This ONLY applies at position 0 - identifiers in the middle are regular arguments. +func mergeMultiParamLambdas(exprs []ast.Expression) []ast.Expression { + if len(exprs) < 2 { + return exprs + } + + // Only check at position 0 - the pattern must start at the beginning + if ident, ok := exprs[0].(*ast.Identifier); ok && len(ident.Parts) == 1 { + // Count consecutive simple identifiers at the start + j := 0 + var params []string + for j < len(exprs) { + if id, ok := exprs[j].(*ast.Identifier); ok && len(id.Parts) == 1 { + params = append(params, id.Name()) + j++ + } else { + break + } + } + // Check if the next expression is a lambda and we have at least one identifier + if j < len(exprs) && len(params) >= 1 { + if lambda, ok := exprs[j].(*ast.Lambda); ok { + // Don't merge if lambda was explicitly parenthesized + // e.g., f(a, (x -> y)) should NOT merge 'a' into the lambda + if lambda.Parenthesized { + return exprs + } + // Merge the identifiers into the lambda's parameters + newParams := make([]string, 0, len(params)+len(lambda.Parameters)) + newParams = append(newParams, params...) + newParams = append(newParams, lambda.Parameters...) + lambda.Parameters = newParams + // Return lambda followed by remaining expressions + result := make([]ast.Expression, 0, len(exprs)-j) + result = append(result, lambda) + result = append(result, exprs[j+1:]...) + return result + } + } + } + + // No merge needed return exprs } @@ -407,22 +459,31 @@ func (p *Parser) parseInfixExpression(left ast.Expression) ast.Expression { case token.ARROW: return p.parseLambda(left) case token.EXCEPT: - // Handle * EXCEPT (col1, col2) + // Handle * EXCEPT (col1, col2) or COLUMNS(...) EXCEPT (col1, col2) if asterisk, ok := left.(*ast.Asterisk); ok { return p.parseAsteriskExcept(asterisk) } + if matcher, ok := left.(*ast.ColumnsMatcher); ok { + return p.parseColumnsExcept(matcher) + } return left case token.REPLACE: - // Handle * REPLACE (expr AS col) + // Handle * REPLACE (expr AS col) or COLUMNS(...) REPLACE (expr AS col) if asterisk, ok := left.(*ast.Asterisk); ok { return p.parseAsteriskReplace(asterisk) } + if matcher, ok := left.(*ast.ColumnsMatcher); ok { + return p.parseColumnsReplace(matcher) + } return left case token.APPLY: - // Handle * APPLY (func) or * APPLY func + // Handle * APPLY (func) or COLUMNS(...) APPLY(func) if asterisk, ok := left.(*ast.Asterisk); ok { return p.parseAsteriskApply(asterisk) } + if matcher, ok := left.(*ast.ColumnsMatcher); ok { + return p.parseColumnsApply(matcher) + } return left case token.NUMBER: // Handle tuple access like t.1 where .1 is lexed as a number @@ -440,6 +501,29 @@ func (p *Parser) parseIdentifierOrFunction() ast.Expression { name := p.current.Value p.nextToken() + // Check for typed literals: DATE '...', TIMESTAMP '...', TIME '...' + // These are converted to toDate(), toDateTime(), toTime() function calls + upperName := strings.ToUpper(name) + if p.currentIs(token.STRING) && (upperName == "DATE" || upperName == "TIMESTAMP" || upperName == "TIME") { + fnName := "toDate" + if upperName == "TIMESTAMP" { + fnName = "toDateTime" + } else if upperName == "TIME" { + fnName = "toTime" + } + strLit := &ast.Literal{ + Position: p.current.Pos, + Type: "String", + Value: p.current.Value, + } + p.nextToken() + return &ast.FunctionCall{ + Position: pos, + Name: fnName, + Arguments: []ast.Expression{strLit}, + } + } + // Check for MySQL-style @@variable syntax (system variables) // Convert to globalVariable('varname') function call with alias @@varname if strings.HasPrefix(name, "@@") { @@ -987,6 +1071,13 @@ func (p *Parser) parseGroupedOrTuple() ast.Expression { binExpr.Parenthesized = true } + // Mark lambda expressions as parenthesized so we don't merge them + // with preceding identifiers in multi-param lambda detection + // e.g., f(a, (x -> y)) should NOT merge 'a' into the lambda + if lambda, ok := first.(*ast.Lambda); ok { + lambda.Parenthesized = true + } + return first } @@ -1353,6 +1444,16 @@ func (p *Parser) parseInterval() ast.Expression { // Use ALIAS_PREC to prevent consuming the unit as an alias expr.Value = p.parseExpression(ALIAS_PREC) + // Handle INTERVAL '2' AS n minute - where AS n is alias on the value + if p.currentIs(token.AS) { + p.nextToken() // skip AS + if p.currentIs(token.IDENT) || p.current.Token.IsKeyword() { + alias := p.current.Value + p.nextToken() + expr.Value = p.wrapWithAlias(expr.Value, alias) + } + } + // Parse unit (interval units are identifiers like DAY, MONTH, etc.) if p.currentIs(token.IDENT) { expr.Unit = strings.ToUpper(p.current.Value) @@ -1857,6 +1958,15 @@ func (p *Parser) parseArrayAccess(left ast.Expression) ast.Expression { } else { break } + } else if p.currentIs(token.COLON) { + // JSON subcolumn type accessor: json.field.:`TypeName` + p.nextToken() // skip : + typePart := ":" + if p.currentIs(token.IDENT) || p.current.Token.IsKeyword() || p.currentIs(token.STRING) { + typePart += "`" + p.current.Value + "`" + p.nextToken() + } + ident.Parts = append(ident.Parts, typePart) } else if p.currentIs(token.IDENT) || p.current.Token.IsKeyword() { ident.Parts = append(ident.Parts, p.current.Value) p.nextToken() @@ -2176,22 +2286,8 @@ func (p *Parser) parseColumnsMatcher() ast.Expression { p.expect(token.RPAREN) - // Handle EXCEPT - if p.currentIs(token.EXCEPT) { - p.nextToken() - if p.expect(token.LPAREN) { - for !p.currentIs(token.RPAREN) && !p.currentIs(token.EOF) { - if p.currentIs(token.IDENT) { - matcher.Except = append(matcher.Except, p.current.Value) - p.nextToken() - } - if p.currentIs(token.COMMA) { - p.nextToken() - } - } - p.expect(token.RPAREN) - } - } + // EXCEPT, REPLACE, and APPLY are now handled via infix parsing + // to preserve transformer ordering return matcher } @@ -2228,22 +2324,8 @@ func (p *Parser) parseQualifiedColumnsMatcher(qualifier string, pos token.Positi p.expect(token.RPAREN) - // Handle EXCEPT - if p.currentIs(token.EXCEPT) { - p.nextToken() - if p.expect(token.LPAREN) { - for !p.currentIs(token.RPAREN) && !p.currentIs(token.EOF) { - if p.currentIs(token.IDENT) { - matcher.Except = append(matcher.Except, p.current.Value) - p.nextToken() - } - if p.currentIs(token.COMMA) { - p.nextToken() - } - } - p.expect(token.RPAREN) - } - } + // EXCEPT, REPLACE, and APPLY are now handled via infix parsing + // to preserve transformer ordering return matcher } @@ -2369,6 +2451,7 @@ func (p *Parser) parseKeywordAsIdentifier() ast.Expression { } func (p *Parser) parseAsteriskExcept(asterisk *ast.Asterisk) ast.Expression { + pos := p.current.Pos p.nextToken() // skip EXCEPT // EXCEPT can have optional parentheses: * EXCEPT (col1, col2) or * EXCEPT col @@ -2377,9 +2460,11 @@ func (p *Parser) parseAsteriskExcept(asterisk *ast.Asterisk) ast.Expression { p.nextToken() // skip ( } + var exceptCols []string // Parse column names (can be IDENT or keywords) for { if p.currentIs(token.IDENT) || p.current.Token.IsKeyword() { + exceptCols = append(exceptCols, p.current.Value) asterisk.Except = append(asterisk.Except, p.current.Value) p.nextToken() } @@ -2391,6 +2476,14 @@ func (p *Parser) parseAsteriskExcept(asterisk *ast.Asterisk) ast.Expression { } } + if len(exceptCols) > 0 { + asterisk.Transformers = append(asterisk.Transformers, &ast.ColumnTransformer{ + Position: pos, + Type: "except", + Except: exceptCols, + }) + } + if hasParens { p.expect(token.RPAREN) } @@ -2399,6 +2492,7 @@ func (p *Parser) parseAsteriskExcept(asterisk *ast.Asterisk) ast.Expression { } func (p *Parser) parseAsteriskReplace(asterisk *ast.Asterisk) ast.Expression { + pos := p.current.Pos p.nextToken() // skip REPLACE // REPLACE can have optional parentheses: REPLACE (expr AS col) or REPLACE expr AS col @@ -2407,6 +2501,7 @@ func (p *Parser) parseAsteriskReplace(asterisk *ast.Asterisk) ast.Expression { p.nextToken() } + var replaces []*ast.ReplaceExpr for { // Stop conditions based on context if hasParens && p.currentIs(token.RPAREN) { @@ -2434,6 +2529,7 @@ func (p *Parser) parseAsteriskReplace(asterisk *ast.Asterisk) ast.Expression { } asterisk.Replace = append(asterisk.Replace, replace) + replaces = append(replaces, replace) if p.currentIs(token.COMMA) { p.nextToken() @@ -2446,6 +2542,14 @@ func (p *Parser) parseAsteriskReplace(asterisk *ast.Asterisk) ast.Expression { } } + if len(replaces) > 0 { + asterisk.Transformers = append(asterisk.Transformers, &ast.ColumnTransformer{ + Position: pos, + Type: "replace", + Replaces: replaces, + }) + } + if hasParens { p.expect(token.RPAREN) } @@ -2454,6 +2558,7 @@ func (p *Parser) parseAsteriskReplace(asterisk *ast.Asterisk) ast.Expression { } func (p *Parser) parseAsteriskApply(asterisk *ast.Asterisk) ast.Expression { + pos := p.current.Pos p.nextToken() // skip APPLY // APPLY can have optional parentheses: * APPLY(func) or * APPLY func @@ -2462,9 +2567,24 @@ func (p *Parser) parseAsteriskApply(asterisk *ast.Asterisk) ast.Expression { p.nextToken() // skip ( } - // Parse function name (can be IDENT or keyword like sum, avg, etc.) - if p.currentIs(token.IDENT) || p.current.Token.IsKeyword() { - asterisk.Apply = append(asterisk.Apply, p.current.Value) + // Check for lambda expression: x -> expr + if p.currentIs(token.IDENT) && p.peekIs(token.ARROW) { + // Parse lambda expression + lambda := p.parseExpression(LOWEST) + asterisk.Transformers = append(asterisk.Transformers, &ast.ColumnTransformer{ + Position: pos, + Type: "apply", + ApplyLambda: lambda, + }) + } else if p.currentIs(token.IDENT) || p.current.Token.IsKeyword() { + // Parse function name (can be IDENT or keyword like sum, avg, etc.) + funcName := p.current.Value + asterisk.Apply = append(asterisk.Apply, funcName) + asterisk.Transformers = append(asterisk.Transformers, &ast.ColumnTransformer{ + Position: pos, + Type: "apply", + Apply: funcName, + }) p.nextToken() } @@ -2474,3 +2594,154 @@ func (p *Parser) parseAsteriskApply(asterisk *ast.Asterisk) ast.Expression { return asterisk } + +func (p *Parser) parseColumnsApply(matcher *ast.ColumnsMatcher) ast.Expression { + pos := p.current.Pos + p.nextToken() // skip APPLY + + // APPLY can have optional parentheses: COLUMNS(...) APPLY(func) or COLUMNS(...) APPLY func + hasParens := p.currentIs(token.LPAREN) + if hasParens { + p.nextToken() // skip ( + } + + // Check for lambda expression: x -> expr + if p.currentIs(token.IDENT) && p.peekIs(token.ARROW) { + // Parse lambda expression + lambda := p.parseExpression(LOWEST) + matcher.Transformers = append(matcher.Transformers, &ast.ColumnTransformer{ + Position: pos, + Type: "apply", + ApplyLambda: lambda, + }) + } else if p.currentIs(token.IDENT) || p.current.Token.IsKeyword() { + // Parse function name (can be IDENT or keyword like sum, avg, etc.) + funcName := p.current.Value + matcher.Apply = append(matcher.Apply, funcName) + matcher.Transformers = append(matcher.Transformers, &ast.ColumnTransformer{ + Position: pos, + Type: "apply", + Apply: funcName, + }) + p.nextToken() + } + + if hasParens { + p.expect(token.RPAREN) + } + + return matcher +} + +func (p *Parser) parseColumnsExcept(matcher *ast.ColumnsMatcher) ast.Expression { + pos := p.current.Pos + p.nextToken() // skip EXCEPT + + // EXCEPT can have optional parentheses: COLUMNS(...) EXCEPT (col1, col2) or COLUMNS(...) EXCEPT col + hasParens := p.currentIs(token.LPAREN) + if hasParens { + p.nextToken() // skip ( + } + + var exceptCols []string + // Parse column names (can be IDENT or keywords) + for { + if p.currentIs(token.IDENT) || p.current.Token.IsKeyword() { + exceptCols = append(exceptCols, p.current.Value) + matcher.Except = append(matcher.Except, p.current.Value) + p.nextToken() + } + + if hasParens && p.currentIs(token.COMMA) { + p.nextToken() + } else { + break + } + } + + if len(exceptCols) > 0 { + matcher.Transformers = append(matcher.Transformers, &ast.ColumnTransformer{ + Position: pos, + Type: "except", + Except: exceptCols, + }) + } + + if hasParens { + p.expect(token.RPAREN) + } + + return matcher +} + +func (p *Parser) parseColumnsReplace(matcher *ast.ColumnsMatcher) ast.Expression { + pos := p.current.Pos + p.nextToken() // skip REPLACE + + // Check for STRICT modifier + if p.currentIs(token.IDENT) && strings.ToUpper(p.current.Value) == "STRICT" { + p.nextToken() + } + + // REPLACE can have optional parentheses: REPLACE (expr AS col) or REPLACE expr AS col + hasParens := p.currentIs(token.LPAREN) + if hasParens { + p.nextToken() + } + + var replaces []*ast.ReplaceExpr + for { + // Stop conditions based on context + if hasParens && p.currentIs(token.RPAREN) { + break + } + if !hasParens && (p.currentIs(token.FROM) || p.currentIs(token.WHERE) || p.currentIs(token.EOF) || + p.currentIs(token.GROUP) || p.currentIs(token.ORDER) || p.currentIs(token.HAVING) || + p.currentIs(token.LIMIT) || p.currentIs(token.SETTINGS) || p.currentIs(token.FORMAT) || + p.currentIs(token.UNION) || p.currentIs(token.EXCEPT) || p.currentIs(token.COMMA) || + p.currentIs(token.APPLY)) { + break + } + + replace := &ast.ReplaceExpr{ + Position: p.current.Pos, + } + + replace.Expr = p.parseExpression(ALIAS_PREC) + + if p.currentIs(token.AS) { + p.nextToken() + if p.currentIs(token.IDENT) { + replace.Name = p.current.Value + p.nextToken() + } + } + + matcher.Replace = append(matcher.Replace, replace) + replaces = append(replaces, replace) + + if p.currentIs(token.COMMA) { + p.nextToken() + // If no parens and we see comma, might be end of select column + if !hasParens { + break + } + } else if !hasParens { + break + } + } + + if len(replaces) > 0 { + matcher.Transformers = append(matcher.Transformers, &ast.ColumnTransformer{ + Position: pos, + Type: "replace", + Replaces: replaces, + }) + } + + if hasParens { + p.expect(token.RPAREN) + } + + return matcher +} diff --git a/parser/parser.go b/parser/parser.go index bdd6bbc125..954a5381fb 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -180,6 +180,8 @@ func (p *Parser) parseStatement() ast.Statement { return p.parseAlter() case token.TRUNCATE: return p.parseTruncate() + case token.UNDROP: + return p.parseUndrop() case token.USE: return p.parseUse() case token.DESCRIBE, token.DESC: @@ -193,6 +195,10 @@ func (p *Parser) parseStatement() ast.Statement { if p.peekIs(token.TRANSACTION) { return p.parseTransactionControl() } + // Check for SET DEFAULT ROLE + if p.peekIs(token.DEFAULT) { + return p.parseSetRole() + } return p.parseSet() case token.OPTIMIZE: return p.parseOptimize() @@ -550,6 +556,10 @@ func (p *Parser) parseSelect() *ast.SelectQuery { sel.GroupBy = p.parseExpressionList() p.expect(token.RPAREN) sel.WithCube = true + } else if p.currentIs(token.ALL) { + // GROUP BY ALL - special ClickHouse syntax + sel.GroupByAll = true + sel.GroupBy = p.parseExpressionList() // Still parse it, but mark as GroupByAll } else { sel.GroupBy = p.parseExpressionList() } @@ -1116,14 +1126,15 @@ func (p *Parser) parseTableExpression() *ast.TableExpression { } } - // Handle alias (keywords like LEFT, RIGHT can be used as aliases after AS) + // Handle alias (keywords like LEFT, RIGHT, FIRST can be used as aliases after AS, + // or without AS if they're not clause keywords) if p.currentIs(token.AS) { p.nextToken() if p.currentIs(token.IDENT) || p.current.Token.IsKeyword() { expr.Alias = p.current.Value p.nextToken() } - } else if p.currentIs(token.IDENT) && !p.isKeywordForClause() { + } else if (p.currentIs(token.IDENT) || p.current.Token.IsKeyword()) && !p.isKeywordForClause() { expr.Alias = p.current.Value p.nextToken() } @@ -1137,7 +1148,12 @@ func (p *Parser) isKeywordForClause() bool { token.OFFSET, token.UNION, token.EXCEPT, token.SETTINGS, token.FORMAT, token.PREWHERE, token.JOIN, token.LEFT, token.RIGHT, token.INNER, token.FULL, token.CROSS, token.PASTE, token.ON, token.USING, token.GLOBAL, - token.ANY, token.ALL, token.SEMI, token.ANTI, token.ASOF: + token.ANY, token.ALL, token.SEMI, token.ANTI, token.ASOF, token.ARRAY, + token.WINDOW, token.WITH, token.INTERSECT, token.SELECT: + return true + } + // Handle TOTALS as a clause keyword when used in "WITH TOTALS" + if p.current.Token == token.IDENT && strings.ToUpper(p.current.Value) == "TOTALS" { return true } return false @@ -1540,8 +1556,8 @@ func (p *Parser) parseCreate() ast.Statement { // CREATE WORKLOAD return p.parseCreateWorkload(pos) case "QUOTA": - // Skip these statements - just consume tokens until semicolon - p.parseCreateGeneric(create) + // CREATE QUOTA + return p.parseCreateQuota(pos) default: p.errors = append(p.errors, fmt.Errorf("expected TABLE, DATABASE, VIEW, FUNCTION, USER after CREATE")) return nil @@ -1961,7 +1977,14 @@ func (p *Parser) parseCreateView(create *ast.CreateQuery) { return } p.nextToken() - create.To = p.parseIdentifierName() + toName := p.parseIdentifierName() + if p.currentIs(token.DOT) { + p.nextToken() + create.ToDatabase = toName + create.To = p.parseIdentifierName() + } else { + create.To = toName + } } // Parse ENGINE (for materialized views) @@ -2348,11 +2371,20 @@ func (p *Parser) parseShowCreateSettingsProfile(pos token.Position) *ast.ShowCre break } - // Skip the rest of the statement - for !p.currentIs(token.EOF) && !p.currentIs(token.SEMICOLON) { + // Skip tokens until FORMAT or end of statement + for !p.currentIs(token.EOF) && !p.currentIs(token.SEMICOLON) && !p.currentIs(token.FORMAT) { p.nextToken() } + // Parse FORMAT clause if present + if p.currentIs(token.FORMAT) { + p.nextToken() + if p.currentIs(token.IDENT) || p.current.Token.IsKeyword() { + query.Format = p.current.Value + p.nextToken() + } + } + return query } @@ -2454,11 +2486,20 @@ func (p *Parser) parseShowCreateRowPolicy(pos token.Position) *ast.ShowCreateRow p.nextToken() } - // Skip the rest of the statement (policy names, ON table, etc.) - for !p.currentIs(token.EOF) && !p.currentIs(token.SEMICOLON) { + // Skip tokens until FORMAT or end of statement + for !p.currentIs(token.EOF) && !p.currentIs(token.SEMICOLON) && !p.currentIs(token.FORMAT) { p.nextToken() } + // Parse FORMAT clause if present + if p.currentIs(token.FORMAT) { + p.nextToken() + if p.currentIs(token.IDENT) || p.current.Token.IsKeyword() { + query.Format = p.current.Value + p.nextToken() + } + } + return query } @@ -2530,6 +2571,30 @@ func (p *Parser) parseAlterRole() *ast.CreateRoleQuery { return query } +func (p *Parser) parseCreateQuota(pos token.Position) *ast.CreateQuotaQuery { + query := &ast.CreateQuotaQuery{ + Position: pos, + } + + // Skip QUOTA keyword + if p.currentIs(token.IDENT) && strings.ToUpper(p.current.Value) == "QUOTA" { + p.nextToken() + } + + // Parse quota name + if p.currentIs(token.IDENT) || p.current.Token.IsKeyword() { + query.Name = p.current.Value + p.nextToken() + } + + // Skip the rest of the statement + for !p.currentIs(token.EOF) && !p.currentIs(token.SEMICOLON) { + p.nextToken() + } + + return query +} + func (p *Parser) parseShowCreateRole(pos token.Position) *ast.ShowCreateRoleQuery { query := &ast.ShowCreateRoleQuery{ Position: pos, @@ -2567,9 +2632,18 @@ func (p *Parser) parseShowCreateRole(pos token.Position) *ast.ShowCreateRoleQuer } } - // Skip the rest of the statement - for !p.currentIs(token.EOF) && !p.currentIs(token.SEMICOLON) { + // Skip tokens until FORMAT or end of statement + for !p.currentIs(token.EOF) && !p.currentIs(token.SEMICOLON) && !p.currentIs(token.FORMAT) { + p.nextToken() + } + + // Parse FORMAT clause if present + if p.currentIs(token.FORMAT) { p.nextToken() + if p.currentIs(token.IDENT) || p.current.Token.IsKeyword() { + query.Format = p.current.Value + p.nextToken() + } } return query @@ -3220,6 +3294,29 @@ func (p *Parser) parseDataType() *ast.DataType { } p.nextToken() + // For MySQL-compatible INT types, handle display width and UNSIGNED/SIGNED + upperName := strings.ToUpper(dt.Name) + isMySQLIntType := upperName == "INT" || upperName == "TINYINT" || upperName == "SMALLINT" || + upperName == "MEDIUMINT" || upperName == "BIGINT" + + if isMySQLIntType && p.currentIs(token.LPAREN) { + // Skip the display width parameter (e.g., INT(11)) + p.nextToken() // skip ( + for !p.currentIs(token.RPAREN) && !p.currentIs(token.EOF) { + p.nextToken() + } + p.expect(token.RPAREN) + } + + // Handle UNSIGNED/SIGNED modifiers for MySQL INT types + if isMySQLIntType && p.currentIs(token.IDENT) { + modifier := strings.ToUpper(p.current.Value) + if modifier == "UNSIGNED" || modifier == "SIGNED" { + dt.Name = dt.Name + " " + p.current.Value + p.nextToken() + } + } + // Parse type parameters if p.currentIs(token.LPAREN) { dt.HasParentheses = true @@ -3233,6 +3330,64 @@ func (p *Parser) parseDataType() *ast.DataType { // Parse type parameters, but stop on keywords that can't be part of type params for !p.currentIs(token.RPAREN) && !p.currentIs(token.EOF) && !p.currentIs(token.COLLATE) { + var param ast.Expression + + // Special handling for SKIP in JSON/OBJECT types: SKIP path or SKIP REGEXP 'pattern' + if isObjectType && (p.currentIs(token.IDENT) || p.current.Token.IsKeyword()) && strings.ToUpper(p.current.Value) == "SKIP" { + pos := p.current.Pos + p.nextToken() // consume SKIP + + // Check for SKIP REGEXP 'pattern' + if p.currentIs(token.REGEXP) || (p.currentIs(token.IDENT) && strings.ToUpper(p.current.Value) == "REGEXP") { + p.nextToken() // consume REGEXP + // Parse the pattern string + if p.currentIs(token.STRING) { + pattern := p.current.Value + p.nextToken() + param = &ast.FunctionCall{ + Position: pos, + Name: "SKIP REGEXP", + Arguments: []ast.Expression{&ast.Literal{Position: pos, Value: pattern, Type: ast.LiteralString}}, + } + } + } else { + // Parse dotted path: a, a.b, a.b.c, etc. + var pathParts []string + for { + if p.currentIs(token.IDENT) || p.current.Token.IsKeyword() { + pathParts = append(pathParts, p.current.Value) + p.nextToken() + } + if p.currentIs(token.DOT) { + p.nextToken() // consume dot + } else { + break + } + } + if len(pathParts) > 0 { + param = &ast.FunctionCall{ + Position: pos, + Name: "SKIP", + Arguments: []ast.Expression{&ast.Identifier{Position: pos, Parts: pathParts}}, + } + } + } + // Wrap in ObjectTypeArgument + if param != nil { + param = &ast.ObjectTypeArgument{ + Position: param.Pos(), + Expr: param, + } + dt.Parameters = append(dt.Parameters, param) + } + if p.currentIs(token.COMMA) { + p.nextToken() + } else { + break + } + continue + } + // Check if this is a named parameter: identifier followed by a type name // e.g., "a UInt32" where "a" is the name and "UInt32" is the type isNamedParam := false @@ -3258,7 +3413,6 @@ func (p *Parser) parseDataType() *ast.DataType { } } - var param ast.Expression if isNamedParam { // Parse as name + type pair pos := p.current.Pos @@ -4079,7 +4233,20 @@ func (p *Parser) parseAlterCommand() *ast.AlterCommand { if p.currentIs(token.COLUMN) { cmd.Type = ast.AlterModifyColumn p.nextToken() - cmd.Column = p.parseColumnDeclaration() + // Handle MODIFY COLUMN name REMOVE ... (e.g., REMOVE COMMENT) + // Check if the next token after column name is REMOVE + if (p.currentIs(token.IDENT) || p.current.Token.IsKeyword()) && p.peek.Token == token.IDENT && strings.ToUpper(p.peek.Value) == "REMOVE" { + // Just parse column name without type + colName := p.current.Value + p.nextToken() // skip column name + cmd.Column = &ast.ColumnDeclaration{Name: colName} + // Skip REMOVE COMMENT etc. + for !p.currentIs(token.EOF) && !p.currentIs(token.SEMICOLON) && !p.currentIs(token.COMMA) { + p.nextToken() + } + } else { + cmd.Column = p.parseColumnDeclaration() + } } else if p.currentIs(token.TTL) { cmd.Type = ast.AlterModifyTTL p.nextToken() @@ -4179,6 +4346,21 @@ func (p *Parser) parseAlterCommand() *ast.AlterCommand { } } } + case token.FETCH: + p.nextToken() + if p.currentIs(token.PARTITION) { + cmd.Type = ast.AlterFetchPartition + p.nextToken() + cmd.Partition = p.parseExpression(LOWEST) + // FROM path + if p.currentIs(token.FROM) { + p.nextToken() + if p.currentIs(token.STRING) { + cmd.FromPath = p.current.Value + p.nextToken() + } + } + } case token.DELETE: // DELETE WHERE condition - mutation to delete rows cmd.Type = ast.AlterDeleteWhere @@ -4266,6 +4448,50 @@ func (p *Parser) parseTruncate() *ast.TruncateQuery { return trunc } +func (p *Parser) parseUndrop() *ast.UndropQuery { + undrop := &ast.UndropQuery{ + Position: p.current.Pos, + } + + p.nextToken() // skip UNDROP + + if p.currentIs(token.TABLE) { + p.nextToken() + } + + // Parse table name (can start with a number in ClickHouse) + tableName := p.parseIdentifierName() + if tableName != "" { + if p.currentIs(token.DOT) { + p.nextToken() + undrop.Database = tableName + undrop.Table = p.parseIdentifierName() + } else { + undrop.Table = tableName + } + } + + // Handle ON CLUSTER + if p.currentIs(token.ON) { + p.nextToken() + if p.currentIs(token.CLUSTER) { + p.nextToken() + undrop.OnCluster = p.parseIdentifierName() + } + } + + // Handle UUID + if p.currentIs(token.IDENT) && strings.ToUpper(p.current.Value) == "UUID" { + p.nextToken() + if p.currentIs(token.STRING) { + undrop.UUID = p.current.Value + p.nextToken() + } + } + + return undrop +} + func (p *Parser) parseUse() *ast.UseQuery { use := &ast.UseQuery{ Position: p.current.Pos, @@ -4346,11 +4572,20 @@ func (p *Parser) parseShow() ast.Statement { // Handle SHOW GRANTS - it has its own statement type if p.currentIs(token.IDENT) && strings.ToUpper(p.current.Value) == "GRANTS" { - // Skip all remaining tokens until end of statement - for !p.currentIs(token.EOF) && !p.currentIs(token.SEMICOLON) { + query := &ast.ShowGrantsQuery{Position: pos} + // Skip tokens until FORMAT or end of statement + for !p.currentIs(token.EOF) && !p.currentIs(token.SEMICOLON) && !p.currentIs(token.FORMAT) { p.nextToken() } - return &ast.ShowGrantsQuery{Position: pos} + // Parse FORMAT clause if present + if p.currentIs(token.FORMAT) { + p.nextToken() + if p.currentIs(token.IDENT) || p.current.Token.IsKeyword() { + query.Format = p.current.Value + p.nextToken() + } + } + return query } show := &ast.ShowQuery{ @@ -4367,6 +4602,10 @@ func (p *Parser) parseShow() ast.Statement { case token.COLUMNS: show.ShowType = ast.ShowColumns p.nextToken() + case token.INDEX: + // SHOW INDEX FROM table - treat as ShowColumns (ClickHouse maps to ShowColumns) + show.ShowType = ast.ShowColumns + p.nextToken() case token.CREATE: p.nextToken() if p.currentIs(token.DATABASE) { @@ -4375,12 +4614,20 @@ func (p *Parser) parseShow() ast.Statement { } else if p.currentIs(token.IDENT) && strings.ToUpper(p.current.Value) == "QUOTA" { // SHOW CREATE QUOTA p.nextToken() - name := "" + query := &ast.ShowCreateQuotaQuery{Position: pos} if p.currentIs(token.IDENT) || p.current.Token.IsKeyword() { - name = p.current.Value + query.Name = p.current.Value p.nextToken() } - return &ast.ShowCreateQuotaQuery{Position: pos, Name: name} + // Parse FORMAT clause if present + if p.currentIs(token.FORMAT) { + p.nextToken() + if p.currentIs(token.IDENT) || p.current.Token.IsKeyword() { + query.Format = p.current.Value + p.nextToken() + } + } + return query } else if p.currentIs(token.SETTINGS) || (p.currentIs(token.IDENT) && strings.ToUpper(p.current.Value) == "PROFILE") { // SHOW CREATE SETTINGS PROFILE or SHOW CREATE PROFILE return p.parseShowCreateSettingsProfile(pos) @@ -4399,13 +4646,24 @@ func (p *Parser) parseShow() ast.Statement { } else if p.currentIs(token.USER) { show.ShowType = ast.ShowCreateUser p.nextToken() - // Skip user name and host pattern - they don't affect explain output - for !p.currentIs(token.EOF) && !p.currentIs(token.SEMICOLON) { + // Skip user name and host pattern until FORMAT or end + for !p.currentIs(token.EOF) && !p.currentIs(token.SEMICOLON) && !p.currentIs(token.FORMAT) { + p.nextToken() + } + // Parse FORMAT clause if present + if p.currentIs(token.FORMAT) { p.nextToken() + if p.currentIs(token.IDENT) || p.current.Token.IsKeyword() { + show.Format = p.current.Value + p.nextToken() + } } } else { show.ShowType = ast.ShowCreate - // Handle SHOW CREATE TABLE, etc. + // Handle SHOW CREATE TABLE, SHOW CREATE TEMPORARY TABLE, etc. + if p.currentIs(token.TEMPORARY) { + p.nextToken() + } if p.currentIs(token.TABLE) { p.nextToken() } @@ -4424,11 +4682,25 @@ func (p *Parser) parseShow() ast.Statement { show.ShowType = ast.ShowDictionaries case "FUNCTIONS": show.ShowType = ast.ShowFunctions + case "INDEXES", "INDICES", "KEYS": + // SHOW INDEXES/INDICES/KEYS FROM table - treat as ShowColumns + show.ShowType = ast.ShowColumns + case "EXTENDED": + // SHOW EXTENDED INDEX FROM table - treat as ShowColumns + p.nextToken() + if p.currentIs(token.INDEX) { + p.nextToken() + } + show.ShowType = ast.ShowColumns + // Don't consume another token, fall through to FROM parsing + goto parseFrom } p.nextToken() } } +parseFrom: + // Parse FROM clause (or table/database name for SHOW CREATE TABLE/DATABASE/DICTIONARY/VIEW) showCreateTypes := show.ShowType == ast.ShowCreate || show.ShowType == ast.ShowCreateDB || show.ShowType == ast.ShowCreateDictionary || show.ShowType == ast.ShowCreateView if p.currentIs(token.FROM) || (showCreateTypes && (p.currentIs(token.IDENT) || p.current.Token.IsKeyword())) { @@ -4452,6 +4724,15 @@ func (p *Parser) parseShow() ast.Statement { } } + // Handle SHOW INDEX FROM table FROM database syntax (second FROM for database) + if p.currentIs(token.FROM) && show.ShowType == ast.ShowColumns { + p.nextToken() + if p.currentIs(token.IDENT) || p.current.Token.IsKeyword() { + show.Database = p.current.Value + p.nextToken() + } + } + // Parse NOT LIKE, LIKE or ILIKE clause if p.currentIs(token.NOT) { p.nextToken() @@ -4600,6 +4881,19 @@ func (p *Parser) parseSet() *ast.SetQuery { return set } +func (p *Parser) parseSetRole() *ast.SetRoleQuery { + query := &ast.SetRoleQuery{ + Position: p.current.Pos, + } + + // Skip SET DEFAULT ROLE ... TO ... + for !p.currentIs(token.EOF) && !p.currentIs(token.SEMICOLON) { + p.nextToken() + } + + return query +} + func (p *Parser) parseOptimize() *ast.OptimizeQuery { opt := &ast.OptimizeQuery{ Position: p.current.Pos, @@ -5343,14 +5637,11 @@ func (p *Parser) parseProjection() *ast.Projection { if p.currentIs(token.BY) { p.nextToken() // BY } - // Parse ORDER BY columns (comma-separated identifiers) + // Parse ORDER BY columns (comma-separated expressions) for !p.currentIs(token.EOF) && !p.currentIs(token.RPAREN) { - if p.currentIs(token.IDENT) || p.current.Token.IsKeyword() { - proj.Select.OrderBy = append(proj.Select.OrderBy, &ast.Identifier{ - Position: p.current.Pos, - Parts: []string{p.current.Value}, - }) - p.nextToken() + expr := p.parseExpression(LOWEST) + if expr != nil { + proj.Select.OrderBy = append(proj.Select.OrderBy, expr) } else { break } diff --git a/parser/testdata/00077_log_tinylog_stripelog/metadata.json b/parser/testdata/00077_log_tinylog_stripelog/metadata.json index 7234f858cd..0967ef424b 100644 --- a/parser/testdata/00077_log_tinylog_stripelog/metadata.json +++ b/parser/testdata/00077_log_tinylog_stripelog/metadata.json @@ -1,10 +1 @@ -{ - "explain_todo": { - "stmt10": true, - "stmt18": true, - "stmt19": true, - "stmt20": true, - "stmt8": true, - "stmt9": true - } -} +{} diff --git a/parser/testdata/00233_position_function_sql_comparibilty/metadata.json b/parser/testdata/00233_position_function_sql_comparibilty/metadata.json index 503bf9ee0a..0967ef424b 100644 --- a/parser/testdata/00233_position_function_sql_comparibilty/metadata.json +++ b/parser/testdata/00233_position_function_sql_comparibilty/metadata.json @@ -1,17 +1 @@ -{ - "explain_todo": { - "stmt10": true, - "stmt11": true, - "stmt12": true, - "stmt13": true, - "stmt14": true, - "stmt2": true, - "stmt3": true, - "stmt4": true, - "stmt5": true, - "stmt6": true, - "stmt7": true, - "stmt8": true, - "stmt9": true - } -} +{} diff --git a/parser/testdata/00255_array_concat_string/metadata.json b/parser/testdata/00255_array_concat_string/metadata.json index 3030f42b2c..4a3785ad92 100644 --- a/parser/testdata/00255_array_concat_string/metadata.json +++ b/parser/testdata/00255_array_concat_string/metadata.json @@ -1 +1,8 @@ -{"explain_todo":{"stmt12":true,"stmt15":true,"stmt16":true,"stmt17":true,"stmt18":true,"stmt20":true}} +{ + "explain_todo": { + "stmt15": true, + "stmt16": true, + "stmt17": true, + "stmt18": true + } +} diff --git a/parser/testdata/00441_nulls_in/metadata.json b/parser/testdata/00441_nulls_in/metadata.json index 5c1dd64ff1..9409bfce8e 100644 --- a/parser/testdata/00441_nulls_in/metadata.json +++ b/parser/testdata/00441_nulls_in/metadata.json @@ -1,13 +1,9 @@ { "explain_todo": { - "stmt1": true, "stmt13": true, "stmt14": true, "stmt15": true, "stmt16": true, - "stmt17": true, - "stmt2": true, - "stmt7": true, - "stmt8": true + "stmt17": true } } diff --git a/parser/testdata/00515_enhanced_time_zones/metadata.json b/parser/testdata/00515_enhanced_time_zones/metadata.json index f881a8c517..0967ef424b 100644 --- a/parser/testdata/00515_enhanced_time_zones/metadata.json +++ b/parser/testdata/00515_enhanced_time_zones/metadata.json @@ -1,6 +1 @@ -{ - "explain_todo": { - "stmt44": true, - "stmt49": true - } -} +{} diff --git a/parser/testdata/00564_temporary_table_management/metadata.json b/parser/testdata/00564_temporary_table_management/metadata.json index 2301576872..d5e9483c45 100644 --- a/parser/testdata/00564_temporary_table_management/metadata.json +++ b/parser/testdata/00564_temporary_table_management/metadata.json @@ -1,7 +1,6 @@ { "explain_todo": { "stmt3": true, - "stmt4": true, "stmt5": true, "stmt7": true } diff --git a/parser/testdata/00674_join_on_syntax/metadata.json b/parser/testdata/00674_join_on_syntax/metadata.json index ef51318230..0967ef424b 100644 --- a/parser/testdata/00674_join_on_syntax/metadata.json +++ b/parser/testdata/00674_join_on_syntax/metadata.json @@ -1,25 +1 @@ -{ - "explain_todo": { - "stmt39": true, - "stmt40": true, - "stmt41": true, - "stmt42": true, - "stmt43": true, - "stmt44": true, - "stmt45": true, - "stmt46": true, - "stmt47": true, - "stmt48": true, - "stmt49": true, - "stmt50": true, - "stmt51": true, - "stmt52": true, - "stmt53": true, - "stmt54": true, - "stmt55": true, - "stmt83": true, - "stmt84": true, - "stmt85": true, - "stmt86": true - } -} +{} diff --git a/parser/testdata/00688_low_cardinality_nullable_cast/metadata.json b/parser/testdata/00688_low_cardinality_nullable_cast/metadata.json index dbdbb76d4f..0967ef424b 100644 --- a/parser/testdata/00688_low_cardinality_nullable_cast/metadata.json +++ b/parser/testdata/00688_low_cardinality_nullable_cast/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt6": true - } -} +{} diff --git a/parser/testdata/00716_allow_ddl/metadata.json b/parser/testdata/00716_allow_ddl/metadata.json index b7645733e4..dbdbb76d4f 100644 --- a/parser/testdata/00716_allow_ddl/metadata.json +++ b/parser/testdata/00716_allow_ddl/metadata.json @@ -1 +1,5 @@ -{"explain_todo":{"stmt5":true,"stmt6":true}} +{ + "explain_todo": { + "stmt6": true + } +} diff --git a/parser/testdata/00727_concat/metadata.json b/parser/testdata/00727_concat/metadata.json index 7082dff93a..898e7ce13d 100644 --- a/parser/testdata/00727_concat/metadata.json +++ b/parser/testdata/00727_concat/metadata.json @@ -1 +1,8 @@ -{"explain_todo":{"stmt19":true,"stmt20":true,"stmt37":true,"stmt39":true,"stmt43":true,"stmt44":true,"stmt45":true,"stmt46":true,"stmt62":true,"stmt63":true,"stmt64":true,"stmt65":true,"stmt66":true,"stmt67":true,"stmt83":true}} +{ + "explain_todo": { + "stmt19": true, + "stmt20": true, + "stmt44": true, + "stmt46": true + } +} diff --git a/parser/testdata/00753_alter_attach/metadata.json b/parser/testdata/00753_alter_attach/metadata.json index 407a67123a..249a399fbe 100644 --- a/parser/testdata/00753_alter_attach/metadata.json +++ b/parser/testdata/00753_alter_attach/metadata.json @@ -1,25 +1,9 @@ { "explain_todo": { - "stmt14": true, - "stmt22": true, - "stmt34": true, - "stmt42": true, - "stmt51": true, "stmt52": true, "stmt53": true, "stmt54": true, "stmt55": true, - "stmt56": true, - "stmt58": true, - "stmt63": true, - "stmt65": true, - "stmt69": true, - "stmt71": true, - "stmt73": true, - "stmt77": true, - "stmt79": true, - "stmt83": true, - "stmt85": true, - "stmt87": true + "stmt58": true } } diff --git a/parser/testdata/00765_sql_compatibility_aliases/metadata.json b/parser/testdata/00765_sql_compatibility_aliases/metadata.json index 380408def5..d94ee08253 100644 --- a/parser/testdata/00765_sql_compatibility_aliases/metadata.json +++ b/parser/testdata/00765_sql_compatibility_aliases/metadata.json @@ -2,11 +2,8 @@ "explain_todo": { "stmt10": true, "stmt2": true, - "stmt25": true, "stmt26": true, - "stmt27": true, "stmt28": true, - "stmt29": true, "stmt3": true } } diff --git a/parser/testdata/00926_multimatch/metadata.json b/parser/testdata/00926_multimatch/metadata.json index 01cf331164..0967ef424b 100644 --- a/parser/testdata/00926_multimatch/metadata.json +++ b/parser/testdata/00926_multimatch/metadata.json @@ -1,10 +1 @@ -{ - "explain_todo": { - "stmt111": true, - "stmt151": true, - "stmt158": true, - "stmt28": true, - "stmt68": true, - "stmt75": true - } -} +{} diff --git a/parser/testdata/00939_test_null_in/metadata.json b/parser/testdata/00939_test_null_in/metadata.json index dbdbb76d4f..0967ef424b 100644 --- a/parser/testdata/00939_test_null_in/metadata.json +++ b/parser/testdata/00939_test_null_in/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt6": true - } -} +{} diff --git a/parser/testdata/01015_attach_part/metadata.json b/parser/testdata/01015_attach_part/metadata.json index 84f57deaf2..6bf8d5b80a 100644 --- a/parser/testdata/01015_attach_part/metadata.json +++ b/parser/testdata/01015_attach_part/metadata.json @@ -1,7 +1,6 @@ { "explain_todo": { "stmt5": true, - "stmt7": true, - "stmt9": true + "stmt7": true } } diff --git a/parser/testdata/01018_ddl_dictionaries_create/metadata.json b/parser/testdata/01018_ddl_dictionaries_create/metadata.json index f858c5980c..aa5bbb6eb4 100644 --- a/parser/testdata/01018_ddl_dictionaries_create/metadata.json +++ b/parser/testdata/01018_ddl_dictionaries_create/metadata.json @@ -1,15 +1,7 @@ { "explain_todo": { - "stmt13": true, "stmt17": true, - "stmt18": true, "stmt22": true, - "stmt23": true, - "stmt28": true, - "stmt37": true, - "stmt43": true, - "stmt48": true, - "stmt51": true, - "stmt53": true + "stmt43": true } } diff --git a/parser/testdata/01047_simple_aggregate_sizes_of_columns_bug/metadata.json b/parser/testdata/01047_simple_aggregate_sizes_of_columns_bug/metadata.json index 3a06a4a1ac..0967ef424b 100644 --- a/parser/testdata/01047_simple_aggregate_sizes_of_columns_bug/metadata.json +++ b/parser/testdata/01047_simple_aggregate_sizes_of_columns_bug/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt5": true - } -} +{} diff --git a/parser/testdata/01090_zookeeper_mutations_and_insert_quorum_long/metadata.json b/parser/testdata/01090_zookeeper_mutations_and_insert_quorum_long/metadata.json index b563327205..0967ef424b 100644 --- a/parser/testdata/01090_zookeeper_mutations_and_insert_quorum_long/metadata.json +++ b/parser/testdata/01090_zookeeper_mutations_and_insert_quorum_long/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt7": true - } -} +{} diff --git a/parser/testdata/01095_tpch_like_smoke/metadata.json b/parser/testdata/01095_tpch_like_smoke/metadata.json index 7a435f68f3..0967ef424b 100644 --- a/parser/testdata/01095_tpch_like_smoke/metadata.json +++ b/parser/testdata/01095_tpch_like_smoke/metadata.json @@ -1,16 +1 @@ -{ - "explain_todo": { - "stmt20": true, - "stmt24": true, - "stmt26": true, - "stmt28": true, - "stmt30": true, - "stmt32": true, - "stmt34": true, - "stmt38": true, - "stmt42": true, - "stmt46": true, - "stmt49": true, - "stmt61": true - } -} +{} diff --git a/parser/testdata/01099_operators_date_and_timestamp/metadata.json b/parser/testdata/01099_operators_date_and_timestamp/metadata.json index 950a708e32..85cc99e9fa 100644 --- a/parser/testdata/01099_operators_date_and_timestamp/metadata.json +++ b/parser/testdata/01099_operators_date_and_timestamp/metadata.json @@ -1,24 +1,5 @@ { "explain_todo": { - "stmt10": true, - "stmt11": true, - "stmt12": true, - "stmt13": true, - "stmt15": true, - "stmt16": true, - "stmt17": true, - "stmt18": true, - "stmt19": true, - "stmt20": true, - "stmt21": true, - "stmt22": true, - "stmt31": true, - "stmt34": true, - "stmt4": true, - "stmt5": true, - "stmt6": true, - "stmt7": true, - "stmt8": true, - "stmt9": true + "stmt34": true } } diff --git a/parser/testdata/01166_truncate_multiple_partitions/metadata.json b/parser/testdata/01166_truncate_multiple_partitions/metadata.json index ad5752d0f4..d0821ccce9 100644 --- a/parser/testdata/01166_truncate_multiple_partitions/metadata.json +++ b/parser/testdata/01166_truncate_multiple_partitions/metadata.json @@ -3,13 +3,11 @@ "stmt10": true, "stmt11": true, "stmt17": true, - "stmt20": true, "stmt22": true, "stmt23": true, "stmt24": true, "stmt25": true, "stmt3": true, - "stmt6": true, "stmt8": true, "stmt9": true } diff --git a/parser/testdata/01200_mutations_memory_consumption/metadata.json b/parser/testdata/01200_mutations_memory_consumption/metadata.json index 4a695f4ad6..0967ef424b 100644 --- a/parser/testdata/01200_mutations_memory_consumption/metadata.json +++ b/parser/testdata/01200_mutations_memory_consumption/metadata.json @@ -1,8 +1 @@ -{ - "explain_todo": { - "stmt12": true, - "stmt19": true, - "stmt26": true, - "stmt5": true - } -} +{} diff --git a/parser/testdata/01231_operator_null_in/metadata.json b/parser/testdata/01231_operator_null_in/metadata.json index dd58de52fb..0967ef424b 100644 --- a/parser/testdata/01231_operator_null_in/metadata.json +++ b/parser/testdata/01231_operator_null_in/metadata.json @@ -1,20 +1 @@ -{ - "explain_todo": { - "stmt10": true, - "stmt12": true, - "stmt13": true, - "stmt15": true, - "stmt17": true, - "stmt19": true, - "stmt20": true, - "stmt22": true, - "stmt23": true, - "stmt25": true, - "stmt26": true, - "stmt28": true, - "stmt4": true, - "stmt6": true, - "stmt7": true, - "stmt9": true - } -} +{} diff --git a/parser/testdata/01268_data_numeric_parameters/metadata.json b/parser/testdata/01268_data_numeric_parameters/metadata.json index b65b07d7a6..0967ef424b 100644 --- a/parser/testdata/01268_data_numeric_parameters/metadata.json +++ b/parser/testdata/01268_data_numeric_parameters/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt4": true - } -} +{} diff --git a/parser/testdata/01292_create_user/metadata.json b/parser/testdata/01292_create_user/metadata.json index fd983695cd..0c27273b2d 100644 --- a/parser/testdata/01292_create_user/metadata.json +++ b/parser/testdata/01292_create_user/metadata.json @@ -1,12 +1,7 @@ { "explain_todo": { - "stmt157": true, - "stmt158": true, - "stmt159": true, - "stmt160": true, "stmt196": true, "stmt197": true, - "stmt200": true, "stmt201": true, "stmt221": true, "stmt239": true diff --git a/parser/testdata/01349_mutation_datetime_key/metadata.json b/parser/testdata/01349_mutation_datetime_key/metadata.json index dbdbb76d4f..0967ef424b 100644 --- a/parser/testdata/01349_mutation_datetime_key/metadata.json +++ b/parser/testdata/01349_mutation_datetime_key/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt6": true - } -} +{} diff --git a/parser/testdata/01358_mutation_delete_null_rows/metadata.json b/parser/testdata/01358_mutation_delete_null_rows/metadata.json index 7ad5569408..0967ef424b 100644 --- a/parser/testdata/01358_mutation_delete_null_rows/metadata.json +++ b/parser/testdata/01358_mutation_delete_null_rows/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt9": true - } -} +{} diff --git a/parser/testdata/01387_clear_column_default_depends/metadata.json b/parser/testdata/01387_clear_column_default_depends/metadata.json index 0411e1f140..13dfdf58b8 100644 --- a/parser/testdata/01387_clear_column_default_depends/metadata.json +++ b/parser/testdata/01387_clear_column_default_depends/metadata.json @@ -1,8 +1,5 @@ { "explain_todo": { - "stmt13": true, - "stmt21": true, - "stmt28": true, - "stmt5": true + "stmt28": true } } diff --git a/parser/testdata/01388_clear_all_columns/metadata.json b/parser/testdata/01388_clear_all_columns/metadata.json index d04cde097d..7ad5569408 100644 --- a/parser/testdata/01388_clear_all_columns/metadata.json +++ b/parser/testdata/01388_clear_all_columns/metadata.json @@ -1,11 +1,5 @@ { "explain_todo": { - "stmt10": true, - "stmt11": true, - "stmt13": true, - "stmt14": true, - "stmt4": true, - "stmt8": true, "stmt9": true } } diff --git a/parser/testdata/01410_nullable_key_and_index/metadata.json b/parser/testdata/01410_nullable_key_and_index/metadata.json index b330691357..0967ef424b 100644 --- a/parser/testdata/01410_nullable_key_and_index/metadata.json +++ b/parser/testdata/01410_nullable_key_and_index/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt26": true - } -} +{} diff --git a/parser/testdata/01410_nullable_key_and_index_negate_cond/metadata.json b/parser/testdata/01410_nullable_key_and_index_negate_cond/metadata.json index 983800a6c0..0967ef424b 100644 --- a/parser/testdata/01410_nullable_key_and_index_negate_cond/metadata.json +++ b/parser/testdata/01410_nullable_key_and_index_negate_cond/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt23": true - } -} +{} diff --git a/parser/testdata/01470_columns_transformers/metadata.json b/parser/testdata/01470_columns_transformers/metadata.json index 2e74062554..34f8786c4b 100644 --- a/parser/testdata/01470_columns_transformers/metadata.json +++ b/parser/testdata/01470_columns_transformers/metadata.json @@ -1,24 +1,13 @@ { "explain_todo": { - "stmt11": true, "stmt12": true, "stmt13": true, "stmt14": true, "stmt15": true, "stmt16": true, "stmt17": true, - "stmt21": true, "stmt22": true, - "stmt26": true, - "stmt29": true, - "stmt35": true, - "stmt36": true, - "stmt37": true, - "stmt38": true, - "stmt39": true, - "stmt40": true, "stmt41": true, - "stmt42": true, - "stmt8": true + "stmt42": true } } diff --git a/parser/testdata/01470_columns_transformers2/metadata.json b/parser/testdata/01470_columns_transformers2/metadata.json index f3773105ca..b65b07d7a6 100644 --- a/parser/testdata/01470_columns_transformers2/metadata.json +++ b/parser/testdata/01470_columns_transformers2/metadata.json @@ -1,7 +1,5 @@ { "explain_todo": { - "stmt4": true, - "stmt6": true, - "stmt7": true + "stmt4": true } } diff --git a/parser/testdata/01493_alter_remove_no_property_zookeeper_long/metadata.json b/parser/testdata/01493_alter_remove_no_property_zookeeper_long/metadata.json index 522845c142..0967ef424b 100644 --- a/parser/testdata/01493_alter_remove_no_property_zookeeper_long/metadata.json +++ b/parser/testdata/01493_alter_remove_no_property_zookeeper_long/metadata.json @@ -1,7 +1 @@ -{ - "explain_todo": { - "stmt10": true, - "stmt4": true, - "stmt9": true - } -} +{} diff --git a/parser/testdata/01493_alter_remove_properties/metadata.json b/parser/testdata/01493_alter_remove_properties/metadata.json index 633b943ce3..182f4d0e03 100644 --- a/parser/testdata/01493_alter_remove_properties/metadata.json +++ b/parser/testdata/01493_alter_remove_properties/metadata.json @@ -1,12 +1,6 @@ { "explain_todo": { - "stmt11": true, - "stmt16": true, "stmt2": true, - "stmt20": true, - "stmt24": true, - "stmt26": true, - "stmt7": true, - "stmt9": true + "stmt24": true } } diff --git a/parser/testdata/01493_alter_remove_properties_zookeeper/metadata.json b/parser/testdata/01493_alter_remove_properties_zookeeper/metadata.json index b748430a1f..c0a6c41fa3 100644 --- a/parser/testdata/01493_alter_remove_properties_zookeeper/metadata.json +++ b/parser/testdata/01493_alter_remove_properties_zookeeper/metadata.json @@ -1,9 +1,5 @@ { "explain_todo": { - "stmt11": true, - "stmt17": true, - "stmt21": true, - "stmt30": true, "stmt34": true, "stmt4": true, "stmt5": true diff --git a/parser/testdata/01493_alter_remove_wrong_default/metadata.json b/parser/testdata/01493_alter_remove_wrong_default/metadata.json index 1295a45747..0967ef424b 100644 --- a/parser/testdata/01493_alter_remove_wrong_default/metadata.json +++ b/parser/testdata/01493_alter_remove_wrong_default/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt3": true - } -} +{} diff --git a/parser/testdata/01497_mutation_support_for_storage_memory/metadata.json b/parser/testdata/01497_mutation_support_for_storage_memory/metadata.json index 342b3ff5b4..0967ef424b 100644 --- a/parser/testdata/01497_mutation_support_for_storage_memory/metadata.json +++ b/parser/testdata/01497_mutation_support_for_storage_memory/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt8": true - } -} +{} diff --git a/parser/testdata/01507_transform_null_in/metadata.json b/parser/testdata/01507_transform_null_in/metadata.json index 4f7d5e224d..0967ef424b 100644 --- a/parser/testdata/01507_transform_null_in/metadata.json +++ b/parser/testdata/01507_transform_null_in/metadata.json @@ -1,7 +1 @@ -{ - "explain_todo": { - "stmt4": true, - "stmt6": true, - "stmt9": true - } -} +{} diff --git a/parser/testdata/01523_interval_operator_support_string_literal/metadata.json b/parser/testdata/01523_interval_operator_support_string_literal/metadata.json index e1ae16abb1..0967ef424b 100644 --- a/parser/testdata/01523_interval_operator_support_string_literal/metadata.json +++ b/parser/testdata/01523_interval_operator_support_string_literal/metadata.json @@ -1,17 +1 @@ -{ - "explain_todo": { - "stmt12": true, - "stmt15": true, - "stmt18": true, - "stmt19": true, - "stmt20": true, - "stmt21": true, - "stmt22": true, - "stmt23": true, - "stmt24": true, - "stmt25": true, - "stmt3": true, - "stmt6": true, - "stmt9": true - } -} +{} diff --git a/parser/testdata/01550_mutation_subquery/metadata.json b/parser/testdata/01550_mutation_subquery/metadata.json index dbdbb76d4f..0967ef424b 100644 --- a/parser/testdata/01550_mutation_subquery/metadata.json +++ b/parser/testdata/01550_mutation_subquery/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt6": true - } -} +{} diff --git a/parser/testdata/01558_transform_null_in/metadata.json b/parser/testdata/01558_transform_null_in/metadata.json index 93db919f01..a08759fb21 100644 --- a/parser/testdata/01558_transform_null_in/metadata.json +++ b/parser/testdata/01558_transform_null_in/metadata.json @@ -1,14 +1,5 @@ { "explain_todo": { - "stmt15": true, - "stmt16": true, - "stmt17": true, - "stmt18": true, - "stmt19": true, - "stmt20": true, - "stmt21": true, - "stmt5": true, - "stmt6": true, - "stmt9": true + "stmt21": true } } diff --git a/parser/testdata/01602_array_aggregation/metadata.json b/parser/testdata/01602_array_aggregation/metadata.json index 8dae11f1e5..0967ef424b 100644 --- a/parser/testdata/01602_array_aggregation/metadata.json +++ b/parser/testdata/01602_array_aggregation/metadata.json @@ -1,8 +1 @@ -{ - "explain_todo": { - "stmt32": true, - "stmt33": true, - "stmt34": true, - "stmt35": true - } -} +{} diff --git a/parser/testdata/01602_temporary_table_in_system_tables/metadata.json b/parser/testdata/01602_temporary_table_in_system_tables/metadata.json index f6d9f2395b..0967ef424b 100644 --- a/parser/testdata/01602_temporary_table_in_system_tables/metadata.json +++ b/parser/testdata/01602_temporary_table_in_system_tables/metadata.json @@ -1,6 +1 @@ -{ - "explain_todo": { - "stmt7": true, - "stmt8": true - } -} +{} diff --git a/parser/testdata/01603_remove_column_ttl/metadata.json b/parser/testdata/01603_remove_column_ttl/metadata.json index b563327205..0967ef424b 100644 --- a/parser/testdata/01603_remove_column_ttl/metadata.json +++ b/parser/testdata/01603_remove_column_ttl/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt7": true - } -} +{} diff --git a/parser/testdata/01630_simple_aggregate_all_functions_in_aggregating_merge_tree/metadata.json b/parser/testdata/01630_simple_aggregate_all_functions_in_aggregating_merge_tree/metadata.json index 342b3ff5b4..0967ef424b 100644 --- a/parser/testdata/01630_simple_aggregate_all_functions_in_aggregating_merge_tree/metadata.json +++ b/parser/testdata/01630_simple_aggregate_all_functions_in_aggregating_merge_tree/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt8": true - } -} +{} diff --git a/parser/testdata/01630_simple_aggregate_all_functions_in_summing_merge_tree/metadata.json b/parser/testdata/01630_simple_aggregate_all_functions_in_summing_merge_tree/metadata.json index 342b3ff5b4..0967ef424b 100644 --- a/parser/testdata/01630_simple_aggregate_all_functions_in_summing_merge_tree/metadata.json +++ b/parser/testdata/01630_simple_aggregate_all_functions_in_summing_merge_tree/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt8": true - } -} +{} diff --git a/parser/testdata/01650_fetch_patition_with_macro_in_zk_path_long/metadata.json b/parser/testdata/01650_fetch_patition_with_macro_in_zk_path_long/metadata.json index dbdbb76d4f..0967ef424b 100644 --- a/parser/testdata/01650_fetch_patition_with_macro_in_zk_path_long/metadata.json +++ b/parser/testdata/01650_fetch_patition_with_macro_in_zk_path_long/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt6": true - } -} +{} diff --git a/parser/testdata/01702_system_query_log/metadata.json b/parser/testdata/01702_system_query_log/metadata.json index cb7a7d102e..0967ef424b 100644 --- a/parser/testdata/01702_system_query_log/metadata.json +++ b/parser/testdata/01702_system_query_log/metadata.json @@ -1,24 +1 @@ -{ - "explain_todo": { - "stmt19": true, - "stmt24": true, - "stmt28": true, - "stmt30": true, - "stmt34": true, - "stmt49": true, - "stmt50": true, - "stmt51": true, - "stmt52": true, - "stmt53": true, - "stmt54": true, - "stmt55": true, - "stmt56": true, - "stmt57": true, - "stmt58": true, - "stmt59": true, - "stmt60": true, - "stmt68": true, - "stmt69": true, - "stmt74": true - } -} +{} diff --git a/parser/testdata/01710_normal_projection_format/metadata.json b/parser/testdata/01710_normal_projection_format/metadata.json index 1295a45747..0967ef424b 100644 --- a/parser/testdata/01710_normal_projection_format/metadata.json +++ b/parser/testdata/01710_normal_projection_format/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt3": true - } -} +{} diff --git a/parser/testdata/01745_alter_delete_view/metadata.json b/parser/testdata/01745_alter_delete_view/metadata.json index b563327205..0967ef424b 100644 --- a/parser/testdata/01745_alter_delete_view/metadata.json +++ b/parser/testdata/01745_alter_delete_view/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt7": true - } -} +{} diff --git a/parser/testdata/01753_mutate_table_predicated_with_table/metadata.json b/parser/testdata/01753_mutate_table_predicated_with_table/metadata.json index 1295a45747..0967ef424b 100644 --- a/parser/testdata/01753_mutate_table_predicated_with_table/metadata.json +++ b/parser/testdata/01753_mutate_table_predicated_with_table/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt3": true - } -} +{} diff --git a/parser/testdata/01756_optimize_skip_unused_shards_rewrite_in/metadata.json b/parser/testdata/01756_optimize_skip_unused_shards_rewrite_in/metadata.json index 224a6c1b3e..3a1aa49b68 100644 --- a/parser/testdata/01756_optimize_skip_unused_shards_rewrite_in/metadata.json +++ b/parser/testdata/01756_optimize_skip_unused_shards_rewrite_in/metadata.json @@ -2,7 +2,6 @@ "explain_todo": { "stmt45": true, "stmt46": true, - "stmt53": true, "stmt56": true, "stmt57": true } diff --git a/parser/testdata/01821_join_table_mutation/metadata.json b/parser/testdata/01821_join_table_mutation/metadata.json index 2cf5e97d8a..0967ef424b 100644 --- a/parser/testdata/01821_join_table_mutation/metadata.json +++ b/parser/testdata/01821_join_table_mutation/metadata.json @@ -1,8 +1 @@ -{ - "explain_todo": { - "stmt11": true, - "stmt14": true, - "stmt16": true, - "stmt6": true - } -} +{} diff --git a/parser/testdata/01825_new_type_json_mutations/metadata.json b/parser/testdata/01825_new_type_json_mutations/metadata.json index f4c74e32be..0967ef424b 100644 --- a/parser/testdata/01825_new_type_json_mutations/metadata.json +++ b/parser/testdata/01825_new_type_json_mutations/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt10": true - } -} +{} diff --git a/parser/testdata/01851_clear_column_referenced_by_mv/metadata.json b/parser/testdata/01851_clear_column_referenced_by_mv/metadata.json index 342b3ff5b4..0967ef424b 100644 --- a/parser/testdata/01851_clear_column_referenced_by_mv/metadata.json +++ b/parser/testdata/01851_clear_column_referenced_by_mv/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt8": true - } -} +{} diff --git a/parser/testdata/01852_cast_operator/metadata.json b/parser/testdata/01852_cast_operator/metadata.json index 718b43bd01..a38745fbb0 100644 --- a/parser/testdata/01852_cast_operator/metadata.json +++ b/parser/testdata/01852_cast_operator/metadata.json @@ -2,11 +2,6 @@ "explain_todo": { "stmt11": true, "stmt12": true, - "stmt17": true, - "stmt29": true, - "stmt3": true, - "stmt30": true, - "stmt31": true, - "stmt4": true + "stmt29": true } } diff --git a/parser/testdata/01852_cast_operator_2/metadata.json b/parser/testdata/01852_cast_operator_2/metadata.json index eaeb241fd9..c0cad435f1 100644 --- a/parser/testdata/01852_cast_operator_2/metadata.json +++ b/parser/testdata/01852_cast_operator_2/metadata.json @@ -1,13 +1,8 @@ { "explain_todo": { - "stmt1": true, "stmt10": true, "stmt11": true, "stmt12": true, - "stmt13": true, - "stmt2": true, - "stmt5": true, - "stmt6": true, "stmt7": true, "stmt8": true, "stmt9": true diff --git a/parser/testdata/01947_mv_subquery/metadata.json b/parser/testdata/01947_mv_subquery/metadata.json index 8eb3175658..0967ef424b 100644 --- a/parser/testdata/01947_mv_subquery/metadata.json +++ b/parser/testdata/01947_mv_subquery/metadata.json @@ -1,6 +1 @@ -{ - "explain_todo": { - "stmt17": true, - "stmt8": true - } -} +{} diff --git a/parser/testdata/02007_test_any_all_operators/metadata.json b/parser/testdata/02007_test_any_all_operators/metadata.json index ce72cf920f..4995e0b439 100644 --- a/parser/testdata/02007_test_any_all_operators/metadata.json +++ b/parser/testdata/02007_test_any_all_operators/metadata.json @@ -1,6 +1,5 @@ { "explain_todo": { - "stmt1": true, "stmt10": true, "stmt11": true, "stmt12": true, @@ -11,14 +10,10 @@ "stmt17": true, "stmt18": true, "stmt19": true, - "stmt2": true, "stmt20": true, - "stmt3": true, - "stmt4": true, "stmt5": true, "stmt6": true, "stmt7": true, - "stmt8": true, - "stmt9": true + "stmt8": true } } diff --git a/parser/testdata/02008_materialize_column/metadata.json b/parser/testdata/02008_materialize_column/metadata.json index c29be7f9f7..f2a7a3e6c2 100644 --- a/parser/testdata/02008_materialize_column/metadata.json +++ b/parser/testdata/02008_materialize_column/metadata.json @@ -1,7 +1,6 @@ { "explain_todo": { "stmt10": true, - "stmt13": true, "stmt14": true, "stmt22": true, "stmt25": true, diff --git a/parser/testdata/02026_describe_include_subcolumns/metadata.json b/parser/testdata/02026_describe_include_subcolumns/metadata.json index a4f8773303..bc5c6edb66 100644 --- a/parser/testdata/02026_describe_include_subcolumns/metadata.json +++ b/parser/testdata/02026_describe_include_subcolumns/metadata.json @@ -1,7 +1,6 @@ { "explain_todo": { "stmt3": true, - "stmt4": true, "stmt5": true } } diff --git a/parser/testdata/02116_tuple_element_analyzer/metadata.json b/parser/testdata/02116_tuple_element_analyzer/metadata.json index 5452d4a529..0967ef424b 100644 --- a/parser/testdata/02116_tuple_element_analyzer/metadata.json +++ b/parser/testdata/02116_tuple_element_analyzer/metadata.json @@ -1,6 +1 @@ -{ - "explain_todo": { - "stmt30": true, - "stmt31": true - } -} +{} diff --git a/parser/testdata/02160_special_functions/metadata.json b/parser/testdata/02160_special_functions/metadata.json index 61cf9382a8..0967ef424b 100644 --- a/parser/testdata/02160_special_functions/metadata.json +++ b/parser/testdata/02160_special_functions/metadata.json @@ -1,24 +1 @@ -{ - "explain_todo": { - "stmt14": true, - "stmt16": true, - "stmt18": true, - "stmt19": true, - "stmt20": true, - "stmt21": true, - "stmt22": true, - "stmt23": true, - "stmt24": true, - "stmt25": true, - "stmt26": true, - "stmt27": true, - "stmt28": true, - "stmt29": true, - "stmt30": true, - "stmt31": true, - "stmt32": true, - "stmt33": true, - "stmt34": true, - "stmt35": true - } -} +{} diff --git a/parser/testdata/02184_default_table_engine/metadata.json b/parser/testdata/02184_default_table_engine/metadata.json index 64ab9858cf..f251b24f78 100644 --- a/parser/testdata/02184_default_table_engine/metadata.json +++ b/parser/testdata/02184_default_table_engine/metadata.json @@ -1,11 +1,9 @@ { "explain_todo": { "stmt107": true, - "stmt114": true, "stmt26": true, "stmt56": true, "stmt61": true, - "stmt69": true, "stmt73": true } } diff --git a/parser/testdata/02267_special_operator_parse_alias_check/metadata.json b/parser/testdata/02267_special_operator_parse_alias_check/metadata.json index b1214a8285..757ac1e443 100644 --- a/parser/testdata/02267_special_operator_parse_alias_check/metadata.json +++ b/parser/testdata/02267_special_operator_parse_alias_check/metadata.json @@ -2,17 +2,11 @@ "explain_todo": { "stmt41": true, "stmt43": true, - "stmt44": true, "stmt46": true, - "stmt47": true, "stmt48": true, - "stmt49": true, "stmt50": true, - "stmt51": true, "stmt52": true, - "stmt53": true, "stmt54": true, - "stmt55": true, "stmt56": true, "stmt57": true, "stmt58": true, diff --git a/parser/testdata/02271_int_sql_compatibility/metadata.json b/parser/testdata/02271_int_sql_compatibility/metadata.json index ce72cf920f..0967ef424b 100644 --- a/parser/testdata/02271_int_sql_compatibility/metadata.json +++ b/parser/testdata/02271_int_sql_compatibility/metadata.json @@ -1,24 +1 @@ -{ - "explain_todo": { - "stmt1": true, - "stmt10": true, - "stmt11": true, - "stmt12": true, - "stmt13": true, - "stmt14": true, - "stmt15": true, - "stmt16": true, - "stmt17": true, - "stmt18": true, - "stmt19": true, - "stmt2": true, - "stmt20": true, - "stmt3": true, - "stmt4": true, - "stmt5": true, - "stmt6": true, - "stmt7": true, - "stmt8": true, - "stmt9": true - } -} +{} diff --git a/parser/testdata/02277_full_sort_join_misc/metadata.json b/parser/testdata/02277_full_sort_join_misc/metadata.json index 3a06a4a1ac..0967ef424b 100644 --- a/parser/testdata/02277_full_sort_join_misc/metadata.json +++ b/parser/testdata/02277_full_sort_join_misc/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt5": true - } -} +{} diff --git a/parser/testdata/02286_vertical_merges_missed_column/metadata.json b/parser/testdata/02286_vertical_merges_missed_column/metadata.json index f4c74e32be..0967ef424b 100644 --- a/parser/testdata/02286_vertical_merges_missed_column/metadata.json +++ b/parser/testdata/02286_vertical_merges_missed_column/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt10": true - } -} +{} diff --git a/parser/testdata/02302_defaults_in_columnar_formats/metadata.json b/parser/testdata/02302_defaults_in_columnar_formats/metadata.json index d6ab88c49c..0967ef424b 100644 --- a/parser/testdata/02302_defaults_in_columnar_formats/metadata.json +++ b/parser/testdata/02302_defaults_in_columnar_formats/metadata.json @@ -1,7 +1 @@ -{ - "explain_todo": { - "stmt1": true, - "stmt3": true, - "stmt5": true - } -} +{} diff --git a/parser/testdata/02319_lightweight_delete_on_merge_tree/metadata.json b/parser/testdata/02319_lightweight_delete_on_merge_tree/metadata.json index 9103ba5f40..006ba4e250 100644 --- a/parser/testdata/02319_lightweight_delete_on_merge_tree/metadata.json +++ b/parser/testdata/02319_lightweight_delete_on_merge_tree/metadata.json @@ -6,7 +6,6 @@ "stmt30": true, "stmt45": true, "stmt52": true, - "stmt57": true, "stmt6": true, "stmt67": true, "stmt72": true, diff --git a/parser/testdata/02319_lightweight_delete_on_merge_tree_compact_parts/metadata.json b/parser/testdata/02319_lightweight_delete_on_merge_tree_compact_parts/metadata.json index 9849199b47..bd3fffc230 100644 --- a/parser/testdata/02319_lightweight_delete_on_merge_tree_compact_parts/metadata.json +++ b/parser/testdata/02319_lightweight_delete_on_merge_tree_compact_parts/metadata.json @@ -6,7 +6,6 @@ "stmt35": true, "stmt50": true, "stmt57": true, - "stmt62": true, "stmt7": true } } diff --git a/parser/testdata/02320_mapped_array_witn_const_nullable/metadata.json b/parser/testdata/02320_mapped_array_witn_const_nullable/metadata.json index b7645733e4..0967ef424b 100644 --- a/parser/testdata/02320_mapped_array_witn_const_nullable/metadata.json +++ b/parser/testdata/02320_mapped_array_witn_const_nullable/metadata.json @@ -1 +1 @@ -{"explain_todo":{"stmt5":true,"stmt6":true}} +{} diff --git a/parser/testdata/02339_analyzer_matcher_basic/metadata.json b/parser/testdata/02339_analyzer_matcher_basic/metadata.json index 2148fda4c3..0967ef424b 100644 --- a/parser/testdata/02339_analyzer_matcher_basic/metadata.json +++ b/parser/testdata/02339_analyzer_matcher_basic/metadata.json @@ -1,20 +1 @@ -{ - "explain_todo": { - "stmt105": true, - "stmt106": true, - "stmt63": true, - "stmt64": true, - "stmt66": true, - "stmt67": true, - "stmt69": true, - "stmt70": true, - "stmt79": true, - "stmt80": true, - "stmt85": true, - "stmt86": true, - "stmt92": true, - "stmt93": true, - "stmt98": true, - "stmt99": true - } -} +{} diff --git a/parser/testdata/02342_analyzer_compound_types/metadata.json b/parser/testdata/02342_analyzer_compound_types/metadata.json index a7826c148e..0967ef424b 100644 --- a/parser/testdata/02342_analyzer_compound_types/metadata.json +++ b/parser/testdata/02342_analyzer_compound_types/metadata.json @@ -1,8 +1 @@ -{ - "explain_todo": { - "stmt5": true, - "stmt6": true, - "stmt7": true, - "stmt8": true - } -} +{} diff --git a/parser/testdata/02343_analyzer_lambdas/metadata.json b/parser/testdata/02343_analyzer_lambdas/metadata.json index 06afe672c2..0967ef424b 100644 --- a/parser/testdata/02343_analyzer_lambdas/metadata.json +++ b/parser/testdata/02343_analyzer_lambdas/metadata.json @@ -1,7 +1 @@ -{ - "explain_todo": { - "stmt31": true, - "stmt32": true, - "stmt33": true - } -} +{} diff --git a/parser/testdata/02352_lightweight_delete/metadata.json b/parser/testdata/02352_lightweight_delete/metadata.json index 7cece2367e..9b85d6a428 100644 --- a/parser/testdata/02352_lightweight_delete/metadata.json +++ b/parser/testdata/02352_lightweight_delete/metadata.json @@ -4,7 +4,6 @@ "stmt19": true, "stmt29": true, "stmt34": true, - "stmt39": true, "stmt44": true, "stmt46": true, "stmt9": true diff --git a/parser/testdata/02378_analyzer_projection_names/metadata.json b/parser/testdata/02378_analyzer_projection_names/metadata.json index f40cb4ffb8..6256fd41ef 100644 --- a/parser/testdata/02378_analyzer_projection_names/metadata.json +++ b/parser/testdata/02378_analyzer_projection_names/metadata.json @@ -1,20 +1,6 @@ { "explain_todo": { - "stmt101": true, - "stmt105": true, - "stmt109": true, "stmt185": true, - "stmt207": true, - "stmt215": true, - "stmt227": true, - "stmt235": true, - "stmt33": true, - "stmt37": true, - "stmt41": true, - "stmt57": true, - "stmt67": true, - "stmt89": true, - "stmt93": true, - "stmt97": true + "stmt67": true } } diff --git a/parser/testdata/02405_avro_read_nested/metadata.json b/parser/testdata/02405_avro_read_nested/metadata.json index 9a8cc69c0b..0967ef424b 100644 --- a/parser/testdata/02405_avro_read_nested/metadata.json +++ b/parser/testdata/02405_avro_read_nested/metadata.json @@ -1,6 +1 @@ -{ - "explain_todo": { - "stmt2": true, - "stmt4": true - } -} +{} diff --git a/parser/testdata/02416_rocksdb_delete_update/metadata.json b/parser/testdata/02416_rocksdb_delete_update/metadata.json index a63599a5bd..d2dcf8d7df 100644 --- a/parser/testdata/02416_rocksdb_delete_update/metadata.json +++ b/parser/testdata/02416_rocksdb_delete_update/metadata.json @@ -2,7 +2,6 @@ "explain_todo": { "stmt12": true, "stmt21": true, - "stmt6": true, - "stmt9": true + "stmt6": true } } diff --git a/parser/testdata/02418_aggregate_combinators/metadata.json b/parser/testdata/02418_aggregate_combinators/metadata.json index 63a23fba1d..0967ef424b 100644 --- a/parser/testdata/02418_aggregate_combinators/metadata.json +++ b/parser/testdata/02418_aggregate_combinators/metadata.json @@ -1,7 +1 @@ -{ - "explain_todo": { - "stmt11": true, - "stmt16": true, - "stmt28": true - } -} +{} diff --git a/parser/testdata/02423_multidimensional_array_get_data_at/metadata.json b/parser/testdata/02423_multidimensional_array_get_data_at/metadata.json index 8b0256d0ad..0967ef424b 100644 --- a/parser/testdata/02423_multidimensional_array_get_data_at/metadata.json +++ b/parser/testdata/02423_multidimensional_array_get_data_at/metadata.json @@ -1,6 +1 @@ -{ - "explain_todo": { - "stmt4": true, - "stmt7": true - } -} +{} diff --git a/parser/testdata/02441_alter_delete_and_drop_column/metadata.json b/parser/testdata/02441_alter_delete_and_drop_column/metadata.json index 25122ac4f4..7ad5569408 100644 --- a/parser/testdata/02441_alter_delete_and_drop_column/metadata.json +++ b/parser/testdata/02441_alter_delete_and_drop_column/metadata.json @@ -1,6 +1,5 @@ { "explain_todo": { - "stmt5": true, "stmt9": true } } diff --git a/parser/testdata/02459_group_by_all/metadata.json b/parser/testdata/02459_group_by_all/metadata.json index 929f4551b7..0967ef424b 100644 --- a/parser/testdata/02459_group_by_all/metadata.json +++ b/parser/testdata/02459_group_by_all/metadata.json @@ -1,24 +1 @@ -{ - "explain_todo": { - "stmt10": true, - "stmt11": true, - "stmt12": true, - "stmt13": true, - "stmt15": true, - "stmt16": true, - "stmt17": true, - "stmt18": true, - "stmt19": true, - "stmt20": true, - "stmt21": true, - "stmt22": true, - "stmt23": true, - "stmt24": true, - "stmt4": true, - "stmt5": true, - "stmt6": true, - "stmt7": true, - "stmt8": true, - "stmt9": true - } -} +{} diff --git a/parser/testdata/02493_analyzer_table_functions_untuple/metadata.json b/parser/testdata/02493_analyzer_table_functions_untuple/metadata.json index 7888b3f2fc..0967ef424b 100644 --- a/parser/testdata/02493_analyzer_table_functions_untuple/metadata.json +++ b/parser/testdata/02493_analyzer_table_functions_untuple/metadata.json @@ -1,7 +1 @@ -{ - "explain_todo": { - "stmt20": true, - "stmt22": true, - "stmt24": true - } -} +{} diff --git a/parser/testdata/02494_query_cache_eligible_queries/metadata.json b/parser/testdata/02494_query_cache_eligible_queries/metadata.json index edf04afbb9..3529d26510 100644 --- a/parser/testdata/02494_query_cache_eligible_queries/metadata.json +++ b/parser/testdata/02494_query_cache_eligible_queries/metadata.json @@ -1,6 +1,5 @@ { "explain_todo": { - "stmt17": true, "stmt23": true, "stmt25": true, "stmt27": true, diff --git a/parser/testdata/02495_concat_with_separator/metadata.json b/parser/testdata/02495_concat_with_separator/metadata.json index a313391ed3..d689cec729 100644 --- a/parser/testdata/02495_concat_with_separator/metadata.json +++ b/parser/testdata/02495_concat_with_separator/metadata.json @@ -1 +1,6 @@ -{"explain_todo":{"stmt40":true,"stmt41":true,"stmt57":true,"stmt58":true}} +{ + "explain_todo": { + "stmt40": true, + "stmt41": true + } +} diff --git a/parser/testdata/02499_analyzer_aggregate_function_lambda_crash_fix/metadata.json b/parser/testdata/02499_analyzer_aggregate_function_lambda_crash_fix/metadata.json index bc141058a4..0967ef424b 100644 --- a/parser/testdata/02499_analyzer_aggregate_function_lambda_crash_fix/metadata.json +++ b/parser/testdata/02499_analyzer_aggregate_function_lambda_crash_fix/metadata.json @@ -1,6 +1 @@ -{ - "explain_todo": { - "stmt2": true, - "stmt3": true - } -} +{} diff --git a/parser/testdata/02499_quantile_nan_ubsan_msan/metadata.json b/parser/testdata/02499_quantile_nan_ubsan_msan/metadata.json index c112bf01c6..0967ef424b 100644 --- a/parser/testdata/02499_quantile_nan_ubsan_msan/metadata.json +++ b/parser/testdata/02499_quantile_nan_ubsan_msan/metadata.json @@ -1,14 +1 @@ -{ - "explain_todo": { - "stmt11": true, - "stmt14": true, - "stmt15": true, - "stmt17": true, - "stmt19": true, - "stmt3": true, - "stmt5": true, - "stmt6": true, - "stmt8": true, - "stmt9": true - } -} +{} diff --git a/parser/testdata/02521_lightweight_delete_and_ttl/metadata.json b/parser/testdata/02521_lightweight_delete_and_ttl/metadata.json index 47f980edf9..007cdea647 100644 --- a/parser/testdata/02521_lightweight_delete_and_ttl/metadata.json +++ b/parser/testdata/02521_lightweight_delete_and_ttl/metadata.json @@ -1,6 +1,5 @@ { "explain_todo": { - "stmt15": true, "stmt18": true, "stmt5": true, "stmt9": true diff --git a/parser/testdata/02577_keepermap_delete_update/metadata.json b/parser/testdata/02577_keepermap_delete_update/metadata.json index a63599a5bd..d2dcf8d7df 100644 --- a/parser/testdata/02577_keepermap_delete_update/metadata.json +++ b/parser/testdata/02577_keepermap_delete_update/metadata.json @@ -2,7 +2,6 @@ "explain_todo": { "stmt12": true, "stmt21": true, - "stmt6": true, - "stmt9": true + "stmt6": true } } diff --git a/parser/testdata/02581_share_big_sets_between_multiple_mutations_tasks_long/metadata.json b/parser/testdata/02581_share_big_sets_between_multiple_mutations_tasks_long/metadata.json index e91f8984c2..6a40e6e6e3 100644 --- a/parser/testdata/02581_share_big_sets_between_multiple_mutations_tasks_long/metadata.json +++ b/parser/testdata/02581_share_big_sets_between_multiple_mutations_tasks_long/metadata.json @@ -1,6 +1,5 @@ { "explain_todo": { - "stmt12": true, "stmt16": true, "stmt2": true } diff --git a/parser/testdata/02675_sparse_columns_clear_column/metadata.json b/parser/testdata/02675_sparse_columns_clear_column/metadata.json index b563327205..0967ef424b 100644 --- a/parser/testdata/02675_sparse_columns_clear_column/metadata.json +++ b/parser/testdata/02675_sparse_columns_clear_column/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt7": true - } -} +{} diff --git a/parser/testdata/02677_analyzer_compound_expressions/metadata.json b/parser/testdata/02677_analyzer_compound_expressions/metadata.json index b0ad0d1a0e..f4c74e32be 100644 --- a/parser/testdata/02677_analyzer_compound_expressions/metadata.json +++ b/parser/testdata/02677_analyzer_compound_expressions/metadata.json @@ -1,9 +1,5 @@ { "explain_todo": { - "stmt10": true, - "stmt2": true, - "stmt3": true, - "stmt4": true, - "stmt5": true + "stmt10": true } } diff --git a/parser/testdata/02681_undrop_query/metadata.json b/parser/testdata/02681_undrop_query/metadata.json index 2919bbb280..cb6306de40 100644 --- a/parser/testdata/02681_undrop_query/metadata.json +++ b/parser/testdata/02681_undrop_query/metadata.json @@ -1,6 +1,5 @@ { "explain_todo": { - "stmt16": true, "stmt22": true, "stmt23": true, "stmt25": true, @@ -9,12 +8,6 @@ "stmt32": true, "stmt34": true, "stmt36": true, - "stmt38": true, - "stmt45": true, - "stmt54": true, - "stmt62": true, - "stmt76": true, - "stmt78": true, - "stmt8": true + "stmt38": true } } diff --git a/parser/testdata/02685_decimal256_various/metadata.json b/parser/testdata/02685_decimal256_various/metadata.json index 6e2f58a192..abe45ba24a 100644 --- a/parser/testdata/02685_decimal256_various/metadata.json +++ b/parser/testdata/02685_decimal256_various/metadata.json @@ -1,11 +1,5 @@ { "explain_todo": { - "stmt27": true, - "stmt30": true, - "stmt31": true, - "stmt32": true, - "stmt33": true, - "stmt34": true, - "stmt35": true + "stmt27": true } } diff --git a/parser/testdata/02706_show_columns/metadata.json b/parser/testdata/02706_show_columns/metadata.json index 5c2629b23d..6fb75fafb6 100644 --- a/parser/testdata/02706_show_columns/metadata.json +++ b/parser/testdata/02706_show_columns/metadata.json @@ -1,13 +1,7 @@ { "explain_todo": { "stmt2": true, - "stmt35": true, - "stmt36": true, - "stmt37": true, - "stmt40": true, - "stmt41": true, "stmt5": true, - "stmt7": true, "stmt9": true } } diff --git a/parser/testdata/02707_keeper_map_delete_update_strict/metadata.json b/parser/testdata/02707_keeper_map_delete_update_strict/metadata.json index 8e865502d5..e4a9d201d5 100644 --- a/parser/testdata/02707_keeper_map_delete_update_strict/metadata.json +++ b/parser/testdata/02707_keeper_map_delete_update_strict/metadata.json @@ -1,6 +1,5 @@ { "explain_todo": { - "stmt10": true, "stmt13": true, "stmt22": true, "stmt7": true diff --git a/parser/testdata/02708_dotProduct/metadata.json b/parser/testdata/02708_dotProduct/metadata.json index 435ccb1955..c594a0f078 100644 --- a/parser/testdata/02708_dotProduct/metadata.json +++ b/parser/testdata/02708_dotProduct/metadata.json @@ -1,23 +1,8 @@ { "explain_todo": { - "stmt10": true, - "stmt11": true, - "stmt12": true, - "stmt13": true, - "stmt14": true, - "stmt15": true, - "stmt16": true, - "stmt17": true, - "stmt18": true, - "stmt19": true, - "stmt20": true, - "stmt21": true, "stmt34": true, - "stmt35": true, - "stmt36": true, "stmt38": true, "stmt54": true, - "stmt55": true, - "stmt56": true + "stmt55": true } } diff --git a/parser/testdata/02718_array_fold/metadata.json b/parser/testdata/02718_array_fold/metadata.json index 5a38f68bcb..0967ef424b 100644 --- a/parser/testdata/02718_array_fold/metadata.json +++ b/parser/testdata/02718_array_fold/metadata.json @@ -1,21 +1 @@ -{ - "explain_todo": { - "stmt10": true, - "stmt12": true, - "stmt13": true, - "stmt14": true, - "stmt15": true, - "stmt16": true, - "stmt17": true, - "stmt18": true, - "stmt20": true, - "stmt21": true, - "stmt22": true, - "stmt27": true, - "stmt34": true, - "stmt6": true, - "stmt7": true, - "stmt8": true, - "stmt9": true - } -} +{} diff --git a/parser/testdata/02724_persist_interval_type/metadata.json b/parser/testdata/02724_persist_interval_type/metadata.json index 48b547ca48..0967ef424b 100644 --- a/parser/testdata/02724_persist_interval_type/metadata.json +++ b/parser/testdata/02724_persist_interval_type/metadata.json @@ -1 +1 @@ -{"explain_todo":{"stmt3":true,"stmt7":true}} +{} diff --git a/parser/testdata/02724_show_indexes/metadata.json b/parser/testdata/02724_show_indexes/metadata.json index ed80134773..0967ef424b 100644 --- a/parser/testdata/02724_show_indexes/metadata.json +++ b/parser/testdata/02724_show_indexes/metadata.json @@ -1,23 +1 @@ -{ - "explain_todo": { - "stmt11": true, - "stmt15": true, - "stmt19": true, - "stmt23": true, - "stmt25": true, - "stmt26": true, - "stmt27": true, - "stmt28": true, - "stmt29": true, - "stmt30": true, - "stmt31": true, - "stmt37": true, - "stmt39": true, - "stmt4": true, - "stmt41": true, - "stmt5": true, - "stmt6": true, - "stmt7": true, - "stmt9": true - } -} +{} diff --git a/parser/testdata/02734_sparse_columns_mutation/metadata.json b/parser/testdata/02734_sparse_columns_mutation/metadata.json index 25122ac4f4..3a06a4a1ac 100644 --- a/parser/testdata/02734_sparse_columns_mutation/metadata.json +++ b/parser/testdata/02734_sparse_columns_mutation/metadata.json @@ -1,6 +1,5 @@ { "explain_todo": { - "stmt5": true, - "stmt9": true + "stmt5": true } } diff --git a/parser/testdata/02735_system_zookeeper_connection/metadata.json b/parser/testdata/02735_system_zookeeper_connection/metadata.json index ef382ce51e..0967ef424b 100644 --- a/parser/testdata/02735_system_zookeeper_connection/metadata.json +++ b/parser/testdata/02735_system_zookeeper_connection/metadata.json @@ -1,6 +1 @@ -{ - "explain_todo": { - "stmt4": true, - "stmt5": true - } -} +{} diff --git a/parser/testdata/02783_parsedatetimebesteffort_syslog/metadata.json b/parser/testdata/02783_parsedatetimebesteffort_syslog/metadata.json index aa21dd9600..0967ef424b 100644 --- a/parser/testdata/02783_parsedatetimebesteffort_syslog/metadata.json +++ b/parser/testdata/02783_parsedatetimebesteffort_syslog/metadata.json @@ -1 +1 @@ -{"explain_todo":{"stmt11":true,"stmt7":true}} +{} diff --git a/parser/testdata/02797_range_nullable/metadata.json b/parser/testdata/02797_range_nullable/metadata.json index 0cdd4a17b5..0967ef424b 100644 --- a/parser/testdata/02797_range_nullable/metadata.json +++ b/parser/testdata/02797_range_nullable/metadata.json @@ -1 +1 @@ -{"explain_todo":{"stmt10":true,"stmt11":true,"stmt12":true,"stmt9":true}} +{} diff --git a/parser/testdata/02806_cte_block_cannot_be_empty/metadata.json b/parser/testdata/02806_cte_block_cannot_be_empty/metadata.json index f7c9a031b3..0967ef424b 100644 --- a/parser/testdata/02806_cte_block_cannot_be_empty/metadata.json +++ b/parser/testdata/02806_cte_block_cannot_be_empty/metadata.json @@ -1,7 +1 @@ -{ - "explain_todo": { - "stmt1": true, - "stmt2": true, - "stmt3": true - } -} +{} diff --git a/parser/testdata/02809_has_subsequence/metadata.json b/parser/testdata/02809_has_subsequence/metadata.json index f894d0f2de..0967ef424b 100644 --- a/parser/testdata/02809_has_subsequence/metadata.json +++ b/parser/testdata/02809_has_subsequence/metadata.json @@ -1 +1 @@ -{"explain_todo":{"stmt61":true}} +{} diff --git a/parser/testdata/02813_optimize_lazy_materialization/metadata.json b/parser/testdata/02813_optimize_lazy_materialization/metadata.json index 5a6e7bbecd..c7108ca34e 100644 --- a/parser/testdata/02813_optimize_lazy_materialization/metadata.json +++ b/parser/testdata/02813_optimize_lazy_materialization/metadata.json @@ -1,6 +1,5 @@ { "explain_todo": { - "stmt118": true, "stmt136": true, "stmt141": true } diff --git a/parser/testdata/02814_age_datediff/metadata.json b/parser/testdata/02814_age_datediff/metadata.json index 091a362101..0967ef424b 100644 --- a/parser/testdata/02814_age_datediff/metadata.json +++ b/parser/testdata/02814_age_datediff/metadata.json @@ -1 +1 @@ -{"explain_todo":{"stmt55":true,"stmt56":true,"stmt57":true,"stmt58":true,"stmt59":true,"stmt60":true,"stmt61":true,"stmt62":true,"stmt63":true,"stmt64":true}} +{} diff --git a/parser/testdata/02816_check_projection_metadata/metadata.json b/parser/testdata/02816_check_projection_metadata/metadata.json index e9d6e46171..0967ef424b 100644 --- a/parser/testdata/02816_check_projection_metadata/metadata.json +++ b/parser/testdata/02816_check_projection_metadata/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt1": true - } -} +{} diff --git a/parser/testdata/02832_alter_delete_indexes_projections/metadata.json b/parser/testdata/02832_alter_delete_indexes_projections/metadata.json index f04990226e..0967ef424b 100644 --- a/parser/testdata/02832_alter_delete_indexes_projections/metadata.json +++ b/parser/testdata/02832_alter_delete_indexes_projections/metadata.json @@ -1,6 +1 @@ -{ - "explain_todo": { - "stmt14": true, - "stmt6": true - } -} +{} diff --git a/parser/testdata/02842_mutations_replace_non_deterministic/metadata.json b/parser/testdata/02842_mutations_replace_non_deterministic/metadata.json index 7389add715..fad6b6f917 100644 --- a/parser/testdata/02842_mutations_replace_non_deterministic/metadata.json +++ b/parser/testdata/02842_mutations_replace_non_deterministic/metadata.json @@ -1,7 +1,6 @@ { "explain_todo": { "stmt28": true, - "stmt41": true, "stmt42": true } } diff --git a/parser/testdata/02842_truncate_database/metadata.json b/parser/testdata/02842_truncate_database/metadata.json index 857cf4b2dc..7bf4b04abe 100644 --- a/parser/testdata/02842_truncate_database/metadata.json +++ b/parser/testdata/02842_truncate_database/metadata.json @@ -1,7 +1,5 @@ { "explain_todo": { - "stmt32": true, - "stmt33": true, - "stmt43": true + "stmt33": true } } diff --git a/parser/testdata/02863_mutation_where_in_set_result_cache_pipeline_stuck_bug/metadata.json b/parser/testdata/02863_mutation_where_in_set_result_cache_pipeline_stuck_bug/metadata.json index dbdbb76d4f..0967ef424b 100644 --- a/parser/testdata/02863_mutation_where_in_set_result_cache_pipeline_stuck_bug/metadata.json +++ b/parser/testdata/02863_mutation_where_in_set_result_cache_pipeline_stuck_bug/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt6": true - } -} +{} diff --git a/parser/testdata/02870_per_column_settings/metadata.json b/parser/testdata/02870_per_column_settings/metadata.json index 4f6d7bf375..4db6ff0adf 100644 --- a/parser/testdata/02870_per_column_settings/metadata.json +++ b/parser/testdata/02870_per_column_settings/metadata.json @@ -1,7 +1,6 @@ { "explain_todo": { "stmt10": true, - "stmt13": true, "stmt16": true, "stmt2": true, "stmt20": true, diff --git a/parser/testdata/02884_interval_operator_support_plural_literal/metadata.json b/parser/testdata/02884_interval_operator_support_plural_literal/metadata.json index 7e650b7f29..0967ef424b 100644 --- a/parser/testdata/02884_interval_operator_support_plural_literal/metadata.json +++ b/parser/testdata/02884_interval_operator_support_plural_literal/metadata.json @@ -1,21 +1 @@ -{ - "explain_todo": { - "stmt11": true, - "stmt12": true, - "stmt14": true, - "stmt15": true, - "stmt17": true, - "stmt18": true, - "stmt19": true, - "stmt2": true, - "stmt20": true, - "stmt21": true, - "stmt22": true, - "stmt23": true, - "stmt3": true, - "stmt5": true, - "stmt6": true, - "stmt8": true, - "stmt9": true - } -} +{} diff --git a/parser/testdata/02889_print_pretty_type_names/metadata.json b/parser/testdata/02889_print_pretty_type_names/metadata.json index b65b07d7a6..0967ef424b 100644 --- a/parser/testdata/02889_print_pretty_type_names/metadata.json +++ b/parser/testdata/02889_print_pretty_type_names/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt4": true - } -} +{} diff --git a/parser/testdata/02922_analyzer_aggregate_nothing_type/metadata.json b/parser/testdata/02922_analyzer_aggregate_nothing_type/metadata.json index 30dca0857e..0967ef424b 100644 --- a/parser/testdata/02922_analyzer_aggregate_nothing_type/metadata.json +++ b/parser/testdata/02922_analyzer_aggregate_nothing_type/metadata.json @@ -1,12 +1 @@ -{ - "explain_todo": { - "stmt27": true, - "stmt28": true, - "stmt29": true, - "stmt3": true, - "stmt30": true, - "stmt4": true, - "stmt7": true, - "stmt82": true - } -} +{} diff --git a/parser/testdata/02922_respect_nulls_extensive/metadata.json b/parser/testdata/02922_respect_nulls_extensive/metadata.json index d689cec729..0967ef424b 100644 --- a/parser/testdata/02922_respect_nulls_extensive/metadata.json +++ b/parser/testdata/02922_respect_nulls_extensive/metadata.json @@ -1,6 +1 @@ -{ - "explain_todo": { - "stmt40": true, - "stmt41": true - } -} +{} diff --git a/parser/testdata/02922_respect_nulls_states/metadata.json b/parser/testdata/02922_respect_nulls_states/metadata.json index 02a89fff19..0967ef424b 100644 --- a/parser/testdata/02922_respect_nulls_states/metadata.json +++ b/parser/testdata/02922_respect_nulls_states/metadata.json @@ -1 +1 @@ -{"explain_todo":{"stmt3":true,"stmt5":true,"stmt7":true,"stmt9":true}} +{} diff --git a/parser/testdata/02932_lwd_and_mutations/metadata.json b/parser/testdata/02932_lwd_and_mutations/metadata.json index 383575e459..57a221f1be 100644 --- a/parser/testdata/02932_lwd_and_mutations/metadata.json +++ b/parser/testdata/02932_lwd_and_mutations/metadata.json @@ -1,11 +1,7 @@ { "explain_todo": { "stmt11": true, - "stmt14": true, - "stmt17": true, - "stmt20": true, "stmt23": true, - "stmt5": true, - "stmt8": true + "stmt5": true } } diff --git a/parser/testdata/02935_format_with_arbitrary_types/metadata.json b/parser/testdata/02935_format_with_arbitrary_types/metadata.json index 4fc28f6ddf..898e7ce13d 100644 --- a/parser/testdata/02935_format_with_arbitrary_types/metadata.json +++ b/parser/testdata/02935_format_with_arbitrary_types/metadata.json @@ -1 +1,8 @@ -{"explain_todo":{"stmt19":true,"stmt20":true,"stmt37":true,"stmt39":true,"stmt43":true,"stmt44":true,"stmt45":true,"stmt46":true,"stmt55":true,"stmt56":true,"stmt57":true,"stmt58":true,"stmt59":true,"stmt60":true,"stmt76":true}} +{ + "explain_todo": { + "stmt19": true, + "stmt20": true, + "stmt44": true, + "stmt46": true + } +} diff --git a/parser/testdata/02942_variant_cast/metadata.json b/parser/testdata/02942_variant_cast/metadata.json index 63554d20f0..0967ef424b 100644 --- a/parser/testdata/02942_variant_cast/metadata.json +++ b/parser/testdata/02942_variant_cast/metadata.json @@ -1 +1 @@ -{"explain_todo":{"stmt12":true,"stmt13":true,"stmt16":true,"stmt17":true,"stmt2":true}} +{} diff --git a/parser/testdata/02943_variant_element/metadata.json b/parser/testdata/02943_variant_element/metadata.json index 4a52a8e22d..0967ef424b 100644 --- a/parser/testdata/02943_variant_element/metadata.json +++ b/parser/testdata/02943_variant_element/metadata.json @@ -1,7 +1 @@ -{ - "explain_todo": { - "stmt11": true, - "stmt3": true, - "stmt9": true - } -} +{} diff --git a/parser/testdata/02944_variant_as_common_type_analyzer/metadata.json b/parser/testdata/02944_variant_as_common_type_analyzer/metadata.json index d25aa33927..0967ef424b 100644 --- a/parser/testdata/02944_variant_as_common_type_analyzer/metadata.json +++ b/parser/testdata/02944_variant_as_common_type_analyzer/metadata.json @@ -1,12 +1 @@ -{ - "explain_todo": { - "stmt10": true, - "stmt11": true, - "stmt18": true, - "stmt19": true, - "stmt26": true, - "stmt27": true, - "stmt34": true, - "stmt35": true - } -} +{} diff --git a/parser/testdata/02969_analyzer_eliminate_injective_functions/metadata.json b/parser/testdata/02969_analyzer_eliminate_injective_functions/metadata.json index 7b4ddafa53..0967ef424b 100644 --- a/parser/testdata/02969_analyzer_eliminate_injective_functions/metadata.json +++ b/parser/testdata/02969_analyzer_eliminate_injective_functions/metadata.json @@ -1,6 +1 @@ -{ - "explain_todo": { - "stmt3": true, - "stmt4": true - } -} +{} diff --git a/parser/testdata/02981_nested_bad_types/metadata.json b/parser/testdata/02981_nested_bad_types/metadata.json index 8f2a6eb399..0967ef424b 100644 --- a/parser/testdata/02981_nested_bad_types/metadata.json +++ b/parser/testdata/02981_nested_bad_types/metadata.json @@ -1 +1 @@ -{"explain_todo":{"stmt17":true,"stmt3":true,"stmt4":true}} +{} diff --git a/parser/testdata/02990_arrayFold_nullable_lc/metadata.json b/parser/testdata/02990_arrayFold_nullable_lc/metadata.json index 76d43ac97c..0967ef424b 100644 --- a/parser/testdata/02990_arrayFold_nullable_lc/metadata.json +++ b/parser/testdata/02990_arrayFold_nullable_lc/metadata.json @@ -1,16 +1 @@ -{ - "explain_todo": { - "stmt18": true, - "stmt19": true, - "stmt20": true, - "stmt21": true, - "stmt22": true, - "stmt24": true, - "stmt25": true, - "stmt5": true, - "stmt6": true, - "stmt7": true, - "stmt8": true, - "stmt9": true - } -} +{} diff --git a/parser/testdata/02996_nullable_arrayReduce/metadata.json b/parser/testdata/02996_nullable_arrayReduce/metadata.json index a62af59386..0967ef424b 100644 --- a/parser/testdata/02996_nullable_arrayReduce/metadata.json +++ b/parser/testdata/02996_nullable_arrayReduce/metadata.json @@ -1 +1 @@ -{"explain_todo":{"stmt6":true,"stmt7":true}} +{} diff --git a/parser/testdata/02997_projections_formatting/metadata.json b/parser/testdata/02997_projections_formatting/metadata.json index 6ed702cc94..0967ef424b 100644 --- a/parser/testdata/02997_projections_formatting/metadata.json +++ b/parser/testdata/02997_projections_formatting/metadata.json @@ -1,8 +1 @@ -{ - "explain_todo": { - "stmt1": true, - "stmt2": true, - "stmt3": true, - "stmt4": true - } -} +{} diff --git a/parser/testdata/02999_variant_suspicious_types/metadata.json b/parser/testdata/02999_variant_suspicious_types/metadata.json index cc22e4816f..0967ef424b 100644 --- a/parser/testdata/02999_variant_suspicious_types/metadata.json +++ b/parser/testdata/02999_variant_suspicious_types/metadata.json @@ -1 +1 @@ -{"explain_todo":{"stmt3":true,"stmt5":true}} +{} diff --git a/parser/testdata/03011_definitive_guide_to_cast/metadata.json b/parser/testdata/03011_definitive_guide_to_cast/metadata.json index 6733b1ee91..4320920101 100644 --- a/parser/testdata/03011_definitive_guide_to_cast/metadata.json +++ b/parser/testdata/03011_definitive_guide_to_cast/metadata.json @@ -1,10 +1,7 @@ { "explain_todo": { "stmt36": true, - "stmt52": true, "stmt53": true, - "stmt84": true, - "stmt86": true, - "stmt88": true + "stmt84": true } } diff --git a/parser/testdata/03015_peder1001/metadata.json b/parser/testdata/03015_peder1001/metadata.json index b65b07d7a6..0967ef424b 100644 --- a/parser/testdata/03015_peder1001/metadata.json +++ b/parser/testdata/03015_peder1001/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt4": true - } -} +{} diff --git a/parser/testdata/03032_string_to_variant_cast/metadata.json b/parser/testdata/03032_string_to_variant_cast/metadata.json index cbba02e8b3..0967ef424b 100644 --- a/parser/testdata/03032_string_to_variant_cast/metadata.json +++ b/parser/testdata/03032_string_to_variant_cast/metadata.json @@ -1,7 +1 @@ -{ - "explain_todo": { - "stmt12": true, - "stmt14": true, - "stmt15": true - } -} +{} diff --git a/parser/testdata/03047_on_fly_mutations_events/metadata.json b/parser/testdata/03047_on_fly_mutations_events/metadata.json index 2ef6a38008..ccc75f74d5 100644 --- a/parser/testdata/03047_on_fly_mutations_events/metadata.json +++ b/parser/testdata/03047_on_fly_mutations_events/metadata.json @@ -1,7 +1,6 @@ { "explain_todo": { "stmt15": true, - "stmt8": true, "stmt9": true } } diff --git a/parser/testdata/03047_on_fly_mutations_non_deterministic_replace/metadata.json b/parser/testdata/03047_on_fly_mutations_non_deterministic_replace/metadata.json index 0c54d3781a..6ba17be167 100644 --- a/parser/testdata/03047_on_fly_mutations_non_deterministic_replace/metadata.json +++ b/parser/testdata/03047_on_fly_mutations_non_deterministic_replace/metadata.json @@ -1,7 +1,6 @@ { "explain_todo": { "stmt36": true, - "stmt55": true, "stmt58": true } } diff --git a/parser/testdata/03047_on_fly_update_delete/metadata.json b/parser/testdata/03047_on_fly_update_delete/metadata.json index 56accf959b..1ed30c5543 100644 --- a/parser/testdata/03047_on_fly_update_delete/metadata.json +++ b/parser/testdata/03047_on_fly_update_delete/metadata.json @@ -1,6 +1,5 @@ { "explain_todo": { - "stmt12": true, "stmt13": true, "stmt6": true } diff --git a/parser/testdata/03100_lwu_10_apply_on_merges/metadata.json b/parser/testdata/03100_lwu_10_apply_on_merges/metadata.json index f2b01e55b3..f216958458 100644 --- a/parser/testdata/03100_lwu_10_apply_on_merges/metadata.json +++ b/parser/testdata/03100_lwu_10_apply_on_merges/metadata.json @@ -2,7 +2,6 @@ "explain_todo": { "stmt11": true, "stmt14": true, - "stmt15": true, "stmt16": true, "stmt18": true, "stmt19": true, diff --git a/parser/testdata/03100_lwu_32_on_fly_filter/metadata.json b/parser/testdata/03100_lwu_32_on_fly_filter/metadata.json index b731c2f0d3..92efb02376 100644 --- a/parser/testdata/03100_lwu_32_on_fly_filter/metadata.json +++ b/parser/testdata/03100_lwu_32_on_fly_filter/metadata.json @@ -1,8 +1,6 @@ { "explain_todo": { - "stmt10": true, "stmt6": true, - "stmt7": true, "stmt8": true } } diff --git a/parser/testdata/03100_lwu_deletes_2/metadata.json b/parser/testdata/03100_lwu_deletes_2/metadata.json index 1c7bcfb64f..a9bcd51630 100644 --- a/parser/testdata/03100_lwu_deletes_2/metadata.json +++ b/parser/testdata/03100_lwu_deletes_2/metadata.json @@ -3,7 +3,6 @@ "stmt10": true, "stmt18": true, "stmt30": true, - "stmt34": true, "stmt38": true } } diff --git a/parser/testdata/03101_analyzer_identifiers_4/metadata.json b/parser/testdata/03101_analyzer_identifiers_4/metadata.json index ca345578d8..16cecbd2f7 100644 --- a/parser/testdata/03101_analyzer_identifiers_4/metadata.json +++ b/parser/testdata/03101_analyzer_identifiers_4/metadata.json @@ -1,7 +1,6 @@ { "explain_todo": { "stmt14": true, - "stmt18": true, "stmt7": true, "stmt9": true } diff --git a/parser/testdata/03144_invalid_filter/metadata.json b/parser/testdata/03144_invalid_filter/metadata.json index 1295a45747..0967ef424b 100644 --- a/parser/testdata/03144_invalid_filter/metadata.json +++ b/parser/testdata/03144_invalid_filter/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt3": true - } -} +{} diff --git a/parser/testdata/03148_mutations_virtual_columns/metadata.json b/parser/testdata/03148_mutations_virtual_columns/metadata.json index 342b3ff5b4..0967ef424b 100644 --- a/parser/testdata/03148_mutations_virtual_columns/metadata.json +++ b/parser/testdata/03148_mutations_virtual_columns/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt8": true - } -} +{} diff --git a/parser/testdata/03152_analyzer_columns_list/metadata.json b/parser/testdata/03152_analyzer_columns_list/metadata.json index 7b4ddafa53..0967ef424b 100644 --- a/parser/testdata/03152_analyzer_columns_list/metadata.json +++ b/parser/testdata/03152_analyzer_columns_list/metadata.json @@ -1,6 +1 @@ -{ - "explain_todo": { - "stmt3": true, - "stmt4": true - } -} +{} diff --git a/parser/testdata/03176_check_timeout_in_index_analysis/metadata.json b/parser/testdata/03176_check_timeout_in_index_analysis/metadata.json index b563327205..0967ef424b 100644 --- a/parser/testdata/03176_check_timeout_in_index_analysis/metadata.json +++ b/parser/testdata/03176_check_timeout_in_index_analysis/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt7": true - } -} +{} diff --git a/parser/testdata/03203_drop_detached_partition_all/metadata.json b/parser/testdata/03203_drop_detached_partition_all/metadata.json index 6bf8d5b80a..b563327205 100644 --- a/parser/testdata/03203_drop_detached_partition_all/metadata.json +++ b/parser/testdata/03203_drop_detached_partition_all/metadata.json @@ -1,6 +1,5 @@ { "explain_todo": { - "stmt5": true, "stmt7": true } } diff --git a/parser/testdata/03205_json_cast_from_string/metadata.json b/parser/testdata/03205_json_cast_from_string/metadata.json index 45ab4e25fe..3a06a4a1ac 100644 --- a/parser/testdata/03205_json_cast_from_string/metadata.json +++ b/parser/testdata/03205_json_cast_from_string/metadata.json @@ -1,11 +1,5 @@ { "explain_todo": { - "stmt10": true, - "stmt11": true, - "stmt12": true, - "stmt5": true, - "stmt6": true, - "stmt7": true, - "stmt8": true + "stmt5": true } } diff --git a/parser/testdata/03206_is_null_constant_result_old_analyzer_bug/metadata.json b/parser/testdata/03206_is_null_constant_result_old_analyzer_bug/metadata.json index 9022255763..0967ef424b 100644 --- a/parser/testdata/03206_is_null_constant_result_old_analyzer_bug/metadata.json +++ b/parser/testdata/03206_is_null_constant_result_old_analyzer_bug/metadata.json @@ -1,6 +1 @@ -{ - "explain_todo": { - "stmt4": true, - "stmt9": true - } -} +{} diff --git a/parser/testdata/03208_array_of_json_read_subcolumns_2_memory/metadata.json b/parser/testdata/03208_array_of_json_read_subcolumns_2_memory/metadata.json index 90fa5ee0a1..3a06a4a1ac 100644 --- a/parser/testdata/03208_array_of_json_read_subcolumns_2_memory/metadata.json +++ b/parser/testdata/03208_array_of_json_read_subcolumns_2_memory/metadata.json @@ -1,17 +1,5 @@ { "explain_todo": { - "stmt18": true, - "stmt20": true, - "stmt23": true, - "stmt24": true, - "stmt27": true, - "stmt28": true, - "stmt30": true, - "stmt32": true, - "stmt35": true, - "stmt36": true, - "stmt39": true, - "stmt40": true, "stmt5": true } } diff --git a/parser/testdata/03208_groupArrayIntersect_serialization/metadata.json b/parser/testdata/03208_groupArrayIntersect_serialization/metadata.json index 6bcb344c6d..0967ef424b 100644 --- a/parser/testdata/03208_groupArrayIntersect_serialization/metadata.json +++ b/parser/testdata/03208_groupArrayIntersect_serialization/metadata.json @@ -1,11 +1 @@ -{ - "explain_todo": { - "stmt11": true, - "stmt13": true, - "stmt15": true, - "stmt28": true, - "stmt5": true, - "stmt7": true, - "stmt9": true - } -} +{} diff --git a/parser/testdata/03210_dynamic_squashing/metadata.json b/parser/testdata/03210_dynamic_squashing/metadata.json index a954a15222..0967ef424b 100644 --- a/parser/testdata/03210_dynamic_squashing/metadata.json +++ b/parser/testdata/03210_dynamic_squashing/metadata.json @@ -1,6 +1 @@ -{ - "explain_todo": { - "stmt10": true, - "stmt5": true - } -} +{} diff --git a/parser/testdata/03212_optimize_with_constraints_logical_error/metadata.json b/parser/testdata/03212_optimize_with_constraints_logical_error/metadata.json index 1295a45747..0967ef424b 100644 --- a/parser/testdata/03212_optimize_with_constraints_logical_error/metadata.json +++ b/parser/testdata/03212_optimize_with_constraints_logical_error/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt3": true - } -} +{} diff --git a/parser/testdata/03223_system_tables_set_not_ready/metadata.json b/parser/testdata/03223_system_tables_set_not_ready/metadata.json index 27369be079..9be7220609 100644 --- a/parser/testdata/03223_system_tables_set_not_ready/metadata.json +++ b/parser/testdata/03223_system_tables_set_not_ready/metadata.json @@ -1,6 +1,5 @@ { "explain_todo": { - "stmt14": true, "stmt22": true } } diff --git a/parser/testdata/03234_evaluate_constant_analyzer/metadata.json b/parser/testdata/03234_evaluate_constant_analyzer/metadata.json index e9d6e46171..0967ef424b 100644 --- a/parser/testdata/03234_evaluate_constant_analyzer/metadata.json +++ b/parser/testdata/03234_evaluate_constant_analyzer/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt1": true - } -} +{} diff --git a/parser/testdata/03243_cluster_not_found_column/metadata.json b/parser/testdata/03243_cluster_not_found_column/metadata.json index ef58f80315..0967ef424b 100644 --- a/parser/testdata/03243_cluster_not_found_column/metadata.json +++ b/parser/testdata/03243_cluster_not_found_column/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt2": true - } -} +{} diff --git a/parser/testdata/03250_avoid_prefetch_empty_parts/metadata.json b/parser/testdata/03250_avoid_prefetch_empty_parts/metadata.json index b65b07d7a6..0967ef424b 100644 --- a/parser/testdata/03250_avoid_prefetch_empty_parts/metadata.json +++ b/parser/testdata/03250_avoid_prefetch_empty_parts/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt4": true - } -} +{} diff --git a/parser/testdata/03253_group_by_cube_too_many_keys/metadata.json b/parser/testdata/03253_group_by_cube_too_many_keys/metadata.json index e9d6e46171..0967ef424b 100644 --- a/parser/testdata/03253_group_by_cube_too_many_keys/metadata.json +++ b/parser/testdata/03253_group_by_cube_too_many_keys/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt1": true - } -} +{} diff --git a/parser/testdata/03254_last_2_samples_aggregate_function_simple/metadata.json b/parser/testdata/03254_last_2_samples_aggregate_function_simple/metadata.json index a74c293460..b65b07d7a6 100644 --- a/parser/testdata/03254_last_2_samples_aggregate_function_simple/metadata.json +++ b/parser/testdata/03254_last_2_samples_aggregate_function_simple/metadata.json @@ -1,7 +1,5 @@ { "explain_todo": { - "stmt4": true, - "stmt8": true, - "stmt9": true + "stmt4": true } } diff --git a/parser/testdata/03254_timeseries_functions_various_arguments/metadata.json b/parser/testdata/03254_timeseries_functions_various_arguments/metadata.json index 904bce3282..0967ef424b 100644 --- a/parser/testdata/03254_timeseries_functions_various_arguments/metadata.json +++ b/parser/testdata/03254_timeseries_functions_various_arguments/metadata.json @@ -1,17 +1 @@ -{ - "explain_todo": { - "stmt44": true, - "stmt46": true, - "stmt47": true, - "stmt48": true, - "stmt49": true, - "stmt50": true, - "stmt51": true, - "stmt52": true, - "stmt53": true, - "stmt54": true, - "stmt55": true, - "stmt56": true, - "stmt61": true - } -} +{} diff --git a/parser/testdata/03254_timeseries_to_grid_aggregate_function/metadata.json b/parser/testdata/03254_timeseries_to_grid_aggregate_function/metadata.json index dd69e2d46b..523415a672 100644 --- a/parser/testdata/03254_timeseries_to_grid_aggregate_function/metadata.json +++ b/parser/testdata/03254_timeseries_to_grid_aggregate_function/metadata.json @@ -4,7 +4,6 @@ "stmt11": true, "stmt12": true, "stmt2": true, - "stmt23": true, "stmt3": true, "stmt8": true, "stmt9": true diff --git a/parser/testdata/03256_invalid_mutation_query/metadata.json b/parser/testdata/03256_invalid_mutation_query/metadata.json index b226c5e534..e18504f0c2 100644 --- a/parser/testdata/03256_invalid_mutation_query/metadata.json +++ b/parser/testdata/03256_invalid_mutation_query/metadata.json @@ -5,7 +5,6 @@ "stmt4": true, "stmt5": true, "stmt6": true, - "stmt7": true, "stmt9": true } } diff --git a/parser/testdata/03261_any_respect_camelCase_aliases/metadata.json b/parser/testdata/03261_any_respect_camelCase_aliases/metadata.json index 31f6f1e5e0..0967ef424b 100644 --- a/parser/testdata/03261_any_respect_camelCase_aliases/metadata.json +++ b/parser/testdata/03261_any_respect_camelCase_aliases/metadata.json @@ -1,9 +1 @@ -{ - "explain_todo": { - "stmt10": true, - "stmt16": true, - "stmt22": true, - "stmt28": true, - "stmt4": true - } -} +{} diff --git a/parser/testdata/03272_json_to_json_cast_3/metadata.json b/parser/testdata/03272_json_to_json_cast_3/metadata.json index b344e2bbfa..0967ef424b 100644 --- a/parser/testdata/03272_json_to_json_cast_3/metadata.json +++ b/parser/testdata/03272_json_to_json_cast_3/metadata.json @@ -1,24 +1 @@ -{ - "explain_todo": { - "stmt10": true, - "stmt16": true, - "stmt24": true, - "stmt28": true, - "stmt30": true, - "stmt32": true, - "stmt34": true, - "stmt38": true, - "stmt46": true, - "stmt52": true, - "stmt54": true, - "stmt56": true, - "stmt58": true, - "stmt60": true, - "stmt62": true, - "stmt66": true, - "stmt68": true, - "stmt70": true, - "stmt72": true, - "stmt74": true - } -} +{} diff --git a/parser/testdata/03275_block_number_mutation/metadata.json b/parser/testdata/03275_block_number_mutation/metadata.json index 4a447480d5..0967ef424b 100644 --- a/parser/testdata/03275_block_number_mutation/metadata.json +++ b/parser/testdata/03275_block_number_mutation/metadata.json @@ -1,6 +1 @@ -{ - "explain_todo": { - "stmt19": true, - "stmt6": true - } -} +{} diff --git a/parser/testdata/03275_subcolumns_in_primary_key_bug/metadata.json b/parser/testdata/03275_subcolumns_in_primary_key_bug/metadata.json index b65b07d7a6..0967ef424b 100644 --- a/parser/testdata/03275_subcolumns_in_primary_key_bug/metadata.json +++ b/parser/testdata/03275_subcolumns_in_primary_key_bug/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt4": true - } -} +{} diff --git a/parser/testdata/03298_analyzer_group_by_all_fix/metadata.json b/parser/testdata/03298_analyzer_group_by_all_fix/metadata.json index 8556c3021f..0967ef424b 100644 --- a/parser/testdata/03298_analyzer_group_by_all_fix/metadata.json +++ b/parser/testdata/03298_analyzer_group_by_all_fix/metadata.json @@ -1 +1 @@ -{"explain_todo":{"stmt5":true}} +{} diff --git a/parser/testdata/03325_alter_ast_format/metadata.json b/parser/testdata/03325_alter_ast_format/metadata.json index e9d6e46171..0967ef424b 100644 --- a/parser/testdata/03325_alter_ast_format/metadata.json +++ b/parser/testdata/03325_alter_ast_format/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt1": true - } -} +{} diff --git a/parser/testdata/03340_projections_formatting/metadata.json b/parser/testdata/03340_projections_formatting/metadata.json index 9685022035..aeb01f1428 100644 --- a/parser/testdata/03340_projections_formatting/metadata.json +++ b/parser/testdata/03340_projections_formatting/metadata.json @@ -1,13 +1,6 @@ { "explain_todo": { "stmt1": true, - "stmt11": true, - "stmt14": true, - "stmt17": true, - "stmt2": true, - "stmt20": true, - "stmt4": true, - "stmt5": true, - "stmt8": true + "stmt4": true } } diff --git a/parser/testdata/03350_alter_table_fetch_partition_thread_pool/metadata.json b/parser/testdata/03350_alter_table_fetch_partition_thread_pool/metadata.json index 342b3ff5b4..0967ef424b 100644 --- a/parser/testdata/03350_alter_table_fetch_partition_thread_pool/metadata.json +++ b/parser/testdata/03350_alter_table_fetch_partition_thread_pool/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt8": true - } -} +{} diff --git a/parser/testdata/03357_arraySymmetricDifference/metadata.json b/parser/testdata/03357_arraySymmetricDifference/metadata.json index a08759fb21..0967ef424b 100644 --- a/parser/testdata/03357_arraySymmetricDifference/metadata.json +++ b/parser/testdata/03357_arraySymmetricDifference/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt21": true - } -} +{} diff --git a/parser/testdata/03370_join_identifiers/metadata.json b/parser/testdata/03370_join_identifiers/metadata.json index 7b4ddafa53..0967ef424b 100644 --- a/parser/testdata/03370_join_identifiers/metadata.json +++ b/parser/testdata/03370_join_identifiers/metadata.json @@ -1,6 +1 @@ -{ - "explain_todo": { - "stmt3": true, - "stmt4": true - } -} +{} diff --git a/parser/testdata/03393_non_constant_second_argument_for_in/metadata.json b/parser/testdata/03393_non_constant_second_argument_for_in/metadata.json index 1e53d6353e..c89ada73f6 100644 --- a/parser/testdata/03393_non_constant_second_argument_for_in/metadata.json +++ b/parser/testdata/03393_non_constant_second_argument_for_in/metadata.json @@ -1,7 +1,5 @@ { "explain_todo": { - "stmt30": true, - "stmt31": true, "stmt43": true, "stmt44": true, "stmt45": true diff --git a/parser/testdata/03401_remote_bool/metadata.json b/parser/testdata/03401_remote_bool/metadata.json index ef58f80315..0967ef424b 100644 --- a/parser/testdata/03401_remote_bool/metadata.json +++ b/parser/testdata/03401_remote_bool/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt2": true - } -} +{} diff --git a/parser/testdata/03402_adding_projection_to_temporary_table/metadata.json b/parser/testdata/03402_adding_projection_to_temporary_table/metadata.json index 1295a45747..0967ef424b 100644 --- a/parser/testdata/03402_adding_projection_to_temporary_table/metadata.json +++ b/parser/testdata/03402_adding_projection_to_temporary_table/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt3": true - } -} +{} diff --git a/parser/testdata/03408_hash_functions_on_null/metadata.json b/parser/testdata/03408_hash_functions_on_null/metadata.json index 8fc71f1a4f..0967ef424b 100644 --- a/parser/testdata/03408_hash_functions_on_null/metadata.json +++ b/parser/testdata/03408_hash_functions_on_null/metadata.json @@ -1,12 +1 @@ -{ - "explain_todo": { - "stmt11": true, - "stmt12": true, - "stmt18": true, - "stmt19": true, - "stmt23": true, - "stmt24": true, - "stmt6": true, - "stmt7": true - } -} +{} diff --git a/parser/testdata/03413_group_by_all_in_subquery/metadata.json b/parser/testdata/03413_group_by_all_in_subquery/metadata.json index b563327205..0967ef424b 100644 --- a/parser/testdata/03413_group_by_all_in_subquery/metadata.json +++ b/parser/testdata/03413_group_by_all_in_subquery/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt7": true - } -} +{} diff --git a/parser/testdata/03442_alter_delete_empty_part/metadata.json b/parser/testdata/03442_alter_delete_empty_part/metadata.json index b563327205..0967ef424b 100644 --- a/parser/testdata/03442_alter_delete_empty_part/metadata.json +++ b/parser/testdata/03442_alter_delete_empty_part/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt7": true - } -} +{} diff --git a/parser/testdata/03442_alter_delete_empty_part_rmt/metadata.json b/parser/testdata/03442_alter_delete_empty_part_rmt/metadata.json index 342b3ff5b4..0967ef424b 100644 --- a/parser/testdata/03442_alter_delete_empty_part_rmt/metadata.json +++ b/parser/testdata/03442_alter_delete_empty_part_rmt/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt8": true - } -} +{} diff --git a/parser/testdata/03442_lightweight_deletes_on_fly/metadata.json b/parser/testdata/03442_lightweight_deletes_on_fly/metadata.json index e3f4c45da5..d316b0c5fc 100644 --- a/parser/testdata/03442_lightweight_deletes_on_fly/metadata.json +++ b/parser/testdata/03442_lightweight_deletes_on_fly/metadata.json @@ -2,7 +2,6 @@ "explain_todo": { "stmt13": true, "stmt16": true, - "stmt7": true, "stmt8": true } } diff --git a/parser/testdata/03443_projection_sparse/metadata.json b/parser/testdata/03443_projection_sparse/metadata.json index ef58f80315..0967ef424b 100644 --- a/parser/testdata/03443_projection_sparse/metadata.json +++ b/parser/testdata/03443_projection_sparse/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt2": true - } -} +{} diff --git a/parser/testdata/03453_group_by_all_grouping/metadata.json b/parser/testdata/03453_group_by_all_grouping/metadata.json index 7da5190820..0967ef424b 100644 --- a/parser/testdata/03453_group_by_all_grouping/metadata.json +++ b/parser/testdata/03453_group_by_all_grouping/metadata.json @@ -1 +1 @@ -{"explain_todo":{"stmt2":true,"stmt3":true,"stmt4":true,"stmt5":true}} +{} diff --git a/parser/testdata/03464_projections_with_subcolumns/metadata.json b/parser/testdata/03464_projections_with_subcolumns/metadata.json index 86dd984b2e..0967ef424b 100644 --- a/parser/testdata/03464_projections_with_subcolumns/metadata.json +++ b/parser/testdata/03464_projections_with_subcolumns/metadata.json @@ -1,26 +1 @@ -{ - "explain_todo": { - "stmt13": true, - "stmt14": true, - "stmt15": true, - "stmt24": true, - "stmt25": true, - "stmt26": true, - "stmt31": true, - "stmt33": true, - "stmt35": true, - "stmt37": true, - "stmt38": true, - "stmt39": true, - "stmt40": true, - "stmt41": true, - "stmt42": true, - "stmt43": true, - "stmt44": true, - "stmt45": true, - "stmt5": true, - "stmt52": true, - "stmt53": true, - "stmt54": true - } -} +{} diff --git a/parser/testdata/03513_simple_aggregate_function_any_respect_nulls_in_aggregating_merge_tree/metadata.json b/parser/testdata/03513_simple_aggregate_function_any_respect_nulls_in_aggregating_merge_tree/metadata.json index a4f8773303..b65b07d7a6 100644 --- a/parser/testdata/03513_simple_aggregate_function_any_respect_nulls_in_aggregating_merge_tree/metadata.json +++ b/parser/testdata/03513_simple_aggregate_function_any_respect_nulls_in_aggregating_merge_tree/metadata.json @@ -1,7 +1,5 @@ { "explain_todo": { - "stmt3": true, - "stmt4": true, - "stmt5": true + "stmt4": true } } diff --git a/parser/testdata/03513_simple_aggregate_function_any_respect_nulls_in_summing_merge_tree/metadata.json b/parser/testdata/03513_simple_aggregate_function_any_respect_nulls_in_summing_merge_tree/metadata.json index a4f8773303..b65b07d7a6 100644 --- a/parser/testdata/03513_simple_aggregate_function_any_respect_nulls_in_summing_merge_tree/metadata.json +++ b/parser/testdata/03513_simple_aggregate_function_any_respect_nulls_in_summing_merge_tree/metadata.json @@ -1,7 +1,5 @@ { "explain_todo": { - "stmt3": true, - "stmt4": true, - "stmt5": true + "stmt4": true } } diff --git a/parser/testdata/03522_function_first_non_default/metadata.json b/parser/testdata/03522_function_first_non_default/metadata.json index 8e042738b6..0967ef424b 100644 --- a/parser/testdata/03522_function_first_non_default/metadata.json +++ b/parser/testdata/03522_function_first_non_default/metadata.json @@ -1,18 +1 @@ -{ - "explain_todo": { - "stmt16": true, - "stmt2": true, - "stmt20": true, - "stmt21": true, - "stmt22": true, - "stmt23": true, - "stmt27": true, - "stmt30": true, - "stmt31": true, - "stmt33": true, - "stmt4": true, - "stmt40": true, - "stmt6": true, - "stmt7": true - } -} +{} diff --git a/parser/testdata/03525_transform_null_in_subqeury_with_not_nullable_type/metadata.json b/parser/testdata/03525_transform_null_in_subqeury_with_not_nullable_type/metadata.json index fffcb7d38b..0967ef424b 100644 --- a/parser/testdata/03525_transform_null_in_subqeury_with_not_nullable_type/metadata.json +++ b/parser/testdata/03525_transform_null_in_subqeury_with_not_nullable_type/metadata.json @@ -1,7 +1 @@ -{ - "explain_todo": { - "stmt2": true, - "stmt3": true, - "stmt4": true - } -} +{} diff --git a/parser/testdata/03532_json_dynamic_updates/metadata.json b/parser/testdata/03532_json_dynamic_updates/metadata.json index 6a233ed346..0967ef424b 100644 --- a/parser/testdata/03532_json_dynamic_updates/metadata.json +++ b/parser/testdata/03532_json_dynamic_updates/metadata.json @@ -1,14 +1 @@ -{ - "explain_todo": { - "stmt12": true, - "stmt14": true, - "stmt24": true, - "stmt26": true, - "stmt33": true, - "stmt39": true, - "stmt41": true, - "stmt51": true, - "stmt53": true, - "stmt6": true - } -} +{} diff --git a/parser/testdata/03533_xirr/metadata.json b/parser/testdata/03533_xirr/metadata.json index d4d1d99f95..0967ef424b 100644 --- a/parser/testdata/03533_xirr/metadata.json +++ b/parser/testdata/03533_xirr/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt14": true - } -} +{} diff --git a/parser/testdata/03538_array_except/metadata.json b/parser/testdata/03538_array_except/metadata.json index ad55ed3111..dc0702ac62 100644 --- a/parser/testdata/03538_array_except/metadata.json +++ b/parser/testdata/03538_array_except/metadata.json @@ -1,7 +1,5 @@ { "explain_todo": { - "stmt10": true, - "stmt11": true, "stmt30": true } } diff --git a/parser/testdata/03573_linear_regression_timeseries_functions_various_arguments/metadata.json b/parser/testdata/03573_linear_regression_timeseries_functions_various_arguments/metadata.json index e74ad9f4ca..0967ef424b 100644 --- a/parser/testdata/03573_linear_regression_timeseries_functions_various_arguments/metadata.json +++ b/parser/testdata/03573_linear_regression_timeseries_functions_various_arguments/metadata.json @@ -1,8 +1 @@ -{ - "explain_todo": { - "stmt30": true, - "stmt32": true, - "stmt33": true, - "stmt34": true - } -} +{} diff --git a/parser/testdata/03577_temporary_table_as/metadata.json b/parser/testdata/03577_temporary_table_as/metadata.json index dbdbb76d4f..0967ef424b 100644 --- a/parser/testdata/03577_temporary_table_as/metadata.json +++ b/parser/testdata/03577_temporary_table_as/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt6": true - } -} +{} diff --git a/parser/testdata/03578_kv_in_type_casts/metadata.json b/parser/testdata/03578_kv_in_type_casts/metadata.json index 1c89544edc..0967ef424b 100644 --- a/parser/testdata/03578_kv_in_type_casts/metadata.json +++ b/parser/testdata/03578_kv_in_type_casts/metadata.json @@ -1,6 +1 @@ -{ - "explain_todo": { - "stmt32": true, - "stmt73": true - } -} +{} diff --git a/parser/testdata/03583_rewrite_in_to_join/metadata.json b/parser/testdata/03583_rewrite_in_to_join/metadata.json index b330691357..0967ef424b 100644 --- a/parser/testdata/03583_rewrite_in_to_join/metadata.json +++ b/parser/testdata/03583_rewrite_in_to_join/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt26": true - } -} +{} diff --git a/parser/testdata/03593_any_join_swap_tables/metadata.json b/parser/testdata/03593_any_join_swap_tables/metadata.json index 7ad5569408..0967ef424b 100644 --- a/parser/testdata/03593_any_join_swap_tables/metadata.json +++ b/parser/testdata/03593_any_join_swap_tables/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt9": true - } -} +{} diff --git a/parser/testdata/03595_changes_timeseries_functions_various_arguments/metadata.json b/parser/testdata/03595_changes_timeseries_functions_various_arguments/metadata.json index 5b9a4a1d70..0967ef424b 100644 --- a/parser/testdata/03595_changes_timeseries_functions_various_arguments/metadata.json +++ b/parser/testdata/03595_changes_timeseries_functions_various_arguments/metadata.json @@ -1,12 +1 @@ -{ - "explain_todo": { - "stmt22": true, - "stmt24": true, - "stmt26": true, - "stmt27": true, - "stmt28": true, - "stmt29": true, - "stmt31": true, - "stmt32": true - } -} +{} diff --git a/parser/testdata/03606_nullable_json_group_by/metadata.json b/parser/testdata/03606_nullable_json_group_by/metadata.json index 1295a45747..0967ef424b 100644 --- a/parser/testdata/03606_nullable_json_group_by/metadata.json +++ b/parser/testdata/03606_nullable_json_group_by/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt3": true - } -} +{} diff --git a/parser/testdata/03628_subcolumns_of_columns_with_dot_in_name/metadata.json b/parser/testdata/03628_subcolumns_of_columns_with_dot_in_name/metadata.json index a3aec753ae..2712c834b2 100644 --- a/parser/testdata/03628_subcolumns_of_columns_with_dot_in_name/metadata.json +++ b/parser/testdata/03628_subcolumns_of_columns_with_dot_in_name/metadata.json @@ -1,10 +1,8 @@ { "explain_todo": { - "stmt10": true, "stmt11": true, "stmt15": true, "stmt20": true, - "stmt23": true, "stmt24": true, "stmt27": true, "stmt31": true diff --git a/parser/testdata/03636_storage_alias_basic/metadata.json b/parser/testdata/03636_storage_alias_basic/metadata.json index f778b3ba0e..fec152526a 100644 --- a/parser/testdata/03636_storage_alias_basic/metadata.json +++ b/parser/testdata/03636_storage_alias_basic/metadata.json @@ -1,6 +1,5 @@ { "explain_todo": { - "stmt32": true, - "stmt55": true + "stmt32": true } } diff --git a/parser/testdata/03639_hash_of_dynamic_column/metadata.json b/parser/testdata/03639_hash_of_dynamic_column/metadata.json index d109968791..0967ef424b 100644 --- a/parser/testdata/03639_hash_of_dynamic_column/metadata.json +++ b/parser/testdata/03639_hash_of_dynamic_column/metadata.json @@ -1 +1 @@ -{"explain_todo":{"stmt10":true,"stmt9":true}} +{} diff --git a/parser/testdata/03639_hash_of_json_column/metadata.json b/parser/testdata/03639_hash_of_json_column/metadata.json index f4c74e32be..0967ef424b 100644 --- a/parser/testdata/03639_hash_of_json_column/metadata.json +++ b/parser/testdata/03639_hash_of_json_column/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt10": true - } -} +{} diff --git a/parser/testdata/03640_multiple_mutations_with_error_with_rewrite_parts/metadata.json b/parser/testdata/03640_multiple_mutations_with_error_with_rewrite_parts/metadata.json index 97c64968a0..6bf8d5b80a 100644 --- a/parser/testdata/03640_multiple_mutations_with_error_with_rewrite_parts/metadata.json +++ b/parser/testdata/03640_multiple_mutations_with_error_with_rewrite_parts/metadata.json @@ -1,6 +1,5 @@ { "explain_todo": { - "stmt4": true, "stmt5": true, "stmt7": true } diff --git a/parser/testdata/03640_multiple_mutations_with_rewrite_parts/metadata.json b/parser/testdata/03640_multiple_mutations_with_rewrite_parts/metadata.json index 114ee38611..0967ef424b 100644 --- a/parser/testdata/03640_multiple_mutations_with_rewrite_parts/metadata.json +++ b/parser/testdata/03640_multiple_mutations_with_rewrite_parts/metadata.json @@ -1,6 +1 @@ -{ - "explain_todo": { - "stmt12": true, - "stmt7": true - } -} +{} diff --git a/parser/testdata/03653_updating_minmax_idx_after_mutation/metadata.json b/parser/testdata/03653_updating_minmax_idx_after_mutation/metadata.json index dbdbb76d4f..0967ef424b 100644 --- a/parser/testdata/03653_updating_minmax_idx_after_mutation/metadata.json +++ b/parser/testdata/03653_updating_minmax_idx_after_mutation/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt6": true - } -} +{} diff --git a/parser/testdata/03702_alter_column_update_and_delete_secondary_index_general/metadata.json b/parser/testdata/03702_alter_column_update_and_delete_secondary_index_general/metadata.json index badb15e09a..0967ef424b 100644 --- a/parser/testdata/03702_alter_column_update_and_delete_secondary_index_general/metadata.json +++ b/parser/testdata/03702_alter_column_update_and_delete_secondary_index_general/metadata.json @@ -1,12 +1 @@ -{ - "explain_todo": { - "stmt14": true, - "stmt16": true, - "stmt32": true, - "stmt34": true, - "stmt53": true, - "stmt55": true, - "stmt90": true, - "stmt92": true - } -} +{} diff --git a/parser/testdata/03704_function_dict_get_keys_cache_type/metadata.json b/parser/testdata/03704_function_dict_get_keys_cache_type/metadata.json index 023227a1d1..6b1cea3567 100644 --- a/parser/testdata/03704_function_dict_get_keys_cache_type/metadata.json +++ b/parser/testdata/03704_function_dict_get_keys_cache_type/metadata.json @@ -1,7 +1,6 @@ { "explain_todo": { "stmt10": true, - "stmt25": true, "stmt26": true } } diff --git a/parser/testdata/03707_function_array_remove/metadata.json b/parser/testdata/03707_function_array_remove/metadata.json index 7ee47c55de..0967ef424b 100644 --- a/parser/testdata/03707_function_array_remove/metadata.json +++ b/parser/testdata/03707_function_array_remove/metadata.json @@ -1,6 +1 @@ -{ - "explain_todo": { - "stmt45": true, - "stmt46": true - } -} +{} diff --git a/parser/testdata/03711_deduplication_blocks_part_log/metadata.json b/parser/testdata/03711_deduplication_blocks_part_log/metadata.json index 7bde622007..0967ef424b 100644 --- a/parser/testdata/03711_deduplication_blocks_part_log/metadata.json +++ b/parser/testdata/03711_deduplication_blocks_part_log/metadata.json @@ -1,23 +1 @@ -{ - "explain_todo": { - "stmt10": true, - "stmt11": true, - "stmt12": true, - "stmt13": true, - "stmt14": true, - "stmt15": true, - "stmt16": true, - "stmt17": true, - "stmt18": true, - "stmt19": true, - "stmt20": true, - "stmt27": true, - "stmt3": true, - "stmt4": true, - "stmt5": true, - "stmt6": true, - "stmt7": true, - "stmt8": true, - "stmt9": true - } -} +{} diff --git a/parser/testdata/03727_tolowcardinality_nullable_cast/metadata.json b/parser/testdata/03727_tolowcardinality_nullable_cast/metadata.json index a954a15222..3a06a4a1ac 100644 --- a/parser/testdata/03727_tolowcardinality_nullable_cast/metadata.json +++ b/parser/testdata/03727_tolowcardinality_nullable_cast/metadata.json @@ -1,6 +1,5 @@ { "explain_todo": { - "stmt10": true, "stmt5": true } } diff --git a/parser/testdata/03748_tuple_of_sparse_elements_bug/metadata.json b/parser/testdata/03748_tuple_of_sparse_elements_bug/metadata.json index 3a06a4a1ac..0967ef424b 100644 --- a/parser/testdata/03748_tuple_of_sparse_elements_bug/metadata.json +++ b/parser/testdata/03748_tuple_of_sparse_elements_bug/metadata.json @@ -1,5 +1 @@ -{ - "explain_todo": { - "stmt5": true - } -} +{} diff --git a/token/token.go b/token/token.go index 8704587dc8..05bf17cbe7 100644 --- a/token/token.go +++ b/token/token.go @@ -191,6 +191,7 @@ const ( TRUE TRUNCATE TTL + UNDROP UNION UPDATE USE @@ -387,6 +388,7 @@ var tokens = [...]string{ TRUE: "TRUE", TRUNCATE: "TRUNCATE", TTL: "TTL", + UNDROP: "UNDROP", UNION: "UNION", UPDATE: "UPDATE", USE: "USE",