1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-03 20:02:46 +03:00

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
This commit is contained in:
Fujii Masao
2025-04-04 19:32:00 +09:00
parent 9ef1851685
commit 534874fac0
4 changed files with 39 additions and 15 deletions

View File

@ -520,16 +520,16 @@ COPY <replaceable class="parameter">count</replaceable>
<title>Notes</title> <title>Notes</title>
<para> <para>
<command>COPY TO</command> can be used only with plain <command>COPY TO</command> can be used with plain
tables, not views, and does not copy rows from child tables tables and populated materialized views.
or child partitions. For example, <literal>COPY <replaceable For example,
class="parameter">table</replaceable> TO</literal> copies <literal>COPY <replaceable class="parameter">table</replaceable>
the same rows as <literal>SELECT * FROM ONLY <replaceable TO</literal> copies the same rows as
class="parameter">table</replaceable></literal>. <literal>SELECT * FROM ONLY <replaceable class="parameter">table</replaceable></literal>.
The syntax <literal>COPY (SELECT * FROM <replaceable However it doesn't directly support other relation types,
class="parameter">table</replaceable>) TO ...</literal> can be used to such as partitioned tables, inheritance child tables, or views.
dump all of the rows in an inheritance hierarchy, partitioned table, To copy all rows from such relations, use <literal>COPY (SELECT * FROM
or view. <replaceable class="parameter">table</replaceable>) TO</literal>.
</para> </para>
<para> <para>

View File

@ -653,11 +653,14 @@ BeginCopyTo(ParseState *pstate,
RelationGetRelationName(rel)), RelationGetRelationName(rel)),
errhint("Try the COPY (SELECT ...) TO variant."))); errhint("Try the COPY (SELECT ...) TO variant.")));
else if (rel->rd_rel->relkind == RELKIND_MATVIEW) else if (rel->rd_rel->relkind == RELKIND_MATVIEW)
ereport(ERROR, {
(errcode(ERRCODE_WRONG_OBJECT_TYPE), if (!RelationIsPopulated(rel))
errmsg("cannot copy from materialized view \"%s\"", ereport(ERROR,
RelationGetRelationName(rel)), errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errhint("Try the COPY (SELECT ...) TO variant."))); errmsg("cannot copy from unpopulated materialized view \"%s\"",
RelationGetRelationName(rel)),
errhint("Use the REFRESH MATERIALIZED VIEW command."));
}
else if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE) else if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE), (errcode(ERRCODE_WRONG_OBJECT_TYPE),

View File

@ -338,3 +338,15 @@ create foreign table copytest_foreign_table (a int) server copytest_server;
copy copytest_foreign_table from stdin (freeze); copy copytest_foreign_table from stdin (freeze);
ERROR: cannot perform COPY FREEZE on a foreign table ERROR: cannot perform COPY FREEZE on a foreign table
rollback; rollback;
-- Tests for COPY TO with materialized views.
-- COPY TO should fail for an unpopulated materialized view
-- but succeed for a populated one.
CREATE MATERIALIZED VIEW copytest_mv AS SELECT 1 AS id WITH NO DATA;
COPY copytest_mv(id) TO stdout WITH (header);
ERROR: cannot copy from unpopulated materialized view "copytest_mv"
HINT: Use the REFRESH MATERIALIZED VIEW command.
REFRESH MATERIALIZED VIEW copytest_mv;
COPY copytest_mv(id) TO stdout WITH (header);
id
1
DROP MATERIALIZED VIEW copytest_mv;

View File

@ -366,3 +366,12 @@ copy copytest_foreign_table from stdin (freeze);
1 1
\. \.
rollback; rollback;
-- Tests for COPY TO with materialized views.
-- COPY TO should fail for an unpopulated materialized view
-- but succeed for a populated one.
CREATE MATERIALIZED VIEW copytest_mv AS SELECT 1 AS id WITH NO DATA;
COPY copytest_mv(id) TO stdout WITH (header);
REFRESH MATERIALIZED VIEW copytest_mv;
COPY copytest_mv(id) TO stdout WITH (header);
DROP MATERIALIZED VIEW copytest_mv;