mirror of
https://github.com/postgres/postgres.git
synced 2025-06-29 10:41:53 +03:00
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.
This commit is contained in:
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.152 2002/01/03 23:19:30 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.153 2002/02/14 15:24:06 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* The PerformAddAttribute() code, like most of the relation
|
* The PerformAddAttribute() code, like most of the relation
|
||||||
@ -103,6 +103,7 @@ PerformPortalFetch(char *name,
|
|||||||
QueryDesc *queryDesc;
|
QueryDesc *queryDesc;
|
||||||
EState *estate;
|
EState *estate;
|
||||||
MemoryContext oldcontext;
|
MemoryContext oldcontext;
|
||||||
|
CommandId savedId;
|
||||||
bool temp_desc = false;
|
bool temp_desc = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -156,7 +157,7 @@ PerformPortalFetch(char *name,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* tell the destination to prepare to receive some tuples.
|
* Tell the destination to prepare to receive some tuples.
|
||||||
*/
|
*/
|
||||||
BeginCommand(name,
|
BeginCommand(name,
|
||||||
queryDesc->operation,
|
queryDesc->operation,
|
||||||
@ -168,6 +169,14 @@ PerformPortalFetch(char *name,
|
|||||||
tag,
|
tag,
|
||||||
queryDesc->dest);
|
queryDesc->dest);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Restore the scanCommandId that was current when the cursor was
|
||||||
|
* opened. This ensures that we see the same tuples throughout the
|
||||||
|
* execution of the cursor.
|
||||||
|
*/
|
||||||
|
savedId = GetScanCommandId();
|
||||||
|
SetScanCommandId(PortalGetCommandId(portal));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Determine which direction to go in, and check to see if we're
|
* Determine which direction to go in, and check to see if we're
|
||||||
* already at the end of the available tuples in that direction. If
|
* already at the end of the available tuples in that direction. If
|
||||||
@ -214,6 +223,11 @@ PerformPortalFetch(char *name,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Restore outer command ID.
|
||||||
|
*/
|
||||||
|
SetScanCommandId(savedId);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Clean up and switch back to old context.
|
* Clean up and switch back to old context.
|
||||||
*/
|
*/
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.64 2002/01/03 20:30:47 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.65 2002/02/14 15:24:08 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -740,9 +740,9 @@ SPI_cursor_open(char *name, void *plan, Datum *Values, char *Nulls)
|
|||||||
_SPI_current->processed = 0;
|
_SPI_current->processed = 0;
|
||||||
_SPI_current->tuptable = NULL;
|
_SPI_current->tuptable = NULL;
|
||||||
|
|
||||||
/* Make up a portal name if none given */
|
|
||||||
if (name == NULL)
|
if (name == NULL)
|
||||||
{
|
{
|
||||||
|
/* Make up a portal name if none given */
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
unnamed_portal_count++;
|
unnamed_portal_count++;
|
||||||
@ -755,11 +755,13 @@ SPI_cursor_open(char *name, void *plan, Datum *Values, char *Nulls)
|
|||||||
|
|
||||||
name = portalname;
|
name = portalname;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
/* Ensure the portal doesn't exist already */
|
{
|
||||||
portal = GetPortalByName(name);
|
/* Ensure the portal doesn't exist already */
|
||||||
if (portal != NULL)
|
portal = GetPortalByName(name);
|
||||||
elog(ERROR, "cursor \"%s\" already in use", name);
|
if (portal != NULL)
|
||||||
|
elog(ERROR, "cursor \"%s\" already in use", name);
|
||||||
|
}
|
||||||
|
|
||||||
/* Create the portal */
|
/* Create the portal */
|
||||||
portal = CreatePortal(name);
|
portal = CreatePortal(name);
|
||||||
@ -1228,6 +1230,7 @@ _SPI_cursor_operation(Portal portal, bool forward, int count,
|
|||||||
QueryDesc *querydesc;
|
QueryDesc *querydesc;
|
||||||
EState *estate;
|
EState *estate;
|
||||||
MemoryContext oldcontext;
|
MemoryContext oldcontext;
|
||||||
|
CommandId savedId;
|
||||||
CommandDest olddest;
|
CommandDest olddest;
|
||||||
|
|
||||||
/* Check that the portal is valid */
|
/* Check that the portal is valid */
|
||||||
@ -1245,6 +1248,7 @@ _SPI_cursor_operation(Portal portal, bool forward, int count,
|
|||||||
|
|
||||||
/* Switch to the portals memory context */
|
/* Switch to the portals memory context */
|
||||||
oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
|
oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
|
||||||
|
|
||||||
querydesc = PortalGetQueryDesc(portal);
|
querydesc = PortalGetQueryDesc(portal);
|
||||||
estate = PortalGetState(portal);
|
estate = PortalGetState(portal);
|
||||||
|
|
||||||
@ -1253,6 +1257,14 @@ _SPI_cursor_operation(Portal portal, bool forward, int count,
|
|||||||
olddest = querydesc->dest;
|
olddest = querydesc->dest;
|
||||||
querydesc->dest = dest;
|
querydesc->dest = dest;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Restore the scanCommandId that was current when the cursor was
|
||||||
|
* opened. This ensures that we see the same tuples throughout the
|
||||||
|
* execution of the cursor.
|
||||||
|
*/
|
||||||
|
savedId = GetScanCommandId();
|
||||||
|
SetScanCommandId(PortalGetCommandId(portal));
|
||||||
|
|
||||||
/* Run the executor like PerformPortalFetch and remember states */
|
/* Run the executor like PerformPortalFetch and remember states */
|
||||||
if (forward)
|
if (forward)
|
||||||
{
|
{
|
||||||
@ -1279,6 +1291,11 @@ _SPI_cursor_operation(Portal portal, bool forward, int count,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Restore outer command ID.
|
||||||
|
*/
|
||||||
|
SetScanCommandId(savedId);
|
||||||
|
|
||||||
/* Restore the old command destination and switch back to callers */
|
/* Restore the old command destination and switch back to callers */
|
||||||
/* memory context */
|
/* memory context */
|
||||||
querydesc->dest = olddest;
|
querydesc->dest = olddest;
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.44 2001/10/25 05:49:51 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.45 2002/02/14 15:24:09 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -168,6 +168,7 @@ PortalSetQuery(Portal portal,
|
|||||||
|
|
||||||
portal->queryDesc = queryDesc;
|
portal->queryDesc = queryDesc;
|
||||||
portal->attinfo = attinfo;
|
portal->attinfo = attinfo;
|
||||||
|
portal->commandId = GetScanCommandId();
|
||||||
portal->state = state;
|
portal->state = state;
|
||||||
portal->atStart = true; /* Allow fetch forward only */
|
portal->atStart = true; /* Allow fetch forward only */
|
||||||
portal->atEnd = false;
|
portal->atEnd = false;
|
||||||
@ -213,6 +214,7 @@ CreatePortal(char *name)
|
|||||||
/* initialize portal query */
|
/* initialize portal query */
|
||||||
portal->queryDesc = NULL;
|
portal->queryDesc = NULL;
|
||||||
portal->attinfo = NULL;
|
portal->attinfo = NULL;
|
||||||
|
portal->commandId = 0;
|
||||||
portal->state = NULL;
|
portal->state = NULL;
|
||||||
portal->atStart = true; /* disallow fetches until query is set */
|
portal->atStart = true; /* disallow fetches until query is set */
|
||||||
portal->atEnd = true;
|
portal->atEnd = true;
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: portal.h,v 1.31 2001/11/05 17:46:36 momjian Exp $
|
* $Id: portal.h,v 1.32 2002/02/14 15:24:10 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -31,6 +31,7 @@ typedef struct PortalData
|
|||||||
MemoryContext heap; /* subsidiary memory */
|
MemoryContext heap; /* subsidiary memory */
|
||||||
QueryDesc *queryDesc; /* Info about query associated with portal */
|
QueryDesc *queryDesc; /* Info about query associated with portal */
|
||||||
TupleDesc attinfo;
|
TupleDesc attinfo;
|
||||||
|
CommandId commandId; /* Command counter value for query */
|
||||||
EState *state; /* Execution state of query */
|
EState *state; /* Execution state of query */
|
||||||
bool atStart; /* T => fetch backwards is not allowed */
|
bool atStart; /* T => fetch backwards is not allowed */
|
||||||
bool atEnd; /* T => fetch forwards is not allowed */
|
bool atEnd; /* T => fetch forwards is not allowed */
|
||||||
@ -48,8 +49,9 @@ typedef struct PortalData
|
|||||||
*/
|
*/
|
||||||
#define PortalGetQueryDesc(portal) ((portal)->queryDesc)
|
#define PortalGetQueryDesc(portal) ((portal)->queryDesc)
|
||||||
#define PortalGetTupleDesc(portal) ((portal)->attinfo)
|
#define PortalGetTupleDesc(portal) ((portal)->attinfo)
|
||||||
#define PortalGetState(portal) ((portal)->state)
|
#define PortalGetCommandId(portal) ((portal)->commandId)
|
||||||
#define PortalGetHeapMemory(portal) ((portal)->heap)
|
#define PortalGetState(portal) ((portal)->state)
|
||||||
|
#define PortalGetHeapMemory(portal) ((portal)->heap)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* estimate of the maximum number of open portals a user would have,
|
* estimate of the maximum number of open portals a user would have,
|
||||||
|
Reference in New Issue
Block a user