Disallow COPY FREEZE on partitioned tables

This didn't actually work: COPY would fail to flush the right files, and
instead would try to flush a non-existing file, causing the whole
transaction to fail.

Cope by raising an error as soon as the command is sent instead, to
avoid a nasty later surprise.  Of course, it would be much better to
make it work, but we don't have a patch for that yet, and we don't know
if we'll want to backpatch one when we do.

Reported-by: Tomas Vondra
Author: David Rowley
Reviewed-by: Amit Langote, Steve Singer, Tomas Vondra
This commit is contained in:
Alvaro Herrera 2018-11-19 11:16:28 -03:00
parent fc47e99a15
commit 5c9a5513a3
5 changed files with 44 additions and 5 deletions

View File

@ -1535,8 +1535,8 @@ SELECT * FROM x, y, a, b, c WHERE something AND somethingelse;
needs to be written, because in case of an error, the files
containing the newly loaded data will be removed anyway.
However, this consideration only applies when
<xref linkend="guc-wal-level"/> is <literal>minimal</literal> as all commands
must write WAL otherwise.
<xref linkend="guc-wal-level"/> is <literal>minimal</literal> for
non-partitioned tables as all commands must write WAL otherwise.
</para>
</sect2>

View File

@ -224,7 +224,9 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
This is intended as a performance option for initial data loading.
Rows will be frozen only if the table being loaded has been created
or truncated in the current subtransaction, there are no cursors
open and there are no older snapshots held by this transaction.
open and there are no older snapshots held by this transaction. It is
currently not possible to perform a <command>COPY FREEZE</command> on
a partitioned table.
</para>
<para>
Note that all other sessions will immediately be able to see the data

View File

@ -2416,11 +2416,20 @@ CopyFrom(CopyState cstate)
* go into pages containing tuples from any other transactions --- but this
* must be the case if we have a new table or new relfilenode, so we need
* no additional work to enforce that.
*
* We currently don't support this optimization if the COPY target is a
* partitioned table as we currently only lazily initialize partition
* information when routing the first tuple to the partition. We cannot
* know at this stage if we can perform this optimization. It should be
* possible to improve on this, but it does mean maintaining heap insert
* option flags per partition and setting them when we first open the
* partition.
*----------
*/
/* createSubid is creation check, newRelfilenodeSubid is truncation check */
if (cstate->rel->rd_createSubid != InvalidSubTransactionId ||
cstate->rel->rd_newRelfilenodeSubid != InvalidSubTransactionId)
if (cstate->rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE &&
(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
cstate->rel->rd_newRelfilenodeSubid != InvalidSubTransactionId))
{
hi_options |= HEAP_INSERT_SKIP_FSM;
if (!XLogIsNeeded())
@ -2440,6 +2449,22 @@ CopyFrom(CopyState cstate)
*/
if (cstate->freeze)
{
/*
* We currently disallow COPY FREEZE on partitioned tables. The
* reason for this is that we've simply not yet opened the partitions
* to determine if the optimization can be applied to them. We could
* go and open them all here, but doing so may be quite a costly
* overhead for small copies. In any case, we may just end up routing
* tuples to a small number of partitions. It seems better just to
* raise an ERROR for partitioned tables.
*/
if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
{
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot perform FREEZE on a partitioned table")));
}
/*
* Tolerate one registration for the benefit of FirstXactSnapshot.
* Scan-bearing queries generally create at least two registrations,

View File

@ -159,6 +159,12 @@ truncate parted_copytest;
copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
-- Ensure COPY FREEZE errors for partitioned tables.
begin;
truncate parted_copytest;
copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' (freeze);
rollback;
select tableoid::regclass,count(*),sum(a) from parted_copytest
group by tableoid order by tableoid::regclass::name;

View File

@ -113,6 +113,12 @@ insert into parted_copytest select x,1,'One' from generate_series(1011,1020) x;
copy (select * from parted_copytest order by a) to '@abs_builddir@/results/parted_copytest.csv';
truncate parted_copytest;
copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
-- Ensure COPY FREEZE errors for partitioned tables.
begin;
truncate parted_copytest;
copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' (freeze);
ERROR: cannot perform FREEZE on a partitioned table
rollback;
select tableoid::regclass,count(*),sum(a) from parted_copytest
group by tableoid order by tableoid::regclass::name;
tableoid | count | sum