aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/commands/portalcmds.c13
-rw-r--r--src/backend/utils/time/snapmgr.c22
-rw-r--r--src/include/utils/snapmgr.h3
-rw-r--r--src/test/regress/expected/triggers.out31
-rw-r--r--src/test/regress/sql/triggers.sql30
5 files changed, 80 insertions, 19 deletions
diff --git a/src/backend/commands/portalcmds.c b/src/backend/commands/portalcmds.c
index d31fde65b6b..f1ae01908a9 100644
--- a/src/backend/commands/portalcmds.c
+++ b/src/backend/commands/portalcmds.c
@@ -14,7 +14,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/portalcmds.c,v 1.79.2.1 2009/10/02 17:58:21 alvherre Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/portalcmds.c,v 1.79.2.2 2009/10/07 16:27:28 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
@@ -47,7 +47,6 @@ PerformCursorOpen(PlannedStmt *stmt, ParamListInfo params,
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");
@@ -120,17 +119,9 @@ PerformCursorOpen(PlannedStmt *stmt, ParamListInfo params,
}
/*
- * 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);
+ PortalStart(portal, params, GetActiveSnapshot());
Assert(portal->strategy == PORTAL_ONE_SELECT);
diff --git a/src/backend/utils/time/snapmgr.c b/src/backend/utils/time/snapmgr.c
index 12ca81616d1..9c06124ba95 100644
--- a/src/backend/utils/time/snapmgr.c
+++ b/src/backend/utils/time/snapmgr.c
@@ -19,7 +19,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/time/snapmgr.c,v 1.10.2.1 2009/10/02 17:58:21 alvherre Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/time/snapmgr.c,v 1.10.2.2 2009/10/07 16:27:28 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
@@ -104,6 +104,7 @@ bool FirstSnapshotSet = false;
static bool registered_serializable = false;
+static Snapshot CopySnapshot(Snapshot snapshot);
static void FreeSnapshot(Snapshot snapshot);
static void SnapshotResetXmin(void);
@@ -191,7 +192,7 @@ SnapshotSetCommandId(CommandId curcid)
* The copy is palloc'd in TopTransactionContext and has initial refcounts set
* to 0. The returned snapshot has the copied flag set.
*/
-Snapshot
+static Snapshot
CopySnapshot(Snapshot snapshot)
{
Snapshot newsnap;
@@ -254,8 +255,9 @@ FreeSnapshot(Snapshot snapshot)
* 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.
+ * 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)
@@ -265,8 +267,16 @@ PushActiveSnapshot(Snapshot snap)
Assert(snap != InvalidSnapshot);
newactive = MemoryContextAlloc(TopTransactionContext, sizeof(ActiveSnapshotElt));
- /* Static snapshot? Create a persistent copy */
- newactive->as_snap = snap->copied ? snap : CopySnapshot(snap);
+
+ /*
+ * 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();
diff --git a/src/include/utils/snapmgr.h b/src/include/utils/snapmgr.h
index d2186116023..b0d0f5149d8 100644
--- a/src/include/utils/snapmgr.h
+++ b/src/include/utils/snapmgr.h
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/utils/snapmgr.h,v 1.5.2.1 2009/10/02 17:58:21 alvherre Exp $
+ * $PostgreSQL: pgsql/src/include/utils/snapmgr.h,v 1.5.2.2 2009/10/07 16:27:29 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
@@ -26,7 +26,6 @@ extern TransactionId RecentGlobalXmin;
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);
diff --git a/src/test/regress/expected/triggers.out b/src/test/regress/expected/triggers.out
index 2a5cb909d70..c0b7645600d 100644
--- a/src/test/regress/expected/triggers.out
+++ b/src/test/regress/expected/triggers.out
@@ -537,6 +537,37 @@ NOTICE: row 1 not changed
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@mail.gmail.com
+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,
diff --git a/src/test/regress/sql/triggers.sql b/src/test/regress/sql/triggers.sql
index 8530030ef8b..878adbb0d4b 100644
--- a/src/test/regress/sql/triggers.sql
+++ b/src/test/regress/sql/triggers.sql
@@ -416,6 +416,36 @@ DROP TABLE trigger_test;
DROP FUNCTION mytrigger();
+-- Test snapshot management in serializable transactions involving triggers
+-- per bug report in 6bc73d4c0910042358k3d1adff3qa36f8df75198ecea@mail.gmail.com
+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