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 6bc73d4c0910042358k3d1adff3qa36f8df75198ecea@xxxxxxxxxxxxxx + 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 6bc73d4c0910042358k3d1adff3qa36f8df75198ecea@xxxxxxxxxxxxxx + 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 (pgsql-general@xxxxxxxxxxxxxx) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-general