would be after running the <command>VACUUM FREEZE</> command.
This is intended as a performance option for initial data loading.
Rows will be frozen only if the table being loaded has been created
- in the current subtransaction, there are no cursors open and there
- are no older snapshots held by this transaction. If those conditions
- are not met the command will continue without error though will not
- freeze rows. It is also possible in rare cases that the request
- cannot be honoured for internal reasons, hence <literal>FREEZE</literal>
- is more of a guideline than a hard rule.
+ or truncated in the current subtransaction, there are no cursors
+ open and there are no older snapshots held by this transaction.
</para>
<para>
Note that all other sessions will immediately be able to see the data
once it has been successfully loaded. This violates the normal rules
- of MVCC visibility and by specifying this option the user acknowledges
- explicitly that this is understood.
+ of MVCC visibility and users specifying should be aware of the
+ potential problems this might cause.
</para>
</listitem>
</varlistentry>
* ROLLBACK TO save;
* COPY ...
*
- * However this is OK since at worst we will fail to make the optimization.
- *
* Also, if the target file is new-in-transaction, we assume that checking
* FSM for free space is a waste of time, even if we must use WAL because
* of archiving. This could possibly be wrong, but it's unlikely.
* no additional work to enforce that.
*----------
*/
+ /* createSubid is creation check, newRelfilenodeSubid is truncation check */
if (cstate->rel->rd_createSubid != InvalidSubTransactionId ||
cstate->rel->rd_newRelfilenodeSubid != InvalidSubTransactionId)
{
* after xact cleanup. Note that the stronger test of exactly
* which subtransaction created it is crucial for correctness
* of this optimisation.
- *
- * As noted above rd_newRelfilenodeSubid is not set in all cases
- * where we can apply the optimization, so in those rare cases
- * where we cannot honour the request we do so silently.
*/
- if (cstate->freeze &&
- ThereAreNoPriorRegisteredSnapshots() &&
- ThereAreNoReadyPortals() &&
- (cstate->rel->rd_newRelfilenodeSubid == GetCurrentSubTransactionId() ||
- cstate->rel->rd_createSubid == GetCurrentSubTransactionId()))
- hi_options |= HEAP_INSERT_FROZEN;
+ if (cstate->freeze)
+ {
+ if (!ThereAreNoPriorRegisteredSnapshots() || !ThereAreNoReadyPortals())
+ ereport(ERROR,
+ (ERRCODE_INVALID_TRANSACTION_STATE,
+ errmsg("cannot perform FREEZE because of prior transaction activity")));
+
+ if (cstate->rel->rd_createSubid == GetCurrentSubTransactionId() ||
+ cstate->rel->rd_newRelfilenodeSubid == GetCurrentSubTransactionId())
+ hi_options |= HEAP_INSERT_FROZEN;
+ else
+ ereport(ERROR,
+ (ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE,
+ errmsg("cannot perform FREEZE because of transaction activity after table creation or truncation")));
+ }
}
+ else if (cstate->freeze)
+ ereport(ERROR,
+ (ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE,
+ errmsg("cannot perform FREEZE because the table was not created or truncated in the current transaction")));
/*
* We need a ResultRelInfo so we can use the regular executor's
COMMIT;
TRUNCATE vistest;
COPY vistest FROM stdin CSV FREEZE;
+ERROR: cannot perform FREEZE because the table was not created or truncated in the current transaction
+BEGIN;
+TRUNCATE vistest;
+SAVEPOINT s1;
+COPY vistest FROM stdin CSV FREEZE;
+ERROR: cannot perform FREEZE because of transaction activity after table creation or truncation
+COMMIT;
BEGIN;
INSERT INTO vistest VALUES ('z');
SAVEPOINT s1;
TRUNCATE vistest;
ROLLBACK TO SAVEPOINT s1;
COPY vistest FROM stdin CSV FREEZE;
-SELECT * FROM vistest;
- a
-----
- p
- g
- z
- d3
- e
-(5 rows)
-
+ERROR: cannot perform FREEZE because the table was not created or truncated in the current transaction
COMMIT;
CREATE FUNCTION truncate_in_subxact() RETURNS VOID AS
$$