diff --git a/src/backend/commands/portalcmds.c b/src/backend/commands/portalcmds.c
index 3ffdbff4695cede49546a1442731061d908e7bc1..0644ffc72b47a216cb7b7656acbb5f6f6964d092 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.80 2009/10/02 17:57:29 alvherre Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/portalcmds.c,v 1.81 2009/10/07 16:27:18 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");
@@ -119,18 +118,10 @@ PerformCursorOpen(PlannedStmt *stmt, ParamListInfo params,
 			portal->cursorOptions |= CURSOR_OPT_NO_SCROLL;
 	}
 
-	/*
-	 * 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 f8531276a470d67db30b80c48937d8609972d498..41ff3405a396f57da997b2c5144cd9b98194b795 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.11 2009/10/02 17:57:30 alvherre Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/time/snapmgr.c,v 1.12 2009/10/07 16:27:18 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 a82e53bb17a7382b1aba436c63c7046e1eb78835..d52051a9166333938df85a4a50c2a8777752b242 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.6 2009/10/02 17:57:30 alvherre Exp $
+ * $PostgreSQL: pgsql/src/include/utils/snapmgr.h,v 1.7 2009/10/07 16:27:18 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 2a5cb909d7027ec9ee0b6d9e940354c0e107378a..c0b7645600dcc5fbf257a6dfaa47b036ad1f77b5 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 8530030ef8b8083ceb07e71919881b654775dbb3..878adbb0d4b5c44b9c296103b7a67f1751e4dd81 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