Skip to content

Commit 0eb4ee8

Browse files
authored
Merge pull request #34659 from teskje/create-replacement-mv
sql-parser: CREATE REPLACEMENT MATERIALIZED VIEW
2 parents bde7483 + 336f1f9 commit 0eb4ee8

File tree

20 files changed

+70
-65
lines changed

20 files changed

+70
-65
lines changed

doc/developer/design/20251111_replacement_materialized_views.md

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ A replacement materialized view allows users to stage the change of definition a
6262
The user can then inspect the replacement, and decide to apply or discard it.
6363

6464
We add the following SQL syntax:
65-
* `CREATE MATERIALIZED VIEW replacement_name REPLACING mv_name AS SELECT ...`
65+
* `CREATE REPLACEMENT MATERIALIZED VIEW replacement_name FOR mv_name AS SELECT ...`
6666
Creates a replacement for the specified materialized view with the new definition.
6767
The usual properties for materialized views apply, such as the cluster and its options.
6868
* `ALTER MATERIALIZED VIEW mv_name APPLY REPLACEMENT replacement_name`
@@ -225,10 +225,3 @@ process, you are responsible for getting answers to these open
225225
questions. All open questions should be answered by the time a design
226226
document is merged.
227227
-->
228-
229-
### SQL syntax
230-
231-
The current proposal uses the term `REPLACING` in the `CREATE MATERIALIZED VIEW` statement.
232-
An alternative is to use `AS REPLACEMENT FOR mv_name`, which might be more explicit.
233-
We could also consider the term `REPLACE`, but that might be confused with `CREATE OR REPLACE`.
234-
Alternatively, we could use `REPLACES` instead of `REPLACING`.

misc/python/materialize/parallel_workload/action.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1048,7 +1048,7 @@ def run(self, exe: Executor) -> bool:
10481048

10491049
tmp_mv = identifier(view.name() + "_" + threading.current_thread().getName())
10501050
exe.execute(
1051-
f"CREATE MATERIALIZED VIEW {tmp_mv} REPLACING {identifier(view.name())} AS {view.get_select()}",
1051+
f"CREATE REPLACEMENT MATERIALIZED VIEW {tmp_mv} FOR {identifier(view.name())} AS {view.get_select()}",
10521052
)
10531053
time.sleep(self.rng.random())
10541054
if self.rng.choice([True, False]):

src/adapter/src/coord/command_handler.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1381,7 +1381,7 @@ impl Coordinator {
13811381
if_exists: cmvs.if_exists,
13821382
name: cmvs.name,
13831383
columns: cmvs.columns,
1384-
replacing: cmvs.replacing,
1384+
replacement_for: cmvs.replacement_for,
13851385
in_cluster: cmvs.in_cluster,
13861386
query: cmvs.query,
13871387
with_options: cmvs.with_options,

src/catalog/src/durable/objects.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1333,9 +1333,9 @@ pub fn item_type(create_sql: &str) -> CatalogItemType {
13331333
let mut tokens = create_sql.split_whitespace();
13341334
assert_eq!(tokens.next(), Some("CREATE"));
13351335

1336-
// Read away TEMPORARY, if any.
1336+
// Read away item type modifiers, if any.
13371337
let next_token = match tokens.next() {
1338-
Some("TEMPORARY") => tokens.next(),
1338+
Some("TEMPORARY") | Some("REPLACEMENT") => tokens.next(),
13391339
token => token,
13401340
};
13411341

src/catalog/src/memory/objects.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1474,7 +1474,7 @@ impl MaterializedView {
14741474
if_exists: old_stmt.if_exists,
14751475
name: old_stmt.name,
14761476
columns: rpl_stmt.columns,
1477-
replacing: None,
1477+
replacement_for: None,
14781478
in_cluster: rpl_stmt.in_cluster,
14791479
query: rpl_stmt.query,
14801480
as_of: rpl_stmt.as_of,

src/sql-lexer/src/keywords.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,6 @@ Reoptimize
392392
Repeatable
393393
Replace
394394
Replacement
395-
Replacing
396395
Replan
397396
Replica
398397
Replicas

src/sql-parser/src/ast/defs/statement.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1387,7 +1387,7 @@ pub struct CreateMaterializedViewStatement<T: AstInfo> {
13871387
pub if_exists: IfExistsBehavior,
13881388
pub name: UnresolvedItemName,
13891389
pub columns: Vec<Ident>,
1390-
pub replacing: Option<T::ItemName>,
1390+
pub replacement_for: Option<T::ItemName>,
13911391
pub in_cluster: Option<T::ClusterName>,
13921392
pub query: Query<T>,
13931393
pub as_of: Option<u64>,
@@ -1400,6 +1400,9 @@ impl<T: AstInfo> AstDisplay for CreateMaterializedViewStatement<T> {
14001400
if self.if_exists == IfExistsBehavior::Replace {
14011401
f.write_str(" OR REPLACE");
14021402
}
1403+
if self.replacement_for.is_some() {
1404+
f.write_str(" REPLACEMENT");
1405+
}
14031406

14041407
f.write_str(" MATERIALIZED VIEW");
14051408

@@ -1416,8 +1419,8 @@ impl<T: AstInfo> AstDisplay for CreateMaterializedViewStatement<T> {
14161419
f.write_str(")");
14171420
}
14181421

1419-
if let Some(target) = &self.replacing {
1420-
f.write_str(" REPLACING ");
1422+
if let Some(target) = &self.replacement_for {
1423+
f.write_str(" FOR ");
14211424
f.write_node(target);
14221425
}
14231426

src/sql-parser/src/parser.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1959,6 +1959,8 @@ impl<'a> Parser<'a> {
19591959
.map_parser_err(StatementKind::CreateConnection)
19601960
} else if self.peek_keywords(&[MATERIALIZED, VIEW])
19611961
|| self.peek_keywords(&[OR, REPLACE, MATERIALIZED, VIEW])
1962+
|| self.peek_keywords(&[REPLACEMENT, MATERIALIZED, VIEW])
1963+
|| self.peek_keywords(&[OR, REPLACE, REPLACEMENT, MATERIALIZED, VIEW])
19621964
{
19631965
self.parse_create_materialized_view()
19641966
.map_parser_err(StatementKind::CreateMaterializedView)
@@ -3855,17 +3857,20 @@ impl<'a> Parser<'a> {
38553857
} else {
38563858
IfExistsBehavior::Error
38573859
};
3860+
let replacement = self.parse_keyword(REPLACEMENT);
38583861
self.expect_keywords(&[MATERIALIZED, VIEW])?;
38593862
if if_exists == IfExistsBehavior::Error && self.parse_if_not_exists()? {
38603863
if_exists = IfExistsBehavior::Skip;
38613864
}
38623865

38633866
let name = self.parse_item_name()?;
38643867
let columns = self.parse_parenthesized_column_list(Optional)?;
3865-
let replacing = self
3866-
.parse_keyword(REPLACING)
3867-
.then(|| self.parse_raw_name())
3868-
.transpose()?;
3868+
let replacement_for = if replacement {
3869+
self.expect_keyword(FOR)?;
3870+
Some(self.parse_raw_name()?)
3871+
} else {
3872+
None
3873+
};
38693874
let in_cluster = self.parse_optional_in_cluster()?;
38703875

38713876
let with_options = if self.parse_keyword(WITH) {
@@ -3886,7 +3891,7 @@ impl<'a> Parser<'a> {
38863891
if_exists,
38873892
name,
38883893
columns,
3889-
replacing,
3894+
replacement_for,
38903895
in_cluster,
38913896
query,
38923897
as_of,

0 commit comments

Comments
 (0)