Stuart Bishop wrote:
> >I don't think the committed patch touches anything involved in what
> >you're testing, but if you could grab CVS tip from the 8.4 branch (or
> >the snapshot from ftp.postgresql.org:/pub/snapshot/stable/8.4 ) and give
> >it a try, that'd be great.
>
> I trigger the same error with a freshly built snapshot.
If you're up for a bit of patching, please test with the attached patch
applied.
--
Alvaro Herrera http://www.CommandPrompt.com/
The PostgreSQL Company - Command Prompt, Inc.
Index: src/backend/commands/portalcmds.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/commands/portalcmds.c,v
retrieving revision 1.79.2.1
diff -c -p -r1.79.2.1 portalcmds.c
*** src/backend/commands/portalcmds.c 2 Oct 2009 17:58:21 -0000 1.79.2.1
--- src/backend/commands/portalcmds.c 6 Oct 2009 19:54:21 -0000
*************** PerformCursorOpen(PlannedStmt *stmt, Par
*** 47,53 ****
DeclareCursorStmt *cstmt = (DeclareCursorStmt *) stmt->utilityStmt;
Portal portal;
MemoryContext oldContext;
- Snapshot snapshot;
if (cstmt == NULL || !IsA(cstmt, DeclareCursorStmt))
elog(ERROR, "PerformCursorOpen called for non-cursor query");
--- 47,52 ----
*************** PerformCursorOpen(PlannedStmt *stmt, Par
*** 120,136 ****
}
/*
- * Set up snapshot for portal. Note that we need a fresh, independent copy
- * of the snapshot because we don't want it to be modified by future
- * CommandCounterIncrement calls. We do not register it, because
- * portalmem.c will take care of that internally.
- */
- snapshot = CopySnapshot(GetActiveSnapshot());
-
- /*
* Start execution, inserting parameters if any.
*/
! PortalStart(portal, params, snapshot);
Assert(portal->strategy == PORTAL_ONE_SELECT);
--- 119,127 ----
}
/*
* Start execution, inserting parameters if any.
*/
! PortalStart(portal, params, GetActiveSnapshot());
Assert(portal->strategy == PORTAL_ONE_SELECT);
Index: src/backend/utils/time/snapmgr.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/utils/time/snapmgr.c,v
retrieving revision 1.10.2.1
diff -c -p -r1.10.2.1 snapmgr.c
*** src/backend/utils/time/snapmgr.c 2 Oct 2009 17:58:21 -0000 1.10.2.1
--- src/backend/utils/time/snapmgr.c 6 Oct 2009 19:54:21 -0000
*************** bool FirstSnapshotSet = false;
*** 104,109 ****
--- 104,110 ----
static bool registered_serializable = false;
+ static Snapshot CopySnapshot(Snapshot snapshot);
static void FreeSnapshot(Snapshot snapshot);
static void SnapshotResetXmin(void);
*************** SnapshotSetCommandId(CommandId curcid)
*** 191,197 ****
* The copy is palloc'd in TopTransactionContext and has initial refcounts set
* to 0. The returned snapshot has the copied flag set.
*/
! Snapshot
CopySnapshot(Snapshot snapshot)
{
Snapshot newsnap;
--- 192,198 ----
* The copy is palloc'd in TopTransactionContext and has initial refcounts set
* to 0. The returned snapshot has the copied flag set.
*/
! static Snapshot
CopySnapshot(Snapshot snapshot)
{
Snapshot newsnap;
*************** FreeSnapshot(Snapshot snapshot)
*** 254,261 ****
* PushActiveSnapshot
* Set the given snapshot as the current active snapshot
*
! * If this is the first use of this snapshot, create a new long-lived copy with
! * active refcount=1. Otherwise, only increment the refcount.
*/
void
PushActiveSnapshot(Snapshot snap)
--- 255,263 ----
* PushActiveSnapshot
* Set the given snapshot as the current active snapshot
*
! * If the passed snapshot is a statically-allocated one, or it is possibly
! * subject to a future command counter update, create a new long-lived copy
! * with active refcount=1. Otherwise, only increment the refcount.
*/
void
PushActiveSnapshot(Snapshot snap)
*************** PushActiveSnapshot(Snapshot snap)
*** 265,272 ****
Assert(snap != InvalidSnapshot);
newactive = MemoryContextAlloc(TopTransactionContext, sizeof(ActiveSnapshotElt));
! /* Static snapshot? Create a persistent copy */
! newactive->as_snap = snap->copied ? snap : CopySnapshot(snap);
newactive->as_next = ActiveSnapshot;
newactive->as_level = GetCurrentTransactionNestLevel();
--- 267,282 ----
Assert(snap != InvalidSnapshot);
newactive = MemoryContextAlloc(TopTransactionContext, sizeof(ActiveSnapshotElt));
!
! /*
! * Checking SecondarySnapshot is probably useless here, but it seems better
! * to be sure.
! */
! if (snap == CurrentSnapshot || snap == SecondarySnapshot || !snap->copied)
! newactive->as_snap = CopySnapshot(snap);
! else
! newactive->as_snap = snap;
!
newactive->as_next = ActiveSnapshot;
newactive->as_level = GetCurrentTransactionNestLevel();
Index: src/include/utils/snapmgr.h
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/include/utils/snapmgr.h,v
retrieving revision 1.5.2.1
diff -c -p -r1.5.2.1 snapmgr.h
*** src/include/utils/snapmgr.h 2 Oct 2009 17:58:21 -0000 1.5.2.1
--- src/include/utils/snapmgr.h 6 Oct 2009 19:54:21 -0000
*************** extern TransactionId RecentGlobalXmin;
*** 26,32 ****
extern Snapshot GetTransactionSnapshot(void);
extern Snapshot GetLatestSnapshot(void);
extern void SnapshotSetCommandId(CommandId curcid);
- extern Snapshot CopySnapshot(Snapshot snapshot);
extern void PushActiveSnapshot(Snapshot snapshot);
extern void PushUpdatedSnapshot(Snapshot snapshot);
--- 26,31 ----
Index: src/test/regress/expected/triggers.out
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/test/regress/expected/triggers.out,v
retrieving revision 1.26
diff -c -p -r1.26 triggers.out
*** src/test/regress/expected/triggers.out 5 Nov 2008 18:49:28 -0000 1.26
--- src/test/regress/expected/triggers.out 6 Oct 2009 19:54:21 -0000
*************** NOTICE: row 1 not changed
*** 537,542 ****
--- 537,573 ----
NOTICE: row 2 not changed
DROP TABLE trigger_test;
DROP FUNCTION mytrigger();
+ -- Test snapshot management in serializable transactions involving triggers
+ -- per bug report in [email protected]
+ CREATE FUNCTION serializable_update_trig() RETURNS trigger LANGUAGE plpgsql AS
+ $$
+ declare
+ rec record;
+ begin
+ new.description = 'updated in trigger';
+ return new;
+ end;
+ $$;
+ CREATE TABLE serializable_update_tab (
+ id int,
+ filler text,
+ description text
+ );
+ CREATE TRIGGER serializable_update_trig BEFORE UPDATE ON serializable_update_tab
+ FOR EACH ROW EXECUTE PROCEDURE serializable_update_trig();
+ INSERT INTO serializable_update_tab SELECT a, repeat('xyzxz', 100), 'new'
+ FROM generate_series(1, 50) a;
+ BEGIN;
+ SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
+ UPDATE serializable_update_tab SET description = 'no no', id = 1 WHERE id = 1;
+ COMMIT;
+ SELECT description FROM serializable_update_tab WHERE id = 1;
+ description
+ --------------------
+ updated in trigger
+ (1 row)
+
+ DROP TABLE serializable_update_tab;
-- minimal update trigger
CREATE TABLE min_updates_test (
f1 text,
Index: src/test/regress/sql/triggers.sql
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/test/regress/sql/triggers.sql,v
retrieving revision 1.15
diff -c -p -r1.15 triggers.sql
*** src/test/regress/sql/triggers.sql 5 Nov 2008 18:49:28 -0000 1.15
--- src/test/regress/sql/triggers.sql 6 Oct 2009 19:54:21 -0000
*************** DROP TABLE trigger_test;
*** 416,421 ****
--- 416,451 ----
DROP FUNCTION mytrigger();
+ -- Test snapshot management in serializable transactions involving triggers
+ -- per bug report in [email protected]
+ CREATE FUNCTION serializable_update_trig() RETURNS trigger LANGUAGE plpgsql AS
+ $$
+ declare
+ rec record;
+ begin
+ new.description = 'updated in trigger';
+ return new;
+ end;
+ $$;
+
+ CREATE TABLE serializable_update_tab (
+ id int,
+ filler text,
+ description text
+ );
+
+ CREATE TRIGGER serializable_update_trig BEFORE UPDATE ON serializable_update_tab
+ FOR EACH ROW EXECUTE PROCEDURE serializable_update_trig();
+
+ INSERT INTO serializable_update_tab SELECT a, repeat('xyzxz', 100), 'new'
+ FROM generate_series(1, 50) a;
+
+ BEGIN;
+ SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
+ UPDATE serializable_update_tab SET description = 'no no', id = 1 WHERE id = 1;
+ COMMIT;
+ SELECT description FROM serializable_update_tab WHERE id = 1;
+ DROP TABLE serializable_update_tab;
-- minimal update trigger
--
Sent via pgsql-general mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-general