Skip to content

Commit caa4cfa

Browse files
committed
Ensure that a cursor has an immutable snapshot throughout its lifespan.
The old coding was using a regular snapshot, referenced elsewhere, that was subject to having its command counter updated. Fix by creating a private copy of the snapshot exclusively for the cursor. Backpatch to 8.4, which is when the bug was introduced during the snapshot management rewrite.
1 parent fabf75c commit caa4cfa

File tree

6 files changed

+44
-11
lines changed

6 files changed

+44
-11
lines changed

src/backend/commands/portalcmds.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
*
1515
*
1616
* IDENTIFICATION
17-
* $PostgreSQL: pgsql/src/backend/commands/portalcmds.c,v 1.79 2009/06/11 14:48:56 momjian Exp $
17+
* $PostgreSQL: pgsql/src/backend/commands/portalcmds.c,v 1.80 2009/10/02 17:57:29 alvherre Exp $
1818
*
1919
*-------------------------------------------------------------------------
2020
*/
@@ -47,6 +47,7 @@ PerformCursorOpen(PlannedStmt *stmt, ParamListInfo params,
4747
DeclareCursorStmt *cstmt = (DeclareCursorStmt *) stmt->utilityStmt;
4848
Portal portal;
4949
MemoryContext oldContext;
50+
Snapshot snapshot;
5051

5152
if (cstmt == NULL || !IsA(cstmt, DeclareCursorStmt))
5253
elog(ERROR, "PerformCursorOpen called for non-cursor query");
@@ -118,10 +119,18 @@ PerformCursorOpen(PlannedStmt *stmt, ParamListInfo params,
118119
portal->cursorOptions |= CURSOR_OPT_NO_SCROLL;
119120
}
120121

122+
/*
123+
* Set up snapshot for portal. Note that we need a fresh, independent copy
124+
* of the snapshot because we don't want it to be modified by future
125+
* CommandCounterIncrement calls. We do not register it, because
126+
* portalmem.c will take care of that internally.
127+
*/
128+
snapshot = CopySnapshot(GetActiveSnapshot());
129+
121130
/*
122131
* Start execution, inserting parameters if any.
123132
*/
124-
PortalStart(portal, params, GetActiveSnapshot());
133+
PortalStart(portal, params, snapshot);
125134

126135
Assert(portal->strategy == PORTAL_ONE_SELECT);
127136

src/backend/executor/spi.c

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.208 2009/06/11 14:48:57 momjian Exp $
11+
* $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.209 2009/10/02 17:57:30 alvherre Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -1211,10 +1211,7 @@ SPI_cursor_open_internal(const char *name, SPIPlanPtr plan,
12111211
}
12121212
}
12131213

1214-
/*
1215-
* Set up the snapshot to use. (PortalStart will do PushActiveSnapshot,
1216-
* so we skip that here.)
1217-
*/
1214+
/* Set up the snapshot to use. */
12181215
if (read_only)
12191216
snapshot = GetActiveSnapshot();
12201217
else

src/backend/utils/time/snapmgr.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
* Portions Copyright (c) 1994, Regents of the University of California
2020
*
2121
* IDENTIFICATION
22-
* $PostgreSQL: pgsql/src/backend/utils/time/snapmgr.c,v 1.10 2009/06/11 14:49:06 momjian Exp $
22+
* $PostgreSQL: pgsql/src/backend/utils/time/snapmgr.c,v 1.11 2009/10/02 17:57:30 alvherre Exp $
2323
*
2424
*-------------------------------------------------------------------------
2525
*/
@@ -104,7 +104,6 @@ bool FirstSnapshotSet = false;
104104
static bool registered_serializable = false;
105105

106106

107-
static Snapshot CopySnapshot(Snapshot snapshot);
108107
static void FreeSnapshot(Snapshot snapshot);
109108
static void SnapshotResetXmin(void);
110109

@@ -192,7 +191,7 @@ SnapshotSetCommandId(CommandId curcid)
192191
* The copy is palloc'd in TopTransactionContext and has initial refcounts set
193192
* to 0. The returned snapshot has the copied flag set.
194193
*/
195-
static Snapshot
194+
Snapshot
196195
CopySnapshot(Snapshot snapshot)
197196
{
198197
Snapshot newsnap;

src/include/utils/snapmgr.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
77
* Portions Copyright (c) 1994, Regents of the University of California
88
*
9-
* $PostgreSQL: pgsql/src/include/utils/snapmgr.h,v 1.5 2009/06/11 14:49:13 momjian Exp $
9+
* $PostgreSQL: pgsql/src/include/utils/snapmgr.h,v 1.6 2009/10/02 17:57:30 alvherre Exp $
1010
*
1111
*-------------------------------------------------------------------------
1212
*/
@@ -26,6 +26,7 @@ extern TransactionId RecentGlobalXmin;
2626
extern Snapshot GetTransactionSnapshot(void);
2727
extern Snapshot GetLatestSnapshot(void);
2828
extern void SnapshotSetCommandId(CommandId curcid);
29+
extern Snapshot CopySnapshot(Snapshot snapshot);
2930

3031
extern void PushActiveSnapshot(Snapshot snapshot);
3132
extern void PushUpdatedSnapshot(Snapshot snapshot);

src/test/regress/expected/portals.out

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1242,3 +1242,18 @@ FETCH FROM c1;
12421242
DELETE FROM ucview WHERE CURRENT OF c1; -- fail, views not supported
12431243
ERROR: WHERE CURRENT OF on a view is not implemented
12441244
ROLLBACK;
1245+
-- Make sure snapshot management works okay, per bug report in
1246+
-- 235395b90909301035v7228ce63q392931f15aa74b31@mail.gmail.com
1247+
BEGIN;
1248+
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
1249+
CREATE TABLE cursor (a int);
1250+
INSERT INTO cursor VALUES (1);
1251+
DECLARE c1 NO SCROLL CURSOR FOR SELECT * FROM cursor FOR UPDATE;
1252+
UPDATE cursor SET a = 2;
1253+
FETCH ALL FROM c1;
1254+
a
1255+
---
1256+
(0 rows)
1257+
1258+
COMMIT;
1259+
DROP TABLE cursor;

src/test/regress/sql/portals.sql

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,3 +458,15 @@ DECLARE c1 CURSOR FOR SELECT * FROM ucview;
458458
FETCH FROM c1;
459459
DELETE FROM ucview WHERE CURRENT OF c1; -- fail, views not supported
460460
ROLLBACK;
461+
462+
-- Make sure snapshot management works okay, per bug report in
463+
-- 235395b90909301035v7228ce63q392931f15aa74b31@mail.gmail.com
464+
BEGIN;
465+
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
466+
CREATE TABLE cursor (a int);
467+
INSERT INTO cursor VALUES (1);
468+
DECLARE c1 NO SCROLL CURSOR FOR SELECT * FROM cursor FOR UPDATE;
469+
UPDATE cursor SET a = 2;
470+
FETCH ALL FROM c1;
471+
COMMIT;
472+
DROP TABLE cursor;

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy