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.
This commit is contained in:
parent
d4bd8423c9
commit
ae35363dce
@ -14,7 +14,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/commands/portalcmds.c,v 1.79 2009/06/11 14:48:56 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/commands/portalcmds.c,v 1.79.2.1 2009/10/02 17:58:21 alvherre Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -47,6 +47,7 @@ PerformCursorOpen(PlannedStmt *stmt, ParamListInfo params,
|
|||||||
DeclareCursorStmt *cstmt = (DeclareCursorStmt *) stmt->utilityStmt;
|
DeclareCursorStmt *cstmt = (DeclareCursorStmt *) stmt->utilityStmt;
|
||||||
Portal portal;
|
Portal portal;
|
||||||
MemoryContext oldContext;
|
MemoryContext oldContext;
|
||||||
|
Snapshot snapshot;
|
||||||
|
|
||||||
if (cstmt == NULL || !IsA(cstmt, DeclareCursorStmt))
|
if (cstmt == NULL || !IsA(cstmt, DeclareCursorStmt))
|
||||||
elog(ERROR, "PerformCursorOpen called for non-cursor query");
|
elog(ERROR, "PerformCursorOpen called for non-cursor query");
|
||||||
@ -118,10 +119,18 @@ PerformCursorOpen(PlannedStmt *stmt, ParamListInfo params,
|
|||||||
portal->cursorOptions |= CURSOR_OPT_NO_SCROLL;
|
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.
|
* Start execution, inserting parameters if any.
|
||||||
*/
|
*/
|
||||||
PortalStart(portal, params, GetActiveSnapshot());
|
PortalStart(portal, params, snapshot);
|
||||||
|
|
||||||
Assert(portal->strategy == PORTAL_ONE_SELECT);
|
Assert(portal->strategy == PORTAL_ONE_SELECT);
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.208 2009/06/11 14:48:57 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.208.2.1 2009/10/02 17:58:21 alvherre Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -1211,10 +1211,7 @@ SPI_cursor_open_internal(const char *name, SPIPlanPtr plan,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* Set up the snapshot to use. */
|
||||||
* Set up the snapshot to use. (PortalStart will do PushActiveSnapshot,
|
|
||||||
* so we skip that here.)
|
|
||||||
*/
|
|
||||||
if (read_only)
|
if (read_only)
|
||||||
snapshot = GetActiveSnapshot();
|
snapshot = GetActiveSnapshot();
|
||||||
else
|
else
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/utils/time/snapmgr.c,v 1.10 2009/06/11 14:49:06 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/utils/time/snapmgr.c,v 1.10.2.1 2009/10/02 17:58:21 alvherre Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -104,7 +104,6 @@ bool FirstSnapshotSet = false;
|
|||||||
static bool registered_serializable = false;
|
static bool registered_serializable = false;
|
||||||
|
|
||||||
|
|
||||||
static Snapshot CopySnapshot(Snapshot snapshot);
|
|
||||||
static void FreeSnapshot(Snapshot snapshot);
|
static void FreeSnapshot(Snapshot snapshot);
|
||||||
static void SnapshotResetXmin(void);
|
static void SnapshotResetXmin(void);
|
||||||
|
|
||||||
@ -192,7 +191,7 @@ SnapshotSetCommandId(CommandId curcid)
|
|||||||
* The copy is palloc'd in TopTransactionContext and has initial refcounts set
|
* The copy is palloc'd in TopTransactionContext and has initial refcounts set
|
||||||
* to 0. The returned snapshot has the copied flag set.
|
* to 0. The returned snapshot has the copied flag set.
|
||||||
*/
|
*/
|
||||||
static Snapshot
|
Snapshot
|
||||||
CopySnapshot(Snapshot snapshot)
|
CopySnapshot(Snapshot snapshot)
|
||||||
{
|
{
|
||||||
Snapshot newsnap;
|
Snapshot newsnap;
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/utils/snapmgr.h,v 1.5 2009/06/11 14:49:13 momjian Exp $
|
* $PostgreSQL: pgsql/src/include/utils/snapmgr.h,v 1.5.2.1 2009/10/02 17:58:21 alvherre Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -26,6 +26,7 @@ extern TransactionId RecentGlobalXmin;
|
|||||||
extern Snapshot GetTransactionSnapshot(void);
|
extern Snapshot GetTransactionSnapshot(void);
|
||||||
extern Snapshot GetLatestSnapshot(void);
|
extern Snapshot GetLatestSnapshot(void);
|
||||||
extern void SnapshotSetCommandId(CommandId curcid);
|
extern void SnapshotSetCommandId(CommandId curcid);
|
||||||
|
extern Snapshot CopySnapshot(Snapshot snapshot);
|
||||||
|
|
||||||
extern void PushActiveSnapshot(Snapshot snapshot);
|
extern void PushActiveSnapshot(Snapshot snapshot);
|
||||||
extern void PushUpdatedSnapshot(Snapshot snapshot);
|
extern void PushUpdatedSnapshot(Snapshot snapshot);
|
||||||
|
@ -1242,3 +1242,18 @@ FETCH FROM c1;
|
|||||||
DELETE FROM ucview WHERE CURRENT OF c1; -- fail, views not supported
|
DELETE FROM ucview WHERE CURRENT OF c1; -- fail, views not supported
|
||||||
ERROR: WHERE CURRENT OF on a view is not implemented
|
ERROR: WHERE CURRENT OF on a view is not implemented
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
|
-- Make sure snapshot management works okay, per bug report in
|
||||||
|
-- 235395b90909301035v7228ce63q392931f15aa74b31@mail.gmail.com
|
||||||
|
BEGIN;
|
||||||
|
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
|
||||||
|
CREATE TABLE cursor (a int);
|
||||||
|
INSERT INTO cursor VALUES (1);
|
||||||
|
DECLARE c1 NO SCROLL CURSOR FOR SELECT * FROM cursor FOR UPDATE;
|
||||||
|
UPDATE cursor SET a = 2;
|
||||||
|
FETCH ALL FROM c1;
|
||||||
|
a
|
||||||
|
---
|
||||||
|
(0 rows)
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
|
DROP TABLE cursor;
|
||||||
|
@ -458,3 +458,15 @@ DECLARE c1 CURSOR FOR SELECT * FROM ucview;
|
|||||||
FETCH FROM c1;
|
FETCH FROM c1;
|
||||||
DELETE FROM ucview WHERE CURRENT OF c1; -- fail, views not supported
|
DELETE FROM ucview WHERE CURRENT OF c1; -- fail, views not supported
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
|
|
||||||
|
-- Make sure snapshot management works okay, per bug report in
|
||||||
|
-- 235395b90909301035v7228ce63q392931f15aa74b31@mail.gmail.com
|
||||||
|
BEGIN;
|
||||||
|
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
|
||||||
|
CREATE TABLE cursor (a int);
|
||||||
|
INSERT INTO cursor VALUES (1);
|
||||||
|
DECLARE c1 NO SCROLL CURSOR FOR SELECT * FROM cursor FOR UPDATE;
|
||||||
|
UPDATE cursor SET a = 2;
|
||||||
|
FETCH ALL FROM c1;
|
||||||
|
COMMIT;
|
||||||
|
DROP TABLE cursor;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user