On Fri, Jan 25, 2013 at 11:08:56PM -0500, Tom Lane wrote:
> Bruce Momjian <[email protected]> writes:
> > ! ereport(ERROR,
> > !
> > (ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE,
> > ! errmsg("cannot perform FREEZE
> > because of previous table activity in the current transaction")));
>
> [ itch... ] What is "table activity"? I always thought of tables as
> being rather passive objects. And anyway, isn't this backwards? What
> we're complaining of is *lack* of activity. I don't see why this isn't
> using the same message as the other code path, namely
Well, here is an example of this message:
BEGIN;
TRUNCATE vistest;
SAVEPOINT s1;
COPY vistest FROM stdin CSV FREEZE;
ERROR: cannot perform FREEZE because of previous table activity in the
current transaction
COMMIT;
Clearly it was truncated in the same transaction, but the savepoint
somehow invalidates the freeze. There is a C comment about it:
* BEGIN;
* TRUNCATE t;
* SAVEPOINT save;
* TRUNCATE t;
* ROLLBACK TO save;
* COPY ...
I changed it to:
ERROR: cannot perform FREEZE because of transaction activity after
table creation or truncation
--
Bruce Momjian <[email protected]> http://momjian.us
EnterpriseDB http://enterprisedb.com
+ It's impossible for everything to be true. +
diff --git a/doc/src/sgml/ref/copy.sgml b/doc/src/sgml/ref/copy.sgml
new file mode 100644
index 6a0fabc..2137c67
*** a/doc/src/sgml/ref/copy.sgml
--- b/doc/src/sgml/ref/copy.sgml
*************** COPY { <replaceable class="parameter">ta
*** 190,207 ****
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.
</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.
</para>
</listitem>
</varlistentry>
--- 190,203 ----
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
! 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 users specifying should be aware of the
! potential problems this might cause.
</para>
</listitem>
</varlistentry>
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
new file mode 100644
index 8778e8b..49cc8dd
*** a/src/backend/commands/copy.c
--- b/src/backend/commands/copy.c
*************** CopyFrom(CopyState cstate)
*** 1978,1985 ****
* 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.
--- 1978,1983 ----
*************** CopyFrom(CopyState cstate)
*** 1991,1996 ****
--- 1989,1995 ----
* 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)
{
*************** CopyFrom(CopyState cstate)
*** 2006,2023 ****
* 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;
}
/*
* We need a ResultRelInfo so we can use the regular executor's
--- 2005,2031 ----
* after xact cleanup. Note that the stronger test of exactly
* which subtransaction created it is crucial for correctness
* of this optimisation.
*/
! 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
diff --git a/src/test/regress/expected/copy2.out b/src/test/regress/expected/copy2.out
new file mode 100644
index 78c601f..5777b24
*** a/src/test/regress/expected/copy2.out
--- b/src/test/regress/expected/copy2.out
*************** SELECT * FROM vistest;
*** 334,355 ****
COMMIT;
TRUNCATE vistest;
COPY vistest FROM stdin CSV FREEZE;
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)
!
COMMIT;
CREATE FUNCTION truncate_in_subxact() RETURNS VOID AS
$$
--- 334,353 ----
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;
! 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
$$
diff --git a/src/test/regress/sql/copy2.sql b/src/test/regress/sql/copy2.sql
new file mode 100644
index 55568e6..c46128b
*** a/src/test/regress/sql/copy2.sql
--- b/src/test/regress/sql/copy2.sql
*************** p
*** 234,239 ****
--- 234,247 ----
g
\.
BEGIN;
+ TRUNCATE vistest;
+ SAVEPOINT s1;
+ COPY vistest FROM stdin CSV FREEZE;
+ m
+ k
+ \.
+ COMMIT;
+ BEGIN;
INSERT INTO vistest VALUES ('z');
SAVEPOINT s1;
TRUNCATE vistest;
*************** COPY vistest FROM stdin CSV FREEZE;
*** 242,248 ****
d3
e
\.
- SELECT * FROM vistest;
COMMIT;
CREATE FUNCTION truncate_in_subxact() RETURNS VOID AS
$$
--- 250,255 ----
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers