1 /*-------------------------------------------------------------------------
4 * POSTGRES process query command code
6 * Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $PostgreSQL: pgsql/src/backend/tcop/pquery.c,v 1.88 2004/10/04 21:52:15 tgl Exp $
13 *-------------------------------------------------------------------------
18 #include "commands/trigger.h"
19 #include "executor/executor.h"
20 #include "miscadmin.h"
21 #include "tcop/tcopprot.h"
22 #include "tcop/pquery.h"
23 #include "tcop/utility.h"
24 #include "utils/guc.h"
25 #include "utils/memutils.h"
29 * ActivePortal is the currently executing Portal (the most closely nested,
30 * if there are several).
32 Portal ActivePortal = NULL;
35 static void ProcessQuery(Query *parsetree,
40 static uint32 RunFromStore(Portal portal, ScanDirection direction, long count,
42 static long PortalRunSelect(Portal portal, bool forward, long count,
44 static void PortalRunUtility(Portal portal, Query *query,
45 DestReceiver *dest, char *completionTag);
46 static void PortalRunMulti(Portal portal,
47 DestReceiver *dest, DestReceiver *altdest,
49 static long DoPortalRunFetch(Portal portal,
50 FetchDirection fdirection,
53 static void DoPortalRewind(Portal portal);
60 CreateQueryDesc(Query *parsetree,
63 Snapshot crosscheck_snapshot,
68 QueryDesc *qd = (QueryDesc *) palloc(sizeof(QueryDesc));
70 qd->operation = parsetree->commandType; /* operation */
71 qd->parsetree = parsetree; /* parse tree */
72 qd->plantree = plantree; /* plan */
73 qd->snapshot = snapshot; /* snapshot */
74 qd->crosscheck_snapshot = crosscheck_snapshot; /* RI check snapshot */
75 qd->dest = dest; /* output dest */
76 qd->params = params; /* parameter values passed into query */
77 qd->doInstrument = doInstrument; /* instrumentation wanted? */
79 /* null these fields until set by ExecutorStart */
91 FreeQueryDesc(QueryDesc *qdesc)
93 /* Can't be a live query */
94 Assert(qdesc->estate == NULL);
95 /* Only the QueryDesc itself need be freed */
102 * Execute a single plannable query within a PORTAL_MULTI_QUERY portal
104 * parsetree: the query tree
105 * plan: the plan tree for the query
106 * params: any parameters needed
107 * dest: where to send results
108 * completionTag: points to a buffer of size COMPLETION_TAG_BUFSIZE
109 * in which to store a command completion status string.
111 * completionTag may be NULL if caller doesn't want a status string.
113 * Must be called in a memory context that will be reset or deleted on
114 * error; otherwise the executor's memory usage will be leaked.
117 ProcessQuery(Query *parsetree,
119 ParamListInfo params,
123 int operation = parsetree->commandType;
124 QueryDesc *queryDesc;
127 (errmsg_internal("ProcessQuery")));
130 * Check for special-case destinations
132 if (operation == CMD_SELECT)
134 if (parsetree->into != NULL)
137 * SELECT INTO table (a/k/a CREATE AS ... SELECT).
139 * Override the normal communication destination; execMain.c
140 * special-cases this case. (Perhaps would be cleaner to have
141 * an additional destination type?)
143 dest = None_Receiver;
148 * Must always set snapshot for plannable queries. Note we assume
149 * that caller will take care of restoring ActiveSnapshot on exit/error.
151 ActiveSnapshot = CopySnapshot(GetTransactionSnapshot());
154 * Create the QueryDesc object
156 queryDesc = CreateQueryDesc(parsetree, plan,
157 ActiveSnapshot, InvalidSnapshot,
158 dest, params, false);
161 * Set up to collect AFTER triggers
163 AfterTriggerBeginQuery();
166 * Call ExecStart to prepare the plan for execution
168 ExecutorStart(queryDesc, false);
171 * Run the plan to completion.
173 ExecutorRun(queryDesc, ForwardScanDirection, 0L);
176 * Build command completion status string, if caller wants one.
185 strcpy(completionTag, "SELECT");
188 if (queryDesc->estate->es_processed == 1)
189 lastOid = queryDesc->estate->es_lastoid;
191 lastOid = InvalidOid;
192 snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
193 "INSERT %u %u", lastOid, queryDesc->estate->es_processed);
196 snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
197 "UPDATE %u", queryDesc->estate->es_processed);
200 snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
201 "DELETE %u", queryDesc->estate->es_processed);
204 strcpy(completionTag, "???");
210 * Now, we close down all the scans and free allocated resources.
212 ExecutorEnd(queryDesc);
214 /* And take care of any queued AFTER triggers */
215 AfterTriggerEndQuery();
217 FreeQueryDesc(queryDesc);
219 FreeSnapshot(ActiveSnapshot);
220 ActiveSnapshot = NULL;
224 * ChoosePortalStrategy
225 * Select portal execution strategy given the intended query list.
227 * See the comments in portal.h.
230 ChoosePortalStrategy(List *parseTrees)
232 PortalStrategy strategy;
234 strategy = PORTAL_MULTI_QUERY; /* default assumption */
236 if (list_length(parseTrees) == 1)
238 Query *query = (Query *) linitial(parseTrees);
240 if (query->commandType == CMD_SELECT &&
243 strategy = PORTAL_ONE_SELECT;
244 else if (query->commandType == CMD_UTILITY &&
246 query->utilityStmt != NULL)
248 if (UtilityReturnsTuples(query->utilityStmt))
249 strategy = PORTAL_UTIL_SELECT;
257 * Prepare a portal for execution.
259 * Caller must already have created the portal, done PortalDefineQuery(),
260 * and adjusted portal options if needed. If parameters are needed by
261 * the query, they must be passed in here (caller is responsible for
262 * giving them appropriate lifetime).
264 * The caller can optionally pass a snapshot to be used; pass InvalidSnapshot
265 * for the normal behavior of setting a new snapshot. This parameter is
266 * presently ignored for non-PORTAL_ONE_SELECT portals (it's only intended
267 * to be used for cursors).
269 * On return, portal is ready to accept PortalRun() calls, and the result
270 * tupdesc (if any) is known.
273 PortalStart(Portal portal, ParamListInfo params, Snapshot snapshot)
275 Portal saveActivePortal;
276 Snapshot saveActiveSnapshot;
277 ResourceOwner saveResourceOwner;
278 MemoryContext savePortalContext;
279 MemoryContext oldContext;
280 QueryDesc *queryDesc;
282 AssertArg(PortalIsValid(portal));
283 AssertState(portal->queryContext != NULL); /* query defined? */
284 AssertState(portal->status == PORTAL_NEW); /* else extra PortalStart */
287 * Set up global portal context pointers. (Should we set
290 saveActivePortal = ActivePortal;
291 saveActiveSnapshot = ActiveSnapshot;
292 saveResourceOwner = CurrentResourceOwner;
293 savePortalContext = PortalContext;
296 ActivePortal = portal;
297 ActiveSnapshot = NULL; /* will be set later */
298 CurrentResourceOwner = portal->resowner;
299 PortalContext = PortalGetHeapMemory(portal);
301 oldContext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
303 /* Must remember portal param list, if any */
304 portal->portalParams = params;
307 * Determine the portal execution strategy
309 portal->strategy = ChoosePortalStrategy(portal->parseTrees);
312 * Fire her up according to the strategy
314 switch (portal->strategy)
316 case PORTAL_ONE_SELECT:
319 * Must set snapshot before starting executor. Be sure to
320 * copy it into the portal's context.
323 ActiveSnapshot = CopySnapshot(snapshot);
325 ActiveSnapshot = CopySnapshot(GetTransactionSnapshot());
328 * Create QueryDesc in portal's context; for the moment,
329 * set the destination to None.
331 queryDesc = CreateQueryDesc((Query *) linitial(portal->parseTrees),
332 (Plan *) linitial(portal->planTrees),
340 * We do *not* call AfterTriggerBeginQuery() here. We
341 * assume that a SELECT cannot queue any triggers. It
342 * would be messy to support triggers since the execution
343 * of the portal may be interleaved with other queries.
347 * Call ExecStart to prepare the plan for execution
349 ExecutorStart(queryDesc, false);
352 * This tells PortalCleanup to shut down the executor
354 portal->queryDesc = queryDesc;
357 * Remember tuple descriptor (computed by ExecutorStart)
359 portal->tupDesc = queryDesc->tupDesc;
362 * Reset cursor position data to "start of query"
364 portal->atStart = true;
365 portal->atEnd = false; /* allow fetches */
366 portal->portalPos = 0;
367 portal->posOverflow = false;
370 case PORTAL_UTIL_SELECT:
373 * We don't set snapshot here, because
374 * PortalRunUtility will take care of it if needed.
377 UtilityTupleDescriptor(((Query *) linitial(portal->parseTrees))->utilityStmt);
380 * Reset cursor position data to "start of query"
382 portal->atStart = true;
383 portal->atEnd = false; /* allow fetches */
384 portal->portalPos = 0;
385 portal->posOverflow = false;
388 case PORTAL_MULTI_QUERY:
389 /* Need do nothing now */
390 portal->tupDesc = NULL;
396 /* Uncaught error while executing portal: mark it dead */
397 portal->status = PORTAL_FAILED;
399 /* Restore global vars and propagate error */
400 ActivePortal = saveActivePortal;
401 ActiveSnapshot = saveActiveSnapshot;
402 CurrentResourceOwner = saveResourceOwner;
403 PortalContext = savePortalContext;
409 MemoryContextSwitchTo(oldContext);
411 ActivePortal = saveActivePortal;
412 ActiveSnapshot = saveActiveSnapshot;
413 CurrentResourceOwner = saveResourceOwner;
414 PortalContext = savePortalContext;
416 portal->status = PORTAL_READY;
420 * PortalSetResultFormat
421 * Select the format codes for a portal's output.
423 * This must be run after PortalStart for a portal that will be read by
424 * a Remote or RemoteExecute destination. It is not presently needed for
425 * other destination types.
427 * formats[] is the client format request, as per Bind message conventions.
430 PortalSetResultFormat(Portal portal, int nFormats, int16 *formats)
435 /* Do nothing if portal won't return tuples */
436 if (portal->tupDesc == NULL)
438 natts = portal->tupDesc->natts;
439 portal->formats = (int16 *)
440 MemoryContextAlloc(PortalGetHeapMemory(portal),
441 natts * sizeof(int16));
444 /* format specified for each column */
445 if (nFormats != natts)
447 (errcode(ERRCODE_PROTOCOL_VIOLATION),
448 errmsg("bind message has %d result formats but query has %d columns",
450 memcpy(portal->formats, formats, natts * sizeof(int16));
452 else if (nFormats > 0)
454 /* single format specified, use for all columns */
455 int16 format1 = formats[0];
457 for (i = 0; i < natts; i++)
458 portal->formats[i] = format1;
462 /* use default format for all columns */
463 for (i = 0; i < natts; i++)
464 portal->formats[i] = 0;
470 * Run a portal's query or queries.
472 * count <= 0 is interpreted as a no-op: the destination gets started up
473 * and shut down, but nothing else happens. Also, count == FETCH_ALL is
474 * interpreted as "all rows". Note that count is ignored in multi-query
475 * situations, where we always run the portal to completion.
477 * dest: where to send output of primary (canSetTag) query
479 * altdest: where to send output of non-primary queries
481 * completionTag: points to a buffer of size COMPLETION_TAG_BUFSIZE
482 * in which to store a command completion status string.
483 * May be NULL if caller doesn't want a status string.
485 * Returns TRUE if the portal's execution is complete, FALSE if it was
486 * suspended due to exhaustion of the count parameter.
489 PortalRun(Portal portal, long count,
490 DestReceiver *dest, DestReceiver *altdest,
494 ResourceOwner saveTopTransactionResourceOwner;
495 MemoryContext saveTopTransactionContext;
496 Portal saveActivePortal;
497 Snapshot saveActiveSnapshot;
498 ResourceOwner saveResourceOwner;
499 MemoryContext savePortalContext;
500 MemoryContext saveQueryContext;
501 MemoryContext saveMemoryContext;
503 AssertArg(PortalIsValid(portal));
505 /* Initialize completion tag to empty string */
507 completionTag[0] = '\0';
509 if (log_executor_stats && portal->strategy != PORTAL_MULTI_QUERY)
512 (errmsg_internal("PortalRun")));
513 /* PORTAL_MULTI_QUERY logs its own stats per query */
518 * Check for improper portal use, and mark portal active.
520 if (portal->status != PORTAL_READY)
522 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
523 errmsg("portal \"%s\" cannot be run", portal->name)));
524 portal->status = PORTAL_ACTIVE;
527 * Set up global portal context pointers.
529 * We have to play a special game here to support utility commands like
530 * VACUUM and CLUSTER, which internally start and commit transactions.
531 * When we are called to execute such a command, CurrentResourceOwner
532 * will be pointing to the TopTransactionResourceOwner --- which will
533 * be destroyed and replaced in the course of the internal commit and
534 * restart. So we need to be prepared to restore it as pointing to
535 * the exit-time TopTransactionResourceOwner. (Ain't that ugly? This
536 * idea of internally starting whole new transactions is not good.)
537 * CurrentMemoryContext has a similar problem, but the other pointers
538 * we save here will be NULL or pointing to longer-lived objects.
540 saveTopTransactionResourceOwner = TopTransactionResourceOwner;
541 saveTopTransactionContext = TopTransactionContext;
542 saveActivePortal = ActivePortal;
543 saveActiveSnapshot = ActiveSnapshot;
544 saveResourceOwner = CurrentResourceOwner;
545 savePortalContext = PortalContext;
546 saveQueryContext = QueryContext;
547 saveMemoryContext = CurrentMemoryContext;
550 ActivePortal = portal;
551 ActiveSnapshot = NULL; /* will be set later */
552 CurrentResourceOwner = portal->resowner;
553 PortalContext = PortalGetHeapMemory(portal);
554 QueryContext = portal->queryContext;
556 MemoryContextSwitchTo(PortalContext);
558 switch (portal->strategy)
560 case PORTAL_ONE_SELECT:
561 (void) PortalRunSelect(portal, true, count, dest);
562 /* we know the query is supposed to set the tag */
563 if (completionTag && portal->commandTag)
564 strcpy(completionTag, portal->commandTag);
566 /* Mark portal not active */
567 portal->status = PORTAL_READY;
570 * Since it's a forward fetch, say DONE iff atEnd is now
573 result = portal->atEnd;
576 case PORTAL_UTIL_SELECT:
579 * If we have not yet run the utility statement, do so,
580 * storing its results in the portal's tuplestore.
582 if (!portal->portalUtilReady)
584 DestReceiver *treceiver;
586 PortalCreateHoldStore(portal);
587 treceiver = CreateDestReceiver(Tuplestore, portal);
588 PortalRunUtility(portal, linitial(portal->parseTrees),
590 (*treceiver->rDestroy) (treceiver);
591 portal->portalUtilReady = true;
595 * Now fetch desired portion of results.
597 (void) PortalRunSelect(portal, true, count, dest);
600 * We know the query is supposed to set the tag; we assume
601 * only the default tag is needed.
603 if (completionTag && portal->commandTag)
604 strcpy(completionTag, portal->commandTag);
606 /* Mark portal not active */
607 portal->status = PORTAL_READY;
610 * Since it's a forward fetch, say DONE iff atEnd is now
613 result = portal->atEnd;
616 case PORTAL_MULTI_QUERY:
617 PortalRunMulti(portal, dest, altdest, completionTag);
619 /* Prevent portal's commands from being re-executed */
620 portal->status = PORTAL_DONE;
622 /* Always complete at end of RunMulti */
627 elog(ERROR, "unrecognized portal strategy: %d",
628 (int) portal->strategy);
629 result = false; /* keep compiler quiet */
635 /* Uncaught error while executing portal: mark it dead */
636 portal->status = PORTAL_FAILED;
638 /* Restore global vars and propagate error */
639 if (saveMemoryContext == saveTopTransactionContext)
640 MemoryContextSwitchTo(TopTransactionContext);
642 MemoryContextSwitchTo(saveMemoryContext);
643 ActivePortal = saveActivePortal;
644 ActiveSnapshot = saveActiveSnapshot;
645 if (saveResourceOwner == saveTopTransactionResourceOwner)
646 CurrentResourceOwner = TopTransactionResourceOwner;
648 CurrentResourceOwner = saveResourceOwner;
649 PortalContext = savePortalContext;
650 QueryContext = saveQueryContext;
656 if (saveMemoryContext == saveTopTransactionContext)
657 MemoryContextSwitchTo(TopTransactionContext);
659 MemoryContextSwitchTo(saveMemoryContext);
660 ActivePortal = saveActivePortal;
661 ActiveSnapshot = saveActiveSnapshot;
662 if (saveResourceOwner == saveTopTransactionResourceOwner)
663 CurrentResourceOwner = TopTransactionResourceOwner;
665 CurrentResourceOwner = saveResourceOwner;
666 PortalContext = savePortalContext;
667 QueryContext = saveQueryContext;
669 if (log_executor_stats && portal->strategy != PORTAL_MULTI_QUERY)
670 ShowUsage("EXECUTOR STATISTICS");
677 * Execute a portal's query in SELECT cases (also UTIL_SELECT).
679 * This handles simple N-rows-forward-or-backward cases. For more complex
680 * nonsequential access to a portal, see PortalRunFetch.
682 * count <= 0 is interpreted as a no-op: the destination gets started up
683 * and shut down, but nothing else happens. Also, count == FETCH_ALL is
684 * interpreted as "all rows".
686 * Caller must already have validated the Portal and done appropriate
687 * setup (cf. PortalRun).
689 * Returns number of rows processed (suitable for use in result tag)
692 PortalRunSelect(Portal portal,
697 QueryDesc *queryDesc;
698 ScanDirection direction;
702 * NB: queryDesc will be NULL if we are fetching from a held cursor or
703 * a completed utility query; can't use it in that path.
705 queryDesc = PortalGetQueryDesc(portal);
707 /* Caller messed up if we have neither a ready query nor held data. */
708 Assert(queryDesc || portal->holdStore);
711 * Force the queryDesc destination to the right thing. This supports
712 * MOVE, for example, which will pass in dest = None. This is okay to
713 * change as long as we do it on every fetch. (The Executor must not
714 * assume that dest never changes.)
717 queryDesc->dest = dest;
720 * Determine which direction to go in, and check to see if we're
721 * already at the end of the available tuples in that direction. If
722 * so, set the direction to NoMovement to avoid trying to fetch any
723 * tuples. (This check exists because not all plan node types are
724 * robust about being called again if they've already returned NULL
725 * once.) Then call the executor (we must not skip this, because the
726 * destination needs to see a setup and shutdown even if no tuples are
727 * available). Finally, update the portal position state depending on
728 * the number of tuples that were retrieved.
732 if (portal->atEnd || count <= 0)
733 direction = NoMovementScanDirection;
735 direction = ForwardScanDirection;
737 /* In the executor, zero count processes all rows */
738 if (count == FETCH_ALL)
741 if (portal->holdStore)
742 nprocessed = RunFromStore(portal, direction, count, dest);
745 ActiveSnapshot = queryDesc->snapshot;
746 ExecutorRun(queryDesc, direction, count);
747 nprocessed = queryDesc->estate->es_processed;
750 if (direction != NoMovementScanDirection)
755 portal->atStart = false; /* OK to go backward now */
757 (unsigned long) nprocessed < (unsigned long) count)
758 portal->atEnd = true; /* we retrieved 'em all */
759 oldPos = portal->portalPos;
760 portal->portalPos += nprocessed;
761 /* portalPos doesn't advance when we fall off the end */
762 if (portal->portalPos < oldPos)
763 portal->posOverflow = true;
768 if (portal->cursorOptions & CURSOR_OPT_NO_SCROLL)
770 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
771 errmsg("cursor can only scan forward"),
772 errhint("Declare it with SCROLL option to enable backward scan.")));
774 if (portal->atStart || count <= 0)
775 direction = NoMovementScanDirection;
777 direction = BackwardScanDirection;
779 /* In the executor, zero count processes all rows */
780 if (count == FETCH_ALL)
783 if (portal->holdStore)
784 nprocessed = RunFromStore(portal, direction, count, dest);
787 ActiveSnapshot = queryDesc->snapshot;
788 ExecutorRun(queryDesc, direction, count);
789 nprocessed = queryDesc->estate->es_processed;
792 if (direction != NoMovementScanDirection)
794 if (nprocessed > 0 && portal->atEnd)
796 portal->atEnd = false; /* OK to go forward now */
797 portal->portalPos++; /* adjust for endpoint case */
800 (unsigned long) nprocessed < (unsigned long) count)
802 portal->atStart = true; /* we retrieved 'em all */
803 portal->portalPos = 0;
804 portal->posOverflow = false;
810 oldPos = portal->portalPos;
811 portal->portalPos -= nprocessed;
812 if (portal->portalPos > oldPos ||
813 portal->portalPos <= 0)
814 portal->posOverflow = true;
824 * Fetch tuples from the portal's tuple store.
826 * Calling conventions are similar to ExecutorRun, except that we
827 * do not depend on having a queryDesc or estate. Therefore we return the
828 * number of tuples processed as the result, not in estate->es_processed.
830 * One difference from ExecutorRun is that the destination receiver functions
831 * are run in the caller's memory context (since we have no estate). Watch
832 * out for memory leaks.
835 RunFromStore(Portal portal, ScanDirection direction, long count,
838 long current_tuple_count = 0;
840 (*dest->rStartup) (dest, CMD_SELECT, portal->tupDesc);
842 if (direction == NoMovementScanDirection)
844 /* do nothing except start/stop the destination */
848 bool forward = (direction == ForwardScanDirection);
852 MemoryContext oldcontext;
856 oldcontext = MemoryContextSwitchTo(portal->holdContext);
858 tup = tuplestore_getheaptuple(portal->holdStore, forward,
861 MemoryContextSwitchTo(oldcontext);
866 (*dest->receiveTuple) (tup, portal->tupDesc, dest);
872 * check our tuple count.. if we've processed the proper
873 * number then quit, else loop again and process more tuples.
874 * Zero count means no limit.
876 current_tuple_count++;
877 if (count && count == current_tuple_count)
882 (*dest->rShutdown) (dest);
884 return (uint32) current_tuple_count;
889 * Execute a utility statement inside a portal.
892 PortalRunUtility(Portal portal, Query *query,
893 DestReceiver *dest, char *completionTag)
895 Node *utilityStmt = query->utilityStmt;
898 (errmsg_internal("ProcessUtility")));
901 * Set snapshot if utility stmt needs one. Most reliable way to do
902 * this seems to be to enumerate those that do not need one; this is a
903 * short list. Transaction control, LOCK, and SET must *not* set a
904 * snapshot since they need to be executable at the start of a
905 * serializable transaction without freezing a snapshot. By extension
906 * we allow SHOW not to set a snapshot. The other stmts listed are
907 * just efficiency hacks. Beware of listing anything that can modify
908 * the database --- if, say, it has to update an index with
909 * expressions that invoke user-defined functions, then it had better
912 * Note we assume that caller will take care of restoring ActiveSnapshot
915 if (!(IsA(utilityStmt, TransactionStmt) ||
916 IsA(utilityStmt, LockStmt) ||
917 IsA(utilityStmt, VariableSetStmt) ||
918 IsA(utilityStmt, VariableShowStmt) ||
919 IsA(utilityStmt, VariableResetStmt) ||
920 IsA(utilityStmt, ConstraintsSetStmt) ||
921 /* efficiency hacks from here down */
922 IsA(utilityStmt, FetchStmt) ||
923 IsA(utilityStmt, ListenStmt) ||
924 IsA(utilityStmt, NotifyStmt) ||
925 IsA(utilityStmt, UnlistenStmt) ||
926 IsA(utilityStmt, CheckPointStmt)))
927 ActiveSnapshot = CopySnapshot(GetTransactionSnapshot());
929 ActiveSnapshot = NULL;
931 if (query->canSetTag)
933 /* utility statement can override default tag string */
934 ProcessUtility(utilityStmt, portal->portalParams, dest, completionTag);
935 if (completionTag && completionTag[0] == '\0' && portal->commandTag)
936 strcpy(completionTag, portal->commandTag); /* use the default */
940 /* utility added by rewrite cannot set tag */
941 ProcessUtility(utilityStmt, portal->portalParams, dest, NULL);
944 /* Some utility statements may change context on us */
945 MemoryContextSwitchTo(PortalGetHeapMemory(portal));
948 FreeSnapshot(ActiveSnapshot);
949 ActiveSnapshot = NULL;
954 * Execute a portal's queries in the general case (multi queries).
957 PortalRunMulti(Portal portal,
958 DestReceiver *dest, DestReceiver *altdest,
961 ListCell *querylist_item;
962 ListCell *planlist_item;
965 * If the destination is RemoteExecute, change to None. The reason is
966 * that the client won't be expecting any tuples, and indeed has no
967 * way to know what they are, since there is no provision for Describe
968 * to send a RowDescription message when this portal execution
969 * strategy is in effect. This presently will only affect SELECT
970 * commands added to non-SELECT queries by rewrite rules: such
971 * commands will be executed, but the results will be discarded unless
972 * you use "simple Query" protocol.
974 if (dest->mydest == RemoteExecute)
975 dest = None_Receiver;
976 if (altdest->mydest == RemoteExecute)
977 altdest = None_Receiver;
980 * Loop to handle the individual queries generated from a single
981 * parsetree by analysis and rewrite.
983 forboth(querylist_item, portal->parseTrees,
984 planlist_item, portal->planTrees)
986 Query *query = (Query *) lfirst(querylist_item);
987 Plan *plan = (Plan *) lfirst(planlist_item);
990 * If we got a cancel signal in prior command, quit
992 CHECK_FOR_INTERRUPTS();
994 if (query->commandType == CMD_UTILITY)
997 * process utility functions (create, destroy, etc..)
999 Assert(plan == NULL);
1001 PortalRunUtility(portal, query,
1002 query->canSetTag ? dest : altdest,
1008 * process a plannable query.
1010 if (log_executor_stats)
1013 if (query->canSetTag)
1015 /* statement can set tag string */
1016 ProcessQuery(query, plan,
1017 portal->portalParams,
1018 dest, completionTag);
1022 /* stmt added by rewrite cannot set tag */
1023 ProcessQuery(query, plan,
1024 portal->portalParams,
1028 if (log_executor_stats)
1029 ShowUsage("EXECUTOR STATISTICS");
1033 * Increment command counter between queries, but not after the
1036 if (planlist_item != NULL)
1037 CommandCounterIncrement();
1040 * Clear subsidiary contexts to recover temporary memory.
1042 Assert(PortalGetHeapMemory(portal) == CurrentMemoryContext);
1044 MemoryContextDeleteChildren(PortalGetHeapMemory(portal));
1048 * If a command completion tag was supplied, use it. Otherwise use
1049 * the portal's commandTag as the default completion tag.
1051 * Exception: clients will expect INSERT/UPDATE/DELETE tags to have
1052 * counts, so fake something up if necessary. (This could happen if
1053 * the original query was replaced by a DO INSTEAD rule.)
1055 if (completionTag && completionTag[0] == '\0')
1057 if (portal->commandTag)
1058 strcpy(completionTag, portal->commandTag);
1059 if (strcmp(completionTag, "INSERT") == 0)
1060 strcpy(completionTag, "INSERT 0 0");
1061 else if (strcmp(completionTag, "UPDATE") == 0)
1062 strcpy(completionTag, "UPDATE 0");
1063 else if (strcmp(completionTag, "DELETE") == 0)
1064 strcpy(completionTag, "DELETE 0");
1070 * Variant form of PortalRun that supports SQL FETCH directions.
1072 * Returns number of rows processed (suitable for use in result tag)
1075 PortalRunFetch(Portal portal,
1076 FetchDirection fdirection,
1081 Portal saveActivePortal;
1082 Snapshot saveActiveSnapshot;
1083 ResourceOwner saveResourceOwner;
1084 MemoryContext savePortalContext;
1085 MemoryContext saveQueryContext;
1086 MemoryContext oldContext;
1088 AssertArg(PortalIsValid(portal));
1091 * Check for improper portal use, and mark portal active.
1093 if (portal->status != PORTAL_READY)
1095 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1096 errmsg("portal \"%s\" cannot be run", portal->name)));
1097 portal->status = PORTAL_ACTIVE;
1100 * Set up global portal context pointers.
1102 saveActivePortal = ActivePortal;
1103 saveActiveSnapshot = ActiveSnapshot;
1104 saveResourceOwner = CurrentResourceOwner;
1105 savePortalContext = PortalContext;
1106 saveQueryContext = QueryContext;
1109 ActivePortal = portal;
1110 ActiveSnapshot = NULL; /* will be set later */
1111 CurrentResourceOwner = portal->resowner;
1112 PortalContext = PortalGetHeapMemory(portal);
1113 QueryContext = portal->queryContext;
1115 oldContext = MemoryContextSwitchTo(PortalContext);
1117 switch (portal->strategy)
1119 case PORTAL_ONE_SELECT:
1120 result = DoPortalRunFetch(portal, fdirection, count, dest);
1124 elog(ERROR, "unsupported portal strategy");
1125 result = 0; /* keep compiler quiet */
1131 /* Uncaught error while executing portal: mark it dead */
1132 portal->status = PORTAL_FAILED;
1134 /* Restore global vars and propagate error */
1135 ActivePortal = saveActivePortal;
1136 ActiveSnapshot = saveActiveSnapshot;
1137 CurrentResourceOwner = saveResourceOwner;
1138 PortalContext = savePortalContext;
1139 QueryContext = saveQueryContext;
1145 MemoryContextSwitchTo(oldContext);
1147 /* Mark portal not active */
1148 portal->status = PORTAL_READY;
1150 ActivePortal = saveActivePortal;
1151 ActiveSnapshot = saveActiveSnapshot;
1152 CurrentResourceOwner = saveResourceOwner;
1153 PortalContext = savePortalContext;
1154 QueryContext = saveQueryContext;
1161 * Guts of PortalRunFetch --- the portal context is already set up
1163 * Returns number of rows processed (suitable for use in result tag)
1166 DoPortalRunFetch(Portal portal,
1167 FetchDirection fdirection,
1173 Assert(portal->strategy == PORTAL_ONE_SELECT);
1180 fdirection = FETCH_BACKWARD;
1183 /* fall out of switch to share code with FETCH_BACKWARD */
1185 case FETCH_BACKWARD:
1188 fdirection = FETCH_FORWARD;
1191 /* fall out of switch to share code with FETCH_FORWARD */
1193 case FETCH_ABSOLUTE:
1197 * Definition: Rewind to start, advance count-1 rows,
1198 * return next row (if any). In practice, if the goal is
1199 * less than halfway back to the start, it's better to
1200 * scan from where we are. In any case, we arrange to
1201 * fetch the target row going forwards.
1203 if (portal->posOverflow || portal->portalPos == LONG_MAX ||
1204 count - 1 <= portal->portalPos / 2)
1206 DoPortalRewind(portal);
1208 PortalRunSelect(portal, true, count - 1,
1213 long pos = portal->portalPos;
1216 pos++; /* need one extra fetch if off end */
1218 PortalRunSelect(portal, false, pos - count + 1,
1220 else if (count > pos + 1)
1221 PortalRunSelect(portal, true, count - pos - 1,
1224 return PortalRunSelect(portal, true, 1L, dest);
1229 * Definition: Advance to end, back up abs(count)-1 rows,
1230 * return prior row (if any). We could optimize this if
1231 * we knew in advance where the end was, but typically we
1232 * won't. (Is it worth considering case where count > half
1233 * of size of query? We could rewind once we know the
1236 PortalRunSelect(portal, true, FETCH_ALL, None_Receiver);
1238 PortalRunSelect(portal, false, -count - 1, None_Receiver);
1239 return PortalRunSelect(portal, false, 1L, dest);
1244 /* Rewind to start, return zero rows */
1245 DoPortalRewind(portal);
1246 return PortalRunSelect(portal, true, 0L, dest);
1249 case FETCH_RELATIVE:
1253 * Definition: advance count-1 rows, return next row (if
1257 PortalRunSelect(portal, true, count - 1, None_Receiver);
1258 return PortalRunSelect(portal, true, 1L, dest);
1263 * Definition: back up abs(count)-1 rows, return prior row
1267 PortalRunSelect(portal, false, -count - 1, None_Receiver);
1268 return PortalRunSelect(portal, false, 1L, dest);
1273 /* Same as FETCH FORWARD 0, so fall out of switch */
1274 fdirection = FETCH_FORWARD;
1278 elog(ERROR, "bogus direction");
1283 * Get here with fdirection == FETCH_FORWARD or FETCH_BACKWARD, and
1286 forward = (fdirection == FETCH_FORWARD);
1289 * Zero count means to re-fetch the current row, if any (per SQL92)
1295 /* Are we sitting on a row? */
1296 on_row = (!portal->atStart && !portal->atEnd);
1298 if (dest->mydest == None)
1300 /* MOVE 0 returns 0/1 based on if FETCH 0 would return a row */
1301 return on_row ? 1L : 0L;
1306 * If we are sitting on a row, back up one so we can re-fetch
1307 * it. If we are not sitting on a row, we still have to start
1308 * up and shut down the executor so that the destination is
1309 * initialized and shut down correctly; so keep going. To
1310 * PortalRunSelect, count == 0 means we will retrieve no row.
1314 PortalRunSelect(portal, false, 1L, None_Receiver);
1315 /* Set up to fetch one row forward */
1323 * Optimize MOVE BACKWARD ALL into a Rewind.
1325 if (!forward && count == FETCH_ALL && dest->mydest == None)
1327 long result = portal->portalPos;
1329 if (result > 0 && !portal->atEnd)
1331 DoPortalRewind(portal);
1332 /* result is bogus if pos had overflowed, but it's best we can do */
1336 return PortalRunSelect(portal, forward, count, dest);
1340 * DoPortalRewind - rewind a Portal to starting point
1343 DoPortalRewind(Portal portal)
1345 if (portal->holdStore)
1347 MemoryContext oldcontext;
1349 oldcontext = MemoryContextSwitchTo(portal->holdContext);
1350 tuplestore_rescan(portal->holdStore);
1351 MemoryContextSwitchTo(oldcontext);
1353 if (PortalGetQueryDesc(portal))
1354 ExecutorRewind(PortalGetQueryDesc(portal));
1356 portal->atStart = true;
1357 portal->atEnd = false;
1358 portal->portalPos = 0;
1359 portal->posOverflow = false;