PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
pquery.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * pquery.c
4 * POSTGRES process query command code
5 *
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
8 *
9 *
10 * IDENTIFICATION
11 * src/backend/tcop/pquery.c
12 *
13 *-------------------------------------------------------------------------
14 */
15
16#include "postgres.h"
17
18#include <limits.h>
19
20#include "access/xact.h"
21#include "commands/prepare.h"
22#include "executor/execdesc.h"
23#include "executor/executor.h"
25#include "miscadmin.h"
26#include "pg_trace.h"
27#include "tcop/pquery.h"
28#include "tcop/utility.h"
29#include "utils/memutils.h"
30#include "utils/snapmgr.h"
31
32
33/*
34 * ActivePortal is the currently executing Portal (the most closely nested,
35 * if there are several).
36 */
38
39
40static void ProcessQuery(PlannedStmt *plan,
41 CachedPlan *cplan,
42 CachedPlanSource *plansource,
43 int query_index,
44 const char *sourceText,
45 ParamListInfo params,
46 QueryEnvironment *queryEnv,
48 QueryCompletion *qc);
49static void FillPortalStore(Portal portal, bool isTopLevel);
50static uint64 RunFromStore(Portal portal, ScanDirection direction, uint64 count,
52static uint64 PortalRunSelect(Portal portal, bool forward, long count,
54static void PortalRunUtility(Portal portal, PlannedStmt *pstmt,
55 bool isTopLevel, bool setHoldSnapshot,
57static void PortalRunMulti(Portal portal,
58 bool isTopLevel, bool setHoldSnapshot,
60 QueryCompletion *qc);
61static uint64 DoPortalRunFetch(Portal portal,
62 FetchDirection fdirection,
63 long count,
65static void DoPortalRewind(Portal portal);
66
67
68/*
69 * CreateQueryDesc
70 */
73 CachedPlan *cplan,
74 const char *sourceText,
75 Snapshot snapshot,
76 Snapshot crosscheck_snapshot,
78 ParamListInfo params,
79 QueryEnvironment *queryEnv,
80 int instrument_options)
81{
82 QueryDesc *qd = (QueryDesc *) palloc(sizeof(QueryDesc));
83
84 qd->operation = plannedstmt->commandType; /* operation */
85 qd->plannedstmt = plannedstmt; /* plan */
86 qd->cplan = cplan; /* CachedPlan supplying the plannedstmt */
87 qd->sourceText = sourceText; /* query text */
88 qd->snapshot = RegisterSnapshot(snapshot); /* snapshot */
89 /* RI check snapshot */
90 qd->crosscheck_snapshot = RegisterSnapshot(crosscheck_snapshot);
91 qd->dest = dest; /* output dest */
92 qd->params = params; /* parameter values passed into query */
93 qd->queryEnv = queryEnv;
94 qd->instrument_options = instrument_options; /* instrumentation wanted? */
95
96 /* null these fields until set by ExecutorStart */
97 qd->tupDesc = NULL;
98 qd->estate = NULL;
99 qd->planstate = NULL;
100 qd->totaltime = NULL;
101
102 /* not yet executed */
103 qd->already_executed = false;
104
105 return qd;
106}
107
108/*
109 * FreeQueryDesc
110 */
111void
113{
114 /* Can't be a live query */
115 Assert(qdesc->estate == NULL);
116
117 /* forget our snapshots */
120
121 /* Only the QueryDesc itself need be freed */
122 pfree(qdesc);
123}
124
125
126/*
127 * ProcessQuery
128 * Execute a single plannable query within a PORTAL_MULTI_QUERY,
129 * PORTAL_ONE_RETURNING, or PORTAL_ONE_MOD_WITH portal
130 *
131 * plan: the plan tree for the query
132 * cplan: CachedPlan supplying the plan
133 * plansource: CachedPlanSource supplying the cplan
134 * query_index: index of the query in plansource->query_list
135 * sourceText: the source text of the query
136 * params: any parameters needed
137 * dest: where to send results
138 * qc: where to store the command completion status data.
139 *
140 * qc may be NULL if caller doesn't want a status string.
141 *
142 * Must be called in a memory context that will be reset or deleted on
143 * error; otherwise the executor's memory usage will be leaked.
144 */
145static void
147 CachedPlan *cplan,
148 CachedPlanSource *plansource,
149 int query_index,
150 const char *sourceText,
151 ParamListInfo params,
152 QueryEnvironment *queryEnv,
154 QueryCompletion *qc)
155{
156 QueryDesc *queryDesc;
157
158 /*
159 * Create the QueryDesc object
160 */
161 queryDesc = CreateQueryDesc(plan, cplan, sourceText,
163 dest, params, queryEnv, 0);
164
165 /*
166 * Prepare the plan for execution
167 */
168 if (queryDesc->cplan)
169 {
170 ExecutorStartCachedPlan(queryDesc, 0, plansource, query_index);
171 Assert(queryDesc->planstate);
172 }
173 else
174 {
175 if (!ExecutorStart(queryDesc, 0))
176 elog(ERROR, "ExecutorStart() failed unexpectedly");
177 }
178
179 /*
180 * Run the plan to completion.
181 */
182 ExecutorRun(queryDesc, ForwardScanDirection, 0);
183
184 /*
185 * Build command completion status data, if caller wants one.
186 */
187 if (qc)
188 {
189 switch (queryDesc->operation)
190 {
191 case CMD_SELECT:
192 SetQueryCompletion(qc, CMDTAG_SELECT, queryDesc->estate->es_processed);
193 break;
194 case CMD_INSERT:
195 SetQueryCompletion(qc, CMDTAG_INSERT, queryDesc->estate->es_processed);
196 break;
197 case CMD_UPDATE:
198 SetQueryCompletion(qc, CMDTAG_UPDATE, queryDesc->estate->es_processed);
199 break;
200 case CMD_DELETE:
201 SetQueryCompletion(qc, CMDTAG_DELETE, queryDesc->estate->es_processed);
202 break;
203 case CMD_MERGE:
204 SetQueryCompletion(qc, CMDTAG_MERGE, queryDesc->estate->es_processed);
205 break;
206 default:
207 SetQueryCompletion(qc, CMDTAG_UNKNOWN, queryDesc->estate->es_processed);
208 break;
209 }
210 }
211
212 /*
213 * Now, we close down all the scans and free allocated resources.
214 */
215 ExecutorFinish(queryDesc);
216 ExecutorEnd(queryDesc);
217
218 FreeQueryDesc(queryDesc);
219}
220
221/*
222 * ChoosePortalStrategy
223 * Select portal execution strategy given the intended statement list.
224 *
225 * The list elements can be Querys or PlannedStmts.
226 * That's more general than portals need, but plancache.c uses this too.
227 *
228 * See the comments in portal.h.
229 */
232{
233 int nSetTag;
234 ListCell *lc;
235
236 /*
237 * PORTAL_ONE_SELECT and PORTAL_UTIL_SELECT need only consider the
238 * single-statement case, since there are no rewrite rules that can add
239 * auxiliary queries to a SELECT or a utility command. PORTAL_ONE_MOD_WITH
240 * likewise allows only one top-level statement.
241 */
242 if (list_length(stmts) == 1)
243 {
244 Node *stmt = (Node *) linitial(stmts);
245
246 if (IsA(stmt, Query))
247 {
248 Query *query = (Query *) stmt;
249
250 if (query->canSetTag)
251 {
252 if (query->commandType == CMD_SELECT)
253 {
254 if (query->hasModifyingCTE)
255 return PORTAL_ONE_MOD_WITH;
256 else
257 return PORTAL_ONE_SELECT;
258 }
259 if (query->commandType == CMD_UTILITY)
260 {
262 return PORTAL_UTIL_SELECT;
263 /* it can't be ONE_RETURNING, so give up */
264 return PORTAL_MULTI_QUERY;
265 }
266 }
267 }
268 else if (IsA(stmt, PlannedStmt))
269 {
270 PlannedStmt *pstmt = (PlannedStmt *) stmt;
271
272 if (pstmt->canSetTag)
273 {
274 if (pstmt->commandType == CMD_SELECT)
275 {
276 if (pstmt->hasModifyingCTE)
277 return PORTAL_ONE_MOD_WITH;
278 else
279 return PORTAL_ONE_SELECT;
280 }
281 if (pstmt->commandType == CMD_UTILITY)
282 {
284 return PORTAL_UTIL_SELECT;
285 /* it can't be ONE_RETURNING, so give up */
286 return PORTAL_MULTI_QUERY;
287 }
288 }
289 }
290 else
291 elog(ERROR, "unrecognized node type: %d", (int) nodeTag(stmt));
292 }
293
294 /*
295 * PORTAL_ONE_RETURNING has to allow auxiliary queries added by rewrite.
296 * Choose PORTAL_ONE_RETURNING if there is exactly one canSetTag query and
297 * it has a RETURNING list.
298 */
299 nSetTag = 0;
300 foreach(lc, stmts)
301 {
302 Node *stmt = (Node *) lfirst(lc);
303
304 if (IsA(stmt, Query))
305 {
306 Query *query = (Query *) stmt;
307
308 if (query->canSetTag)
309 {
310 if (++nSetTag > 1)
311 return PORTAL_MULTI_QUERY; /* no need to look further */
312 if (query->commandType == CMD_UTILITY ||
313 query->returningList == NIL)
314 return PORTAL_MULTI_QUERY; /* no need to look further */
315 }
316 }
317 else if (IsA(stmt, PlannedStmt))
318 {
319 PlannedStmt *pstmt = (PlannedStmt *) stmt;
320
321 if (pstmt->canSetTag)
322 {
323 if (++nSetTag > 1)
324 return PORTAL_MULTI_QUERY; /* no need to look further */
325 if (pstmt->commandType == CMD_UTILITY ||
326 !pstmt->hasReturning)
327 return PORTAL_MULTI_QUERY; /* no need to look further */
328 }
329 }
330 else
331 elog(ERROR, "unrecognized node type: %d", (int) nodeTag(stmt));
332 }
333 if (nSetTag == 1)
335
336 /* Else, it's the general case... */
337 return PORTAL_MULTI_QUERY;
338}
339
340/*
341 * FetchPortalTargetList
342 * Given a portal that returns tuples, extract the query targetlist.
343 * Returns NIL if the portal doesn't have a determinable targetlist.
344 *
345 * Note: do not modify the result.
346 */
347List *
349{
350 /* no point in looking if we determined it doesn't return tuples */
351 if (portal->strategy == PORTAL_MULTI_QUERY)
352 return NIL;
353 /* get the primary statement and find out what it returns */
355}
356
357/*
358 * FetchStatementTargetList
359 * Given a statement that returns tuples, extract the query targetlist.
360 * Returns NIL if the statement doesn't have a determinable targetlist.
361 *
362 * This can be applied to a Query or a PlannedStmt.
363 * That's more general than portals need, but plancache.c uses this too.
364 *
365 * Note: do not modify the result.
366 *
367 * XXX be careful to keep this in sync with UtilityReturnsTuples.
368 */
369List *
371{
372 if (stmt == NULL)
373 return NIL;
374 if (IsA(stmt, Query))
375 {
376 Query *query = (Query *) stmt;
377
378 if (query->commandType == CMD_UTILITY)
379 {
380 /* transfer attention to utility statement */
381 stmt = query->utilityStmt;
382 }
383 else
384 {
385 if (query->commandType == CMD_SELECT)
386 return query->targetList;
387 if (query->returningList)
388 return query->returningList;
389 return NIL;
390 }
391 }
392 if (IsA(stmt, PlannedStmt))
393 {
394 PlannedStmt *pstmt = (PlannedStmt *) stmt;
395
396 if (pstmt->commandType == CMD_UTILITY)
397 {
398 /* transfer attention to utility statement */
399 stmt = pstmt->utilityStmt;
400 }
401 else
402 {
403 if (pstmt->commandType == CMD_SELECT)
404 return pstmt->planTree->targetlist;
405 if (pstmt->hasReturning)
406 return pstmt->planTree->targetlist;
407 return NIL;
408 }
409 }
410 if (IsA(stmt, FetchStmt))
411 {
412 FetchStmt *fstmt = (FetchStmt *) stmt;
413 Portal subportal;
414
415 Assert(!fstmt->ismove);
416 subportal = GetPortalByName(fstmt->portalname);
417 Assert(PortalIsValid(subportal));
418 return FetchPortalTargetList(subportal);
419 }
420 if (IsA(stmt, ExecuteStmt))
421 {
422 ExecuteStmt *estmt = (ExecuteStmt *) stmt;
423 PreparedStatement *entry;
424
425 entry = FetchPreparedStatement(estmt->name, true);
427 }
428 return NIL;
429}
430
431/*
432 * PortalStart
433 * Prepare a portal for execution.
434 *
435 * Caller must already have created the portal, done PortalDefineQuery(),
436 * and adjusted portal options if needed.
437 *
438 * If parameters are needed by the query, they must be passed in "params"
439 * (caller is responsible for giving them appropriate lifetime).
440 *
441 * The caller can also provide an initial set of "eflags" to be passed to
442 * ExecutorStart (but note these can be modified internally, and they are
443 * currently only honored for PORTAL_ONE_SELECT portals). Most callers
444 * should simply pass zero.
445 *
446 * The caller can optionally pass a snapshot to be used; pass InvalidSnapshot
447 * for the normal behavior of setting a new snapshot. This parameter is
448 * presently ignored for non-PORTAL_ONE_SELECT portals (it's only intended
449 * to be used for cursors).
450 *
451 * On return, portal is ready to accept PortalRun() calls, and the result
452 * tupdesc (if any) is known.
453 */
454void
456 int eflags, Snapshot snapshot)
457{
458 Portal saveActivePortal;
459 ResourceOwner saveResourceOwner;
460 MemoryContext savePortalContext;
461 MemoryContext oldContext;
462 QueryDesc *queryDesc;
463 int myeflags;
464
465 Assert(PortalIsValid(portal));
466 Assert(portal->status == PORTAL_DEFINED);
467
468 /*
469 * Set up global portal context pointers.
470 */
471 saveActivePortal = ActivePortal;
472 saveResourceOwner = CurrentResourceOwner;
473 savePortalContext = PortalContext;
474 PG_TRY();
475 {
476 ActivePortal = portal;
477 if (portal->resowner)
480
482
483 /* Must remember portal param list, if any */
484 portal->portalParams = params;
485
486 /*
487 * Determine the portal execution strategy
488 */
489 portal->strategy = ChoosePortalStrategy(portal->stmts);
490
491 /*
492 * Fire her up according to the strategy
493 */
494 switch (portal->strategy)
495 {
497
498 /* Must set snapshot before starting executor. */
499 if (snapshot)
500 PushActiveSnapshot(snapshot);
501 else
503
504 /*
505 * We could remember the snapshot in portal->portalSnapshot,
506 * but presently there seems no need to, as this code path
507 * cannot be used for non-atomic execution. Hence there can't
508 * be any commit/abort that might destroy the snapshot. Since
509 * we don't do that, there's also no need to force a
510 * non-default nesting level for the snapshot.
511 */
512
513 /*
514 * Create QueryDesc in portal's context; for the moment, set
515 * the destination to DestNone.
516 */
517 queryDesc = CreateQueryDesc(linitial_node(PlannedStmt, portal->stmts),
518 portal->cplan,
519 portal->sourceText,
523 params,
524 portal->queryEnv,
525 0);
526
527 /*
528 * If it's a scrollable cursor, executor needs to support
529 * REWIND and backwards scan, as well as whatever the caller
530 * might've asked for.
531 */
532 if (portal->cursorOptions & CURSOR_OPT_SCROLL)
533 myeflags = eflags | EXEC_FLAG_REWIND | EXEC_FLAG_BACKWARD;
534 else
535 myeflags = eflags;
536
537 /*
538 * Prepare the plan for execution.
539 */
540 if (portal->cplan)
541 {
542 ExecutorStartCachedPlan(queryDesc, myeflags,
543 portal->plansource, 0);
544 Assert(queryDesc->planstate);
545 }
546 else
547 {
548 if (!ExecutorStart(queryDesc, myeflags))
549 elog(ERROR, "ExecutorStart() failed unexpectedly");
550 }
551
552 /*
553 * This tells PortalCleanup to shut down the executor
554 */
555 portal->queryDesc = queryDesc;
556
557 /*
558 * Remember tuple descriptor (computed by ExecutorStart)
559 */
560 portal->tupDesc = queryDesc->tupDesc;
561
562 /*
563 * Reset cursor position data to "start of query"
564 */
565 portal->atStart = true;
566 portal->atEnd = false; /* allow fetches */
567 portal->portalPos = 0;
568
570 break;
571
574
575 /*
576 * We don't start the executor until we are told to run the
577 * portal. We do need to set up the result tupdesc.
578 */
579 {
580 PlannedStmt *pstmt;
581
582 pstmt = PortalGetPrimaryStmt(portal);
583 portal->tupDesc =
585 }
586
587 /*
588 * Reset cursor position data to "start of query"
589 */
590 portal->atStart = true;
591 portal->atEnd = false; /* allow fetches */
592 portal->portalPos = 0;
593 break;
594
596
597 /*
598 * We don't set snapshot here, because PortalRunUtility will
599 * take care of it if needed.
600 */
601 {
602 PlannedStmt *pstmt = PortalGetPrimaryStmt(portal);
603
604 Assert(pstmt->commandType == CMD_UTILITY);
606 }
607
608 /*
609 * Reset cursor position data to "start of query"
610 */
611 portal->atStart = true;
612 portal->atEnd = false; /* allow fetches */
613 portal->portalPos = 0;
614 break;
615
617 /* Need do nothing now */
618 portal->tupDesc = NULL;
619 break;
620 }
621 }
622 PG_CATCH();
623 {
624 /* Uncaught error while executing portal: mark it dead */
625 MarkPortalFailed(portal);
626
627 /* Restore global vars and propagate error */
628 ActivePortal = saveActivePortal;
629 CurrentResourceOwner = saveResourceOwner;
630 PortalContext = savePortalContext;
631
632 PG_RE_THROW();
633 }
634 PG_END_TRY();
635
636 MemoryContextSwitchTo(oldContext);
637
638 ActivePortal = saveActivePortal;
639 CurrentResourceOwner = saveResourceOwner;
640 PortalContext = savePortalContext;
641
642 portal->status = PORTAL_READY;
643}
644
645/*
646 * PortalSetResultFormat
647 * Select the format codes for a portal's output.
648 *
649 * This must be run after PortalStart for a portal that will be read by
650 * a DestRemote or DestRemoteExecute destination. It is not presently needed
651 * for other destination types.
652 *
653 * formats[] is the client format request, as per Bind message conventions.
654 */
655void
656PortalSetResultFormat(Portal portal, int nFormats, int16 *formats)
657{
658 int natts;
659 int i;
660
661 /* Do nothing if portal won't return tuples */
662 if (portal->tupDesc == NULL)
663 return;
664 natts = portal->tupDesc->natts;
665 portal->formats = (int16 *)
667 natts * sizeof(int16));
668 if (nFormats > 1)
669 {
670 /* format specified for each column */
671 if (nFormats != natts)
673 (errcode(ERRCODE_PROTOCOL_VIOLATION),
674 errmsg("bind message has %d result formats but query has %d columns",
675 nFormats, natts)));
676 memcpy(portal->formats, formats, natts * sizeof(int16));
677 }
678 else if (nFormats > 0)
679 {
680 /* single format specified, use for all columns */
681 int16 format1 = formats[0];
682
683 for (i = 0; i < natts; i++)
684 portal->formats[i] = format1;
685 }
686 else
687 {
688 /* use default format for all columns */
689 for (i = 0; i < natts; i++)
690 portal->formats[i] = 0;
691 }
692}
693
694/*
695 * PortalRun
696 * Run a portal's query or queries.
697 *
698 * count <= 0 is interpreted as a no-op: the destination gets started up
699 * and shut down, but nothing else happens. Also, count == FETCH_ALL is
700 * interpreted as "all rows". Note that count is ignored in multi-query
701 * situations, where we always run the portal to completion.
702 *
703 * isTopLevel: true if query is being executed at backend "top level"
704 * (that is, directly from a client command message)
705 *
706 * dest: where to send output of primary (canSetTag) query
707 *
708 * altdest: where to send output of non-primary queries
709 *
710 * qc: where to store command completion status data.
711 * May be NULL if caller doesn't want status data.
712 *
713 * Returns true if the portal's execution is complete, false if it was
714 * suspended due to exhaustion of the count parameter.
715 */
716bool
717PortalRun(Portal portal, long count, bool isTopLevel,
718 DestReceiver *dest, DestReceiver *altdest,
719 QueryCompletion *qc)
720{
721 bool result;
722 uint64 nprocessed;
723 ResourceOwner saveTopTransactionResourceOwner;
724 MemoryContext saveTopTransactionContext;
725 Portal saveActivePortal;
726 ResourceOwner saveResourceOwner;
727 MemoryContext savePortalContext;
728 MemoryContext saveMemoryContext;
729
730 Assert(PortalIsValid(portal));
731
732 TRACE_POSTGRESQL_QUERY_EXECUTE_START();
733
734 /* Initialize empty completion data */
735 if (qc)
737
739 {
740 elog(DEBUG3, "PortalRun");
741 /* PORTAL_MULTI_QUERY logs its own stats per query */
742 ResetUsage();
743 }
744
745 /*
746 * Check for improper portal use, and mark portal active.
747 */
748 MarkPortalActive(portal);
749
750 /*
751 * Set up global portal context pointers.
752 *
753 * We have to play a special game here to support utility commands like
754 * VACUUM and CLUSTER, which internally start and commit transactions.
755 * When we are called to execute such a command, CurrentResourceOwner will
756 * be pointing to the TopTransactionResourceOwner --- which will be
757 * destroyed and replaced in the course of the internal commit and
758 * restart. So we need to be prepared to restore it as pointing to the
759 * exit-time TopTransactionResourceOwner. (Ain't that ugly? This idea of
760 * internally starting whole new transactions is not good.)
761 * CurrentMemoryContext has a similar problem, but the other pointers we
762 * save here will be NULL or pointing to longer-lived objects.
763 */
764 saveTopTransactionResourceOwner = TopTransactionResourceOwner;
765 saveTopTransactionContext = TopTransactionContext;
766 saveActivePortal = ActivePortal;
767 saveResourceOwner = CurrentResourceOwner;
768 savePortalContext = PortalContext;
769 saveMemoryContext = CurrentMemoryContext;
770 PG_TRY();
771 {
772 ActivePortal = portal;
773 if (portal->resowner)
776
778
779 switch (portal->strategy)
780 {
785
786 /*
787 * If we have not yet run the command, do so, storing its
788 * results in the portal's tuplestore. But we don't do that
789 * for the PORTAL_ONE_SELECT case.
790 */
791 if (portal->strategy != PORTAL_ONE_SELECT && !portal->holdStore)
792 FillPortalStore(portal, isTopLevel);
793
794 /*
795 * Now fetch desired portion of results.
796 */
797 nprocessed = PortalRunSelect(portal, true, count, dest);
798
799 /*
800 * If the portal result contains a command tag and the caller
801 * gave us a pointer to store it, copy it and update the
802 * rowcount.
803 */
804 if (qc && portal->qc.commandTag != CMDTAG_UNKNOWN)
805 {
806 CopyQueryCompletion(qc, &portal->qc);
807 qc->nprocessed = nprocessed;
808 }
809
810 /* Mark portal not active */
811 portal->status = PORTAL_READY;
812
813 /*
814 * Since it's a forward fetch, say DONE iff atEnd is now true.
815 */
816 result = portal->atEnd;
817 break;
818
820 PortalRunMulti(portal, isTopLevel, false,
821 dest, altdest, qc);
822
823 /* Prevent portal's commands from being re-executed */
824 MarkPortalDone(portal);
825
826 /* Always complete at end of RunMulti */
827 result = true;
828 break;
829
830 default:
831 elog(ERROR, "unrecognized portal strategy: %d",
832 (int) portal->strategy);
833 result = false; /* keep compiler quiet */
834 break;
835 }
836 }
837 PG_CATCH();
838 {
839 /* Uncaught error while executing portal: mark it dead */
840 MarkPortalFailed(portal);
841
842 /* Restore global vars and propagate error */
843 if (saveMemoryContext == saveTopTransactionContext)
845 else
846 MemoryContextSwitchTo(saveMemoryContext);
847 ActivePortal = saveActivePortal;
848 if (saveResourceOwner == saveTopTransactionResourceOwner)
850 else
851 CurrentResourceOwner = saveResourceOwner;
852 PortalContext = savePortalContext;
853
854 PG_RE_THROW();
855 }
856 PG_END_TRY();
857
858 if (saveMemoryContext == saveTopTransactionContext)
860 else
861 MemoryContextSwitchTo(saveMemoryContext);
862 ActivePortal = saveActivePortal;
863 if (saveResourceOwner == saveTopTransactionResourceOwner)
865 else
866 CurrentResourceOwner = saveResourceOwner;
867 PortalContext = savePortalContext;
868
870 ShowUsage("EXECUTOR STATISTICS");
871
872 TRACE_POSTGRESQL_QUERY_EXECUTE_DONE();
873
874 return result;
875}
876
877/*
878 * PortalRunSelect
879 * Execute a portal's query in PORTAL_ONE_SELECT mode, and also
880 * when fetching from a completed holdStore in PORTAL_ONE_RETURNING,
881 * PORTAL_ONE_MOD_WITH, and PORTAL_UTIL_SELECT cases.
882 *
883 * This handles simple N-rows-forward-or-backward cases. For more complex
884 * nonsequential access to a portal, see PortalRunFetch.
885 *
886 * count <= 0 is interpreted as a no-op: the destination gets started up
887 * and shut down, but nothing else happens. Also, count == FETCH_ALL is
888 * interpreted as "all rows". (cf FetchStmt.howMany)
889 *
890 * Caller must already have validated the Portal and done appropriate
891 * setup (cf. PortalRun).
892 *
893 * Returns number of rows processed (suitable for use in result tag)
894 */
895static uint64
897 bool forward,
898 long count,
900{
901 QueryDesc *queryDesc;
902 ScanDirection direction;
903 uint64 nprocessed;
904
905 /*
906 * NB: queryDesc will be NULL if we are fetching from a held cursor or a
907 * completed utility query; can't use it in that path.
908 */
909 queryDesc = portal->queryDesc;
910
911 /* Caller messed up if we have neither a ready query nor held data. */
912 Assert(queryDesc || portal->holdStore);
913
914 /*
915 * Force the queryDesc destination to the right thing. This supports
916 * MOVE, for example, which will pass in dest = DestNone. This is okay to
917 * change as long as we do it on every fetch. (The Executor must not
918 * assume that dest never changes.)
919 */
920 if (queryDesc)
921 queryDesc->dest = dest;
922
923 /*
924 * Determine which direction to go in, and check to see if we're already
925 * at the end of the available tuples in that direction. If so, set the
926 * direction to NoMovement to avoid trying to fetch any tuples. (This
927 * check exists because not all plan node types are robust about being
928 * called again if they've already returned NULL once.) Then call the
929 * executor (we must not skip this, because the destination needs to see a
930 * setup and shutdown even if no tuples are available). Finally, update
931 * the portal position state depending on the number of tuples that were
932 * retrieved.
933 */
934 if (forward)
935 {
936 if (portal->atEnd || count <= 0)
937 {
938 direction = NoMovementScanDirection;
939 count = 0; /* don't pass negative count to executor */
940 }
941 else
942 direction = ForwardScanDirection;
943
944 /* In the executor, zero count processes all rows */
945 if (count == FETCH_ALL)
946 count = 0;
947
948 if (portal->holdStore)
949 nprocessed = RunFromStore(portal, direction, (uint64) count, dest);
950 else
951 {
952 PushActiveSnapshot(queryDesc->snapshot);
953 ExecutorRun(queryDesc, direction, (uint64) count);
954 nprocessed = queryDesc->estate->es_processed;
956 }
957
958 if (!ScanDirectionIsNoMovement(direction))
959 {
960 if (nprocessed > 0)
961 portal->atStart = false; /* OK to go backward now */
962 if (count == 0 || nprocessed < (uint64) count)
963 portal->atEnd = true; /* we retrieved 'em all */
964 portal->portalPos += nprocessed;
965 }
966 }
967 else
968 {
971 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
972 errmsg("cursor can only scan forward"),
973 errhint("Declare it with SCROLL option to enable backward scan.")));
974
975 if (portal->atStart || count <= 0)
976 {
977 direction = NoMovementScanDirection;
978 count = 0; /* don't pass negative count to executor */
979 }
980 else
981 direction = BackwardScanDirection;
982
983 /* In the executor, zero count processes all rows */
984 if (count == FETCH_ALL)
985 count = 0;
986
987 if (portal->holdStore)
988 nprocessed = RunFromStore(portal, direction, (uint64) count, dest);
989 else
990 {
991 PushActiveSnapshot(queryDesc->snapshot);
992 ExecutorRun(queryDesc, direction, (uint64) count);
993 nprocessed = queryDesc->estate->es_processed;
995 }
996
997 if (!ScanDirectionIsNoMovement(direction))
998 {
999 if (nprocessed > 0 && portal->atEnd)
1000 {
1001 portal->atEnd = false; /* OK to go forward now */
1002 portal->portalPos++; /* adjust for endpoint case */
1003 }
1004 if (count == 0 || nprocessed < (uint64) count)
1005 {
1006 portal->atStart = true; /* we retrieved 'em all */
1007 portal->portalPos = 0;
1008 }
1009 else
1010 {
1011 portal->portalPos -= nprocessed;
1012 }
1013 }
1014 }
1015
1016 return nprocessed;
1017}
1018
1019/*
1020 * FillPortalStore
1021 * Run the query and load result tuples into the portal's tuple store.
1022 *
1023 * This is used for PORTAL_ONE_RETURNING, PORTAL_ONE_MOD_WITH, and
1024 * PORTAL_UTIL_SELECT cases only.
1025 */
1026static void
1027FillPortalStore(Portal portal, bool isTopLevel)
1028{
1029 DestReceiver *treceiver;
1030 QueryCompletion qc;
1031
1033 PortalCreateHoldStore(portal);
1036 portal->holdStore,
1037 portal->holdContext,
1038 false,
1039 NULL,
1040 NULL);
1041
1042 switch (portal->strategy)
1043 {
1046
1047 /*
1048 * Run the portal to completion just as for the default
1049 * PORTAL_MULTI_QUERY case, but send the primary query's output to
1050 * the tuplestore. Auxiliary query outputs are discarded. Set the
1051 * portal's holdSnapshot to the snapshot used (or a copy of it).
1052 */
1053 PortalRunMulti(portal, isTopLevel, true,
1054 treceiver, None_Receiver, &qc);
1055 break;
1056
1057 case PORTAL_UTIL_SELECT:
1059 isTopLevel, true, treceiver, &qc);
1060 break;
1061
1062 default:
1063 elog(ERROR, "unsupported portal strategy: %d",
1064 (int) portal->strategy);
1065 break;
1066 }
1067
1068 /* Override portal completion data with actual command results */
1069 if (qc.commandTag != CMDTAG_UNKNOWN)
1070 CopyQueryCompletion(&portal->qc, &qc);
1071
1072 treceiver->rDestroy(treceiver);
1073}
1074
1075/*
1076 * RunFromStore
1077 * Fetch tuples from the portal's tuple store.
1078 *
1079 * Calling conventions are similar to ExecutorRun, except that we
1080 * do not depend on having a queryDesc or estate. Therefore we return the
1081 * number of tuples processed as the result, not in estate->es_processed.
1082 *
1083 * One difference from ExecutorRun is that the destination receiver functions
1084 * are run in the caller's memory context (since we have no estate). Watch
1085 * out for memory leaks.
1086 */
1087static uint64
1088RunFromStore(Portal portal, ScanDirection direction, uint64 count,
1090{
1091 uint64 current_tuple_count = 0;
1092 TupleTableSlot *slot;
1093
1095
1096 dest->rStartup(dest, CMD_SELECT, portal->tupDesc);
1097
1098 if (ScanDirectionIsNoMovement(direction))
1099 {
1100 /* do nothing except start/stop the destination */
1101 }
1102 else
1103 {
1104 bool forward = ScanDirectionIsForward(direction);
1105
1106 for (;;)
1107 {
1108 MemoryContext oldcontext;
1109 bool ok;
1110
1111 oldcontext = MemoryContextSwitchTo(portal->holdContext);
1112
1113 ok = tuplestore_gettupleslot(portal->holdStore, forward, false,
1114 slot);
1115
1116 MemoryContextSwitchTo(oldcontext);
1117
1118 if (!ok)
1119 break;
1120
1121 /*
1122 * If we are not able to send the tuple, we assume the destination
1123 * has closed and no more tuples can be sent. If that's the case,
1124 * end the loop.
1125 */
1126 if (!dest->receiveSlot(slot, dest))
1127 break;
1128
1129 ExecClearTuple(slot);
1130
1131 /*
1132 * check our tuple count.. if we've processed the proper number
1133 * then quit, else loop again and process more tuples. Zero count
1134 * means no limit.
1135 */
1136 current_tuple_count++;
1137 if (count && count == current_tuple_count)
1138 break;
1139 }
1140 }
1141
1142 dest->rShutdown(dest);
1143
1145
1146 return current_tuple_count;
1147}
1148
1149/*
1150 * PortalRunUtility
1151 * Execute a utility statement inside a portal.
1152 */
1153static void
1155 bool isTopLevel, bool setHoldSnapshot,
1157{
1158 /*
1159 * Set snapshot if utility stmt needs one.
1160 */
1161 if (PlannedStmtRequiresSnapshot(pstmt))
1162 {
1163 Snapshot snapshot = GetTransactionSnapshot();
1164
1165 /* If told to, register the snapshot we're using and save in portal */
1166 if (setHoldSnapshot)
1167 {
1168 snapshot = RegisterSnapshot(snapshot);
1169 portal->holdSnapshot = snapshot;
1170 }
1171
1172 /*
1173 * In any case, make the snapshot active and remember it in portal.
1174 * Because the portal now references the snapshot, we must tell
1175 * snapmgr.c that the snapshot belongs to the portal's transaction
1176 * level, else we risk portalSnapshot becoming a dangling pointer.
1177 */
1178 PushActiveSnapshotWithLevel(snapshot, portal->createLevel);
1179 /* PushActiveSnapshotWithLevel might have copied the snapshot */
1181 }
1182 else
1183 portal->portalSnapshot = NULL;
1184
1185 ProcessUtility(pstmt,
1186 portal->sourceText,
1187 (portal->cplan != NULL), /* protect tree if in plancache */
1189 portal->portalParams,
1190 portal->queryEnv,
1191 dest,
1192 qc);
1193
1194 /* Some utility statements may change context on us */
1196
1197 /*
1198 * Some utility commands (e.g., VACUUM) pop the ActiveSnapshot stack from
1199 * under us, so don't complain if it's now empty. Otherwise, our snapshot
1200 * should be the top one; pop it. Note that this could be a different
1201 * snapshot from the one we made above; see EnsurePortalSnapshotExists.
1202 */
1203 if (portal->portalSnapshot != NULL && ActiveSnapshotSet())
1204 {
1207 }
1208 portal->portalSnapshot = NULL;
1209}
1210
1211/*
1212 * PortalRunMulti
1213 * Execute a portal's queries in the general case (multi queries
1214 * or non-SELECT-like queries)
1215 */
1216static void
1218 bool isTopLevel, bool setHoldSnapshot,
1219 DestReceiver *dest, DestReceiver *altdest,
1220 QueryCompletion *qc)
1221{
1222 bool active_snapshot_set = false;
1223 ListCell *stmtlist_item;
1224 int query_index = 0;
1225
1226 /*
1227 * If the destination is DestRemoteExecute, change to DestNone. The
1228 * reason is that the client won't be expecting any tuples, and indeed has
1229 * no way to know what they are, since there is no provision for Describe
1230 * to send a RowDescription message when this portal execution strategy is
1231 * in effect. This presently will only affect SELECT commands added to
1232 * non-SELECT queries by rewrite rules: such commands will be executed,
1233 * but the results will be discarded unless you use "simple Query"
1234 * protocol.
1235 */
1236 if (dest->mydest == DestRemoteExecute)
1238 if (altdest->mydest == DestRemoteExecute)
1239 altdest = None_Receiver;
1240
1241 /*
1242 * Loop to handle the individual queries generated from a single parsetree
1243 * by analysis and rewrite.
1244 */
1245 foreach(stmtlist_item, portal->stmts)
1246 {
1247 PlannedStmt *pstmt = lfirst_node(PlannedStmt, stmtlist_item);
1248
1249 /*
1250 * If we got a cancel signal in prior command, quit
1251 */
1253
1254 if (pstmt->utilityStmt == NULL)
1255 {
1256 /*
1257 * process a plannable query.
1258 */
1259 TRACE_POSTGRESQL_QUERY_EXECUTE_START();
1260
1262 ResetUsage();
1263
1264 /*
1265 * Must always have a snapshot for plannable queries. First time
1266 * through, take a new snapshot; for subsequent queries in the
1267 * same portal, just update the snapshot's copy of the command
1268 * counter.
1269 */
1270 if (!active_snapshot_set)
1271 {
1272 Snapshot snapshot = GetTransactionSnapshot();
1273
1274 /* If told to, register the snapshot and save in portal */
1275 if (setHoldSnapshot)
1276 {
1277 snapshot = RegisterSnapshot(snapshot);
1278 portal->holdSnapshot = snapshot;
1279 }
1280
1281 /*
1282 * We can't have the holdSnapshot also be the active one,
1283 * because UpdateActiveSnapshotCommandId would complain. So
1284 * force an extra snapshot copy. Plain PushActiveSnapshot
1285 * would have copied the transaction snapshot anyway, so this
1286 * only adds a copy step when setHoldSnapshot is true. (It's
1287 * okay for the command ID of the active snapshot to diverge
1288 * from what holdSnapshot has.)
1289 */
1290 PushCopiedSnapshot(snapshot);
1291
1292 /*
1293 * As for PORTAL_ONE_SELECT portals, it does not seem
1294 * necessary to maintain portal->portalSnapshot here.
1295 */
1296
1297 active_snapshot_set = true;
1298 }
1299 else
1301
1302 if (pstmt->canSetTag)
1303 {
1304 /* statement can set tag string */
1305 ProcessQuery(pstmt,
1306 portal->cplan,
1307 portal->plansource,
1308 query_index,
1309 portal->sourceText,
1310 portal->portalParams,
1311 portal->queryEnv,
1312 dest, qc);
1313 }
1314 else
1315 {
1316 /* stmt added by rewrite cannot set tag */
1317 ProcessQuery(pstmt,
1318 portal->cplan,
1319 portal->plansource,
1320 query_index,
1321 portal->sourceText,
1322 portal->portalParams,
1323 portal->queryEnv,
1324 altdest, NULL);
1325 }
1326
1328 ShowUsage("EXECUTOR STATISTICS");
1329
1330 TRACE_POSTGRESQL_QUERY_EXECUTE_DONE();
1331 }
1332 else
1333 {
1334 /*
1335 * process utility functions (create, destroy, etc..)
1336 *
1337 * We must not set a snapshot here for utility commands (if one is
1338 * needed, PortalRunUtility will do it). If a utility command is
1339 * alone in a portal then everything's fine. The only case where
1340 * a utility command can be part of a longer list is that rules
1341 * are allowed to include NotifyStmt. NotifyStmt doesn't care
1342 * whether it has a snapshot or not, so we just leave the current
1343 * snapshot alone if we have one.
1344 */
1345 if (pstmt->canSetTag)
1346 {
1347 Assert(!active_snapshot_set);
1348 /* statement can set tag string */
1349 PortalRunUtility(portal, pstmt, isTopLevel, false,
1350 dest, qc);
1351 }
1352 else
1353 {
1354 Assert(IsA(pstmt->utilityStmt, NotifyStmt));
1355 /* stmt added by rewrite cannot set tag */
1356 PortalRunUtility(portal, pstmt, isTopLevel, false,
1357 altdest, NULL);
1358 }
1359 }
1360
1361 /*
1362 * Clear subsidiary contexts to recover temporary memory.
1363 */
1365
1367
1368 /*
1369 * Avoid crashing if portal->stmts has been reset. This can only
1370 * occur if a CALL or DO utility statement executed an internal
1371 * COMMIT/ROLLBACK (cf PortalReleaseCachedPlan). The CALL or DO must
1372 * have been the only statement in the portal, so there's nothing left
1373 * for us to do; but we don't want to dereference a now-dangling list
1374 * pointer.
1375 */
1376 if (portal->stmts == NIL)
1377 break;
1378
1379 /*
1380 * Increment command counter between queries, but not after the last
1381 * one.
1382 */
1383 if (lnext(portal->stmts, stmtlist_item) != NULL)
1385
1386 query_index++;
1387 }
1388
1389 /* Pop the snapshot if we pushed one. */
1390 if (active_snapshot_set)
1392
1393 /*
1394 * If a query completion data was supplied, use it. Otherwise use the
1395 * portal's query completion data.
1396 *
1397 * Exception: Clients expect INSERT/UPDATE/DELETE tags to have counts, so
1398 * fake them with zeros. This can happen with DO INSTEAD rules if there
1399 * is no replacement query of the same type as the original. We print "0
1400 * 0" here because technically there is no query of the matching tag type,
1401 * and printing a non-zero count for a different query type seems wrong,
1402 * e.g. an INSERT that does an UPDATE instead should not print "0 1" if
1403 * one row was updated. See QueryRewrite(), step 3, for details.
1404 */
1405 if (qc && qc->commandTag == CMDTAG_UNKNOWN)
1406 {
1407 if (portal->qc.commandTag != CMDTAG_UNKNOWN)
1408 CopyQueryCompletion(qc, &portal->qc);
1409 /* If the caller supplied a qc, we should have set it by now. */
1410 Assert(qc->commandTag != CMDTAG_UNKNOWN);
1411 }
1412}
1413
1414/*
1415 * PortalRunFetch
1416 * Variant form of PortalRun that supports SQL FETCH directions.
1417 *
1418 * Note: we presently assume that no callers of this want isTopLevel = true.
1419 *
1420 * count <= 0 is interpreted as a no-op: the destination gets started up
1421 * and shut down, but nothing else happens. Also, count == FETCH_ALL is
1422 * interpreted as "all rows". (cf FetchStmt.howMany)
1423 *
1424 * Returns number of rows processed (suitable for use in result tag)
1425 */
1426uint64
1428 FetchDirection fdirection,
1429 long count,
1431{
1432 uint64 result;
1433 Portal saveActivePortal;
1434 ResourceOwner saveResourceOwner;
1435 MemoryContext savePortalContext;
1436 MemoryContext oldContext;
1437
1438 Assert(PortalIsValid(portal));
1439
1440 /*
1441 * Check for improper portal use, and mark portal active.
1442 */
1443 MarkPortalActive(portal);
1444
1445 /*
1446 * Set up global portal context pointers.
1447 */
1448 saveActivePortal = ActivePortal;
1449 saveResourceOwner = CurrentResourceOwner;
1450 savePortalContext = PortalContext;
1451 PG_TRY();
1452 {
1453 ActivePortal = portal;
1454 if (portal->resowner)
1456 PortalContext = portal->portalContext;
1457
1459
1460 switch (portal->strategy)
1461 {
1462 case PORTAL_ONE_SELECT:
1463 result = DoPortalRunFetch(portal, fdirection, count, dest);
1464 break;
1465
1468 case PORTAL_UTIL_SELECT:
1469
1470 /*
1471 * If we have not yet run the command, do so, storing its
1472 * results in the portal's tuplestore.
1473 */
1474 if (!portal->holdStore)
1475 FillPortalStore(portal, false /* isTopLevel */ );
1476
1477 /*
1478 * Now fetch desired portion of results.
1479 */
1480 result = DoPortalRunFetch(portal, fdirection, count, dest);
1481 break;
1482
1483 default:
1484 elog(ERROR, "unsupported portal strategy");
1485 result = 0; /* keep compiler quiet */
1486 break;
1487 }
1488 }
1489 PG_CATCH();
1490 {
1491 /* Uncaught error while executing portal: mark it dead */
1492 MarkPortalFailed(portal);
1493
1494 /* Restore global vars and propagate error */
1495 ActivePortal = saveActivePortal;
1496 CurrentResourceOwner = saveResourceOwner;
1497 PortalContext = savePortalContext;
1498
1499 PG_RE_THROW();
1500 }
1501 PG_END_TRY();
1502
1503 MemoryContextSwitchTo(oldContext);
1504
1505 /* Mark portal not active */
1506 portal->status = PORTAL_READY;
1507
1508 ActivePortal = saveActivePortal;
1509 CurrentResourceOwner = saveResourceOwner;
1510 PortalContext = savePortalContext;
1511
1512 return result;
1513}
1514
1515/*
1516 * DoPortalRunFetch
1517 * Guts of PortalRunFetch --- the portal context is already set up
1518 *
1519 * Here, count < 0 typically reverses the direction. Also, count == FETCH_ALL
1520 * is interpreted as "all rows". (cf FetchStmt.howMany)
1521 *
1522 * Returns number of rows processed (suitable for use in result tag)
1523 */
1524static uint64
1526 FetchDirection fdirection,
1527 long count,
1529{
1530 bool forward;
1531
1532 Assert(portal->strategy == PORTAL_ONE_SELECT ||
1533 portal->strategy == PORTAL_ONE_RETURNING ||
1534 portal->strategy == PORTAL_ONE_MOD_WITH ||
1535 portal->strategy == PORTAL_UTIL_SELECT);
1536
1537 /*
1538 * Note: we disallow backwards fetch (including re-fetch of current row)
1539 * for NO SCROLL cursors, but we interpret that very loosely: you can use
1540 * any of the FetchDirection options, so long as the end result is to move
1541 * forwards by at least one row. Currently it's sufficient to check for
1542 * NO SCROLL in DoPortalRewind() and in the forward == false path in
1543 * PortalRunSelect(); but someday we might prefer to account for that
1544 * restriction explicitly here.
1545 */
1546 switch (fdirection)
1547 {
1548 case FETCH_FORWARD:
1549 if (count < 0)
1550 {
1551 fdirection = FETCH_BACKWARD;
1552 count = -count;
1553 }
1554 /* fall out of switch to share code with FETCH_BACKWARD */
1555 break;
1556 case FETCH_BACKWARD:
1557 if (count < 0)
1558 {
1559 fdirection = FETCH_FORWARD;
1560 count = -count;
1561 }
1562 /* fall out of switch to share code with FETCH_FORWARD */
1563 break;
1564 case FETCH_ABSOLUTE:
1565 if (count > 0)
1566 {
1567 /*
1568 * Definition: Rewind to start, advance count-1 rows, return
1569 * next row (if any).
1570 *
1571 * In practice, if the goal is less than halfway back to the
1572 * start, it's better to scan from where we are.
1573 *
1574 * Also, if current portalPos is outside the range of "long",
1575 * do it the hard way to avoid possible overflow of the count
1576 * argument to PortalRunSelect. We must exclude exactly
1577 * LONG_MAX, as well, lest the count look like FETCH_ALL.
1578 *
1579 * In any case, we arrange to fetch the target row going
1580 * forwards.
1581 */
1582 if ((uint64) (count - 1) <= portal->portalPos / 2 ||
1583 portal->portalPos >= (uint64) LONG_MAX)
1584 {
1585 DoPortalRewind(portal);
1586 if (count > 1)
1587 PortalRunSelect(portal, true, count - 1,
1589 }
1590 else
1591 {
1592 long pos = (long) portal->portalPos;
1593
1594 if (portal->atEnd)
1595 pos++; /* need one extra fetch if off end */
1596 if (count <= pos)
1597 PortalRunSelect(portal, false, pos - count + 1,
1599 else if (count > pos + 1)
1600 PortalRunSelect(portal, true, count - pos - 1,
1602 }
1603 return PortalRunSelect(portal, true, 1L, dest);
1604 }
1605 else if (count < 0)
1606 {
1607 /*
1608 * Definition: Advance to end, back up abs(count)-1 rows,
1609 * return prior row (if any). We could optimize this if we
1610 * knew in advance where the end was, but typically we won't.
1611 * (Is it worth considering case where count > half of size of
1612 * query? We could rewind once we know the size ...)
1613 */
1614 PortalRunSelect(portal, true, FETCH_ALL, None_Receiver);
1615 if (count < -1)
1616 PortalRunSelect(portal, false, -count - 1, None_Receiver);
1617 return PortalRunSelect(portal, false, 1L, dest);
1618 }
1619 else
1620 {
1621 /* count == 0 */
1622 /* Rewind to start, return zero rows */
1623 DoPortalRewind(portal);
1624 return PortalRunSelect(portal, true, 0L, dest);
1625 }
1626 break;
1627 case FETCH_RELATIVE:
1628 if (count > 0)
1629 {
1630 /*
1631 * Definition: advance count-1 rows, return next row (if any).
1632 */
1633 if (count > 1)
1634 PortalRunSelect(portal, true, count - 1, None_Receiver);
1635 return PortalRunSelect(portal, true, 1L, dest);
1636 }
1637 else if (count < 0)
1638 {
1639 /*
1640 * Definition: back up abs(count)-1 rows, return prior row (if
1641 * any).
1642 */
1643 if (count < -1)
1644 PortalRunSelect(portal, false, -count - 1, None_Receiver);
1645 return PortalRunSelect(portal, false, 1L, dest);
1646 }
1647 else
1648 {
1649 /* count == 0 */
1650 /* Same as FETCH FORWARD 0, so fall out of switch */
1651 fdirection = FETCH_FORWARD;
1652 }
1653 break;
1654 default:
1655 elog(ERROR, "bogus direction");
1656 break;
1657 }
1658
1659 /*
1660 * Get here with fdirection == FETCH_FORWARD or FETCH_BACKWARD, and count
1661 * >= 0.
1662 */
1663 forward = (fdirection == FETCH_FORWARD);
1664
1665 /*
1666 * Zero count means to re-fetch the current row, if any (per SQL)
1667 */
1668 if (count == 0)
1669 {
1670 bool on_row;
1671
1672 /* Are we sitting on a row? */
1673 on_row = (!portal->atStart && !portal->atEnd);
1674
1675 if (dest->mydest == DestNone)
1676 {
1677 /* MOVE 0 returns 0/1 based on if FETCH 0 would return a row */
1678 return on_row ? 1 : 0;
1679 }
1680 else
1681 {
1682 /*
1683 * If we are sitting on a row, back up one so we can re-fetch it.
1684 * If we are not sitting on a row, we still have to start up and
1685 * shut down the executor so that the destination is initialized
1686 * and shut down correctly; so keep going. To PortalRunSelect,
1687 * count == 0 means we will retrieve no row.
1688 */
1689 if (on_row)
1690 {
1691 PortalRunSelect(portal, false, 1L, None_Receiver);
1692 /* Set up to fetch one row forward */
1693 count = 1;
1694 forward = true;
1695 }
1696 }
1697 }
1698
1699 /*
1700 * Optimize MOVE BACKWARD ALL into a Rewind.
1701 */
1702 if (!forward && count == FETCH_ALL && dest->mydest == DestNone)
1703 {
1704 uint64 result = portal->portalPos;
1705
1706 if (result > 0 && !portal->atEnd)
1707 result--;
1708 DoPortalRewind(portal);
1709 return result;
1710 }
1711
1712 return PortalRunSelect(portal, forward, count, dest);
1713}
1714
1715/*
1716 * DoPortalRewind - rewind a Portal to starting point
1717 */
1718static void
1720{
1721 QueryDesc *queryDesc;
1722
1723 /*
1724 * No work is needed if we've not advanced nor attempted to advance the
1725 * cursor (and we don't want to throw a NO SCROLL error in this case).
1726 */
1727 if (portal->atStart && !portal->atEnd)
1728 return;
1729
1730 /* Otherwise, cursor must allow scrolling */
1731 if (portal->cursorOptions & CURSOR_OPT_NO_SCROLL)
1732 ereport(ERROR,
1733 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1734 errmsg("cursor can only scan forward"),
1735 errhint("Declare it with SCROLL option to enable backward scan.")));
1736
1737 /* Rewind holdStore, if we have one */
1738 if (portal->holdStore)
1739 {
1740 MemoryContext oldcontext;
1741
1742 oldcontext = MemoryContextSwitchTo(portal->holdContext);
1744 MemoryContextSwitchTo(oldcontext);
1745 }
1746
1747 /* Rewind executor, if active */
1748 queryDesc = portal->queryDesc;
1749 if (queryDesc)
1750 {
1751 PushActiveSnapshot(queryDesc->snapshot);
1752 ExecutorRewind(queryDesc);
1754 }
1755
1756 portal->atStart = true;
1757 portal->atEnd = false;
1758 portal->portalPos = 0;
1759}
1760
1761/*
1762 * PlannedStmtRequiresSnapshot - what it says on the tin
1763 */
1764bool
1766{
1767 Node *utilityStmt = pstmt->utilityStmt;
1768
1769 /* If it's not a utility statement, it definitely needs a snapshot */
1770 if (utilityStmt == NULL)
1771 return true;
1772
1773 /*
1774 * Most utility statements need a snapshot, and the default presumption
1775 * about new ones should be that they do too. Hence, enumerate those that
1776 * do not need one.
1777 *
1778 * Transaction control, LOCK, and SET must *not* set a snapshot, since
1779 * they need to be executable at the start of a transaction-snapshot-mode
1780 * transaction without freezing a snapshot. By extension we allow SHOW
1781 * not to set a snapshot. The other stmts listed are just efficiency
1782 * hacks. Beware of listing anything that can modify the database --- if,
1783 * say, it has to update an index with expressions that invoke
1784 * user-defined functions, then it had better have a snapshot.
1785 */
1786 if (IsA(utilityStmt, TransactionStmt) ||
1787 IsA(utilityStmt, LockStmt) ||
1788 IsA(utilityStmt, VariableSetStmt) ||
1789 IsA(utilityStmt, VariableShowStmt) ||
1790 IsA(utilityStmt, ConstraintsSetStmt) ||
1791 /* efficiency hacks from here down */
1792 IsA(utilityStmt, FetchStmt) ||
1793 IsA(utilityStmt, ListenStmt) ||
1794 IsA(utilityStmt, NotifyStmt) ||
1795 IsA(utilityStmt, UnlistenStmt) ||
1796 IsA(utilityStmt, CheckPointStmt))
1797 return false;
1798
1799 return true;
1800}
1801
1802/*
1803 * EnsurePortalSnapshotExists - recreate Portal-level snapshot, if needed
1804 *
1805 * Generally, we will have an active snapshot whenever we are executing
1806 * inside a Portal, unless the Portal's query is one of the utility
1807 * statements exempted from that rule (see PlannedStmtRequiresSnapshot).
1808 * However, procedures and DO blocks can commit or abort the transaction,
1809 * and thereby destroy all snapshots. This function can be called to
1810 * re-establish the Portal-level snapshot when none exists.
1811 */
1812void
1814{
1815 Portal portal;
1816
1817 /*
1818 * Nothing to do if a snapshot is set. (We take it on faith that the
1819 * outermost active snapshot belongs to some Portal; or if there is no
1820 * Portal, it's somebody else's responsibility to manage things.)
1821 */
1822 if (ActiveSnapshotSet())
1823 return;
1824
1825 /* Otherwise, we'd better have an active Portal */
1826 portal = ActivePortal;
1827 if (unlikely(portal == NULL))
1828 elog(ERROR, "cannot execute SQL without an outer snapshot or portal");
1829 Assert(portal->portalSnapshot == NULL);
1830
1831 /*
1832 * Create a new snapshot, make it active, and remember it in portal.
1833 * Because the portal now references the snapshot, we must tell snapmgr.c
1834 * that the snapshot belongs to the portal's transaction level, else we
1835 * risk portalSnapshot becoming a dangling pointer.
1836 */
1838 /* PushActiveSnapshotWithLevel might have copied the snapshot */
1840}
PreparedStatement * FetchPreparedStatement(const char *stmt_name, bool throwError)
Definition: prepare.c:435
List * FetchPreparedStatementTargetList(PreparedStatement *stmt)
Definition: prepare.c:490
int16_t int16
Definition: c.h:497
uint64_t uint64
Definition: c.h:503
#define unlikely(x)
Definition: c.h:347
void InitializeQueryCompletion(QueryCompletion *qc)
Definition: cmdtag.c:40
static void SetQueryCompletion(QueryCompletion *qc, CommandTag commandTag, uint64 nprocessed)
Definition: cmdtag.h:37
static void CopyQueryCompletion(QueryCompletion *dst, const QueryCompletion *src)
Definition: cmdtag.h:45
DestReceiver * CreateDestReceiver(CommandDest dest)
Definition: dest.c:113
DestReceiver * None_Receiver
Definition: dest.c:96
@ DestTuplestore
Definition: dest.h:93
@ DestRemoteExecute
Definition: dest.h:90
@ DestNone
Definition: dest.h:87
int errhint(const char *fmt,...)
Definition: elog.c:1318
int errcode(int sqlerrcode)
Definition: elog.c:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define PG_RE_THROW()
Definition: elog.h:405
#define DEBUG3
Definition: elog.h:28
#define PG_TRY(...)
Definition: elog.h:372
#define PG_END_TRY(...)
Definition: elog.h:397
#define ERROR
Definition: elog.h:39
#define PG_CATCH(...)
Definition: elog.h:382
#define elog(elevel,...)
Definition: elog.h:226
#define ereport(elevel,...)
Definition: elog.h:149
bool ExecutorStart(QueryDesc *queryDesc, int eflags)
Definition: execMain.c:128
void ExecutorStartCachedPlan(QueryDesc *queryDesc, int eflags, CachedPlanSource *plansource, int query_index)
Definition: execMain.c:295
void ExecutorEnd(QueryDesc *queryDesc)
Definition: execMain.c:538
void ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:475
void ExecutorRewind(QueryDesc *queryDesc)
Definition: execMain.c:615
void ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count)
Definition: execMain.c:365
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1427
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1443
TupleDesc ExecCleanTypeFromTL(List *targetList)
Definition: execTuples.c:2139
const TupleTableSlotOps TTSOpsMinimalTuple
Definition: execTuples.c:86
#define EXEC_FLAG_BACKWARD
Definition: executor.h:69
#define EXEC_FLAG_REWIND
Definition: executor.h:68
bool log_executor_stats
Definition: guc_tables.c:521
Assert(PointerIsAligned(start, uint64))
#define stmt
Definition: indent_codes.h:59
int i
Definition: isn.c:77
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:81
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1260
MemoryContext TopTransactionContext
Definition: mcxt.c:170
void pfree(void *pointer)
Definition: mcxt.c:2150
void MemoryContextDeleteChildren(MemoryContext context)
Definition: mcxt.c:570
void * palloc(Size size)
Definition: mcxt.c:1943
MemoryContext CurrentMemoryContext
Definition: mcxt.c:159
MemoryContext PortalContext
Definition: mcxt.c:174
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:123
#define IsA(nodeptr, _type_)
Definition: nodes.h:164
#define nodeTag(nodeptr)
Definition: nodes.h:139
@ CMD_MERGE
Definition: nodes.h:275
@ CMD_UTILITY
Definition: nodes.h:276
@ CMD_INSERT
Definition: nodes.h:273
@ CMD_DELETE
Definition: nodes.h:274
@ CMD_UPDATE
Definition: nodes.h:272
@ CMD_SELECT
Definition: nodes.h:271
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
#define CURSOR_OPT_SCROLL
Definition: parsenodes.h:3376
#define FETCH_ALL
Definition: parsenodes.h:3420
FetchDirection
Definition: parsenodes.h:3411
@ FETCH_RELATIVE
Definition: parsenodes.h:3417
@ FETCH_ABSOLUTE
Definition: parsenodes.h:3416
@ FETCH_FORWARD
Definition: parsenodes.h:3413
@ FETCH_BACKWARD
Definition: parsenodes.h:3414
#define CURSOR_OPT_NO_SCROLL
Definition: parsenodes.h:3377
#define lfirst(lc)
Definition: pg_list.h:172
#define lfirst_node(type, lc)
Definition: pg_list.h:176
static int list_length(const List *l)
Definition: pg_list.h:152
#define linitial_node(type, l)
Definition: pg_list.h:181
#define NIL
Definition: pg_list.h:68
#define linitial(l)
Definition: pg_list.h:178
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:343
#define plan(x)
Definition: pg_regress.c:161
@ PORTAL_READY
Definition: portal.h:107
@ PORTAL_DEFINED
Definition: portal.h:106
PortalStrategy
Definition: portal.h:90
@ PORTAL_ONE_RETURNING
Definition: portal.h:92
@ PORTAL_MULTI_QUERY
Definition: portal.h:95
@ PORTAL_ONE_SELECT
Definition: portal.h:91
@ PORTAL_ONE_MOD_WITH
Definition: portal.h:93
@ PORTAL_UTIL_SELECT
Definition: portal.h:94
#define PortalIsValid(p)
Definition: portal.h:212
void MarkPortalDone(Portal portal)
Definition: portalmem.c:416
void MarkPortalFailed(Portal portal)
Definition: portalmem.c:444
PlannedStmt * PortalGetPrimaryStmt(Portal portal)
Definition: portalmem.c:151
void MarkPortalActive(Portal portal)
Definition: portalmem.c:397
Portal GetPortalByName(const char *name)
Definition: portalmem.c:130
void PortalCreateHoldStore(Portal portal)
Definition: portalmem.c:333
void ShowUsage(const char *title)
Definition: postgres.c:5064
void ResetUsage(void)
Definition: postgres.c:5057
void FreeQueryDesc(QueryDesc *qdesc)
Definition: pquery.c:112
PortalStrategy ChoosePortalStrategy(List *stmts)
Definition: pquery.c:231
static void PortalRunMulti(Portal portal, bool isTopLevel, bool setHoldSnapshot, DestReceiver *dest, DestReceiver *altdest, QueryCompletion *qc)
Definition: pquery.c:1217
static void FillPortalStore(Portal portal, bool isTopLevel)
Definition: pquery.c:1027
bool PlannedStmtRequiresSnapshot(PlannedStmt *pstmt)
Definition: pquery.c:1765
void EnsurePortalSnapshotExists(void)
Definition: pquery.c:1813
Portal ActivePortal
Definition: pquery.c:37
void PortalSetResultFormat(Portal portal, int nFormats, int16 *formats)
Definition: pquery.c:656
void PortalStart(Portal portal, ParamListInfo params, int eflags, Snapshot snapshot)
Definition: pquery.c:455
static uint64 PortalRunSelect(Portal portal, bool forward, long count, DestReceiver *dest)
Definition: pquery.c:896
static uint64 RunFromStore(Portal portal, ScanDirection direction, uint64 count, DestReceiver *dest)
Definition: pquery.c:1088
List * FetchStatementTargetList(Node *stmt)
Definition: pquery.c:370
uint64 PortalRunFetch(Portal portal, FetchDirection fdirection, long count, DestReceiver *dest)
Definition: pquery.c:1427
QueryDesc * CreateQueryDesc(PlannedStmt *plannedstmt, CachedPlan *cplan, const char *sourceText, Snapshot snapshot, Snapshot crosscheck_snapshot, DestReceiver *dest, ParamListInfo params, QueryEnvironment *queryEnv, int instrument_options)
Definition: pquery.c:72
static void ProcessQuery(PlannedStmt *plan, CachedPlan *cplan, CachedPlanSource *plansource, int query_index, const char *sourceText, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *qc)
Definition: pquery.c:146
List * FetchPortalTargetList(Portal portal)
Definition: pquery.c:348
bool PortalRun(Portal portal, long count, bool isTopLevel, DestReceiver *dest, DestReceiver *altdest, QueryCompletion *qc)
Definition: pquery.c:717
static uint64 DoPortalRunFetch(Portal portal, FetchDirection fdirection, long count, DestReceiver *dest)
Definition: pquery.c:1525
static void DoPortalRewind(Portal portal)
Definition: pquery.c:1719
static void PortalRunUtility(Portal portal, PlannedStmt *pstmt, bool isTopLevel, bool setHoldSnapshot, DestReceiver *dest, QueryCompletion *qc)
Definition: pquery.c:1154
ResourceOwner TopTransactionResourceOwner
Definition: resowner.c:175
ResourceOwner CurrentResourceOwner
Definition: resowner.c:173
#define ScanDirectionIsForward(direction)
Definition: sdir.h:64
#define ScanDirectionIsNoMovement(direction)
Definition: sdir.h:57
ScanDirection
Definition: sdir.h:25
@ NoMovementScanDirection
Definition: sdir.h:27
@ BackwardScanDirection
Definition: sdir.h:26
@ ForwardScanDirection
Definition: sdir.h:28
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:271
void UnregisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:853
void PushActiveSnapshot(Snapshot snapshot)
Definition: snapmgr.c:669
void UpdateActiveSnapshotCommandId(void)
Definition: snapmgr.c:731
bool ActiveSnapshotSet(void)
Definition: snapmgr.c:799
Snapshot RegisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:811
void PopActiveSnapshot(void)
Definition: snapmgr.c:762
void PushCopiedSnapshot(Snapshot snapshot)
Definition: snapmgr.c:719
void PushActiveSnapshotWithLevel(Snapshot snapshot, int snap_level)
Definition: snapmgr.c:683
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:787
#define InvalidSnapshot
Definition: snapshot.h:119
uint64 es_processed
Definition: execnodes.h:712
char * name
Definition: parsenodes.h:4143
bool ismove
Definition: parsenodes.h:3428
char * portalname
Definition: parsenodes.h:3427
Definition: pg_list.h:54
Definition: nodes.h:135
List * targetlist
Definition: plannodes.h:209
struct Plan * planTree
Definition: plannodes.h:83
bool hasModifyingCTE
Definition: plannodes.h:65
bool canSetTag
Definition: plannodes.h:68
bool hasReturning
Definition: plannodes.h:62
CmdType commandType
Definition: plannodes.h:53
Node * utilityStmt
Definition: plannodes.h:139
CachedPlanSource * plansource
Definition: portal.h:141
Snapshot portalSnapshot
Definition: portal.h:170
uint64 portalPos
Definition: portal.h:201
QueryDesc * queryDesc
Definition: portal.h:157
const char * sourceText
Definition: portal.h:136
bool atEnd
Definition: portal.h:200
bool atStart
Definition: portal.h:199
List * stmts
Definition: portal.h:139
ResourceOwner resowner
Definition: portal.h:121
int createLevel
Definition: portal.h:133
MemoryContext holdContext
Definition: portal.h:178
QueryEnvironment * queryEnv
Definition: portal.h:144
QueryCompletion qc
Definition: portal.h:138
MemoryContext portalContext
Definition: portal.h:120
int16 * formats
Definition: portal.h:162
ParamListInfo portalParams
Definition: portal.h:143
Snapshot holdSnapshot
Definition: portal.h:188
TupleDesc tupDesc
Definition: portal.h:160
CachedPlan * cplan
Definition: portal.h:140
Tuplestorestate * holdStore
Definition: portal.h:177
int cursorOptions
Definition: portal.h:148
PortalStrategy strategy
Definition: portal.h:147
PortalStatus status
Definition: portal.h:151
uint64 nprocessed
Definition: cmdtag.h:32
CommandTag commandTag
Definition: cmdtag.h:31
const char * sourceText
Definition: execdesc.h:39
ParamListInfo params
Definition: execdesc.h:43
DestReceiver * dest
Definition: execdesc.h:42
int instrument_options
Definition: execdesc.h:45
EState * estate
Definition: execdesc.h:49
CachedPlan * cplan
Definition: execdesc.h:38
CmdType operation
Definition: execdesc.h:36
Snapshot snapshot
Definition: execdesc.h:40
bool already_executed
Definition: execdesc.h:53
PlannedStmt * plannedstmt
Definition: execdesc.h:37
struct Instrumentation * totaltime
Definition: execdesc.h:56
QueryEnvironment * queryEnv
Definition: execdesc.h:44
TupleDesc tupDesc
Definition: execdesc.h:48
Snapshot crosscheck_snapshot
Definition: execdesc.h:41
PlanState * planstate
Definition: execdesc.h:50
List * returningList
Definition: parsenodes.h:209
CmdType commandType
Definition: parsenodes.h:121
Node * utilityStmt
Definition: parsenodes.h:136
List * targetList
Definition: parsenodes.h:193
void(* rDestroy)(DestReceiver *self)
Definition: dest.h:126
CommandDest mydest
Definition: dest.h:128
void SetTuplestoreDestReceiverParams(DestReceiver *self, Tuplestorestate *tStore, MemoryContext tContext, bool detoast, TupleDesc target_tupdesc, const char *map_failure_msg)
bool tuplestore_gettupleslot(Tuplestorestate *state, bool forward, bool copy, TupleTableSlot *slot)
Definition: tuplestore.c:1130
void tuplestore_rescan(Tuplestorestate *state)
Definition: tuplestore.c:1285
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:458
void ProcessUtility(PlannedStmt *pstmt, const char *queryString, bool readOnlyTree, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *qc)
Definition: utility.c:499
bool UtilityReturnsTuples(Node *parsetree)
Definition: utility.c:2028
TupleDesc UtilityTupleDescriptor(Node *parsetree)
Definition: utility.c:2084
@ PROCESS_UTILITY_TOPLEVEL
Definition: utility.h:22
@ PROCESS_UTILITY_QUERY
Definition: utility.h:23
void CommandCounterIncrement(void)
Definition: xact.c:1100