From 61f8edce41c48dda0bee27653e8811e4e1e5224b Mon Sep 17 00:00:00 2001 From: Sharad Gaur Date: Thu, 14 May 2026 15:27:53 -0400 Subject: [PATCH] fix: support column list before ENGINE and fix DEPENDS ON multi-table in CREATE MATERIALIZED VIEW 1. Column list before ENGINE (new): ClickHouse SHOW CREATE TABLE for refreshable materialized views with ENGINE (e.g. Memory) outputs the column list between REFRESH and ENGINE: CREATE MATERIALIZED VIEW db1.mv_name REFRESH EVERY 1 SECOND (col1 String, col2 Int8) ENGINE = Memory AS SELECT ... The parser previously expected TO or ENGINE immediately after REFRESH clauses. Added support for (columns) before ENGINE by parsing a TableSchemaClause when a left paren is encountered. 2. DEPENDS ON multi-table (bug fix): The comma in 'DEPENDS ON db1.mv_a, db1.mv_b' was not consumed before parsing the next table identifier. Added missing consumeToken() call in the comma loop, matching the pattern used in parser_query.go. Changes: - parser/parser_view.go: handle (columns) before ENGINE; consume comma in DEPENDS ON loop - parser/ast.go: add TableSchema field to CreateMaterializedView - parser/format.go: emit TableSchema before ENGINE in FormatSQL - parser/walk.go: traverse TableSchema in Walk Tests: - create_materialized_view_rmv_engine_with_columns.sql (column list + ENGINE) - create_materialized_view_rmv_depends_on_multi.sql (multi-table DEPENDS ON) - All 21 MV syntax variants tested, all existing tests pass --- parser/ast.go | 6 + parser/format.go | 4 + parser/parser_view.go | 17 + ...materialized_view_rmv_depends_on_multi.sql | 10 + ...erialized_view_rmv_engine_with_columns.sql | 36 + ...materialized_view_rmv_depends_on_multi.sql | 26 + ...erialized_view_rmv_engine_with_columns.sql | 82 ++ ...materialized_view_rmv_depends_on_multi.sql | 15 + ...erialized_view_rmv_engine_with_columns.sql | 41 + .../ddl/output/bug_001.sql.golden.json | 1 + ...te_materialized_view_basic.sql.golden.json | 1 + ..._view_rmv_depends_on_multi.sql.golden.json | 197 +++++ ...ew_rmv_engine_with_columns.sql.golden.json | 744 ++++++++++++++++++ ...iew_with_comment_before_as.sql.golden.json | 1 + ...rialized_view_with_definer.sql.golden.json | 1 + ...ew_with_empty_table_schema.sql.golden.json | 1 + ...materialized_view_with_gcs.sql.golden.json | 1 + ...rialized_view_with_refresh.sql.golden.json | 1 + .../create_mv_with_not_op.sql.golden.json | 1 + .../create_mv_with_order_by.sql.golden.json | 2 + parser/walk.go | 3 + 21 files changed, 1191 insertions(+) create mode 100644 parser/testdata/ddl/create_materialized_view_rmv_depends_on_multi.sql create mode 100644 parser/testdata/ddl/create_materialized_view_rmv_engine_with_columns.sql create mode 100644 parser/testdata/ddl/format/beautify/create_materialized_view_rmv_depends_on_multi.sql create mode 100644 parser/testdata/ddl/format/beautify/create_materialized_view_rmv_engine_with_columns.sql create mode 100644 parser/testdata/ddl/format/create_materialized_view_rmv_depends_on_multi.sql create mode 100644 parser/testdata/ddl/format/create_materialized_view_rmv_engine_with_columns.sql create mode 100644 parser/testdata/ddl/output/create_materialized_view_rmv_depends_on_multi.sql.golden.json create mode 100644 parser/testdata/ddl/output/create_materialized_view_rmv_engine_with_columns.sql.golden.json diff --git a/parser/ast.go b/parser/ast.go index 1a0050c4..90454766 100644 --- a/parser/ast.go +++ b/parser/ast.go @@ -1356,6 +1356,7 @@ type CreateMaterializedView struct { Settings *SettingsClause HasAppend bool Engine *EngineExpr + TableSchema *TableSchemaClause // column list for ENGINE-based MVs (no TO clause) HasEmpty bool Destination *DestinationClause SubQuery *SubQuery @@ -1410,6 +1411,11 @@ func (c *CreateMaterializedView) Accept(visitor ASTVisitor) error { return err } } + if c.TableSchema != nil { + if err := c.TableSchema.Accept(visitor); err != nil { + return err + } + } if c.Engine != nil { if err := c.Engine.Accept(visitor); err != nil { return err diff --git a/parser/format.go b/parser/format.go index f5f7d7a3..ba915de8 100644 --- a/parser/format.go +++ b/parser/format.go @@ -907,6 +907,10 @@ func (c *CreateMaterializedView) FormatSQL(formatter *Formatter) { formatter.Break() formatter.WriteString("APPEND") } + if c.TableSchema != nil { + formatter.Break() + formatter.WriteExpr(c.TableSchema) + } if c.Engine != nil { formatter.Break() formatter.WriteExpr(c.Engine) diff --git a/parser/parser_view.go b/parser/parser_view.go index cd0eac5a..20f5c1a1 100644 --- a/parser/parser_view.go +++ b/parser/parser_view.go @@ -66,6 +66,7 @@ func (p *Parser) parseCreateMaterializedView(pos Pos) (*CreateMaterializedView, } dependsOnTables = append(dependsOnTables, table) for p.matchTokenKind(TokenKindComma) { + _ = p.lexer.consumeToken() table, err := p.parseTableIdentifier(p.Pos()) if err != nil { return nil, err @@ -96,6 +97,22 @@ func (p *Parser) parseCreateMaterializedView(pos Pos) (*CreateMaterializedView, } createMaterializedView.Destination.TableSchema = tableSchema } + case p.matchTokenKind(TokenKindLParen): + // Column list before ENGINE (e.g. SHOW CREATE TABLE output for RMVs with ENGINE = Memory) + tableSchema, err := p.parseTableSchemaClause(p.Pos()) + if err != nil { + return nil, err + } + createMaterializedView.TableSchema = tableSchema + if !p.matchKeyword(KeywordEngine) { + return nil, fmt.Errorf("unexpected token: %q, expected ENGINE after column list", p.lastTokenKind()) + } + engineExpr, err := p.parseEngineExpr(p.Pos()) + if err != nil { + return nil, err + } + createMaterializedView.Engine = engineExpr + createMaterializedView.StatementEnd = engineExpr.End() case p.matchKeyword(KeywordEngine): engineExpr, err := p.parseEngineExpr(p.Pos()) if err != nil { diff --git a/parser/testdata/ddl/create_materialized_view_rmv_depends_on_multi.sql b/parser/testdata/ddl/create_materialized_view_rmv_depends_on_multi.sql new file mode 100644 index 00000000..31b82f52 --- /dev/null +++ b/parser/testdata/ddl/create_materialized_view_rmv_depends_on_multi.sql @@ -0,0 +1,10 @@ +CREATE MATERIALIZED VIEW db1.attrs_rollup_v0 +REFRESH EVERY 5 MINUTE +DEPENDS ON db1.metadata_mv_v0, db1.metadata_mv_v1 +ENGINE = Memory +AS SELECT DISTINCT + service_name, + attr_key, + 'profiles' AS dataset, + 'string' AS attr_type +FROM db1.metadata_v0 diff --git a/parser/testdata/ddl/create_materialized_view_rmv_engine_with_columns.sql b/parser/testdata/ddl/create_materialized_view_rmv_engine_with_columns.sql new file mode 100644 index 00000000..33ab6fc4 --- /dev/null +++ b/parser/testdata/ddl/create_materialized_view_rmv_engine_with_columns.sql @@ -0,0 +1,36 @@ +CREATE MATERIALIZED VIEW db1.config_memory_v0 +REFRESH EVERY 1 SECOND +( + `schedule_id` String, + `sample_rate` Int8, + `start_at` DateTime64(9), + `end_at` DateTime64(9), + `created_at` DateTime64(9), + `created_by` String, + `properties` Map(String, String), + `cluster_percentage` Float64, + `schedule_filters` String +) +ENGINE = Memory +SETTINGS min_rows_to_keep = 250000, max_rows_to_keep = 500000 +DEFINER = default SQL SECURITY DEFINER +COMMENT 'test comment' +AS SELECT + schedule_id, + sample_rate, + start_at, + end_at, + created_at, + created_by, + properties, + cluster_percentage, + schedule_filters +FROM +( + SELECT + *, + row_number() OVER (PARTITION BY schedule_filters ORDER BY created_at DESC) AS rn + FROM db1.config_v0 + WHERE schedule_filters != '{}' +) +WHERE rn = 1 diff --git a/parser/testdata/ddl/format/beautify/create_materialized_view_rmv_depends_on_multi.sql b/parser/testdata/ddl/format/beautify/create_materialized_view_rmv_depends_on_multi.sql new file mode 100644 index 00000000..7c4a2b19 --- /dev/null +++ b/parser/testdata/ddl/format/beautify/create_materialized_view_rmv_depends_on_multi.sql @@ -0,0 +1,26 @@ +-- Origin SQL: +CREATE MATERIALIZED VIEW db1.attrs_rollup_v0 +REFRESH EVERY 5 MINUTE +DEPENDS ON db1.metadata_mv_v0, db1.metadata_mv_v1 +ENGINE = Memory +AS SELECT DISTINCT + service_name, + attr_key, + 'profiles' AS dataset, + 'string' AS attr_type +FROM db1.metadata_v0 + + +-- Beautify SQL: +CREATE MATERIALIZED VIEW db1.attrs_rollup_v0 +REFRESH EVERY 5 MINUTE +DEPENDS ON db1.metadata_mv_v0, db1.metadata_mv_v1 +ENGINE = Memory +AS + SELECT DISTINCT + service_name, + attr_key, + 'profiles' AS dataset, + 'string' AS attr_type + FROM + db1.metadata_v0; diff --git a/parser/testdata/ddl/format/beautify/create_materialized_view_rmv_engine_with_columns.sql b/parser/testdata/ddl/format/beautify/create_materialized_view_rmv_engine_with_columns.sql new file mode 100644 index 00000000..f1d75bd9 --- /dev/null +++ b/parser/testdata/ddl/format/beautify/create_materialized_view_rmv_engine_with_columns.sql @@ -0,0 +1,82 @@ +-- Origin SQL: +CREATE MATERIALIZED VIEW db1.config_memory_v0 +REFRESH EVERY 1 SECOND +( + `schedule_id` String, + `sample_rate` Int8, + `start_at` DateTime64(9), + `end_at` DateTime64(9), + `created_at` DateTime64(9), + `created_by` String, + `properties` Map(String, String), + `cluster_percentage` Float64, + `schedule_filters` String +) +ENGINE = Memory +SETTINGS min_rows_to_keep = 250000, max_rows_to_keep = 500000 +DEFINER = default SQL SECURITY DEFINER +COMMENT 'test comment' +AS SELECT + schedule_id, + sample_rate, + start_at, + end_at, + created_at, + created_by, + properties, + cluster_percentage, + schedule_filters +FROM +( + SELECT + *, + row_number() OVER (PARTITION BY schedule_filters ORDER BY created_at DESC) AS rn + FROM db1.config_v0 + WHERE schedule_filters != '{}' +) +WHERE rn = 1 + + +-- Beautify SQL: +CREATE MATERIALIZED VIEW db1.config_memory_v0 +REFRESH EVERY 1 SECOND +( + `schedule_id` String, + `sample_rate` Int8, + `start_at` DateTime64(9), + `end_at` DateTime64(9), + `created_at` DateTime64(9), + `created_by` String, + `properties` Map(String, String), + `cluster_percentage` Float64, + `schedule_filters` String +) +ENGINE = Memory +SETTINGS + min_rows_to_keep=250000, + max_rows_to_keep=500000 +DEFINER = default +SQL SECURITY DEFINER +AS + SELECT + schedule_id, + sample_rate, + start_at, + end_at, + created_at, + created_by, + properties, + cluster_percentage, + schedule_filters + FROM + (SELECT + *, + row_number() OVER (PARTITION BY schedule_filters ORDER BY + created_at DESC) AS rn + FROM + db1.config_v0 + WHERE + schedule_filters != '{}') + WHERE + rn = 1 +COMMENT 'test comment'; diff --git a/parser/testdata/ddl/format/create_materialized_view_rmv_depends_on_multi.sql b/parser/testdata/ddl/format/create_materialized_view_rmv_depends_on_multi.sql new file mode 100644 index 00000000..6fdd2680 --- /dev/null +++ b/parser/testdata/ddl/format/create_materialized_view_rmv_depends_on_multi.sql @@ -0,0 +1,15 @@ +-- Origin SQL: +CREATE MATERIALIZED VIEW db1.attrs_rollup_v0 +REFRESH EVERY 5 MINUTE +DEPENDS ON db1.metadata_mv_v0, db1.metadata_mv_v1 +ENGINE = Memory +AS SELECT DISTINCT + service_name, + attr_key, + 'profiles' AS dataset, + 'string' AS attr_type +FROM db1.metadata_v0 + + +-- Format SQL: +CREATE MATERIALIZED VIEW db1.attrs_rollup_v0 REFRESH EVERY 5 MINUTE DEPENDS ON db1.metadata_mv_v0, db1.metadata_mv_v1 ENGINE = Memory AS SELECT DISTINCT service_name, attr_key, 'profiles' AS dataset, 'string' AS attr_type FROM db1.metadata_v0; diff --git a/parser/testdata/ddl/format/create_materialized_view_rmv_engine_with_columns.sql b/parser/testdata/ddl/format/create_materialized_view_rmv_engine_with_columns.sql new file mode 100644 index 00000000..6435cacd --- /dev/null +++ b/parser/testdata/ddl/format/create_materialized_view_rmv_engine_with_columns.sql @@ -0,0 +1,41 @@ +-- Origin SQL: +CREATE MATERIALIZED VIEW db1.config_memory_v0 +REFRESH EVERY 1 SECOND +( + `schedule_id` String, + `sample_rate` Int8, + `start_at` DateTime64(9), + `end_at` DateTime64(9), + `created_at` DateTime64(9), + `created_by` String, + `properties` Map(String, String), + `cluster_percentage` Float64, + `schedule_filters` String +) +ENGINE = Memory +SETTINGS min_rows_to_keep = 250000, max_rows_to_keep = 500000 +DEFINER = default SQL SECURITY DEFINER +COMMENT 'test comment' +AS SELECT + schedule_id, + sample_rate, + start_at, + end_at, + created_at, + created_by, + properties, + cluster_percentage, + schedule_filters +FROM +( + SELECT + *, + row_number() OVER (PARTITION BY schedule_filters ORDER BY created_at DESC) AS rn + FROM db1.config_v0 + WHERE schedule_filters != '{}' +) +WHERE rn = 1 + + +-- Format SQL: +CREATE MATERIALIZED VIEW db1.config_memory_v0 REFRESH EVERY 1 SECOND (`schedule_id` String, `sample_rate` Int8, `start_at` DateTime64(9), `end_at` DateTime64(9), `created_at` DateTime64(9), `created_by` String, `properties` Map(String, String), `cluster_percentage` Float64, `schedule_filters` String) ENGINE = Memory SETTINGS min_rows_to_keep=250000, max_rows_to_keep=500000 DEFINER = default SQL SECURITY DEFINER AS SELECT schedule_id, sample_rate, start_at, end_at, created_at, created_by, properties, cluster_percentage, schedule_filters FROM (SELECT *, row_number() OVER (PARTITION BY schedule_filters ORDER BY created_at DESC) AS rn FROM db1.config_v0 WHERE schedule_filters != '{}') WHERE rn = 1 COMMENT 'test comment'; diff --git a/parser/testdata/ddl/output/bug_001.sql.golden.json b/parser/testdata/ddl/output/bug_001.sql.golden.json index 029d265f..091e3a00 100644 --- a/parser/testdata/ddl/output/bug_001.sql.golden.json +++ b/parser/testdata/ddl/output/bug_001.sql.golden.json @@ -31,6 +31,7 @@ "Settings": null, "HasAppend": false, "Engine": null, + "TableSchema": null, "HasEmpty": false, "Destination": { "ToPos": 89, 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 7de4a72c..cbf7b1a4 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 @@ -31,6 +31,7 @@ "Settings": null, "HasAppend": false, "Engine": null, + "TableSchema": null, "HasEmpty": false, "Destination": { "ToPos": 78, 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 new file mode 100644 index 00000000..0edc7f3c --- /dev/null +++ b/parser/testdata/ddl/output/create_materialized_view_rmv_depends_on_multi.sql.golden.json @@ -0,0 +1,197 @@ +[ + { + "CreatePos": 0, + "StatementEnd": 258, + "Name": { + "Database": { + "Name": "db1", + "QuoteType": 1, + "NamePos": 25, + "NameEnd": 28 + }, + "Table": { + "Name": "attrs_rollup_v0", + "QuoteType": 1, + "NamePos": 29, + "NameEnd": 44 + } + }, + "IfNotExists": false, + "OnCluster": null, + "Refresh": { + "RefreshPos": 45, + "Frequency": "EVERY", + "Interval": { + "IntervalPos": 0, + "Expr": { + "NumPos": 59, + "NumEnd": 60, + "Literal": "5", + "Base": 10 + }, + "Unit": { + "Name": "MINUTE", + "QuoteType": 1, + "NamePos": 61, + "NameEnd": 67 + } + }, + "Offset": null + }, + "RandomizeFor": null, + "DependsOn": [ + { + "Database": { + "Name": "db1", + "QuoteType": 1, + "NamePos": 79, + "NameEnd": 82 + }, + "Table": { + "Name": "metadata_mv_v0", + "QuoteType": 1, + "NamePos": 83, + "NameEnd": 97 + } + }, + { + "Database": { + "Name": "db1", + "QuoteType": 1, + "NamePos": 99, + "NameEnd": 102 + }, + "Table": { + "Name": "metadata_mv_v1", + "QuoteType": 1, + "NamePos": 103, + "NameEnd": 117 + } + } + ], + "Settings": null, + "HasAppend": false, + "Engine": { + "EnginePos": 118, + "EngineEnd": 133, + "Name": "Memory", + "Params": null, + "PrimaryKey": null, + "PartitionBy": null, + "SampleBy": null, + "TTL": null, + "Settings": null, + "OrderBy": null + }, + "TableSchema": null, + "HasEmpty": false, + "Destination": null, + "SubQuery": { + "HasParen": false, + "Select": { + "SelectPos": 137, + "StatementEnd": 258, + "With": null, + "Top": null, + "HasDistinct": true, + "DistinctOn": null, + "SelectItems": [ + { + "Expr": { + "Name": "service_name", + "QuoteType": 1, + "NamePos": 157, + "NameEnd": 169 + }, + "Modifiers": [], + "Alias": null + }, + { + "Expr": { + "Name": "attr_key", + "QuoteType": 1, + "NamePos": 175, + "NameEnd": 183 + }, + "Modifiers": [], + "Alias": null + }, + { + "Expr": { + "LiteralPos": 190, + "LiteralEnd": 198, + "Literal": "profiles" + }, + "Modifiers": [], + "Alias": { + "Name": "dataset", + "QuoteType": 1, + "NamePos": 203, + "NameEnd": 210 + } + }, + { + "Expr": { + "LiteralPos": 217, + "LiteralEnd": 223, + "Literal": "string" + }, + "Modifiers": [], + "Alias": { + "Name": "attr_type", + "QuoteType": 1, + "NamePos": 228, + "NameEnd": 237 + } + } + ], + "From": { + "FromPos": 238, + "Expr": { + "Table": { + "TablePos": 243, + "TableEnd": 258, + "Alias": null, + "Expr": { + "Database": { + "Name": "db1", + "QuoteType": 1, + "NamePos": 243, + "NameEnd": 246 + }, + "Table": { + "Name": "metadata_v0", + "QuoteType": 1, + "NamePos": 247, + "NameEnd": 258 + } + }, + "HasFinal": false + }, + "StatementEnd": 258, + "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 + } + }, + "Populate": false, + "Comment": null, + "Definer": null, + "SQLSecurity": "" + } +] \ No newline at end of file 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 new file mode 100644 index 00000000..f83b0605 --- /dev/null +++ b/parser/testdata/ddl/output/create_materialized_view_rmv_engine_with_columns.sql.golden.json @@ -0,0 +1,744 @@ +[ + { + "CreatePos": 0, + "StatementEnd": 833, + "Name": { + "Database": { + "Name": "db1", + "QuoteType": 1, + "NamePos": 25, + "NameEnd": 28 + }, + "Table": { + "Name": "config_memory_v0", + "QuoteType": 1, + "NamePos": 29, + "NameEnd": 45 + } + }, + "IfNotExists": false, + "OnCluster": null, + "Refresh": { + "RefreshPos": 46, + "Frequency": "EVERY", + "Interval": { + "IntervalPos": 0, + "Expr": { + "NumPos": 60, + "NumEnd": 61, + "Literal": "1", + "Base": 10 + }, + "Unit": { + "Name": "SECOND", + "QuoteType": 1, + "NamePos": 62, + "NameEnd": 68 + } + }, + "Offset": null + }, + "RandomizeFor": null, + "DependsOn": null, + "Settings": null, + "HasAppend": false, + "Engine": { + "EnginePos": 340, + "EngineEnd": 417, + "Name": "Memory", + "Params": null, + "PrimaryKey": null, + "PartitionBy": null, + "SampleBy": null, + "TTL": null, + "Settings": { + "SettingsPos": 356, + "ListEnd": 417, + "Items": [ + { + "SettingsPos": 365, + "Name": { + "Name": "min_rows_to_keep", + "QuoteType": 1, + "NamePos": 365, + "NameEnd": 381 + }, + "Expr": { + "NumPos": 384, + "NumEnd": 390, + "Literal": "250000", + "Base": 10 + } + }, + { + "SettingsPos": 392, + "Name": { + "Name": "max_rows_to_keep", + "QuoteType": 1, + "NamePos": 392, + "NameEnd": 408 + }, + "Expr": { + "NumPos": 411, + "NumEnd": 417, + "Literal": "500000", + "Base": 10 + } + } + ] + }, + "OrderBy": null + }, + "TableSchema": { + "SchemaPos": 69, + "SchemaEnd": 338, + "Columns": [ + { + "NamePos": 76, + "ColumnEnd": 95, + "Name": { + "Ident": { + "Name": "schedule_id", + "QuoteType": 3, + "NamePos": 76, + "NameEnd": 87 + }, + "DotIdent": null + }, + "Type": { + "Name": { + "Name": "String", + "QuoteType": 1, + "NamePos": 89, + "NameEnd": 95 + } + }, + "NotNull": null, + "Nullable": null, + "DefaultExpr": null, + "MaterializedExpr": null, + "AliasExpr": null, + "Codec": null, + "TTL": null, + "Comment": null, + "CompressionCodec": null + }, + { + "NamePos": 102, + "ColumnEnd": 119, + "Name": { + "Ident": { + "Name": "sample_rate", + "QuoteType": 3, + "NamePos": 102, + "NameEnd": 113 + }, + "DotIdent": null + }, + "Type": { + "Name": { + "Name": "Int8", + "QuoteType": 1, + "NamePos": 115, + "NameEnd": 119 + } + }, + "NotNull": null, + "Nullable": null, + "DefaultExpr": null, + "MaterializedExpr": null, + "AliasExpr": null, + "Codec": null, + "TTL": null, + "Comment": null, + "CompressionCodec": null + }, + { + "NamePos": 126, + "ColumnEnd": 148, + "Name": { + "Ident": { + "Name": "start_at", + "QuoteType": 3, + "NamePos": 126, + "NameEnd": 134 + }, + "DotIdent": null + }, + "Type": { + "LeftParenPos": 147, + "RightParenPos": 148, + "Name": { + "Name": "DateTime64", + "QuoteType": 1, + "NamePos": 136, + "NameEnd": 146 + }, + "Params": [ + { + "NumPos": 147, + "NumEnd": 148, + "Literal": "9", + "Base": 10 + } + ] + }, + "NotNull": null, + "Nullable": null, + "DefaultExpr": null, + "MaterializedExpr": null, + "AliasExpr": null, + "Codec": null, + "TTL": null, + "Comment": null, + "CompressionCodec": null + }, + { + "NamePos": 156, + "ColumnEnd": 176, + "Name": { + "Ident": { + "Name": "end_at", + "QuoteType": 3, + "NamePos": 156, + "NameEnd": 162 + }, + "DotIdent": null + }, + "Type": { + "LeftParenPos": 175, + "RightParenPos": 176, + "Name": { + "Name": "DateTime64", + "QuoteType": 1, + "NamePos": 164, + "NameEnd": 174 + }, + "Params": [ + { + "NumPos": 175, + "NumEnd": 176, + "Literal": "9", + "Base": 10 + } + ] + }, + "NotNull": null, + "Nullable": null, + "DefaultExpr": null, + "MaterializedExpr": null, + "AliasExpr": null, + "Codec": null, + "TTL": null, + "Comment": null, + "CompressionCodec": null + }, + { + "NamePos": 184, + "ColumnEnd": 208, + "Name": { + "Ident": { + "Name": "created_at", + "QuoteType": 3, + "NamePos": 184, + "NameEnd": 194 + }, + "DotIdent": null + }, + "Type": { + "LeftParenPos": 207, + "RightParenPos": 208, + "Name": { + "Name": "DateTime64", + "QuoteType": 1, + "NamePos": 196, + "NameEnd": 206 + }, + "Params": [ + { + "NumPos": 207, + "NumEnd": 208, + "Literal": "9", + "Base": 10 + } + ] + }, + "NotNull": null, + "Nullable": null, + "DefaultExpr": null, + "MaterializedExpr": null, + "AliasExpr": null, + "Codec": null, + "TTL": null, + "Comment": null, + "CompressionCodec": null + }, + { + "NamePos": 216, + "ColumnEnd": 234, + "Name": { + "Ident": { + "Name": "created_by", + "QuoteType": 3, + "NamePos": 216, + "NameEnd": 226 + }, + "DotIdent": null + }, + "Type": { + "Name": { + "Name": "String", + "QuoteType": 1, + "NamePos": 228, + "NameEnd": 234 + } + }, + "NotNull": null, + "Nullable": null, + "DefaultExpr": null, + "MaterializedExpr": null, + "AliasExpr": null, + "Codec": null, + "TTL": null, + "Comment": null, + "CompressionCodec": null + }, + { + "NamePos": 241, + "ColumnEnd": 271, + "Name": { + "Ident": { + "Name": "properties", + "QuoteType": 3, + "NamePos": 241, + "NameEnd": 251 + }, + "DotIdent": null + }, + "Type": { + "LeftParenPos": 257, + "RightParenPos": 271, + "Name": { + "Name": "Map", + "QuoteType": 1, + "NamePos": 253, + "NameEnd": 256 + }, + "Params": [ + { + "Name": { + "Name": "String", + "QuoteType": 1, + "NamePos": 257, + "NameEnd": 263 + } + }, + { + "Name": { + "Name": "String", + "QuoteType": 1, + "NamePos": 265, + "NameEnd": 271 + } + } + ] + }, + "NotNull": null, + "Nullable": null, + "DefaultExpr": null, + "MaterializedExpr": null, + "AliasExpr": null, + "Codec": null, + "TTL": null, + "Comment": null, + "CompressionCodec": null + }, + { + "NamePos": 279, + "ColumnEnd": 306, + "Name": { + "Ident": { + "Name": "cluster_percentage", + "QuoteType": 3, + "NamePos": 279, + "NameEnd": 297 + }, + "DotIdent": null + }, + "Type": { + "Name": { + "Name": "Float64", + "QuoteType": 1, + "NamePos": 299, + "NameEnd": 306 + } + }, + "NotNull": null, + "Nullable": null, + "DefaultExpr": null, + "MaterializedExpr": null, + "AliasExpr": null, + "Codec": null, + "TTL": null, + "Comment": null, + "CompressionCodec": null + }, + { + "NamePos": 313, + "ColumnEnd": 337, + "Name": { + "Ident": { + "Name": "schedule_filters", + "QuoteType": 3, + "NamePos": 313, + "NameEnd": 329 + }, + "DotIdent": null + }, + "Type": { + "Name": { + "Name": "String", + "QuoteType": 1, + "NamePos": 331, + "NameEnd": 337 + } + }, + "NotNull": null, + "Nullable": null, + "DefaultExpr": null, + "MaterializedExpr": null, + "AliasExpr": null, + "Codec": null, + "TTL": null, + "Comment": null, + "CompressionCodec": null + } + ], + "AliasTable": null, + "TableFunction": null + }, + "HasEmpty": false, + "Destination": null, + "SubQuery": { + "HasParen": false, + "Select": { + "SelectPos": 483, + "StatementEnd": 833, + "With": null, + "Top": null, + "HasDistinct": false, + "DistinctOn": null, + "SelectItems": [ + { + "Expr": { + "Name": "schedule_id", + "QuoteType": 1, + "NamePos": 494, + "NameEnd": 505 + }, + "Modifiers": [], + "Alias": null + }, + { + "Expr": { + "Name": "sample_rate", + "QuoteType": 1, + "NamePos": 511, + "NameEnd": 522 + }, + "Modifiers": [], + "Alias": null + }, + { + "Expr": { + "Name": "start_at", + "QuoteType": 1, + "NamePos": 528, + "NameEnd": 536 + }, + "Modifiers": [], + "Alias": null + }, + { + "Expr": { + "Name": "end_at", + "QuoteType": 1, + "NamePos": 542, + "NameEnd": 548 + }, + "Modifiers": [], + "Alias": null + }, + { + "Expr": { + "Name": "created_at", + "QuoteType": 1, + "NamePos": 554, + "NameEnd": 564 + }, + "Modifiers": [], + "Alias": null + }, + { + "Expr": { + "Name": "created_by", + "QuoteType": 1, + "NamePos": 570, + "NameEnd": 580 + }, + "Modifiers": [], + "Alias": null + }, + { + "Expr": { + "Name": "properties", + "QuoteType": 1, + "NamePos": 586, + "NameEnd": 596 + }, + "Modifiers": [], + "Alias": null + }, + { + "Expr": { + "Name": "cluster_percentage", + "QuoteType": 1, + "NamePos": 602, + "NameEnd": 620 + }, + "Modifiers": [], + "Alias": null + }, + { + "Expr": { + "Name": "schedule_filters", + "QuoteType": 1, + "NamePos": 626, + "NameEnd": 642 + }, + "Modifiers": [], + "Alias": null + } + ], + "From": { + "FromPos": 643, + "Expr": { + "Table": { + "TablePos": 648, + "TableEnd": 817, + "Alias": null, + "Expr": { + "HasParen": true, + "Select": { + "SelectPos": 654, + "StatementEnd": 817, + "With": null, + "Top": null, + "HasDistinct": false, + "DistinctOn": null, + "SelectItems": [ + { + "Expr": { + "Name": "*", + "QuoteType": 0, + "NamePos": 669, + "NameEnd": 669 + }, + "Modifiers": [], + "Alias": null + }, + { + "Expr": { + "Function": { + "Name": { + "Name": "row_number", + "QuoteType": 1, + "NamePos": 680, + "NameEnd": 690 + }, + "Params": { + "LeftParenPos": 690, + "RightParenPos": 691, + "Items": { + "ListPos": 691, + "ListEnd": 691, + "HasDistinct": false, + "Items": [] + }, + "ColumnArgList": null + } + }, + "OverPos": 693, + "OverExpr": { + "LeftParenPos": 698, + "RightParenPos": 753, + "WindowName": null, + "PartitionBy": { + "PartitionPos": 698, + "Expr": { + "ListPos": 712, + "ListEnd": 728, + "HasDistinct": false, + "Items": [ + { + "Expr": { + "Name": "schedule_filters", + "QuoteType": 1, + "NamePos": 712, + "NameEnd": 728 + }, + "Alias": null + } + ] + } + }, + "OrderBy": { + "OrderPos": 729, + "ListEnd": 748, + "Items": [ + { + "OrderPos": 729, + "Expr": { + "Name": "created_at", + "QuoteType": 1, + "NamePos": 738, + "NameEnd": 748 + }, + "Alias": null, + "Direction": "DESC", + "Fill": null + } + ], + "Interpolate": null + }, + "Frame": null + } + }, + "Modifiers": [], + "Alias": { + "Name": "rn", + "QuoteType": 1, + "NamePos": 758, + "NameEnd": 760 + } + } + ], + "From": { + "FromPos": 765, + "Expr": { + "Table": { + "TablePos": 770, + "TableEnd": 783, + "Alias": null, + "Expr": { + "Database": { + "Name": "db1", + "QuoteType": 1, + "NamePos": 770, + "NameEnd": 773 + }, + "Table": { + "Name": "config_v0", + "QuoteType": 1, + "NamePos": 774, + "NameEnd": 783 + } + }, + "HasFinal": false + }, + "StatementEnd": 783, + "SampleRatio": null, + "HasFinal": false + } + }, + "Window": null, + "Prewhere": null, + "Where": { + "WherePos": 788, + "Expr": { + "LeftExpr": { + "Name": "schedule_filters", + "QuoteType": 1, + "NamePos": 794, + "NameEnd": 810 + }, + "Operation": "!=", + "RightExpr": { + "LiteralPos": 815, + "LiteralEnd": 817, + "Literal": "{}" + }, + "HasGlobal": false, + "HasNot": false + } + }, + "GroupBy": null, + "WithTotal": false, + "Having": null, + "OrderBy": null, + "LimitBy": null, + "Limit": null, + "Settings": null, + "Format": null, + "UnionAll": null, + "UnionDistinct": null, + "Except": null + } + }, + "HasFinal": false + }, + "StatementEnd": 817, + "SampleRatio": null, + "HasFinal": false + } + }, + "Window": null, + "Prewhere": null, + "Where": { + "WherePos": 821, + "Expr": { + "LeftExpr": { + "Name": "rn", + "QuoteType": 1, + "NamePos": 827, + "NameEnd": 829 + }, + "Operation": "=", + "RightExpr": { + "NumPos": 832, + "NumEnd": 833, + "Literal": "1", + "Base": 10 + }, + "HasGlobal": false, + "HasNot": false + } + }, + "GroupBy": null, + "WithTotal": false, + "Having": null, + "OrderBy": null, + "LimitBy": null, + "Limit": null, + "Settings": null, + "Format": null, + "UnionAll": null, + "UnionDistinct": null, + "Except": null + } + }, + "Populate": false, + "Comment": { + "LiteralPos": 466, + "LiteralEnd": 478, + "Literal": "test comment" + }, + "Definer": { + "Name": "default", + "QuoteType": 1, + "NamePos": 428, + "NameEnd": 435 + }, + "SQLSecurity": "DEFINER" + } +] \ No newline at end of file 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 fa71349b..4adfca45 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 @@ -24,6 +24,7 @@ "Settings": null, "HasAppend": false, "Engine": null, + "TableSchema": null, "HasEmpty": false, "Destination": { "ToPos": 44, 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 3b033c83..0773eafe 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 @@ -52,6 +52,7 @@ "Settings": null, "HasAppend": true, "Engine": null, + "TableSchema": null, "HasEmpty": false, "Destination": { "ToPos": 79, 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 8564946b..08ab669b 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 @@ -144,6 +144,7 @@ "Interpolate": null } }, + "TableSchema": null, "HasEmpty": false, "Destination": null, "SubQuery": { 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 c228bf3f..76b44fbc 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 @@ -43,6 +43,7 @@ "Settings": null, "HasAppend": false, "Engine": null, + "TableSchema": null, "HasEmpty": false, "Destination": { "ToPos": 80, 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 bf7e9461..b64d1e34 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 @@ -126,6 +126,7 @@ }, "HasAppend": true, "Engine": null, + "TableSchema": null, "HasEmpty": true, "Destination": { "ToPos": 207, 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 95a7a7b5..80e64aa0 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 @@ -31,6 +31,7 @@ "Settings": null, "HasAppend": false, "Engine": null, + "TableSchema": null, "HasEmpty": false, "Destination": { "ToPos": 77, 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 6a0b151a..6ef31b42 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 @@ -96,6 +96,7 @@ "Interpolate": null } }, + "TableSchema": null, "HasEmpty": false, "Destination": null, "SubQuery": { @@ -227,6 +228,7 @@ "Settings": null, "OrderBy": null }, + "TableSchema": null, "HasEmpty": false, "Destination": null, "SubQuery": { diff --git a/parser/walk.go b/parser/walk.go index bfc58c65..0cd7d168 100644 --- a/parser/walk.go +++ b/parser/walk.go @@ -668,6 +668,9 @@ func Walk(node Expr, fn WalkFunc) bool { if !Walk(n.Settings, fn) { return false } + if !Walk(n.TableSchema, fn) { + return false + } if !Walk(n.Engine, fn) { return false }