Skip to content

Commit 534874f

Browse files
committed
Allow "COPY table TO" command to copy rows from materialized views.
Previously, "COPY table TO" command worked only with plain tables and did not support materialized views, even when they were populated and had physical storage. To copy rows from materialized views, "COPY (query) TO" command had to be used, instead. This commit extends "COPY table TO" to support populated materialized views directly, improving usability and performance, as "COPY table TO" is generally faster than "COPY (query) TO". Note that copying from unpopulated materialized views will still result in an error. Author: jian he <jian.universality@gmail.com> Reviewed-by: Kirill Reshke <reshkekirill@gmail.com> Reviewed-by: David G. Johnston <david.g.johnston@gmail.com> Reviewed-by: Vignesh C <vignesh21@gmail.com> Reviewed-by: Fujii Masao <masao.fujii@gmail.com> Discussion: https://postgr.es/m/CACJufxHVxnyRYy67hiPePNCPwVBMzhTQ6FaL9_Te5On9udG=yg@mail.gmail.com
1 parent 9ef1851 commit 534874f

File tree

4 files changed

+39
-15
lines changed

4 files changed

+39
-15
lines changed

doc/src/sgml/ref/copy.sgml

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -520,16 +520,16 @@ COPY <replaceable class="parameter">count</replaceable>
520520
<title>Notes</title>
521521

522522
<para>
523-
<command>COPY TO</command> can be used only with plain
524-
tables, not views, and does not copy rows from child tables
525-
or child partitions. For example, <literal>COPY <replaceable
526-
class="parameter">table</replaceable> TO</literal> copies
527-
the same rows as <literal>SELECT * FROM ONLY <replaceable
528-
class="parameter">table</replaceable></literal>.
529-
The syntax <literal>COPY (SELECT * FROM <replaceable
530-
class="parameter">table</replaceable>) TO ...</literal> can be used to
531-
dump all of the rows in an inheritance hierarchy, partitioned table,
532-
or view.
523+
<command>COPY TO</command> can be used with plain
524+
tables and populated materialized views.
525+
For example,
526+
<literal>COPY <replaceable class="parameter">table</replaceable>
527+
TO</literal> copies the same rows as
528+
<literal>SELECT * FROM ONLY <replaceable class="parameter">table</replaceable></literal>.
529+
However it doesn't directly support other relation types,
530+
such as partitioned tables, inheritance child tables, or views.
531+
To copy all rows from such relations, use <literal>COPY (SELECT * FROM
532+
<replaceable class="parameter">table</replaceable>) TO</literal>.
533533
</para>
534534

535535
<para>

src/backend/commands/copyto.c

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -653,11 +653,14 @@ BeginCopyTo(ParseState *pstate,
653653
RelationGetRelationName(rel)),
654654
errhint("Try the COPY (SELECT ...) TO variant.")));
655655
else if (rel->rd_rel->relkind == RELKIND_MATVIEW)
656-
ereport(ERROR,
657-
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
658-
errmsg("cannot copy from materialized view \"%s\"",
659-
RelationGetRelationName(rel)),
660-
errhint("Try the COPY (SELECT ...) TO variant.")));
656+
{
657+
if (!RelationIsPopulated(rel))
658+
ereport(ERROR,
659+
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
660+
errmsg("cannot copy from unpopulated materialized view \"%s\"",
661+
RelationGetRelationName(rel)),
662+
errhint("Use the REFRESH MATERIALIZED VIEW command."));
663+
}
661664
else if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
662665
ereport(ERROR,
663666
(errcode(ERRCODE_WRONG_OBJECT_TYPE),

src/test/regress/expected/copy.out

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,3 +338,15 @@ create foreign table copytest_foreign_table (a int) server copytest_server;
338338
copy copytest_foreign_table from stdin (freeze);
339339
ERROR: cannot perform COPY FREEZE on a foreign table
340340
rollback;
341+
-- Tests for COPY TO with materialized views.
342+
-- COPY TO should fail for an unpopulated materialized view
343+
-- but succeed for a populated one.
344+
CREATE MATERIALIZED VIEW copytest_mv AS SELECT 1 AS id WITH NO DATA;
345+
COPY copytest_mv(id) TO stdout WITH (header);
346+
ERROR: cannot copy from unpopulated materialized view "copytest_mv"
347+
HINT: Use the REFRESH MATERIALIZED VIEW command.
348+
REFRESH MATERIALIZED VIEW copytest_mv;
349+
COPY copytest_mv(id) TO stdout WITH (header);
350+
id
351+
1
352+
DROP MATERIALIZED VIEW copytest_mv;

src/test/regress/sql/copy.sql

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,3 +366,12 @@ copy copytest_foreign_table from stdin (freeze);
366366
1
367367
\.
368368
rollback;
369+
370+
-- Tests for COPY TO with materialized views.
371+
-- COPY TO should fail for an unpopulated materialized view
372+
-- but succeed for a populated one.
373+
CREATE MATERIALIZED VIEW copytest_mv AS SELECT 1 AS id WITH NO DATA;
374+
COPY copytest_mv(id) TO stdout WITH (header);
375+
REFRESH MATERIALIZED VIEW copytest_mv;
376+
COPY copytest_mv(id) TO stdout WITH (header);
377+
DROP MATERIALIZED VIEW copytest_mv;

0 commit comments

Comments
 (0)