1 /*-------------------------------------------------------------------------
6 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/backend/commands/portalcmds.c,v 1.3 2002/09/04 20:31:15 momjian Exp $
13 *-------------------------------------------------------------------------
18 #include "commands/portalcmds.h"
19 #include "executor/executor.h"
26 PortalCleanup(Portal portal)
28 MemoryContext oldcontext;
33 AssertArg(PortalIsValid(portal));
34 AssertArg(portal->cleanup == PortalCleanup);
37 * set proper portal-executor context before calling ExecMain.
39 oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
42 * tell the executor to shutdown the query
44 ExecutorEnd(PortalGetQueryDesc(portal), PortalGetState(portal));
47 * switch back to previous context
49 MemoryContextSwitchTo(oldcontext);
56 * name: name of portal
57 * forward: forward or backward fetch?
58 * count: # of tuples to fetch (0 implies all)
59 * dest: where to send results
60 * completionTag: points to a buffer of size COMPLETION_TAG_BUFSIZE
61 * in which to store a command completion status string.
63 * completionTag may be NULL if caller doesn't want a status string.
66 PerformPortalFetch(char *name,
75 MemoryContext oldcontext;
76 ScanDirection direction;
77 bool temp_desc = false;
79 /* initialize completion status in case of early exit */
81 strcpy(completionTag, (dest == None) ? "MOVE 0" : "FETCH 0");
88 elog(WARNING, "PerformPortalFetch: missing portal name");
93 * get the portal from the portal name
95 portal = GetPortalByName(name);
96 if (!PortalIsValid(portal))
98 elog(WARNING, "PerformPortalFetch: portal \"%s\" not found",
104 * switch into the portal context
106 oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
108 queryDesc = PortalGetQueryDesc(portal);
109 estate = PortalGetState(portal);
112 * If the requested destination is not the same as the query's
113 * original destination, make a temporary QueryDesc with the proper
114 * destination. This supports MOVE, for example, which will pass in
117 * EXCEPTION: if the query's original dest is RemoteInternal (ie, it's a
118 * binary cursor) and the request is Remote, we do NOT override the
119 * original dest. This is necessary since a FETCH command will pass
120 * dest = Remote, not knowing whether the cursor is binary or not.
122 if (dest != queryDesc->dest &&
123 !(queryDesc->dest == RemoteInternal && dest == Remote))
125 QueryDesc *qdesc = (QueryDesc *) palloc(sizeof(QueryDesc));
127 memcpy(qdesc, queryDesc, sizeof(QueryDesc));
134 * Determine which direction to go in, and check to see if we're
135 * already at the end of the available tuples in that direction. If
136 * so, set the direction to NoMovement to avoid trying to fetch any
137 * tuples. (This check exists because not all plan node types are
138 * robust about being called again if they've already returned NULL
139 * once.) Then call the executor (we must not skip this, because the
140 * destination needs to see a setup and shutdown even if no tuples are
141 * available). Finally, update the atStart/atEnd state depending on
142 * the number of tuples that were retrieved.
147 direction = NoMovementScanDirection;
149 direction = ForwardScanDirection;
151 ExecutorRun(queryDesc, estate, direction, (long) count);
153 if (estate->es_processed > 0)
154 portal->atStart = false; /* OK to back up now */
155 if (count <= 0 || (int) estate->es_processed < count)
156 portal->atEnd = true; /* we retrieved 'em all */
161 direction = NoMovementScanDirection;
163 direction = BackwardScanDirection;
165 ExecutorRun(queryDesc, estate, direction, (long) count);
167 if (estate->es_processed > 0)
168 portal->atEnd = false; /* OK to go forward now */
169 if (count <= 0 || (int) estate->es_processed < count)
170 portal->atStart = true; /* we retrieved 'em all */
173 /* Return command status if wanted */
175 snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "%s %u",
176 (dest == None) ? "MOVE" : "FETCH",
177 estate->es_processed);
180 * Clean up and switch back to old context.
185 MemoryContextSwitchTo(oldcontext);
192 PerformPortalClose(char *name, CommandDest dest)
201 elog(WARNING, "PerformPortalClose: missing portal name");
206 * get the portal from the portal name
208 portal = GetPortalByName(name);
209 if (!PortalIsValid(portal))
211 elog(WARNING, "PerformPortalClose: portal \"%s\" not found",
217 * Note: PortalCleanup is called as a side-effect