Skip to content

Commit 4deb57d

Browse files
committed
Issue ERROR if FREEZE mode can't be honored by COPY
Previously non-honored FREEZE mode was ignored. This also issues an appropriate error message based on the cause of the failure, per suggestion from Tom. Additional regression test case added.
1 parent 7e2322d commit 4deb57d

File tree

4 files changed

+40
-31
lines changed

4 files changed

+40
-31
lines changed

doc/src/sgml/ref/copy.sgml

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -190,18 +190,14 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
190190
would be after running the <command>VACUUM FREEZE</> command.
191191
This is intended as a performance option for initial data loading.
192192
Rows will be frozen only if the table being loaded has been created
193-
in the current subtransaction, there are no cursors open and there
194-
are no older snapshots held by this transaction. If those conditions
195-
are not met the command will continue without error though will not
196-
freeze rows. It is also possible in rare cases that the request
197-
cannot be honoured for internal reasons, hence <literal>FREEZE</literal>
198-
is more of a guideline than a hard rule.
193+
or truncated in the current subtransaction, there are no cursors
194+
open and there are no older snapshots held by this transaction.
199195
</para>
200196
<para>
201197
Note that all other sessions will immediately be able to see the data
202198
once it has been successfully loaded. This violates the normal rules
203-
of MVCC visibility and by specifying this option the user acknowledges
204-
explicitly that this is understood.
199+
of MVCC visibility and users specifying should be aware of the
200+
potential problems this might cause.
205201
</para>
206202
</listitem>
207203
</varlistentry>

src/backend/commands/copy.c

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1978,8 +1978,6 @@ CopyFrom(CopyState cstate)
19781978
* ROLLBACK TO save;
19791979
* COPY ...
19801980
*
1981-
* However this is OK since at worst we will fail to make the optimization.
1982-
*
19831981
* Also, if the target file is new-in-transaction, we assume that checking
19841982
* FSM for free space is a waste of time, even if we must use WAL because
19851983
* of archiving. This could possibly be wrong, but it's unlikely.
@@ -1991,6 +1989,7 @@ CopyFrom(CopyState cstate)
19911989
* no additional work to enforce that.
19921990
*----------
19931991
*/
1992+
/* createSubid is creation check, newRelfilenodeSubid is truncation check */
19941993
if (cstate->rel->rd_createSubid != InvalidSubTransactionId ||
19951994
cstate->rel->rd_newRelfilenodeSubid != InvalidSubTransactionId)
19961995
{
@@ -2006,18 +2005,27 @@ CopyFrom(CopyState cstate)
20062005
* after xact cleanup. Note that the stronger test of exactly
20072006
* which subtransaction created it is crucial for correctness
20082007
* of this optimisation.
2009-
*
2010-
* As noted above rd_newRelfilenodeSubid is not set in all cases
2011-
* where we can apply the optimization, so in those rare cases
2012-
* where we cannot honour the request we do so silently.
20132008
*/
2014-
if (cstate->freeze &&
2015-
ThereAreNoPriorRegisteredSnapshots() &&
2016-
ThereAreNoReadyPortals() &&
2017-
(cstate->rel->rd_newRelfilenodeSubid == GetCurrentSubTransactionId() ||
2018-
cstate->rel->rd_createSubid == GetCurrentSubTransactionId()))
2019-
hi_options |= HEAP_INSERT_FROZEN;
2009+
if (cstate->freeze)
2010+
{
2011+
if (!ThereAreNoPriorRegisteredSnapshots() || !ThereAreNoReadyPortals())
2012+
ereport(ERROR,
2013+
(ERRCODE_INVALID_TRANSACTION_STATE,
2014+
errmsg("cannot perform FREEZE because of prior transaction activity")));
2015+
2016+
if (cstate->rel->rd_createSubid == GetCurrentSubTransactionId() ||
2017+
cstate->rel->rd_newRelfilenodeSubid == GetCurrentSubTransactionId())
2018+
hi_options |= HEAP_INSERT_FROZEN;
2019+
else
2020+
ereport(ERROR,
2021+
(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE,
2022+
errmsg("cannot perform FREEZE because of transaction activity after table creation or truncation")));
2023+
}
20202024
}
2025+
else if (cstate->freeze)
2026+
ereport(ERROR,
2027+
(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE,
2028+
errmsg("cannot perform FREEZE because the table was not created or truncated in the current transaction")));
20212029

20222030
/*
20232031
* We need a ResultRelInfo so we can use the regular executor's

src/test/regress/expected/copy2.out

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -334,22 +334,20 @@ SELECT * FROM vistest;
334334
COMMIT;
335335
TRUNCATE vistest;
336336
COPY vistest FROM stdin CSV FREEZE;
337+
ERROR: cannot perform FREEZE because the table was not created or truncated in the current transaction
338+
BEGIN;
339+
TRUNCATE vistest;
340+
SAVEPOINT s1;
341+
COPY vistest FROM stdin CSV FREEZE;
342+
ERROR: cannot perform FREEZE because of transaction activity after table creation or truncation
343+
COMMIT;
337344
BEGIN;
338345
INSERT INTO vistest VALUES ('z');
339346
SAVEPOINT s1;
340347
TRUNCATE vistest;
341348
ROLLBACK TO SAVEPOINT s1;
342349
COPY vistest FROM stdin CSV FREEZE;
343-
SELECT * FROM vistest;
344-
a
345-
----
346-
p
347-
g
348-
z
349-
d3
350-
e
351-
(5 rows)
352-
350+
ERROR: cannot perform FREEZE because the table was not created or truncated in the current transaction
353351
COMMIT;
354352
CREATE FUNCTION truncate_in_subxact() RETURNS VOID AS
355353
$$

src/test/regress/sql/copy2.sql

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,14 @@ p
234234
g
235235
\.
236236
BEGIN;
237+
TRUNCATE vistest;
238+
SAVEPOINT s1;
239+
COPY vistest FROM stdin CSV FREEZE;
240+
m
241+
k
242+
\.
243+
COMMIT;
244+
BEGIN;
237245
INSERT INTO vistest VALUES ('z');
238246
SAVEPOINT s1;
239247
TRUNCATE vistest;
@@ -242,7 +250,6 @@ COPY vistest FROM stdin CSV FREEZE;
242250
d3
243251
e
244252
\.
245-
SELECT * FROM vistest;
246253
COMMIT;
247254
CREATE FUNCTION truncate_in_subxact() RETURNS VOID AS
248255
$$

0 commit comments

Comments
 (0)