LCOV - differential code coverage report
Current view: top level - src/backend/tcop - pquery.c (source / functions) Coverage Total Hit UBC GNC CBC DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 92.3 % 570 526 44 5 521 5
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 19 19 4 15
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

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

Generated by: LCOV version v1.16-55-g56c0a2a