Skip to content

Commit 36a8e9b

Browse files
ewieCommitfest Bot
authored andcommitted
Add WITH OLD DATA to CREATE OR REPLACE MATERIALIZED VIEW
This keeps the matview populated when replacing its definition.
1 parent acf3ebb commit 36a8e9b

File tree

6 files changed

+84
-12
lines changed

6 files changed

+84
-12
lines changed

doc/src/sgml/ref/create_materialized_view.sgml

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ CREATE [ OR REPLACE ] MATERIALIZED VIEW [ IF NOT EXISTS ] <replaceable>table_nam
2727
[ WITH ( <replaceable class="parameter">storage_parameter</replaceable> [= <replaceable class="parameter">value</replaceable>] [, ... ] ) ]
2828
[ TABLESPACE <replaceable class="parameter">tablespace_name</replaceable> ]
2929
AS <replaceable>query</replaceable>
30-
[ WITH [ NO ] DATA ]
30+
[ WITH [ NO | OLD ] DATA ]
3131
</synopsis>
3232
</refsynopsisdiv>
3333

@@ -37,7 +37,8 @@ CREATE [ OR REPLACE ] MATERIALIZED VIEW [ IF NOT EXISTS ] <replaceable>table_nam
3737
<para>
3838
<command>CREATE MATERIALIZED VIEW</command> defines a materialized view of
3939
a query. The query is executed and used to populate the view at the time
40-
the command is issued (unless <command>WITH NO DATA</command> is used) and may be
40+
the command is issued (unless <command>WITH NO DATA</command> or
41+
<command>WITH OLD DATA</command> is used) and may be
4142
refreshed later using <command>REFRESH MATERIALIZED VIEW</command>.
4243
</para>
4344

@@ -162,14 +163,22 @@ CREATE [ OR REPLACE ] MATERIALIZED VIEW [ IF NOT EXISTS ] <replaceable>table_nam
162163
</varlistentry>
163164

164165
<varlistentry>
165-
<term><literal>WITH [ NO ] DATA</literal></term>
166+
<term><literal>WITH [ NO | OLD ] DATA</literal></term>
166167
<listitem>
167168
<para>
168169
This clause specifies whether or not the materialized view should be
169170
populated at creation time. If not, the materialized view will be
170171
flagged as unscannable and cannot be queried until <command>REFRESH
171172
MATERIALIZED VIEW</command> is used.
172173
</para>
174+
175+
<para>
176+
The form <command>WITH OLD DATA</command> keeps the already stored data
177+
when replacing an existing materialized view to keep it populated. Use
178+
this form if you want to use <command>REFRESH MATERIALIZED VIEW CONCURRENTLY</command>
179+
as it requires a populated materialized view. It is an error to use this
180+
form when creating a new materialized view.
181+
</para>
173182
</listitem>
174183
</varlistentry>
175184

src/backend/commands/createas.c

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -329,18 +329,26 @@ ExecCreateTableAs(ParseState *pstate, CreateTableAsStmt *stmt,
329329
/* An existing materialized view can be replaced. */
330330
if (is_matview && into->replace)
331331
{
332-
RefreshMatViewStmt *refresh;
333-
334332
/* Change the relation to match the new query and other options. */
335-
(void) create_ctas_nodata(query->targetList, into);
333+
address = create_ctas_nodata(query->targetList, into);
334+
335+
/*
336+
* Refresh the materialized view with a fake statement unless we
337+
* must keep the old data.
338+
*/
339+
if (!into->keepData)
340+
{
341+
RefreshMatViewStmt *refresh;
342+
343+
refresh = makeNode(RefreshMatViewStmt);
344+
refresh->relation = into->rel;
345+
refresh->skipData = into->skipData;
346+
refresh->concurrent = false;
336347

337-
/* Refresh the materialized view with a fake statement. */
338-
refresh = makeNode(RefreshMatViewStmt);
339-
refresh->relation = into->rel;
340-
refresh->skipData = into->skipData;
341-
refresh->concurrent = false;
348+
address = ExecRefreshMatView(refresh, pstate->p_sourcetext, qc);
349+
}
342350

343-
return ExecRefreshMatView(refresh, pstate->p_sourcetext, qc);
351+
return address;
344352
}
345353

346354
return InvalidObjectAddress;
@@ -383,6 +391,9 @@ ExecCreateTableAs(ParseState *pstate, CreateTableAsStmt *stmt,
383391
*/
384392
if (is_matview)
385393
{
394+
if (into->keepData)
395+
elog(ERROR, "must not specify WITH OLD DATA when creating a new materialized view");
396+
386397
do_refresh = !into->skipData;
387398
into->skipData = true;
388399
}

src/backend/parser/gram.y

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4944,6 +4944,22 @@ CreateMatViewStmt:
49444944
$7->replace = true;
49454945
$$ = (Node *) ctas;
49464946
}
4947+
| CREATE OR REPLACE OptNoLog MATERIALIZED VIEW create_mv_target AS SelectStmt WITH OLD DATA_P
4948+
{
4949+
CreateTableAsStmt *ctas = makeNode(CreateTableAsStmt);
4950+
4951+
ctas->query = $9;
4952+
ctas->into = $7;
4953+
ctas->objtype = OBJECT_MATVIEW;
4954+
ctas->is_select_into = false;
4955+
ctas->if_not_exists = false;
4956+
/* cram additional flags into the IntoClause */
4957+
$7->rel->relpersistence = $4;
4958+
$7->skipData = false;
4959+
$7->keepData = true;
4960+
$7->replace = true;
4961+
$$ = (Node *) ctas;
4962+
}
49474963
;
49484964

49494965
create_mv_target:

src/include/nodes/primnodes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ typedef struct IntoClause
169169
/* materialized view's SELECT query */
170170
struct Query *viewQuery pg_node_attr(query_jumble_ignore);
171171
bool skipData; /* true for WITH NO DATA */
172+
bool keepData; /* true for WITH OLD DATA */
172173
bool replace; /* replace existing matview? */
173174
} IntoClause;
174175

src/test/regress/expected/matview.out

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,23 @@ SELECT * FROM mvtest_replace;
731731
3
732732
(1 row)
733733

734+
-- replace query but keep old data
735+
CREATE OR REPLACE MATERIALIZED VIEW mvtest_replace AS
736+
SELECT 5 AS a
737+
WITH OLD DATA;
738+
SELECT * FROM mvtest_replace;
739+
a
740+
---
741+
3
742+
(1 row)
743+
744+
REFRESH MATERIALIZED VIEW mvtest_replace;
745+
SELECT * FROM mvtest_replace;
746+
a
747+
---
748+
5
749+
(1 row)
750+
734751
-- add column
735752
CREATE OR REPLACE MATERIALIZED VIEW mvtest_replace AS
736753
SELECT 4 AS a, 1 b;
@@ -899,3 +916,8 @@ ERROR: syntax error at or near "NOT"
899916
LINE 1: CREATE OR REPLACE MATERIALIZED VIEW IF NOT EXISTS mvtest_rep...
900917
^
901918
DROP MATERIALIZED VIEW mvtest_replace;
919+
-- Clause WITH OLD DATA is not allowed when creating a new matview.
920+
CREATE OR REPLACE MATERIALIZED VIEW mvtest_replace AS
921+
SELECT 17 AS a
922+
WITH OLD DATA; -- error
923+
ERROR: must not specify WITH OLD DATA when creating a new materialized view

src/test/regress/sql/matview.sql

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,14 @@ SELECT * FROM mvtest_replace; -- error: not populated
338338
REFRESH MATERIALIZED VIEW mvtest_replace;
339339
SELECT * FROM mvtest_replace;
340340

341+
-- replace query but keep old data
342+
CREATE OR REPLACE MATERIALIZED VIEW mvtest_replace AS
343+
SELECT 5 AS a
344+
WITH OLD DATA;
345+
SELECT * FROM mvtest_replace;
346+
REFRESH MATERIALIZED VIEW mvtest_replace;
347+
SELECT * FROM mvtest_replace;
348+
341349
-- add column
342350
CREATE OR REPLACE MATERIALIZED VIEW mvtest_replace AS
343351
SELECT 4 AS a, 1 b;
@@ -431,3 +439,8 @@ CREATE OR REPLACE MATERIALIZED VIEW IF NOT EXISTS mvtest_replace AS
431439
SELECT 1 AS a;
432440

433441
DROP MATERIALIZED VIEW mvtest_replace;
442+
443+
-- Clause WITH OLD DATA is not allowed when creating a new matview.
444+
CREATE OR REPLACE MATERIALIZED VIEW mvtest_replace AS
445+
SELECT 17 AS a
446+
WITH OLD DATA; -- error

0 commit comments

Comments
 (0)