Skip to content

Commit 120ff65

Browse files
authored
Support COMMENT before AS SELECT in CREATE MATERIALIZED VIEW (#262)
ClickHouse 26.2+ changed SHOW CREATE TABLE output to place COMMENT before AS SELECT, while 25.x places it after. The parser only supported COMMENT after AS SELECT, causing parse failures on 26.2+. Now tries COMMENT in both positions: - Before AS SELECT (ClickHouse 26.2+ SHOW CREATE TABLE format) - After AS SELECT (ClickHouse 25.x SHOW CREATE TABLE format) This closes #261.
1 parent 5a72214 commit 120ff65

5 files changed

Lines changed: 335 additions & 4 deletions

parser/parser_view.go

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,15 @@ func (p *Parser) parseCreateMaterializedView(pos Pos) (*CreateMaterializedView,
141141
createMaterializedView.StatementEnd = p.Pos()
142142
}
143143

144+
// COMMENT can appear either before or after AS SELECT.
145+
// ClickHouse 26.2+ outputs COMMENT before AS SELECT in SHOW CREATE TABLE,
146+
// while 25.8 outputs it after AS SELECT.
147+
comment, err := p.tryParseComment()
148+
if err != nil {
149+
return nil, err
150+
}
151+
createMaterializedView.Comment = comment
152+
144153
if p.tryConsumeKeywords(KeywordAs) {
145154
subQuery, err := p.parseSubQuery(p.Pos())
146155
if err != nil {
@@ -150,11 +159,14 @@ func (p *Parser) parseCreateMaterializedView(pos Pos) (*CreateMaterializedView,
150159
createMaterializedView.StatementEnd = subQuery.End()
151160
}
152161

153-
comment, err := p.tryParseComment()
154-
if err != nil {
155-
return nil, err
162+
// Also try parsing COMMENT after AS SELECT (ClickHouse 25.x format)
163+
if createMaterializedView.Comment == nil {
164+
comment, err = p.tryParseComment()
165+
if err != nil {
166+
return nil, err
167+
}
168+
createMaterializedView.Comment = comment
156169
}
157-
createMaterializedView.Comment = comment
158170
return createMaterializedView, nil
159171
}
160172

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
CREATE MATERIALIZED VIEW db.mv_with_comment TO db.dst_table
2+
(
3+
`shop_id` UInt64,
4+
`event_type` LowCardinality(String),
5+
`created_at` DateTime64(9)
6+
)
7+
COMMENT '{"blueprint_hash":"abc123","timestamp":"2026-04-08T12:00:00Z"}'
8+
AS SELECT
9+
shop_id,
10+
event_type,
11+
created_at
12+
FROM db.src_table;
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
-- Origin SQL:
2+
CREATE MATERIALIZED VIEW db.mv_with_comment TO db.dst_table
3+
(
4+
`shop_id` UInt64,
5+
`event_type` LowCardinality(String),
6+
`created_at` DateTime64(9)
7+
)
8+
COMMENT '{"blueprint_hash":"abc123","timestamp":"2026-04-08T12:00:00Z"}'
9+
AS SELECT
10+
shop_id,
11+
event_type,
12+
created_at
13+
FROM db.src_table;
14+
15+
16+
-- Beautify SQL:
17+
CREATE MATERIALIZED VIEW db.mv_with_comment
18+
TO db.dst_table
19+
(
20+
`shop_id` UInt64,
21+
`event_type` LowCardinality(String),
22+
`created_at` DateTime64(9)
23+
)
24+
AS
25+
SELECT
26+
shop_id,
27+
event_type,
28+
created_at
29+
FROM
30+
db.src_table
31+
COMMENT '{"blueprint_hash":"abc123","timestamp":"2026-04-08T12:00:00Z"}';
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
-- Origin SQL:
2+
CREATE MATERIALIZED VIEW db.mv_with_comment TO db.dst_table
3+
(
4+
`shop_id` UInt64,
5+
`event_type` LowCardinality(String),
6+
`created_at` DateTime64(9)
7+
)
8+
COMMENT '{"blueprint_hash":"abc123","timestamp":"2026-04-08T12:00:00Z"}'
9+
AS SELECT
10+
shop_id,
11+
event_type,
12+
created_at
13+
FROM db.src_table;
14+
15+
16+
-- Format SQL:
17+
CREATE MATERIALIZED VIEW db.mv_with_comment TO db.dst_table (`shop_id` UInt64, `event_type` LowCardinality(String), `created_at` DateTime64(9)) AS SELECT shop_id, event_type, created_at FROM db.src_table COMMENT '{"blueprint_hash":"abc123","timestamp":"2026-04-08T12:00:00Z"}';
Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
[
2+
{
3+
"CreatePos": 0,
4+
"StatementEnd": 302,
5+
"Name": {
6+
"Database": {
7+
"Name": "db",
8+
"QuoteType": 1,
9+
"NamePos": 25,
10+
"NameEnd": 27
11+
},
12+
"Table": {
13+
"Name": "mv_with_comment",
14+
"QuoteType": 1,
15+
"NamePos": 28,
16+
"NameEnd": 43
17+
}
18+
},
19+
"IfNotExists": false,
20+
"OnCluster": null,
21+
"Refresh": null,
22+
"RandomizeFor": null,
23+
"DependsOn": null,
24+
"Settings": null,
25+
"HasAppend": false,
26+
"Engine": null,
27+
"HasEmpty": false,
28+
"Destination": {
29+
"ToPos": 44,
30+
"TableIdentifier": {
31+
"Database": {
32+
"Name": "db",
33+
"QuoteType": 1,
34+
"NamePos": 47,
35+
"NameEnd": 49
36+
},
37+
"Table": {
38+
"Name": "dst_table",
39+
"QuoteType": 1,
40+
"NamePos": 50,
41+
"NameEnd": 59
42+
}
43+
},
44+
"TableSchema": {
45+
"SchemaPos": 60,
46+
"SchemaEnd": 156,
47+
"Columns": [
48+
{
49+
"NamePos": 67,
50+
"ColumnEnd": 82,
51+
"Name": {
52+
"Ident": {
53+
"Name": "shop_id",
54+
"QuoteType": 3,
55+
"NamePos": 67,
56+
"NameEnd": 74
57+
},
58+
"DotIdent": null
59+
},
60+
"Type": {
61+
"Name": {
62+
"Name": "UInt64",
63+
"QuoteType": 1,
64+
"NamePos": 76,
65+
"NameEnd": 82
66+
}
67+
},
68+
"NotNull": null,
69+
"Nullable": null,
70+
"DefaultExpr": null,
71+
"MaterializedExpr": null,
72+
"AliasExpr": null,
73+
"Codec": null,
74+
"TTL": null,
75+
"Comment": null,
76+
"CompressionCodec": null
77+
},
78+
{
79+
"NamePos": 89,
80+
"ColumnEnd": 122,
81+
"Name": {
82+
"Ident": {
83+
"Name": "event_type",
84+
"QuoteType": 3,
85+
"NamePos": 89,
86+
"NameEnd": 99
87+
},
88+
"DotIdent": null
89+
},
90+
"Type": {
91+
"LeftParenPos": 116,
92+
"RightParenPos": 122,
93+
"Name": {
94+
"Name": "LowCardinality",
95+
"QuoteType": 1,
96+
"NamePos": 101,
97+
"NameEnd": 115
98+
},
99+
"Params": [
100+
{
101+
"Name": {
102+
"Name": "String",
103+
"QuoteType": 1,
104+
"NamePos": 116,
105+
"NameEnd": 122
106+
}
107+
}
108+
]
109+
},
110+
"NotNull": null,
111+
"Nullable": null,
112+
"DefaultExpr": null,
113+
"MaterializedExpr": null,
114+
"AliasExpr": null,
115+
"Codec": null,
116+
"TTL": null,
117+
"Comment": null,
118+
"CompressionCodec": null
119+
},
120+
{
121+
"NamePos": 130,
122+
"ColumnEnd": 154,
123+
"Name": {
124+
"Ident": {
125+
"Name": "created_at",
126+
"QuoteType": 3,
127+
"NamePos": 130,
128+
"NameEnd": 140
129+
},
130+
"DotIdent": null
131+
},
132+
"Type": {
133+
"LeftParenPos": 153,
134+
"RightParenPos": 154,
135+
"Name": {
136+
"Name": "DateTime64",
137+
"QuoteType": 1,
138+
"NamePos": 142,
139+
"NameEnd": 152
140+
},
141+
"Params": [
142+
{
143+
"NumPos": 153,
144+
"NumEnd": 154,
145+
"Literal": "9",
146+
"Base": 10
147+
}
148+
]
149+
},
150+
"NotNull": null,
151+
"Nullable": null,
152+
"DefaultExpr": null,
153+
"MaterializedExpr": null,
154+
"AliasExpr": null,
155+
"Codec": null,
156+
"TTL": null,
157+
"Comment": null,
158+
"CompressionCodec": null
159+
}
160+
],
161+
"AliasTable": null,
162+
"TableFunction": null
163+
}
164+
},
165+
"SubQuery": {
166+
"HasParen": false,
167+
"Select": {
168+
"SelectPos": 234,
169+
"StatementEnd": 302,
170+
"With": null,
171+
"Top": null,
172+
"HasDistinct": false,
173+
"DistinctOn": null,
174+
"SelectItems": [
175+
{
176+
"Expr": {
177+
"Name": "shop_id",
178+
"QuoteType": 1,
179+
"NamePos": 245,
180+
"NameEnd": 252
181+
},
182+
"Modifiers": [],
183+
"Alias": null
184+
},
185+
{
186+
"Expr": {
187+
"Name": "event_type",
188+
"QuoteType": 1,
189+
"NamePos": 258,
190+
"NameEnd": 268
191+
},
192+
"Modifiers": [],
193+
"Alias": null
194+
},
195+
{
196+
"Expr": {
197+
"Name": "created_at",
198+
"QuoteType": 1,
199+
"NamePos": 274,
200+
"NameEnd": 284
201+
},
202+
"Modifiers": [],
203+
"Alias": null
204+
}
205+
],
206+
"From": {
207+
"FromPos": 285,
208+
"Expr": {
209+
"Table": {
210+
"TablePos": 290,
211+
"TableEnd": 302,
212+
"Alias": null,
213+
"Expr": {
214+
"Database": {
215+
"Name": "db",
216+
"QuoteType": 1,
217+
"NamePos": 290,
218+
"NameEnd": 292
219+
},
220+
"Table": {
221+
"Name": "src_table",
222+
"QuoteType": 1,
223+
"NamePos": 293,
224+
"NameEnd": 302
225+
}
226+
},
227+
"HasFinal": false
228+
},
229+
"StatementEnd": 302,
230+
"SampleRatio": null,
231+
"HasFinal": false
232+
}
233+
},
234+
"Window": null,
235+
"Prewhere": null,
236+
"Where": null,
237+
"GroupBy": null,
238+
"WithTotal": false,
239+
"Having": null,
240+
"OrderBy": null,
241+
"LimitBy": null,
242+
"Limit": null,
243+
"Settings": null,
244+
"Format": null,
245+
"UnionAll": null,
246+
"UnionDistinct": null,
247+
"Except": null
248+
}
249+
},
250+
"Populate": false,
251+
"Comment": {
252+
"LiteralPos": 167,
253+
"LiteralEnd": 229,
254+
"Literal": "{\"blueprint_hash\":\"abc123\",\"timestamp\":\"2026-04-08T12:00:00Z\"}"
255+
},
256+
"Definer": null,
257+
"SQLSecurity": ""
258+
}
259+
]

0 commit comments

Comments
 (0)