diff --git a/parser/ast.go b/parser/ast.go index 3566641..40492bb 100644 --- a/parser/ast.go +++ b/parser/ast.go @@ -1406,6 +1406,7 @@ func (c *CreateTable) Accept(visitor ASTVisitor) error { type CreateMaterializedView struct { CreatePos Pos // position of CREATE|ATTACH keyword StatementEnd Pos + OrReplace bool Name *TableIdentifier IfNotExists bool OnCluster *ClusterClause @@ -2476,6 +2477,8 @@ type TTLPolicyRule struct { ToVolume *StringLiteral ToDisk *StringLiteral Action *TTLPolicyRuleAction + GroupBy *GroupByClause + Set []*UpdateAssignment } func (t *TTLPolicyRule) Pos() Pos { @@ -2483,6 +2486,12 @@ func (t *TTLPolicyRule) Pos() Pos { } func (t *TTLPolicyRule) End() Pos { + if len(t.Set) > 0 { + return t.Set[len(t.Set)-1].End() + } + if t.GroupBy != nil { + return t.GroupBy.End() + } if t.Action != nil { return t.Action.End() } @@ -2510,29 +2519,32 @@ func (t *TTLPolicyRule) Accept(visitor ASTVisitor) error { return err } } + if t.GroupBy != nil { + if err := t.GroupBy.Accept(visitor); err != nil { + return err + } + } + for _, set := range t.Set { + if err := set.Accept(visitor); err != nil { + return err + } + } return visitor.VisitTTLPolicyRule(t) } type TTLPolicy struct { - Item *TTLPolicyRule - Where *WhereClause - GroupBy *GroupByClause + Item *TTLPolicyRule + Where *WhereClause } func (t *TTLPolicy) Pos() Pos { if t.Item != nil { return t.Item.Pos() } - if t.Where != nil { - return t.Where.Pos() - } - return t.GroupBy.Pos() + return t.Where.Pos() } func (t *TTLPolicy) End() Pos { - if t.GroupBy != nil { - return t.GroupBy.End() - } if t.Where != nil { return t.Where.End() } @@ -2552,11 +2564,6 @@ func (t *TTLPolicy) Accept(visitor ASTVisitor) error { return err } } - if t.GroupBy != nil { - if err := t.GroupBy.Accept(visitor); err != nil { - return err - } - } return visitor.VisitTTLPolicy(t) } @@ -2571,6 +2578,9 @@ func (t *TTLExpr) Pos() Pos { } func (t *TTLExpr) End() Pos { + if t.Policy != nil { + return t.Policy.End() + } return t.Expr.End() } diff --git a/parser/format.go b/parser/format.go index 1f55d2d..1e2067e 100644 --- a/parser/format.go +++ b/parser/format.go @@ -886,7 +886,11 @@ func (c *CreateLiveView) FormatSQL(formatter *Formatter) { } func (c *CreateMaterializedView) FormatSQL(formatter *Formatter) { - formatter.WriteString("CREATE MATERIALIZED VIEW ") + formatter.WriteString("CREATE") + if c.OrReplace { + formatter.WriteString(" OR REPLACE") + } + formatter.WriteString(" MATERIALIZED VIEW ") if c.IfNotExists { formatter.WriteString("IF NOT EXISTS ") } @@ -2581,10 +2585,6 @@ func (t *TTLPolicy) FormatSQL(formatter *Formatter) { formatter.WriteByte(whitespace) formatter.WriteExpr(t.Where) } - if t.GroupBy != nil { - formatter.WriteByte(whitespace) - formatter.WriteExpr(t.GroupBy) - } } func (t *TTLPolicyRule) FormatSQL(formatter *Formatter) { @@ -2596,6 +2596,17 @@ func (t *TTLPolicyRule) FormatSQL(formatter *Formatter) { formatter.WriteExpr(t.ToDisk) } else if t.Action != nil { formatter.WriteExpr(t.Action) + } else if t.GroupBy != nil { + formatter.WriteExpr(t.GroupBy) + } + if len(t.Set) > 0 { + formatter.WriteString(" SET ") + for i, set := range t.Set { + if i > 0 { + formatter.WriteString(", ") + } + formatter.WriteExpr(set) + } } } diff --git a/parser/parser_table.go b/parser/parser_table.go index 6525050..7e07434 100644 --- a/parser/parser_table.go +++ b/parser/parser_table.go @@ -10,10 +10,19 @@ func (p *Parser) parseDDL(pos Pos) (DDL, error) { switch { case p.matchKeyword(KeywordCreate), p.matchKeyword(KeywordAttach): + isAttach := p.matchKeyword(KeywordAttach) _ = p.lexer.consumeToken() orReplace := p.tryConsumeKeywords(KeywordOr, KeywordReplace) - if orReplace && !p.matchOneOfKeywords(KeywordTemporary, KeywordTable, KeywordView, KeywordFunction, KeywordDictionary) { - return nil, fmt.Errorf("expected keyword: TEMPORARY|TABLE|VIEW|FUNCTION|DICTIONARY, but got %q", p.currentTokenString()) + if orReplace { + // MATERIALIZED VIEW accepts OR REPLACE only under CREATE; + // ClickHouse rejects an ATTACH OR REPLACE combination. + if isAttach { + if !p.matchOneOfKeywords(KeywordTemporary, KeywordTable, KeywordView, KeywordFunction, KeywordDictionary) { + return nil, fmt.Errorf("expected keyword: TEMPORARY|TABLE|VIEW|FUNCTION|DICTIONARY, but got %q", p.currentTokenString()) + } + } else if !p.matchOneOfKeywords(KeywordTemporary, KeywordTable, KeywordView, KeywordFunction, KeywordDictionary, KeywordMaterialized) { + return nil, fmt.Errorf("expected keyword: TEMPORARY|TABLE|VIEW|FUNCTION|DICTIONARY|MATERIALIZED, but got %q", p.currentTokenString()) + } } switch { case p.matchKeyword(KeywordNamed): @@ -28,7 +37,7 @@ func (p *Parser) parseDDL(pos Pos) (DDL, error) { case p.matchKeyword(KeywordFunction): return p.parseCreateFunction(pos, orReplace) case p.matchKeyword(KeywordMaterialized): - return p.parseCreateMaterializedView(pos) + return p.parseCreateMaterializedView(pos, orReplace) case p.matchKeyword(KeywordLive): return p.parseCreateLiveView(pos) case p.matchKeyword(KeywordView): @@ -1211,6 +1220,7 @@ func (p *Parser) parseTTLClause(pos Pos, allowMultiValues bool) ([]*TTLExpr, err func (p *Parser) tryParseTTLPolicy(pos Pos) (*TTLPolicy, error) { var rule *TTLPolicyRule + var where *WhereClause switch { case p.tryConsumeKeywords(KeywordTo): if p.tryConsumeKeywords(KeywordDisk) { @@ -1229,6 +1239,7 @@ func (p *Parser) tryParseTTLPolicy(pos Pos) (*TTLPolicy, error) { return nil, fmt.Errorf("unexpected token: %q, expected DISK or VOLUME", p.currentTokenKind()) } case p.matchKeyword(KeywordDelete), p.matchKeyword(KeywordRecompress): + isDelete := p.matchKeyword(KeywordDelete) token := p.current() _ = p.lexer.consumeToken() action := &TTLPolicyRuleAction{ @@ -1242,23 +1253,128 @@ func (p *Parser) tryParseTTLPolicy(pos Pos) (*TTLPolicy, error) { } action.Codec = codec rule = &TTLPolicyRule{RulePos: pos, Action: action} + // A TTL WHERE clause belongs only to the DELETE action; ClickHouse + // rejects it after RECOMPRESS, TO DISK/VOLUME, and GROUP BY, so it + // is left unconsumed for the statement parser in those cases. + if isDelete { + where, err = p.tryParseWhereClause(p.Pos()) + if err != nil { + return nil, err + } + } + case p.matchKeyword(KeywordGroup): + groupBy, err := p.parseTTLPolicyGroupBy(pos) + if err != nil { + return nil, err + } + rule = groupBy default: return nil, nil // nolint } - policy := &TTLPolicy{Item: rule} + return &TTLPolicy{Item: rule, Where: where}, nil +} - where, err := p.tryParseWhereClause(p.Pos()) - if err != nil { +// parseTTLPolicyGroupBy parses the TTL GROUP BY action: a plain key +// expression list, optionally followed by SET = assignments. +// +// ClickHouse rejects the query-level GROUP BY forms (ALL, +// CUBE/ROLLUP/GROUPING SETS, WITH CUBE/ROLLUP/TOTALS) inside a TTL, so the +// keys are parsed directly as a list instead of reusing parseGroupByClause +// and then discarding those forms: building the clause from the expected +// shape keeps any future query-level GROUP BY sugar out of the TTL grammar +// as well. +func (p *Parser) parseTTLPolicyGroupBy(pos Pos) (*TTLPolicyRule, error) { + if err := p.expectKeyword(KeywordGroup); err != nil { + return nil, err + } + if err := p.expectKeyword(KeywordBy); err != nil { return nil, err } - policy.Where = where + keys := &ColumnExprList{ListPos: p.Pos()} + for { + var key Expr + var err error + if p.matchTokenKind(TokenKindKeyword) { + // Bare keywords (e.g. ALL) are valid TTL GROUP BY keys even + // when followed by SET or a closing engine clause; + // parseColumnExpr only reads a keyword as an identifier for a + // narrower lookahead, so fall back to it when an expression + // cannot start here. + savedState := p.lexer.saveState() + key, err = p.parseExpr(p.Pos()) + if err != nil { + p.lexer.restoreState(savedState) + key, err = p.parseAnyKeyword() + } + } else { + key, err = p.parseExpr(p.Pos()) + } + if err != nil { + return nil, err + } + keys.Items = append(keys.Items, key) + keys.ListEnd = key.End() + if p.tryConsumeTokenKind(TokenKindComma) == nil { + break + } + } + rule := &TTLPolicyRule{ + RulePos: pos, + GroupBy: &GroupByClause{ + GroupByPos: pos, + GroupByEnd: keys.End(), + Expr: keys, + }, + } + if p.tryConsumeKeywords(KeywordSet) { + set, err := p.parseTTLPolicySet(p.Pos()) + if err != nil { + return nil, err + } + rule.Set = append(rule.Set, set) + for { + // A comma either continues the SET assignment list or starts + // the next TTL expression of a multi-value TTL clause; consume + // it and probe for another assignment, rolling both back when + // none follows so parseTTLClause can treat the comma as a rule + // separator. + savedState := p.lexer.saveState() + if p.tryConsumeTokenKind(TokenKindComma) == nil { + break + } + set, err := p.parseTTLPolicySet(p.Pos()) + if err != nil { + p.lexer.restoreState(savedState) + break + } + rule.Set = append(rule.Set, set) + } + } + return rule, nil +} - groupBy, err := p.tryParseGroupByClause(p.Pos()) +// parseTTLPolicySet parses one TTL SET assignment: = . +// Unlike parseUpdateAssignment, the right-hand side is read with full +// expression precedence: a TTL SET has no trailing clause like the IN +// PARTITION that bounds an ALTER TABLE UPDATE assignment, so expressions +// such as `SET x = max(y) > 0` are valid here. +func (p *Parser) parseTTLPolicySet(pos Pos) (*UpdateAssignment, error) { + column, err := p.ParseNestedIdentifier(p.Pos()) + if err != nil { + return nil, err + } + if err := p.expectTokenKind(TokenKindSingleEQ); err != nil { + return nil, err + } + expr, err := p.parseExpr(p.Pos()) if err != nil { return nil, err } - policy.GroupBy = groupBy - return policy, nil + return &UpdateAssignment{ + AssignmentPos: pos, + Column: column, + Expr: expr, + }, nil } func (p *Parser) parseTTLExpr(pos Pos) (*TTLExpr, error) { diff --git a/parser/parser_test.go b/parser/parser_test.go index 142c4e8..b84f210 100644 --- a/parser/parser_test.go +++ b/parser/parser_test.go @@ -192,6 +192,29 @@ func TestParser_InvalidSyntax(t *testing.T) { "CREATE TABLE t (x String DEFAULT CAST(a +, 'String'))", "CREATE TABLE t (x String MATERIALIZED a +)", "CREATE TABLE t (x String ALIAS a +)", + // A TTL GROUP BY action only accepts a plain expression list; the + // query-level modifiers are syntax errors for ClickHouse in a TTL. + // (GROUP BY ALL and CUBE/ROLLUP(...) read as ordinary key + // expressions there and are only rejected semantically.) + "CREATE TABLE t (id UInt64, created DateTime) ENGINE = MergeTree() ORDER BY id TTL created + INTERVAL 1 DAY GROUP BY id WITH TOTALS", + "CREATE TABLE t (id UInt64, created DateTime) ENGINE = MergeTree() ORDER BY id TTL created + INTERVAL 1 DAY GROUP BY id WITH ROLLUP", + "CREATE TABLE t (id UInt64, created DateTime) ENGINE = MergeTree() ORDER BY id TTL created + INTERVAL 1 DAY GROUP BY id WITH CUBE", + "CREATE TABLE t (id UInt64, created DateTime) ENGINE = MergeTree() ORDER BY id TTL created + INTERVAL 1 DAY GROUP BY GROUPING SETS (id)", + // OR REPLACE is only accepted for MATERIALIZED VIEW under CREATE, + // never under ATTACH + "ATTACH OR REPLACE MATERIALIZED VIEW mv TO dest AS SELECT * FROM src", + // A TTL GROUP BY key list is greedy: after the keys the comma + // continues the list, so a trailing TTL action after a + // comma-separated key is rejected by ClickHouse (unlike after a + // complete SET assignment, where the comma starts the next TTL + // rule). + "CREATE TABLE t (id UInt64, created DateTime) ENGINE = MergeTree() ORDER BY id TTL created + INTERVAL 1 DAY GROUP BY id, created + INTERVAL 2 DAY DELETE", + // A TTL WHERE clause belongs only to the DELETE action; ClickHouse + // rejects it after GROUP BY, RECOMPRESS, and TO DISK/VOLUME. + "CREATE TABLE t (id UInt64, created DateTime, x UInt64) ENGINE = MergeTree() ORDER BY id TTL created + INTERVAL 1 DAY GROUP BY id SET x = sum(x) WHERE id > 0", + "CREATE TABLE t (id UInt64, created DateTime) ENGINE = MergeTree() ORDER BY id TTL created + INTERVAL 1 DAY GROUP BY id WHERE id > 0", + "CREATE TABLE t (id UInt64, created DateTime) ENGINE = MergeTree() ORDER BY id TTL created + INTERVAL 1 DAY RECOMPRESS CODEC(ZSTD(1)) WHERE id > 0", + "CREATE TABLE t (id UInt64, created DateTime) ENGINE = MergeTree() ORDER BY id TTL created + INTERVAL 1 DAY TO VOLUME 'v1' WHERE id > 0", // Invalid ARRAY JOIN types (only ARRAY JOIN, LEFT ARRAY JOIN, and INNER ARRAY JOIN are valid) "SELECT * FROM t RIGHT ARRAY JOIN arr AS a", // RIGHT ARRAY JOIN not supported "SELECT * FROM t FULL ARRAY JOIN arr AS a", // FULL ARRAY JOIN not supported diff --git a/parser/parser_view.go b/parser/parser_view.go index 02e31bc..effbb9c 100644 --- a/parser/parser_view.go +++ b/parser/parser_view.go @@ -16,7 +16,9 @@ import "fmt" // [DEFINER = { user | CURRENT_USER }] [SQL SECURITY { DEFINER | NONE }] // AS SELECT ... // [COMMENT 'comment'] -func (p *Parser) parseCreateMaterializedView(pos Pos) (*CreateMaterializedView, error) { +// +//nolint:funlen +func (p *Parser) parseCreateMaterializedView(pos Pos, orReplace bool) (*CreateMaterializedView, error) { if err := p.expectKeyword(KeywordMaterialized); err != nil { return nil, err } @@ -24,7 +26,7 @@ func (p *Parser) parseCreateMaterializedView(pos Pos) (*CreateMaterializedView, return nil, err } - createMaterializedView := &CreateMaterializedView{CreatePos: pos} + createMaterializedView := &CreateMaterializedView{CreatePos: pos, OrReplace: orReplace} // parse IF NOT EXISTS clause if exists var err error diff --git a/parser/testdata/ddl/create_or_replace_materialized_view.sql b/parser/testdata/ddl/create_or_replace_materialized_view.sql new file mode 100644 index 0000000..a72697c --- /dev/null +++ b/parser/testdata/ddl/create_or_replace_materialized_view.sql @@ -0,0 +1 @@ +CREATE OR REPLACE MATERIALIZED VIEW mv TO dest AS SELECT * FROM src; \ No newline at end of file diff --git a/parser/testdata/ddl/create_table_ttl_group_by.sql b/parser/testdata/ddl/create_table_ttl_group_by.sql new file mode 100644 index 0000000..8e64f25 --- /dev/null +++ b/parser/testdata/ddl/create_table_ttl_group_by.sql @@ -0,0 +1,11 @@ +CREATE TABLE t (id UInt64, created DateTime, x UInt64) ENGINE = MergeTree() ORDER BY id TTL created + INTERVAL 1 DAY GROUP BY id SET x = sum(x); + +CREATE TABLE t (id UInt64, created DateTime, x UInt64) ENGINE = MergeTree() ORDER BY id TTL created + INTERVAL 1 DAY GROUP BY id; + +CREATE TABLE t (id UInt64, created DateTime, x UInt64, total UInt64) ENGINE = MergeTree() ORDER BY (id, created) TTL created + INTERVAL 1 DAY GROUP BY id, created SET x = sum(x), total = count(); + +CREATE TABLE t (id UInt64, created DateTime, x UInt64) ENGINE = MergeTree() ORDER BY id TTL created + INTERVAL 1 DAY GROUP BY id SET x = sum(x), created + INTERVAL 2 DAY DELETE; + +CREATE TABLE t (id UInt64, created DateTime, x UInt64) ENGINE = MergeTree() ORDER BY id TTL created + INTERVAL 1 DAY GROUP BY ALL SET x = sum(x); + +CREATE TABLE t (id UInt64, created DateTime, x UInt64, y UInt64) ENGINE = MergeTree() ORDER BY id TTL created + INTERVAL 1 DAY GROUP BY id SET x = max(y) > 0; \ No newline at end of file diff --git a/parser/testdata/ddl/format/beautify/create_or_replace_materialized_view.sql b/parser/testdata/ddl/format/beautify/create_or_replace_materialized_view.sql new file mode 100644 index 0000000..89c3c5a --- /dev/null +++ b/parser/testdata/ddl/format/beautify/create_or_replace_materialized_view.sql @@ -0,0 +1,11 @@ +-- Origin SQL: +CREATE OR REPLACE MATERIALIZED VIEW mv TO dest AS SELECT * FROM src; + +-- Beautify SQL: +CREATE OR REPLACE MATERIALIZED VIEW mv +TO dest +AS + SELECT + * + FROM + src; diff --git a/parser/testdata/ddl/format/beautify/create_table_ttl_group_by.sql b/parser/testdata/ddl/format/beautify/create_table_ttl_group_by.sql new file mode 100644 index 0000000..631bc9b --- /dev/null +++ b/parser/testdata/ddl/format/beautify/create_table_ttl_group_by.sql @@ -0,0 +1,82 @@ +-- Origin SQL: +CREATE TABLE t (id UInt64, created DateTime, x UInt64) ENGINE = MergeTree() ORDER BY id TTL created + INTERVAL 1 DAY GROUP BY id SET x = sum(x); + +CREATE TABLE t (id UInt64, created DateTime, x UInt64) ENGINE = MergeTree() ORDER BY id TTL created + INTERVAL 1 DAY GROUP BY id; + +CREATE TABLE t (id UInt64, created DateTime, x UInt64, total UInt64) ENGINE = MergeTree() ORDER BY (id, created) TTL created + INTERVAL 1 DAY GROUP BY id, created SET x = sum(x), total = count(); + +CREATE TABLE t (id UInt64, created DateTime, x UInt64) ENGINE = MergeTree() ORDER BY id TTL created + INTERVAL 1 DAY GROUP BY id SET x = sum(x), created + INTERVAL 2 DAY DELETE; + +CREATE TABLE t (id UInt64, created DateTime, x UInt64) ENGINE = MergeTree() ORDER BY id TTL created + INTERVAL 1 DAY GROUP BY ALL SET x = sum(x); + +CREATE TABLE t (id UInt64, created DateTime, x UInt64, y UInt64) ENGINE = MergeTree() ORDER BY id TTL created + INTERVAL 1 DAY GROUP BY id SET x = max(y) > 0; + +-- Beautify SQL: +CREATE TABLE t +( + id UInt64, + created DateTime, + x UInt64 +) +ENGINE = MergeTree() +ORDER BY + id +TTL created + INTERVAL 1 DAY GROUP BY + id SET x = sum(x); +CREATE TABLE t +( + id UInt64, + created DateTime, + x UInt64 +) +ENGINE = MergeTree() +ORDER BY + id +TTL created + INTERVAL 1 DAY GROUP BY + id; +CREATE TABLE t +( + id UInt64, + created DateTime, + x UInt64, + total UInt64 +) +ENGINE = MergeTree() +ORDER BY + (id, created) +TTL created + INTERVAL 1 DAY GROUP BY + id, created SET x = sum(x), total = count(); +CREATE TABLE t +( + id UInt64, + created DateTime, + x UInt64 +) +ENGINE = MergeTree() +ORDER BY + id +TTL created + INTERVAL 1 DAY GROUP BY + id SET x = sum(x), created + INTERVAL 2 DAY DELETE; +CREATE TABLE t +( + id UInt64, + created DateTime, + x UInt64 +) +ENGINE = MergeTree() +ORDER BY + id +TTL created + INTERVAL 1 DAY GROUP BY + ALL SET x = sum(x); +CREATE TABLE t +( + id UInt64, + created DateTime, + x UInt64, + y UInt64 +) +ENGINE = MergeTree() +ORDER BY + id +TTL created + INTERVAL 1 DAY GROUP BY + id SET x = max(y) > 0; diff --git a/parser/testdata/ddl/format/create_or_replace_materialized_view.sql b/parser/testdata/ddl/format/create_or_replace_materialized_view.sql new file mode 100644 index 0000000..360ff72 --- /dev/null +++ b/parser/testdata/ddl/format/create_or_replace_materialized_view.sql @@ -0,0 +1,5 @@ +-- Origin SQL: +CREATE OR REPLACE MATERIALIZED VIEW mv TO dest AS SELECT * FROM src; + +-- Format SQL: +CREATE OR REPLACE MATERIALIZED VIEW mv TO dest AS SELECT * FROM src; diff --git a/parser/testdata/ddl/format/create_table_ttl_group_by.sql b/parser/testdata/ddl/format/create_table_ttl_group_by.sql new file mode 100644 index 0000000..c24e683 --- /dev/null +++ b/parser/testdata/ddl/format/create_table_ttl_group_by.sql @@ -0,0 +1,20 @@ +-- Origin SQL: +CREATE TABLE t (id UInt64, created DateTime, x UInt64) ENGINE = MergeTree() ORDER BY id TTL created + INTERVAL 1 DAY GROUP BY id SET x = sum(x); + +CREATE TABLE t (id UInt64, created DateTime, x UInt64) ENGINE = MergeTree() ORDER BY id TTL created + INTERVAL 1 DAY GROUP BY id; + +CREATE TABLE t (id UInt64, created DateTime, x UInt64, total UInt64) ENGINE = MergeTree() ORDER BY (id, created) TTL created + INTERVAL 1 DAY GROUP BY id, created SET x = sum(x), total = count(); + +CREATE TABLE t (id UInt64, created DateTime, x UInt64) ENGINE = MergeTree() ORDER BY id TTL created + INTERVAL 1 DAY GROUP BY id SET x = sum(x), created + INTERVAL 2 DAY DELETE; + +CREATE TABLE t (id UInt64, created DateTime, x UInt64) ENGINE = MergeTree() ORDER BY id TTL created + INTERVAL 1 DAY GROUP BY ALL SET x = sum(x); + +CREATE TABLE t (id UInt64, created DateTime, x UInt64, y UInt64) ENGINE = MergeTree() ORDER BY id TTL created + INTERVAL 1 DAY GROUP BY id SET x = max(y) > 0; + +-- Format SQL: +CREATE TABLE t (id UInt64, created DateTime, x UInt64) ENGINE = MergeTree() ORDER BY id TTL created + INTERVAL 1 DAY GROUP BY id SET x = sum(x); +CREATE TABLE t (id UInt64, created DateTime, x UInt64) ENGINE = MergeTree() ORDER BY id TTL created + INTERVAL 1 DAY GROUP BY id; +CREATE TABLE t (id UInt64, created DateTime, x UInt64, total UInt64) ENGINE = MergeTree() ORDER BY (id, created) TTL created + INTERVAL 1 DAY GROUP BY id, created SET x = sum(x), total = count(); +CREATE TABLE t (id UInt64, created DateTime, x UInt64) ENGINE = MergeTree() ORDER BY id TTL created + INTERVAL 1 DAY GROUP BY id SET x = sum(x), created + INTERVAL 2 DAY DELETE; +CREATE TABLE t (id UInt64, created DateTime, x UInt64) ENGINE = MergeTree() ORDER BY id TTL created + INTERVAL 1 DAY GROUP BY ALL SET x = sum(x); +CREATE TABLE t (id UInt64, created DateTime, x UInt64, y UInt64) ENGINE = MergeTree() ORDER BY id TTL created + INTERVAL 1 DAY GROUP BY id SET x = max(y) > 0; diff --git a/parser/testdata/ddl/output/bug_001.sql.golden.json b/parser/testdata/ddl/output/bug_001.sql.golden.json index 9716734..dcc786c 100644 --- a/parser/testdata/ddl/output/bug_001.sql.golden.json +++ b/parser/testdata/ddl/output/bug_001.sql.golden.json @@ -2,6 +2,7 @@ { "CreatePos": 0, "StatementEnd": 635, + "OrReplace": false, "Name": { "Database": { "Name": "db", diff --git a/parser/testdata/ddl/output/create_materialized_view_basic.sql.golden.json b/parser/testdata/ddl/output/create_materialized_view_basic.sql.golden.json index 282afa8..fc6eda9 100644 --- a/parser/testdata/ddl/output/create_materialized_view_basic.sql.golden.json +++ b/parser/testdata/ddl/output/create_materialized_view_basic.sql.golden.json @@ -2,6 +2,7 @@ { "CreatePos": 0, "StatementEnd": 537, + "OrReplace": false, "Name": { "Database": { "Name": "infra_bm", diff --git a/parser/testdata/ddl/output/create_materialized_view_rmv_depends_on_multi.sql.golden.json b/parser/testdata/ddl/output/create_materialized_view_rmv_depends_on_multi.sql.golden.json index 229f78b..3c5a270 100644 --- a/parser/testdata/ddl/output/create_materialized_view_rmv_depends_on_multi.sql.golden.json +++ b/parser/testdata/ddl/output/create_materialized_view_rmv_depends_on_multi.sql.golden.json @@ -2,6 +2,7 @@ { "CreatePos": 0, "StatementEnd": 258, + "OrReplace": false, "Name": { "Database": { "Name": "db1", diff --git a/parser/testdata/ddl/output/create_materialized_view_rmv_engine_with_columns.sql.golden.json b/parser/testdata/ddl/output/create_materialized_view_rmv_engine_with_columns.sql.golden.json index ebf5e6f..81fceca 100644 --- a/parser/testdata/ddl/output/create_materialized_view_rmv_engine_with_columns.sql.golden.json +++ b/parser/testdata/ddl/output/create_materialized_view_rmv_engine_with_columns.sql.golden.json @@ -2,6 +2,7 @@ { "CreatePos": 0, "StatementEnd": 833, + "OrReplace": false, "Name": { "Database": { "Name": "db1", diff --git a/parser/testdata/ddl/output/create_materialized_view_with_comment_before_as.sql.golden.json b/parser/testdata/ddl/output/create_materialized_view_with_comment_before_as.sql.golden.json index 334a26b..f97db25 100644 --- a/parser/testdata/ddl/output/create_materialized_view_with_comment_before_as.sql.golden.json +++ b/parser/testdata/ddl/output/create_materialized_view_with_comment_before_as.sql.golden.json @@ -2,6 +2,7 @@ { "CreatePos": 0, "StatementEnd": 302, + "OrReplace": false, "Name": { "Database": { "Name": "db", diff --git a/parser/testdata/ddl/output/create_materialized_view_with_definer.sql.golden.json b/parser/testdata/ddl/output/create_materialized_view_with_definer.sql.golden.json index 7fee8ad..e5463ed 100644 --- a/parser/testdata/ddl/output/create_materialized_view_with_definer.sql.golden.json +++ b/parser/testdata/ddl/output/create_materialized_view_with_definer.sql.golden.json @@ -2,6 +2,7 @@ { "CreatePos": 0, "StatementEnd": 355, + "OrReplace": false, "Name": { "Database": null, "Table": { diff --git a/parser/testdata/ddl/output/create_materialized_view_with_empty_table_schema.sql.golden.json b/parser/testdata/ddl/output/create_materialized_view_with_empty_table_schema.sql.golden.json index 475f7e6..d01f81e 100644 --- a/parser/testdata/ddl/output/create_materialized_view_with_empty_table_schema.sql.golden.json +++ b/parser/testdata/ddl/output/create_materialized_view_with_empty_table_schema.sql.golden.json @@ -2,6 +2,7 @@ { "CreatePos": 0, "StatementEnd": 460, + "OrReplace": false, "Name": { "Database": { "Name": "test", diff --git a/parser/testdata/ddl/output/create_materialized_view_with_gcs.sql.golden.json b/parser/testdata/ddl/output/create_materialized_view_with_gcs.sql.golden.json index ed3d0de..ae8809c 100644 --- a/parser/testdata/ddl/output/create_materialized_view_with_gcs.sql.golden.json +++ b/parser/testdata/ddl/output/create_materialized_view_with_gcs.sql.golden.json @@ -2,6 +2,7 @@ { "CreatePos": 0, "StatementEnd": 206, + "OrReplace": false, "Name": { "Database": { "Name": "database_name", diff --git a/parser/testdata/ddl/output/create_materialized_view_with_refresh.sql.golden.json b/parser/testdata/ddl/output/create_materialized_view_with_refresh.sql.golden.json index 9a19fb6..40438a9 100644 --- a/parser/testdata/ddl/output/create_materialized_view_with_refresh.sql.golden.json +++ b/parser/testdata/ddl/output/create_materialized_view_with_refresh.sql.golden.json @@ -2,6 +2,7 @@ { "CreatePos": 0, "StatementEnd": 302, + "OrReplace": false, "Name": { "Database": null, "Table": { diff --git a/parser/testdata/ddl/output/create_mv_with_not_op.sql.golden.json b/parser/testdata/ddl/output/create_mv_with_not_op.sql.golden.json index dc3e3f4..1134a4d 100644 --- a/parser/testdata/ddl/output/create_mv_with_not_op.sql.golden.json +++ b/parser/testdata/ddl/output/create_mv_with_not_op.sql.golden.json @@ -2,6 +2,7 @@ { "CreatePos": 0, "StatementEnd": 559, + "OrReplace": false, "Name": { "Database": { "Name": "infra_bm", diff --git a/parser/testdata/ddl/output/create_mv_with_order_by.sql.golden.json b/parser/testdata/ddl/output/create_mv_with_order_by.sql.golden.json index fa0688d..dd2be4b 100644 --- a/parser/testdata/ddl/output/create_mv_with_order_by.sql.golden.json +++ b/parser/testdata/ddl/output/create_mv_with_order_by.sql.golden.json @@ -2,6 +2,7 @@ { "CreatePos": 0, "StatementEnd": 135, + "OrReplace": false, "Name": { "Database": null, "Table": { @@ -168,6 +169,7 @@ { "CreatePos": 138, "StatementEnd": 259, + "OrReplace": false, "Name": { "Database": null, "Table": { diff --git a/parser/testdata/ddl/output/create_or_replace_materialized_view.sql.golden.json b/parser/testdata/ddl/output/create_or_replace_materialized_view.sql.golden.json new file mode 100644 index 0000000..7fed6e5 --- /dev/null +++ b/parser/testdata/ddl/output/create_or_replace_materialized_view.sql.golden.json @@ -0,0 +1,104 @@ +[ + { + "CreatePos": 0, + "StatementEnd": 67, + "OrReplace": true, + "Name": { + "Database": null, + "Table": { + "Name": "mv", + "QuoteType": 1, + "NamePos": 36, + "NameEnd": 38 + } + }, + "IfNotExists": false, + "OnCluster": null, + "Refresh": null, + "RandomizeFor": null, + "DependsOn": null, + "Settings": null, + "HasAppend": false, + "Engine": null, + "TableSchema": null, + "HasEmpty": false, + "Destination": { + "ToPos": 39, + "TableIdentifier": { + "Database": null, + "Table": { + "Name": "dest", + "QuoteType": 1, + "NamePos": 42, + "NameEnd": 46 + } + }, + "TableSchema": null + }, + "SubQuery": { + "HasParen": false, + "Select": { + "SelectPos": 50, + "StatementEnd": 67, + "With": null, + "Top": null, + "HasDistinct": false, + "DistinctOn": null, + "SelectItems": [ + { + "Expr": { + "Name": "*", + "QuoteType": 0, + "NamePos": 57, + "NameEnd": 57 + }, + "Modifiers": [], + "Alias": null + } + ], + "From": { + "FromPos": 59, + "Expr": { + "Table": { + "TablePos": 64, + "TableEnd": 67, + "Alias": null, + "Expr": { + "Database": null, + "Table": { + "Name": "src", + "QuoteType": 1, + "NamePos": 64, + "NameEnd": 67 + } + }, + "HasFinal": false + }, + "StatementEnd": 67, + "SampleRatio": null, + "HasFinal": false + } + }, + "Window": null, + "Prewhere": null, + "Where": null, + "GroupBy": null, + "WithTotal": false, + "Having": null, + "OrderBy": null, + "LimitBy": null, + "Limit": null, + "Settings": null, + "Format": null, + "UnionAll": null, + "UnionDistinct": null, + "Except": null, + "Intersect": null + } + }, + "Populate": false, + "Comment": null, + "Definer": null, + "SQLSecurity": "" + } +] \ No newline at end of file diff --git a/parser/testdata/ddl/output/create_table_ttl_group_by.sql.golden.json b/parser/testdata/ddl/output/create_table_ttl_group_by.sql.golden.json new file mode 100644 index 0000000..4264fcc --- /dev/null +++ b/parser/testdata/ddl/output/create_table_ttl_group_by.sql.golden.json @@ -0,0 +1,1733 @@ +[ + { + "CreatePos": 0, + "StatementEnd": 142, + "OrReplace": false, + "Name": { + "Database": null, + "Table": { + "Name": "t", + "QuoteType": 1, + "NamePos": 13, + "NameEnd": 14 + } + }, + "IfNotExists": false, + "UUID": null, + "OnCluster": null, + "TableSchema": { + "SchemaPos": 15, + "SchemaEnd": 53, + "Columns": [ + { + "NamePos": 16, + "ColumnEnd": 25, + "Name": { + "Ident": { + "Name": "id", + "QuoteType": 1, + "NamePos": 16, + "NameEnd": 18 + }, + "DotIdent": null + }, + "Type": { + "Name": { + "Name": "UInt64", + "QuoteType": 1, + "NamePos": 19, + "NameEnd": 25 + } + }, + "NotNull": null, + "Nullable": null, + "DefaultExpr": null, + "MaterializedExpr": null, + "AliasExpr": null, + "Codec": null, + "TTL": null, + "Comment": null, + "CompressionCodec": null + }, + { + "NamePos": 27, + "ColumnEnd": 43, + "Name": { + "Ident": { + "Name": "created", + "QuoteType": 1, + "NamePos": 27, + "NameEnd": 34 + }, + "DotIdent": null + }, + "Type": { + "Name": { + "Name": "DateTime", + "QuoteType": 1, + "NamePos": 35, + "NameEnd": 43 + } + }, + "NotNull": null, + "Nullable": null, + "DefaultExpr": null, + "MaterializedExpr": null, + "AliasExpr": null, + "Codec": null, + "TTL": null, + "Comment": null, + "CompressionCodec": null + }, + { + "NamePos": 45, + "ColumnEnd": 53, + "Name": { + "Ident": { + "Name": "x", + "QuoteType": 1, + "NamePos": 45, + "NameEnd": 46 + }, + "DotIdent": null + }, + "Type": { + "Name": { + "Name": "UInt64", + "QuoteType": 1, + "NamePos": 47, + "NameEnd": 53 + } + }, + "NotNull": null, + "Nullable": null, + "DefaultExpr": null, + "MaterializedExpr": null, + "AliasExpr": null, + "Codec": null, + "TTL": null, + "Comment": null, + "CompressionCodec": null + } + ], + "AliasTable": null, + "TableFunction": null + }, + "Engine": { + "EnginePos": 55, + "EngineEnd": 142, + "Name": "MergeTree", + "Params": { + "LeftParenPos": 73, + "RightParenPos": 74, + "Items": { + "ListPos": 74, + "ListEnd": 74, + "HasDistinct": false, + "Items": [] + }, + "ColumnArgList": null + }, + "PrimaryKey": null, + "PartitionBy": null, + "SampleBy": null, + "TTL": { + "TTLPos": 88, + "ListEnd": 142, + "Items": [ + { + "TTLPos": 88, + "Expr": { + "LeftExpr": { + "Name": "created", + "QuoteType": 1, + "NamePos": 92, + "NameEnd": 99 + }, + "Operation": "+", + "RightExpr": { + "IntervalPos": 102, + "Expr": { + "NumPos": 111, + "NumEnd": 112, + "Literal": "1", + "Base": 10 + }, + "Unit": { + "Name": "DAY", + "QuoteType": 1, + "NamePos": 113, + "NameEnd": 116 + } + }, + "HasGlobal": false, + "HasNot": false + }, + "Policy": { + "Item": { + "RulePos": 117, + "ToVolume": null, + "ToDisk": null, + "Action": null, + "GroupBy": { + "GroupByPos": 117, + "GroupByEnd": 128, + "AggregateType": "", + "Expr": { + "ListPos": 126, + "ListEnd": 128, + "HasDistinct": false, + "Items": [ + { + "Name": "id", + "QuoteType": 1, + "NamePos": 126, + "NameEnd": 128 + } + ] + }, + "WithCube": false, + "WithRollup": false, + "WithTotals": false + }, + "Set": [ + { + "AssignmentPos": 133, + "Column": { + "Ident": { + "Name": "x", + "QuoteType": 1, + "NamePos": 133, + "NameEnd": 134 + }, + "DotIdent": null + }, + "Expr": { + "Name": { + "Name": "sum", + "QuoteType": 1, + "NamePos": 137, + "NameEnd": 140 + }, + "Params": { + "LeftParenPos": 140, + "RightParenPos": 142, + "Items": { + "ListPos": 141, + "ListEnd": 142, + "HasDistinct": false, + "Items": [ + { + "Expr": { + "Name": "x", + "QuoteType": 1, + "NamePos": 141, + "NameEnd": 142 + }, + "Alias": null + } + ] + }, + "ColumnArgList": null + } + } + } + ] + }, + "Where": null + } + } + ] + }, + "Settings": null, + "OrderBy": { + "OrderPos": 76, + "ListEnd": 87, + "Items": [ + { + "OrderPos": 76, + "Expr": { + "Name": "id", + "QuoteType": 1, + "NamePos": 85, + "NameEnd": 87 + }, + "Alias": null, + "Direction": "", + "Fill": null + } + ], + "Interpolate": null + } + }, + "SubQuery": null, + "TableFunction": null, + "HasTemporary": false, + "Comment": null + }, + { + "CreatePos": 146, + "StatementEnd": 274, + "OrReplace": false, + "Name": { + "Database": null, + "Table": { + "Name": "t", + "QuoteType": 1, + "NamePos": 159, + "NameEnd": 160 + } + }, + "IfNotExists": false, + "UUID": null, + "OnCluster": null, + "TableSchema": { + "SchemaPos": 161, + "SchemaEnd": 199, + "Columns": [ + { + "NamePos": 162, + "ColumnEnd": 171, + "Name": { + "Ident": { + "Name": "id", + "QuoteType": 1, + "NamePos": 162, + "NameEnd": 164 + }, + "DotIdent": null + }, + "Type": { + "Name": { + "Name": "UInt64", + "QuoteType": 1, + "NamePos": 165, + "NameEnd": 171 + } + }, + "NotNull": null, + "Nullable": null, + "DefaultExpr": null, + "MaterializedExpr": null, + "AliasExpr": null, + "Codec": null, + "TTL": null, + "Comment": null, + "CompressionCodec": null + }, + { + "NamePos": 173, + "ColumnEnd": 189, + "Name": { + "Ident": { + "Name": "created", + "QuoteType": 1, + "NamePos": 173, + "NameEnd": 180 + }, + "DotIdent": null + }, + "Type": { + "Name": { + "Name": "DateTime", + "QuoteType": 1, + "NamePos": 181, + "NameEnd": 189 + } + }, + "NotNull": null, + "Nullable": null, + "DefaultExpr": null, + "MaterializedExpr": null, + "AliasExpr": null, + "Codec": null, + "TTL": null, + "Comment": null, + "CompressionCodec": null + }, + { + "NamePos": 191, + "ColumnEnd": 199, + "Name": { + "Ident": { + "Name": "x", + "QuoteType": 1, + "NamePos": 191, + "NameEnd": 192 + }, + "DotIdent": null + }, + "Type": { + "Name": { + "Name": "UInt64", + "QuoteType": 1, + "NamePos": 193, + "NameEnd": 199 + } + }, + "NotNull": null, + "Nullable": null, + "DefaultExpr": null, + "MaterializedExpr": null, + "AliasExpr": null, + "Codec": null, + "TTL": null, + "Comment": null, + "CompressionCodec": null + } + ], + "AliasTable": null, + "TableFunction": null + }, + "Engine": { + "EnginePos": 201, + "EngineEnd": 274, + "Name": "MergeTree", + "Params": { + "LeftParenPos": 219, + "RightParenPos": 220, + "Items": { + "ListPos": 220, + "ListEnd": 220, + "HasDistinct": false, + "Items": [] + }, + "ColumnArgList": null + }, + "PrimaryKey": null, + "PartitionBy": null, + "SampleBy": null, + "TTL": { + "TTLPos": 234, + "ListEnd": 274, + "Items": [ + { + "TTLPos": 234, + "Expr": { + "LeftExpr": { + "Name": "created", + "QuoteType": 1, + "NamePos": 238, + "NameEnd": 245 + }, + "Operation": "+", + "RightExpr": { + "IntervalPos": 248, + "Expr": { + "NumPos": 257, + "NumEnd": 258, + "Literal": "1", + "Base": 10 + }, + "Unit": { + "Name": "DAY", + "QuoteType": 1, + "NamePos": 259, + "NameEnd": 262 + } + }, + "HasGlobal": false, + "HasNot": false + }, + "Policy": { + "Item": { + "RulePos": 263, + "ToVolume": null, + "ToDisk": null, + "Action": null, + "GroupBy": { + "GroupByPos": 263, + "GroupByEnd": 274, + "AggregateType": "", + "Expr": { + "ListPos": 272, + "ListEnd": 274, + "HasDistinct": false, + "Items": [ + { + "Name": "id", + "QuoteType": 1, + "NamePos": 272, + "NameEnd": 274 + } + ] + }, + "WithCube": false, + "WithRollup": false, + "WithTotals": false + }, + "Set": null + }, + "Where": null + } + } + ] + }, + "Settings": null, + "OrderBy": { + "OrderPos": 222, + "ListEnd": 233, + "Items": [ + { + "OrderPos": 222, + "Expr": { + "Name": "id", + "QuoteType": 1, + "NamePos": 231, + "NameEnd": 233 + }, + "Alias": null, + "Direction": "", + "Fill": null + } + ], + "Interpolate": null + } + }, + "SubQuery": null, + "TableFunction": null, + "HasTemporary": false, + "Comment": null + }, + { + "CreatePos": 277, + "StatementEnd": 470, + "OrReplace": false, + "Name": { + "Database": null, + "Table": { + "Name": "t", + "QuoteType": 1, + "NamePos": 290, + "NameEnd": 291 + } + }, + "IfNotExists": false, + "UUID": null, + "OnCluster": null, + "TableSchema": { + "SchemaPos": 292, + "SchemaEnd": 344, + "Columns": [ + { + "NamePos": 293, + "ColumnEnd": 302, + "Name": { + "Ident": { + "Name": "id", + "QuoteType": 1, + "NamePos": 293, + "NameEnd": 295 + }, + "DotIdent": null + }, + "Type": { + "Name": { + "Name": "UInt64", + "QuoteType": 1, + "NamePos": 296, + "NameEnd": 302 + } + }, + "NotNull": null, + "Nullable": null, + "DefaultExpr": null, + "MaterializedExpr": null, + "AliasExpr": null, + "Codec": null, + "TTL": null, + "Comment": null, + "CompressionCodec": null + }, + { + "NamePos": 304, + "ColumnEnd": 320, + "Name": { + "Ident": { + "Name": "created", + "QuoteType": 1, + "NamePos": 304, + "NameEnd": 311 + }, + "DotIdent": null + }, + "Type": { + "Name": { + "Name": "DateTime", + "QuoteType": 1, + "NamePos": 312, + "NameEnd": 320 + } + }, + "NotNull": null, + "Nullable": null, + "DefaultExpr": null, + "MaterializedExpr": null, + "AliasExpr": null, + "Codec": null, + "TTL": null, + "Comment": null, + "CompressionCodec": null + }, + { + "NamePos": 322, + "ColumnEnd": 330, + "Name": { + "Ident": { + "Name": "x", + "QuoteType": 1, + "NamePos": 322, + "NameEnd": 323 + }, + "DotIdent": null + }, + "Type": { + "Name": { + "Name": "UInt64", + "QuoteType": 1, + "NamePos": 324, + "NameEnd": 330 + } + }, + "NotNull": null, + "Nullable": null, + "DefaultExpr": null, + "MaterializedExpr": null, + "AliasExpr": null, + "Codec": null, + "TTL": null, + "Comment": null, + "CompressionCodec": null + }, + { + "NamePos": 332, + "ColumnEnd": 344, + "Name": { + "Ident": { + "Name": "total", + "QuoteType": 1, + "NamePos": 332, + "NameEnd": 337 + }, + "DotIdent": null + }, + "Type": { + "Name": { + "Name": "UInt64", + "QuoteType": 1, + "NamePos": 338, + "NameEnd": 344 + } + }, + "NotNull": null, + "Nullable": null, + "DefaultExpr": null, + "MaterializedExpr": null, + "AliasExpr": null, + "Codec": null, + "TTL": null, + "Comment": null, + "CompressionCodec": null + } + ], + "AliasTable": null, + "TableFunction": null + }, + "Engine": { + "EnginePos": 346, + "EngineEnd": 470, + "Name": "MergeTree", + "Params": { + "LeftParenPos": 364, + "RightParenPos": 365, + "Items": { + "ListPos": 365, + "ListEnd": 365, + "HasDistinct": false, + "Items": [] + }, + "ColumnArgList": null + }, + "PrimaryKey": null, + "PartitionBy": null, + "SampleBy": null, + "TTL": { + "TTLPos": 390, + "ListEnd": 470, + "Items": [ + { + "TTLPos": 390, + "Expr": { + "LeftExpr": { + "Name": "created", + "QuoteType": 1, + "NamePos": 394, + "NameEnd": 401 + }, + "Operation": "+", + "RightExpr": { + "IntervalPos": 404, + "Expr": { + "NumPos": 413, + "NumEnd": 414, + "Literal": "1", + "Base": 10 + }, + "Unit": { + "Name": "DAY", + "QuoteType": 1, + "NamePos": 415, + "NameEnd": 418 + } + }, + "HasGlobal": false, + "HasNot": false + }, + "Policy": { + "Item": { + "RulePos": 419, + "ToVolume": null, + "ToDisk": null, + "Action": null, + "GroupBy": { + "GroupByPos": 419, + "GroupByEnd": 439, + "AggregateType": "", + "Expr": { + "ListPos": 428, + "ListEnd": 439, + "HasDistinct": false, + "Items": [ + { + "Name": "id", + "QuoteType": 1, + "NamePos": 428, + "NameEnd": 430 + }, + { + "Name": "created", + "QuoteType": 1, + "NamePos": 432, + "NameEnd": 439 + } + ] + }, + "WithCube": false, + "WithRollup": false, + "WithTotals": false + }, + "Set": [ + { + "AssignmentPos": 444, + "Column": { + "Ident": { + "Name": "x", + "QuoteType": 1, + "NamePos": 444, + "NameEnd": 445 + }, + "DotIdent": null + }, + "Expr": { + "Name": { + "Name": "sum", + "QuoteType": 1, + "NamePos": 448, + "NameEnd": 451 + }, + "Params": { + "LeftParenPos": 451, + "RightParenPos": 453, + "Items": { + "ListPos": 452, + "ListEnd": 453, + "HasDistinct": false, + "Items": [ + { + "Expr": { + "Name": "x", + "QuoteType": 1, + "NamePos": 452, + "NameEnd": 453 + }, + "Alias": null + } + ] + }, + "ColumnArgList": null + } + } + }, + { + "AssignmentPos": 456, + "Column": { + "Ident": { + "Name": "total", + "QuoteType": 1, + "NamePos": 456, + "NameEnd": 461 + }, + "DotIdent": null + }, + "Expr": { + "Name": { + "Name": "count", + "QuoteType": 1, + "NamePos": 464, + "NameEnd": 469 + }, + "Params": { + "LeftParenPos": 469, + "RightParenPos": 470, + "Items": { + "ListPos": 470, + "ListEnd": 470, + "HasDistinct": false, + "Items": [] + }, + "ColumnArgList": null + } + } + } + ] + }, + "Where": null + } + } + ] + }, + "Settings": null, + "OrderBy": { + "OrderPos": 367, + "ListEnd": 388, + "Items": [ + { + "OrderPos": 367, + "Expr": { + "LeftParenPos": 376, + "RightParenPos": 388, + "Items": { + "ListPos": 377, + "ListEnd": 388, + "HasDistinct": false, + "Items": [ + { + "Expr": { + "Name": "id", + "QuoteType": 1, + "NamePos": 377, + "NameEnd": 379 + }, + "Alias": null + }, + { + "Expr": { + "Name": "created", + "QuoteType": 1, + "NamePos": 381, + "NameEnd": 388 + }, + "Alias": null + } + ] + }, + "ColumnArgList": null + }, + "Alias": null, + "Direction": "", + "Fill": null + } + ], + "Interpolate": null + } + }, + "SubQuery": null, + "TableFunction": null, + "HasTemporary": false, + "Comment": null + }, + { + "CreatePos": 474, + "StatementEnd": 650, + "OrReplace": false, + "Name": { + "Database": null, + "Table": { + "Name": "t", + "QuoteType": 1, + "NamePos": 487, + "NameEnd": 488 + } + }, + "IfNotExists": false, + "UUID": null, + "OnCluster": null, + "TableSchema": { + "SchemaPos": 489, + "SchemaEnd": 527, + "Columns": [ + { + "NamePos": 490, + "ColumnEnd": 499, + "Name": { + "Ident": { + "Name": "id", + "QuoteType": 1, + "NamePos": 490, + "NameEnd": 492 + }, + "DotIdent": null + }, + "Type": { + "Name": { + "Name": "UInt64", + "QuoteType": 1, + "NamePos": 493, + "NameEnd": 499 + } + }, + "NotNull": null, + "Nullable": null, + "DefaultExpr": null, + "MaterializedExpr": null, + "AliasExpr": null, + "Codec": null, + "TTL": null, + "Comment": null, + "CompressionCodec": null + }, + { + "NamePos": 501, + "ColumnEnd": 517, + "Name": { + "Ident": { + "Name": "created", + "QuoteType": 1, + "NamePos": 501, + "NameEnd": 508 + }, + "DotIdent": null + }, + "Type": { + "Name": { + "Name": "DateTime", + "QuoteType": 1, + "NamePos": 509, + "NameEnd": 517 + } + }, + "NotNull": null, + "Nullable": null, + "DefaultExpr": null, + "MaterializedExpr": null, + "AliasExpr": null, + "Codec": null, + "TTL": null, + "Comment": null, + "CompressionCodec": null + }, + { + "NamePos": 519, + "ColumnEnd": 527, + "Name": { + "Ident": { + "Name": "x", + "QuoteType": 1, + "NamePos": 519, + "NameEnd": 520 + }, + "DotIdent": null + }, + "Type": { + "Name": { + "Name": "UInt64", + "QuoteType": 1, + "NamePos": 521, + "NameEnd": 527 + } + }, + "NotNull": null, + "Nullable": null, + "DefaultExpr": null, + "MaterializedExpr": null, + "AliasExpr": null, + "Codec": null, + "TTL": null, + "Comment": null, + "CompressionCodec": null + } + ], + "AliasTable": null, + "TableFunction": null + }, + "Engine": { + "EnginePos": 529, + "EngineEnd": 650, + "Name": "MergeTree", + "Params": { + "LeftParenPos": 547, + "RightParenPos": 548, + "Items": { + "ListPos": 548, + "ListEnd": 548, + "HasDistinct": false, + "Items": [] + }, + "ColumnArgList": null + }, + "PrimaryKey": null, + "PartitionBy": null, + "SampleBy": null, + "TTL": { + "TTLPos": 562, + "ListEnd": 650, + "Items": [ + { + "TTLPos": 562, + "Expr": { + "LeftExpr": { + "Name": "created", + "QuoteType": 1, + "NamePos": 566, + "NameEnd": 573 + }, + "Operation": "+", + "RightExpr": { + "IntervalPos": 576, + "Expr": { + "NumPos": 585, + "NumEnd": 586, + "Literal": "1", + "Base": 10 + }, + "Unit": { + "Name": "DAY", + "QuoteType": 1, + "NamePos": 587, + "NameEnd": 590 + } + }, + "HasGlobal": false, + "HasNot": false + }, + "Policy": { + "Item": { + "RulePos": 591, + "ToVolume": null, + "ToDisk": null, + "Action": null, + "GroupBy": { + "GroupByPos": 591, + "GroupByEnd": 602, + "AggregateType": "", + "Expr": { + "ListPos": 600, + "ListEnd": 602, + "HasDistinct": false, + "Items": [ + { + "Name": "id", + "QuoteType": 1, + "NamePos": 600, + "NameEnd": 602 + } + ] + }, + "WithCube": false, + "WithRollup": false, + "WithTotals": false + }, + "Set": [ + { + "AssignmentPos": 607, + "Column": { + "Ident": { + "Name": "x", + "QuoteType": 1, + "NamePos": 607, + "NameEnd": 608 + }, + "DotIdent": null + }, + "Expr": { + "Name": { + "Name": "sum", + "QuoteType": 1, + "NamePos": 611, + "NameEnd": 614 + }, + "Params": { + "LeftParenPos": 614, + "RightParenPos": 616, + "Items": { + "ListPos": 615, + "ListEnd": 616, + "HasDistinct": false, + "Items": [ + { + "Expr": { + "Name": "x", + "QuoteType": 1, + "NamePos": 615, + "NameEnd": 616 + }, + "Alias": null + } + ] + }, + "ColumnArgList": null + } + } + } + ] + }, + "Where": null + } + }, + { + "TTLPos": 562, + "Expr": { + "LeftExpr": { + "Name": "created", + "QuoteType": 1, + "NamePos": 619, + "NameEnd": 626 + }, + "Operation": "+", + "RightExpr": { + "IntervalPos": 629, + "Expr": { + "NumPos": 638, + "NumEnd": 639, + "Literal": "2", + "Base": 10 + }, + "Unit": { + "Name": "DAY", + "QuoteType": 1, + "NamePos": 640, + "NameEnd": 643 + } + }, + "HasGlobal": false, + "HasNot": false + }, + "Policy": { + "Item": { + "RulePos": 644, + "ToVolume": null, + "ToDisk": null, + "Action": { + "ActionPos": 644, + "ActionEnd": 650, + "Action": "DELETE", + "Codec": null + }, + "GroupBy": null, + "Set": null + }, + "Where": null + } + } + ] + }, + "Settings": null, + "OrderBy": { + "OrderPos": 550, + "ListEnd": 561, + "Items": [ + { + "OrderPos": 550, + "Expr": { + "Name": "id", + "QuoteType": 1, + "NamePos": 559, + "NameEnd": 561 + }, + "Alias": null, + "Direction": "", + "Fill": null + } + ], + "Interpolate": null + } + }, + "SubQuery": null, + "TableFunction": null, + "HasTemporary": false, + "Comment": null + }, + { + "CreatePos": 653, + "StatementEnd": 796, + "OrReplace": false, + "Name": { + "Database": null, + "Table": { + "Name": "t", + "QuoteType": 1, + "NamePos": 666, + "NameEnd": 667 + } + }, + "IfNotExists": false, + "UUID": null, + "OnCluster": null, + "TableSchema": { + "SchemaPos": 668, + "SchemaEnd": 706, + "Columns": [ + { + "NamePos": 669, + "ColumnEnd": 678, + "Name": { + "Ident": { + "Name": "id", + "QuoteType": 1, + "NamePos": 669, + "NameEnd": 671 + }, + "DotIdent": null + }, + "Type": { + "Name": { + "Name": "UInt64", + "QuoteType": 1, + "NamePos": 672, + "NameEnd": 678 + } + }, + "NotNull": null, + "Nullable": null, + "DefaultExpr": null, + "MaterializedExpr": null, + "AliasExpr": null, + "Codec": null, + "TTL": null, + "Comment": null, + "CompressionCodec": null + }, + { + "NamePos": 680, + "ColumnEnd": 696, + "Name": { + "Ident": { + "Name": "created", + "QuoteType": 1, + "NamePos": 680, + "NameEnd": 687 + }, + "DotIdent": null + }, + "Type": { + "Name": { + "Name": "DateTime", + "QuoteType": 1, + "NamePos": 688, + "NameEnd": 696 + } + }, + "NotNull": null, + "Nullable": null, + "DefaultExpr": null, + "MaterializedExpr": null, + "AliasExpr": null, + "Codec": null, + "TTL": null, + "Comment": null, + "CompressionCodec": null + }, + { + "NamePos": 698, + "ColumnEnd": 706, + "Name": { + "Ident": { + "Name": "x", + "QuoteType": 1, + "NamePos": 698, + "NameEnd": 699 + }, + "DotIdent": null + }, + "Type": { + "Name": { + "Name": "UInt64", + "QuoteType": 1, + "NamePos": 700, + "NameEnd": 706 + } + }, + "NotNull": null, + "Nullable": null, + "DefaultExpr": null, + "MaterializedExpr": null, + "AliasExpr": null, + "Codec": null, + "TTL": null, + "Comment": null, + "CompressionCodec": null + } + ], + "AliasTable": null, + "TableFunction": null + }, + "Engine": { + "EnginePos": 708, + "EngineEnd": 796, + "Name": "MergeTree", + "Params": { + "LeftParenPos": 726, + "RightParenPos": 727, + "Items": { + "ListPos": 727, + "ListEnd": 727, + "HasDistinct": false, + "Items": [] + }, + "ColumnArgList": null + }, + "PrimaryKey": null, + "PartitionBy": null, + "SampleBy": null, + "TTL": { + "TTLPos": 741, + "ListEnd": 796, + "Items": [ + { + "TTLPos": 741, + "Expr": { + "LeftExpr": { + "Name": "created", + "QuoteType": 1, + "NamePos": 745, + "NameEnd": 752 + }, + "Operation": "+", + "RightExpr": { + "IntervalPos": 755, + "Expr": { + "NumPos": 764, + "NumEnd": 765, + "Literal": "1", + "Base": 10 + }, + "Unit": { + "Name": "DAY", + "QuoteType": 1, + "NamePos": 766, + "NameEnd": 769 + } + }, + "HasGlobal": false, + "HasNot": false + }, + "Policy": { + "Item": { + "RulePos": 770, + "ToVolume": null, + "ToDisk": null, + "Action": null, + "GroupBy": { + "GroupByPos": 770, + "GroupByEnd": 782, + "AggregateType": "", + "Expr": { + "ListPos": 779, + "ListEnd": 782, + "HasDistinct": false, + "Items": [ + { + "Name": "ALL", + "QuoteType": 1, + "NamePos": 779, + "NameEnd": 782 + } + ] + }, + "WithCube": false, + "WithRollup": false, + "WithTotals": false + }, + "Set": [ + { + "AssignmentPos": 787, + "Column": { + "Ident": { + "Name": "x", + "QuoteType": 1, + "NamePos": 787, + "NameEnd": 788 + }, + "DotIdent": null + }, + "Expr": { + "Name": { + "Name": "sum", + "QuoteType": 1, + "NamePos": 791, + "NameEnd": 794 + }, + "Params": { + "LeftParenPos": 794, + "RightParenPos": 796, + "Items": { + "ListPos": 795, + "ListEnd": 796, + "HasDistinct": false, + "Items": [ + { + "Expr": { + "Name": "x", + "QuoteType": 1, + "NamePos": 795, + "NameEnd": 796 + }, + "Alias": null + } + ] + }, + "ColumnArgList": null + } + } + } + ] + }, + "Where": null + } + } + ] + }, + "Settings": null, + "OrderBy": { + "OrderPos": 729, + "ListEnd": 740, + "Items": [ + { + "OrderPos": 729, + "Expr": { + "Name": "id", + "QuoteType": 1, + "NamePos": 738, + "NameEnd": 740 + }, + "Alias": null, + "Direction": "", + "Fill": null + } + ], + "Interpolate": null + } + }, + "SubQuery": null, + "TableFunction": null, + "HasTemporary": false, + "Comment": null + }, + { + "CreatePos": 800, + "StatementEnd": 957, + "OrReplace": false, + "Name": { + "Database": null, + "Table": { + "Name": "t", + "QuoteType": 1, + "NamePos": 813, + "NameEnd": 814 + } + }, + "IfNotExists": false, + "UUID": null, + "OnCluster": null, + "TableSchema": { + "SchemaPos": 815, + "SchemaEnd": 863, + "Columns": [ + { + "NamePos": 816, + "ColumnEnd": 825, + "Name": { + "Ident": { + "Name": "id", + "QuoteType": 1, + "NamePos": 816, + "NameEnd": 818 + }, + "DotIdent": null + }, + "Type": { + "Name": { + "Name": "UInt64", + "QuoteType": 1, + "NamePos": 819, + "NameEnd": 825 + } + }, + "NotNull": null, + "Nullable": null, + "DefaultExpr": null, + "MaterializedExpr": null, + "AliasExpr": null, + "Codec": null, + "TTL": null, + "Comment": null, + "CompressionCodec": null + }, + { + "NamePos": 827, + "ColumnEnd": 843, + "Name": { + "Ident": { + "Name": "created", + "QuoteType": 1, + "NamePos": 827, + "NameEnd": 834 + }, + "DotIdent": null + }, + "Type": { + "Name": { + "Name": "DateTime", + "QuoteType": 1, + "NamePos": 835, + "NameEnd": 843 + } + }, + "NotNull": null, + "Nullable": null, + "DefaultExpr": null, + "MaterializedExpr": null, + "AliasExpr": null, + "Codec": null, + "TTL": null, + "Comment": null, + "CompressionCodec": null + }, + { + "NamePos": 845, + "ColumnEnd": 853, + "Name": { + "Ident": { + "Name": "x", + "QuoteType": 1, + "NamePos": 845, + "NameEnd": 846 + }, + "DotIdent": null + }, + "Type": { + "Name": { + "Name": "UInt64", + "QuoteType": 1, + "NamePos": 847, + "NameEnd": 853 + } + }, + "NotNull": null, + "Nullable": null, + "DefaultExpr": null, + "MaterializedExpr": null, + "AliasExpr": null, + "Codec": null, + "TTL": null, + "Comment": null, + "CompressionCodec": null + }, + { + "NamePos": 855, + "ColumnEnd": 863, + "Name": { + "Ident": { + "Name": "y", + "QuoteType": 1, + "NamePos": 855, + "NameEnd": 856 + }, + "DotIdent": null + }, + "Type": { + "Name": { + "Name": "UInt64", + "QuoteType": 1, + "NamePos": 857, + "NameEnd": 863 + } + }, + "NotNull": null, + "Nullable": null, + "DefaultExpr": null, + "MaterializedExpr": null, + "AliasExpr": null, + "Codec": null, + "TTL": null, + "Comment": null, + "CompressionCodec": null + } + ], + "AliasTable": null, + "TableFunction": null + }, + "Engine": { + "EnginePos": 865, + "EngineEnd": 957, + "Name": "MergeTree", + "Params": { + "LeftParenPos": 883, + "RightParenPos": 884, + "Items": { + "ListPos": 884, + "ListEnd": 884, + "HasDistinct": false, + "Items": [] + }, + "ColumnArgList": null + }, + "PrimaryKey": null, + "PartitionBy": null, + "SampleBy": null, + "TTL": { + "TTLPos": 898, + "ListEnd": 957, + "Items": [ + { + "TTLPos": 898, + "Expr": { + "LeftExpr": { + "Name": "created", + "QuoteType": 1, + "NamePos": 902, + "NameEnd": 909 + }, + "Operation": "+", + "RightExpr": { + "IntervalPos": 912, + "Expr": { + "NumPos": 921, + "NumEnd": 922, + "Literal": "1", + "Base": 10 + }, + "Unit": { + "Name": "DAY", + "QuoteType": 1, + "NamePos": 923, + "NameEnd": 926 + } + }, + "HasGlobal": false, + "HasNot": false + }, + "Policy": { + "Item": { + "RulePos": 927, + "ToVolume": null, + "ToDisk": null, + "Action": null, + "GroupBy": { + "GroupByPos": 927, + "GroupByEnd": 938, + "AggregateType": "", + "Expr": { + "ListPos": 936, + "ListEnd": 938, + "HasDistinct": false, + "Items": [ + { + "Name": "id", + "QuoteType": 1, + "NamePos": 936, + "NameEnd": 938 + } + ] + }, + "WithCube": false, + "WithRollup": false, + "WithTotals": false + }, + "Set": [ + { + "AssignmentPos": 943, + "Column": { + "Ident": { + "Name": "x", + "QuoteType": 1, + "NamePos": 943, + "NameEnd": 944 + }, + "DotIdent": null + }, + "Expr": { + "LeftExpr": { + "Name": { + "Name": "max", + "QuoteType": 1, + "NamePos": 947, + "NameEnd": 950 + }, + "Params": { + "LeftParenPos": 950, + "RightParenPos": 952, + "Items": { + "ListPos": 951, + "ListEnd": 952, + "HasDistinct": false, + "Items": [ + { + "Expr": { + "Name": "y", + "QuoteType": 1, + "NamePos": 951, + "NameEnd": 952 + }, + "Alias": null + } + ] + }, + "ColumnArgList": null + } + }, + "Operation": "\u003e", + "RightExpr": { + "NumPos": 956, + "NumEnd": 957, + "Literal": "0", + "Base": 10 + }, + "HasGlobal": false, + "HasNot": false + } + } + ] + }, + "Where": null + } + } + ] + }, + "Settings": null, + "OrderBy": { + "OrderPos": 886, + "ListEnd": 897, + "Items": [ + { + "OrderPos": 886, + "Expr": { + "Name": "id", + "QuoteType": 1, + "NamePos": 895, + "NameEnd": 897 + }, + "Alias": null, + "Direction": "", + "Fill": null + } + ], + "Interpolate": null + } + }, + "SubQuery": null, + "TableFunction": null, + "HasTemporary": false, + "Comment": null + } +] \ No newline at end of file diff --git a/parser/testdata/ddl/output/create_table_with_ttl_policy.sql.golden.json b/parser/testdata/ddl/output/create_table_with_ttl_policy.sql.golden.json index 39be9e7..3ab8cc6 100644 --- a/parser/testdata/ddl/output/create_table_with_ttl_policy.sql.golden.json +++ b/parser/testdata/ddl/output/create_table_with_ttl_policy.sql.golden.json @@ -1,7 +1,7 @@ [ { "CreatePos": 0, - "StatementEnd": 203, + "StatementEnd": 216, "OrReplace": false, "Name": { "Database": null, @@ -85,7 +85,7 @@ }, "Engine": { "EnginePos": 51, - "EngineEnd": 203, + "EngineEnd": 216, "Name": "MergeTree", "Params": null, "PrimaryKey": null, @@ -134,7 +134,7 @@ "SampleBy": null, "TTL": { "TTLPos": 106, - "ListEnd": 203, + "ListEnd": 216, "Items": [ { "TTLPos": 106, @@ -174,10 +174,11 @@ "ActionEnd": 137, "Action": "DELETE", "Codec": null - } + }, + "GroupBy": null, + "Set": null }, - "Where": null, - "GroupBy": null + "Where": null } }, { @@ -217,10 +218,11 @@ "Literal": "aaa" }, "ToDisk": null, - "Action": null + "Action": null, + "GroupBy": null, + "Set": null }, - "Where": null, - "GroupBy": null + "Where": null } }, { @@ -260,10 +262,11 @@ "LiteralEnd": 216, "Literal": "bbb" }, - "Action": null + "Action": null, + "GroupBy": null, + "Set": null }, - "Where": null, - "GroupBy": null + "Where": null } } ] @@ -296,7 +299,7 @@ }, { "CreatePos": 221, - "StatementEnd": 364, + "StatementEnd": 396, "OrReplace": false, "Name": { "Database": null, @@ -380,7 +383,7 @@ }, "Engine": { "EnginePos": 285, - "EngineEnd": 364, + "EngineEnd": 396, "Name": "MergeTree", "Params": null, "PrimaryKey": null, @@ -429,7 +432,7 @@ "SampleBy": null, "TTL": { "TTLPos": 340, - "ListEnd": 364, + "ListEnd": 396, "Items": [ { "TTLPos": 340, @@ -469,7 +472,9 @@ "ActionEnd": 371, "Action": "DELETE", "Codec": null - } + }, + "GroupBy": null, + "Set": null }, "Where": { "WherePos": 372, @@ -513,8 +518,7 @@ "HasGlobal": false, "HasNot": false } - }, - "GroupBy": null + } } } ] @@ -697,7 +701,7 @@ "SampleBy": null, "TTL": { "TTLPos": 542, - "ListEnd": 614, + "ListEnd": 642, "Items": [ { "TTLPos": 542, @@ -754,10 +758,11 @@ "Base": 10 } } - } + }, + "GroupBy": null, + "Set": null }, - "Where": null, - "GroupBy": null + "Where": null } }, { @@ -815,10 +820,11 @@ "Base": 10 } } - } + }, + "GroupBy": null, + "Set": null }, - "Where": null, - "GroupBy": null + "Where": null } } ] diff --git a/parser/testdata/dml/output/alter_table_modify_ttl_multiple.sql.golden.json b/parser/testdata/dml/output/alter_table_modify_ttl_multiple.sql.golden.json index 2086e21..66bed1e 100644 --- a/parser/testdata/dml/output/alter_table_modify_ttl_multiple.sql.golden.json +++ b/parser/testdata/dml/output/alter_table_modify_ttl_multiple.sql.golden.json @@ -104,10 +104,11 @@ "LiteralEnd": 125, "Literal": "gcs" }, - "Action": null + "Action": null, + "GroupBy": null, + "Set": null }, - "Where": null, - "GroupBy": null + "Where": null } }, { diff --git a/parser/walk.go b/parser/walk.go index 67ff901..5cbcd7c 100644 --- a/parser/walk.go +++ b/parser/walk.go @@ -1177,9 +1177,6 @@ func Walk(node Expr, fn WalkFunc) bool { if !Walk(n.Where, fn) { return false } - if !Walk(n.GroupBy, fn) { - return false - } case *TTLPolicyRule: if !Walk(n.ToVolume, fn) { return false @@ -1190,6 +1187,14 @@ func Walk(node Expr, fn WalkFunc) bool { if !Walk(n.Action, fn) { return false } + if !Walk(n.GroupBy, fn) { + return false + } + for _, set := range n.Set { + if !Walk(set, fn) { + return false + } + } case *TTLPolicyRuleAction: if !Walk(n.Codec, fn) { return false