mirror of
https://github.com/postgres/postgres.git
synced 2025-08-18 12:22:09 +03:00
The contents of command.c, creatinh.c, define.c, remove.c and rename.c
have been divided according to the type of object manipulated - so ALTER TABLE code is in tablecmds.c, aggregate commands in aggregatecmds.c and so on. A few common support routines remain in define.c (prototypes in src/include/commands/defrem.h). No code has been changed except for includes to reflect the new files. The prototypes for aggregatecmds.c, functioncmds.c, operatorcmds.c, and typecmds.c remain in src/include/commands/defrem.h. From John Gray <jgray@azuli.co.uk>
This commit is contained in:
234
src/backend/commands/portalcmds.c
Normal file
234
src/backend/commands/portalcmds.c
Normal file
@@ -0,0 +1,234 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* portalcmds.c
|
||||
* portal support code
|
||||
*
|
||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/portalcmds.c,v 1.1 2002/04/15 05:22:03 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "postgres.h"
|
||||
|
||||
#include "commands/portalcmds.h"
|
||||
#include "executor/executor.h"
|
||||
|
||||
|
||||
/*
|
||||
* PortalCleanup
|
||||
*/
|
||||
void
|
||||
PortalCleanup(Portal portal)
|
||||
{
|
||||
MemoryContext oldcontext;
|
||||
|
||||
/*
|
||||
* sanity checks
|
||||
*/
|
||||
AssertArg(PortalIsValid(portal));
|
||||
AssertArg(portal->cleanup == PortalCleanup);
|
||||
|
||||
/*
|
||||
* set proper portal-executor context before calling ExecMain.
|
||||
*/
|
||||
oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
|
||||
|
||||
/*
|
||||
* tell the executor to shutdown the query
|
||||
*/
|
||||
ExecutorEnd(PortalGetQueryDesc(portal), PortalGetState(portal));
|
||||
|
||||
/*
|
||||
* switch back to previous context
|
||||
*/
|
||||
MemoryContextSwitchTo(oldcontext);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* PerformPortalFetch
|
||||
*
|
||||
* name: name of portal
|
||||
* forward: forward or backward fetch?
|
||||
* count: # of tuples to fetch (0 implies all)
|
||||
* dest: where to send results
|
||||
* completionTag: points to a buffer of size COMPLETION_TAG_BUFSIZE
|
||||
* in which to store a command completion status string.
|
||||
*
|
||||
* completionTag may be NULL if caller doesn't want a status string.
|
||||
*/
|
||||
void
|
||||
PerformPortalFetch(char *name,
|
||||
bool forward,
|
||||
int count,
|
||||
CommandDest dest,
|
||||
char *completionTag)
|
||||
{
|
||||
Portal portal;
|
||||
QueryDesc *queryDesc;
|
||||
EState *estate;
|
||||
MemoryContext oldcontext;
|
||||
ScanDirection direction;
|
||||
CommandId savedId;
|
||||
bool temp_desc = false;
|
||||
|
||||
/* initialize completion status in case of early exit */
|
||||
if (completionTag)
|
||||
strcpy(completionTag, (dest == None) ? "MOVE 0" : "FETCH 0");
|
||||
|
||||
/*
|
||||
* sanity checks
|
||||
*/
|
||||
if (name == NULL)
|
||||
{
|
||||
elog(WARNING, "PerformPortalFetch: missing portal name");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* get the portal from the portal name
|
||||
*/
|
||||
portal = GetPortalByName(name);
|
||||
if (!PortalIsValid(portal))
|
||||
{
|
||||
elog(WARNING, "PerformPortalFetch: portal \"%s\" not found",
|
||||
name);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* switch into the portal context
|
||||
*/
|
||||
oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
|
||||
|
||||
queryDesc = PortalGetQueryDesc(portal);
|
||||
estate = PortalGetState(portal);
|
||||
|
||||
/*
|
||||
* If the requested destination is not the same as the query's
|
||||
* original destination, make a temporary QueryDesc with the proper
|
||||
* destination. This supports MOVE, for example, which will pass in
|
||||
* dest = None.
|
||||
*
|
||||
* EXCEPTION: if the query's original dest is RemoteInternal (ie, it's a
|
||||
* binary cursor) and the request is Remote, we do NOT override the
|
||||
* original dest. This is necessary since a FETCH command will pass
|
||||
* dest = Remote, not knowing whether the cursor is binary or not.
|
||||
*/
|
||||
if (dest != queryDesc->dest &&
|
||||
!(queryDesc->dest == RemoteInternal && dest == Remote))
|
||||
{
|
||||
QueryDesc *qdesc = (QueryDesc *) palloc(sizeof(QueryDesc));
|
||||
|
||||
memcpy(qdesc, queryDesc, sizeof(QueryDesc));
|
||||
qdesc->dest = dest;
|
||||
queryDesc = qdesc;
|
||||
temp_desc = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
* already at the end of the available tuples in that direction. If
|
||||
* so, set the direction to NoMovement to avoid trying to fetch any
|
||||
* tuples. (This check exists because not all plan node types
|
||||
* are robust about being called again if they've already returned
|
||||
* NULL once.) Then call the executor (we must not skip this, because
|
||||
* the destination needs to see a setup and shutdown even if no tuples
|
||||
* are available). Finally, update the atStart/atEnd state depending
|
||||
* on the number of tuples that were retrieved.
|
||||
*/
|
||||
if (forward)
|
||||
{
|
||||
if (portal->atEnd)
|
||||
direction = NoMovementScanDirection;
|
||||
else
|
||||
direction = ForwardScanDirection;
|
||||
|
||||
ExecutorRun(queryDesc, estate, direction, (long) count);
|
||||
|
||||
if (estate->es_processed > 0)
|
||||
portal->atStart = false; /* OK to back up now */
|
||||
if (count <= 0 || (int) estate->es_processed < count)
|
||||
portal->atEnd = true; /* we retrieved 'em all */
|
||||
}
|
||||
else
|
||||
{
|
||||
if (portal->atStart)
|
||||
direction = NoMovementScanDirection;
|
||||
else
|
||||
direction = BackwardScanDirection;
|
||||
|
||||
ExecutorRun(queryDesc, estate, direction, (long) count);
|
||||
|
||||
if (estate->es_processed > 0)
|
||||
portal->atEnd = false; /* OK to go forward now */
|
||||
if (count <= 0 || (int) estate->es_processed < count)
|
||||
portal->atStart = true; /* we retrieved 'em all */
|
||||
}
|
||||
|
||||
/* Return command status if wanted */
|
||||
if (completionTag)
|
||||
snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "%s %u",
|
||||
(dest == None) ? "MOVE" : "FETCH",
|
||||
estate->es_processed);
|
||||
|
||||
/*
|
||||
* Restore outer command ID.
|
||||
*/
|
||||
SetScanCommandId(savedId);
|
||||
|
||||
/*
|
||||
* Clean up and switch back to old context.
|
||||
*/
|
||||
if (temp_desc)
|
||||
pfree(queryDesc);
|
||||
|
||||
MemoryContextSwitchTo(oldcontext);
|
||||
}
|
||||
|
||||
/*
|
||||
* PerformPortalClose
|
||||
*/
|
||||
void
|
||||
PerformPortalClose(char *name, CommandDest dest)
|
||||
{
|
||||
Portal portal;
|
||||
|
||||
/*
|
||||
* sanity checks
|
||||
*/
|
||||
if (name == NULL)
|
||||
{
|
||||
elog(WARNING, "PerformPortalClose: missing portal name");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* get the portal from the portal name
|
||||
*/
|
||||
portal = GetPortalByName(name);
|
||||
if (!PortalIsValid(portal))
|
||||
{
|
||||
elog(WARNING, "PerformPortalClose: portal \"%s\" not found",
|
||||
name);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note: PortalCleanup is called as a side-effect
|
||||
*/
|
||||
PortalDrop(portal);
|
||||
}
|
Reference in New Issue
Block a user