Skip to content

Commit 3576820

Browse files
committed
Ensure that a cursor is scanned under the same scanCommandId it was
originally created with, so that the set of visible tuples does not change as a result of other activity. This essentially makes PG cursors INSENSITIVE per the SQL92 definition. See bug report of 13-Feb-02.
1 parent 1392042 commit 3576820

File tree

4 files changed

+48
-13
lines changed

4 files changed

+48
-13
lines changed

src/backend/commands/command.c

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.152 2002/01/03 23:19:30 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.153 2002/02/14 15:24:06 tgl Exp $
1212
*
1313
* NOTES
1414
* The PerformAddAttribute() code, like most of the relation
@@ -103,6 +103,7 @@ PerformPortalFetch(char *name,
103103
QueryDesc *queryDesc;
104104
EState *estate;
105105
MemoryContext oldcontext;
106+
CommandId savedId;
106107
bool temp_desc = false;
107108

108109
/*
@@ -156,7 +157,7 @@ PerformPortalFetch(char *name,
156157
}
157158

158159
/*
159-
* tell the destination to prepare to receive some tuples.
160+
* Tell the destination to prepare to receive some tuples.
160161
*/
161162
BeginCommand(name,
162163
queryDesc->operation,
@@ -168,6 +169,14 @@ PerformPortalFetch(char *name,
168169
tag,
169170
queryDesc->dest);
170171

172+
/*
173+
* Restore the scanCommandId that was current when the cursor was
174+
* opened. This ensures that we see the same tuples throughout the
175+
* execution of the cursor.
176+
*/
177+
savedId = GetScanCommandId();
178+
SetScanCommandId(PortalGetCommandId(portal));
179+
171180
/*
172181
* Determine which direction to go in, and check to see if we're
173182
* already at the end of the available tuples in that direction. If
@@ -214,6 +223,11 @@ PerformPortalFetch(char *name,
214223
}
215224
}
216225

226+
/*
227+
* Restore outer command ID.
228+
*/
229+
SetScanCommandId(savedId);
230+
217231
/*
218232
* Clean up and switch back to old context.
219233
*/

src/backend/executor/spi.c

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.64 2002/01/03 20:30:47 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.65 2002/02/14 15:24:08 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -740,9 +740,9 @@ SPI_cursor_open(char *name, void *plan, Datum *Values, char *Nulls)
740740
_SPI_current->processed = 0;
741741
_SPI_current->tuptable = NULL;
742742

743-
/* Make up a portal name if none given */
744743
if (name == NULL)
745744
{
745+
/* Make up a portal name if none given */
746746
for (;;)
747747
{
748748
unnamed_portal_count++;
@@ -755,11 +755,13 @@ SPI_cursor_open(char *name, void *plan, Datum *Values, char *Nulls)
755755

756756
name = portalname;
757757
}
758-
759-
/* Ensure the portal doesn't exist already */
760-
portal = GetPortalByName(name);
761-
if (portal != NULL)
762-
elog(ERROR, "cursor \"%s\" already in use", name);
758+
else
759+
{
760+
/* Ensure the portal doesn't exist already */
761+
portal = GetPortalByName(name);
762+
if (portal != NULL)
763+
elog(ERROR, "cursor \"%s\" already in use", name);
764+
}
763765

764766
/* Create the portal */
765767
portal = CreatePortal(name);
@@ -1228,6 +1230,7 @@ _SPI_cursor_operation(Portal portal, bool forward, int count,
12281230
QueryDesc *querydesc;
12291231
EState *estate;
12301232
MemoryContext oldcontext;
1233+
CommandId savedId;
12311234
CommandDest olddest;
12321235

12331236
/* Check that the portal is valid */
@@ -1245,6 +1248,7 @@ _SPI_cursor_operation(Portal portal, bool forward, int count,
12451248

12461249
/* Switch to the portals memory context */
12471250
oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
1251+
12481252
querydesc = PortalGetQueryDesc(portal);
12491253
estate = PortalGetState(portal);
12501254

@@ -1253,6 +1257,14 @@ _SPI_cursor_operation(Portal portal, bool forward, int count,
12531257
olddest = querydesc->dest;
12541258
querydesc->dest = dest;
12551259

1260+
/*
1261+
* Restore the scanCommandId that was current when the cursor was
1262+
* opened. This ensures that we see the same tuples throughout the
1263+
* execution of the cursor.
1264+
*/
1265+
savedId = GetScanCommandId();
1266+
SetScanCommandId(PortalGetCommandId(portal));
1267+
12561268
/* Run the executor like PerformPortalFetch and remember states */
12571269
if (forward)
12581270
{
@@ -1279,6 +1291,11 @@ _SPI_cursor_operation(Portal portal, bool forward, int count,
12791291
}
12801292
}
12811293

1294+
/*
1295+
* Restore outer command ID.
1296+
*/
1297+
SetScanCommandId(savedId);
1298+
12821299
/* Restore the old command destination and switch back to callers */
12831300
/* memory context */
12841301
querydesc->dest = olddest;

src/backend/utils/mmgr/portalmem.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.44 2001/10/25 05:49:51 momjian Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.45 2002/02/14 15:24:09 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -168,6 +168,7 @@ PortalSetQuery(Portal portal,
168168

169169
portal->queryDesc = queryDesc;
170170
portal->attinfo = attinfo;
171+
portal->commandId = GetScanCommandId();
171172
portal->state = state;
172173
portal->atStart = true; /* Allow fetch forward only */
173174
portal->atEnd = false;
@@ -213,6 +214,7 @@ CreatePortal(char *name)
213214
/* initialize portal query */
214215
portal->queryDesc = NULL;
215216
portal->attinfo = NULL;
217+
portal->commandId = 0;
216218
portal->state = NULL;
217219
portal->atStart = true; /* disallow fetches until query is set */
218220
portal->atEnd = true;

src/include/utils/portal.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $Id: portal.h,v 1.31 2001/11/05 17:46:36 momjian Exp $
10+
* $Id: portal.h,v 1.32 2002/02/14 15:24:10 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -31,6 +31,7 @@ typedef struct PortalData
3131
MemoryContext heap; /* subsidiary memory */
3232
QueryDesc *queryDesc; /* Info about query associated with portal */
3333
TupleDesc attinfo;
34+
CommandId commandId; /* Command counter value for query */
3435
EState *state; /* Execution state of query */
3536
bool atStart; /* T => fetch backwards is not allowed */
3637
bool atEnd; /* T => fetch forwards is not allowed */
@@ -48,8 +49,9 @@ typedef struct PortalData
4849
*/
4950
#define PortalGetQueryDesc(portal) ((portal)->queryDesc)
5051
#define PortalGetTupleDesc(portal) ((portal)->attinfo)
51-
#define PortalGetState(portal) ((portal)->state)
52-
#define PortalGetHeapMemory(portal) ((portal)->heap)
52+
#define PortalGetCommandId(portal) ((portal)->commandId)
53+
#define PortalGetState(portal) ((portal)->state)
54+
#define PortalGetHeapMemory(portal) ((portal)->heap)
5355

5456
/*
5557
* estimate of the maximum number of open portals a user would have,

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