LCOV - differential code coverage report
Current view: top level - src/backend/executor - spi.c (source / functions) Coverage Total Hit UNC UBC GNC CBC DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 73.4 % 1250 918 1 331 5 913 1 5
Current Date: 2023-04-08 15:15:32 Functions: 83.3 % 84 70 14 1 69
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  Line data    Source code
       1                 : /*-------------------------------------------------------------------------
       2                 :  *
       3                 :  * spi.c
       4                 :  *              Server Programming Interface
       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/executor/spi.c
      12                 :  *
      13                 :  *-------------------------------------------------------------------------
      14                 :  */
      15                 : #include "postgres.h"
      16                 : 
      17                 : #include "access/htup_details.h"
      18                 : #include "access/printtup.h"
      19                 : #include "access/sysattr.h"
      20                 : #include "access/xact.h"
      21                 : #include "catalog/heap.h"
      22                 : #include "catalog/pg_type.h"
      23                 : #include "commands/trigger.h"
      24                 : #include "executor/executor.h"
      25                 : #include "executor/spi_priv.h"
      26                 : #include "miscadmin.h"
      27                 : #include "tcop/pquery.h"
      28                 : #include "tcop/utility.h"
      29                 : #include "utils/builtins.h"
      30                 : #include "utils/datum.h"
      31                 : #include "utils/lsyscache.h"
      32                 : #include "utils/memutils.h"
      33                 : #include "utils/rel.h"
      34                 : #include "utils/snapmgr.h"
      35                 : #include "utils/syscache.h"
      36                 : #include "utils/typcache.h"
      37                 : 
      38                 : 
      39                 : /*
      40                 :  * These global variables are part of the API for various SPI functions
      41                 :  * (a horrible API choice, but it's too late now).  To reduce the risk of
      42                 :  * interference between different SPI callers, we save and restore them
      43                 :  * when entering/exiting a SPI nesting level.
      44                 :  */
      45                 : uint64      SPI_processed = 0;
      46                 : SPITupleTable *SPI_tuptable = NULL;
      47                 : int         SPI_result = 0;
      48                 : 
      49                 : static _SPI_connection *_SPI_stack = NULL;
      50                 : static _SPI_connection *_SPI_current = NULL;
      51                 : static int  _SPI_stack_depth = 0;   /* allocated size of _SPI_stack */
      52                 : static int  _SPI_connected = -1;    /* current stack index */
      53                 : 
      54                 : typedef struct SPICallbackArg
      55                 : {
      56                 :     const char *query;
      57                 :     RawParseMode mode;
      58                 : } SPICallbackArg;
      59                 : 
      60                 : static Portal SPI_cursor_open_internal(const char *name, SPIPlanPtr plan,
      61                 :                                        ParamListInfo paramLI, bool read_only);
      62                 : 
      63                 : static void _SPI_prepare_plan(const char *src, SPIPlanPtr plan);
      64                 : 
      65                 : static void _SPI_prepare_oneshot_plan(const char *src, SPIPlanPtr plan);
      66                 : 
      67                 : static int  _SPI_execute_plan(SPIPlanPtr plan, const SPIExecuteOptions *options,
      68                 :                               Snapshot snapshot, Snapshot crosscheck_snapshot,
      69                 :                               bool fire_triggers);
      70                 : 
      71                 : static ParamListInfo _SPI_convert_params(int nargs, Oid *argtypes,
      72                 :                                          Datum *Values, const char *Nulls);
      73                 : 
      74                 : static int  _SPI_pquery(QueryDesc *queryDesc, bool fire_triggers, uint64 tcount);
      75                 : 
      76                 : static void _SPI_error_callback(void *arg);
      77                 : 
      78                 : static void _SPI_cursor_operation(Portal portal,
      79                 :                                   FetchDirection direction, long count,
      80                 :                                   DestReceiver *dest);
      81                 : 
      82                 : static SPIPlanPtr _SPI_make_plan_non_temp(SPIPlanPtr plan);
      83                 : static SPIPlanPtr _SPI_save_plan(SPIPlanPtr plan);
      84                 : 
      85                 : static int  _SPI_begin_call(bool use_exec);
      86                 : static int  _SPI_end_call(bool use_exec);
      87                 : static MemoryContext _SPI_execmem(void);
      88                 : static MemoryContext _SPI_procmem(void);
      89                 : static bool _SPI_checktuples(void);
      90                 : 
      91                 : 
      92                 : /* =================== interface functions =================== */
      93                 : 
      94                 : int
      95 CBC        7605 : SPI_connect(void)
      96                 : {
      97            7605 :     return SPI_connect_ext(0);
      98                 : }
      99                 : 
     100                 : int
     101           48790 : SPI_connect_ext(int options)
     102                 : {
     103                 :     int         newdepth;
     104                 : 
     105                 :     /* Enlarge stack if necessary */
     106           48790 :     if (_SPI_stack == NULL)
     107                 :     {
     108             666 :         if (_SPI_connected != -1 || _SPI_stack_depth != 0)
     109 UBC           0 :             elog(ERROR, "SPI stack corrupted");
     110 CBC         666 :         newdepth = 16;
     111             666 :         _SPI_stack = (_SPI_connection *)
     112             666 :             MemoryContextAlloc(TopMemoryContext,
     113                 :                                newdepth * sizeof(_SPI_connection));
     114             666 :         _SPI_stack_depth = newdepth;
     115                 :     }
     116                 :     else
     117                 :     {
     118           48124 :         if (_SPI_stack_depth <= 0 || _SPI_stack_depth <= _SPI_connected)
     119 UBC           0 :             elog(ERROR, "SPI stack corrupted");
     120 CBC       48124 :         if (_SPI_stack_depth == _SPI_connected + 1)
     121                 :         {
     122              13 :             newdepth = _SPI_stack_depth * 2;
     123              13 :             _SPI_stack = (_SPI_connection *)
     124              13 :                 repalloc(_SPI_stack,
     125                 :                          newdepth * sizeof(_SPI_connection));
     126              13 :             _SPI_stack_depth = newdepth;
     127                 :         }
     128                 :     }
     129                 : 
     130                 :     /* Enter new stack level */
     131           48790 :     _SPI_connected++;
     132           48790 :     Assert(_SPI_connected >= 0 && _SPI_connected < _SPI_stack_depth);
     133                 : 
     134           48790 :     _SPI_current = &(_SPI_stack[_SPI_connected]);
     135           48790 :     _SPI_current->processed = 0;
     136           48790 :     _SPI_current->tuptable = NULL;
     137           48790 :     _SPI_current->execSubid = InvalidSubTransactionId;
     138           48790 :     slist_init(&_SPI_current->tuptables);
     139           48790 :     _SPI_current->procCxt = NULL;    /* in case we fail to create 'em */
     140           48790 :     _SPI_current->execCxt = NULL;
     141           48790 :     _SPI_current->connectSubid = GetCurrentSubTransactionId();
     142           48790 :     _SPI_current->queryEnv = NULL;
     143           48790 :     _SPI_current->atomic = (options & SPI_OPT_NONATOMIC ? false : true);
     144           48790 :     _SPI_current->internal_xact = false;
     145           48790 :     _SPI_current->outer_processed = SPI_processed;
     146           48790 :     _SPI_current->outer_tuptable = SPI_tuptable;
     147           48790 :     _SPI_current->outer_result = SPI_result;
     148                 : 
     149                 :     /*
     150                 :      * Create memory contexts for this procedure
     151                 :      *
     152                 :      * In atomic contexts (the normal case), we use TopTransactionContext,
     153                 :      * otherwise PortalContext, so that it lives across transaction
     154                 :      * boundaries.
     155                 :      *
     156                 :      * XXX It could be better to use PortalContext as the parent context in
     157                 :      * all cases, but we may not be inside a portal (consider deferred-trigger
     158                 :      * execution).  Perhaps CurTransactionContext could be an option?  For now
     159                 :      * it doesn't matter because we clean up explicitly in AtEOSubXact_SPI();
     160                 :      * but see also AtEOXact_SPI().
     161                 :      */
     162           48790 :     _SPI_current->procCxt = AllocSetContextCreate(_SPI_current->atomic ? TopTransactionContext : PortalContext,
     163                 :                                                   "SPI Proc",
     164                 :                                                   ALLOCSET_DEFAULT_SIZES);
     165           48790 :     _SPI_current->execCxt = AllocSetContextCreate(_SPI_current->atomic ? TopTransactionContext : _SPI_current->procCxt,
     166                 :                                                   "SPI Exec",
     167                 :                                                   ALLOCSET_DEFAULT_SIZES);
     168                 :     /* ... and switch to procedure's context */
     169           48790 :     _SPI_current->savedcxt = MemoryContextSwitchTo(_SPI_current->procCxt);
     170                 : 
     171                 :     /*
     172                 :      * Reset API global variables so that current caller cannot accidentally
     173                 :      * depend on state of an outer caller.
     174                 :      */
     175           48790 :     SPI_processed = 0;
     176           48790 :     SPI_tuptable = NULL;
     177           48790 :     SPI_result = 0;
     178                 : 
     179           48790 :     return SPI_OK_CONNECT;
     180                 : }
     181                 : 
     182                 : int
     183           47542 : SPI_finish(void)
     184                 : {
     185                 :     int         res;
     186                 : 
     187           47542 :     res = _SPI_begin_call(false);   /* just check we're connected */
     188           47542 :     if (res < 0)
     189 UBC           0 :         return res;
     190                 : 
     191                 :     /* Restore memory context as it was before procedure call */
     192 CBC       47542 :     MemoryContextSwitchTo(_SPI_current->savedcxt);
     193                 : 
     194                 :     /* Release memory used in procedure call (including tuptables) */
     195           47542 :     MemoryContextDelete(_SPI_current->execCxt);
     196           47542 :     _SPI_current->execCxt = NULL;
     197           47542 :     MemoryContextDelete(_SPI_current->procCxt);
     198           47542 :     _SPI_current->procCxt = NULL;
     199                 : 
     200                 :     /*
     201                 :      * Restore outer API variables, especially SPI_tuptable which is probably
     202                 :      * pointing at a just-deleted tuptable
     203                 :      */
     204           47542 :     SPI_processed = _SPI_current->outer_processed;
     205           47542 :     SPI_tuptable = _SPI_current->outer_tuptable;
     206           47542 :     SPI_result = _SPI_current->outer_result;
     207                 : 
     208                 :     /* Exit stack level */
     209           47542 :     _SPI_connected--;
     210           47542 :     if (_SPI_connected < 0)
     211           41480 :         _SPI_current = NULL;
     212                 :     else
     213            6062 :         _SPI_current = &(_SPI_stack[_SPI_connected]);
     214                 : 
     215           47542 :     return SPI_OK_FINISH;
     216                 : }
     217                 : 
     218                 : /*
     219                 :  * SPI_start_transaction is a no-op, kept for backwards compatibility.
     220                 :  * SPI callers are *always* inside a transaction.
     221                 :  */
     222                 : void
     223 UBC           0 : SPI_start_transaction(void)
     224                 : {
     225               0 : }
     226                 : 
     227                 : static void
     228 CBC        2142 : _SPI_commit(bool chain)
     229                 : {
     230            2142 :     MemoryContext oldcontext = CurrentMemoryContext;
     231                 :     SavedTransactionCharacteristics savetc;
     232                 : 
     233                 :     /*
     234                 :      * Complain if we are in a context that doesn't permit transaction
     235                 :      * termination.  (Note: here and _SPI_rollback should be the only places
     236                 :      * that throw ERRCODE_INVALID_TRANSACTION_TERMINATION, so that callers can
     237                 :      * test for that with security that they know what happened.)
     238                 :      */
     239            2142 :     if (_SPI_current->atomic)
     240              16 :         ereport(ERROR,
     241                 :                 (errcode(ERRCODE_INVALID_TRANSACTION_TERMINATION),
     242                 :                  errmsg("invalid transaction termination")));
     243                 : 
     244                 :     /*
     245                 :      * This restriction is required by PLs implemented on top of SPI.  They
     246                 :      * use subtransactions to establish exception blocks that are supposed to
     247                 :      * be rolled back together if there is an error.  Terminating the
     248                 :      * top-level transaction in such a block violates that idea.  A future PL
     249                 :      * implementation might have different ideas about this, in which case
     250                 :      * this restriction would have to be refined or the check possibly be
     251                 :      * moved out of SPI into the PLs.  Note however that the code below relies
     252                 :      * on not being within a subtransaction.
     253                 :      */
     254            2126 :     if (IsSubTransaction())
     255               3 :         ereport(ERROR,
     256                 :                 (errcode(ERRCODE_INVALID_TRANSACTION_TERMINATION),
     257                 :                  errmsg("cannot commit while a subtransaction is active")));
     258                 : 
     259            2123 :     if (chain)
     260               2 :         SaveTransactionCharacteristics(&savetc);
     261                 : 
     262                 :     /* Catch any error occurring during the COMMIT */
     263            2123 :     PG_TRY();
     264                 :     {
     265                 :         /* Protect current SPI stack entry against deletion */
     266            2123 :         _SPI_current->internal_xact = true;
     267                 : 
     268                 :         /*
     269                 :          * Hold any pinned portals that any PLs might be using.  We have to do
     270                 :          * this before changing transaction state, since this will run
     271                 :          * user-defined code that might throw an error.
     272                 :          */
     273            2123 :         HoldPinnedPortals();
     274                 : 
     275                 :         /* Release snapshots associated with portals */
     276            2122 :         ForgetPortalSnapshots();
     277                 : 
     278                 :         /* Do the deed */
     279            2122 :         CommitTransactionCommand();
     280                 : 
     281                 :         /* Immediately start a new transaction */
     282            2115 :         StartTransactionCommand();
     283            2115 :         if (chain)
     284               2 :             RestoreTransactionCharacteristics(&savetc);
     285                 : 
     286            2115 :         MemoryContextSwitchTo(oldcontext);
     287                 : 
     288            2115 :         _SPI_current->internal_xact = false;
     289                 :     }
     290               8 :     PG_CATCH();
     291                 :     {
     292                 :         ErrorData  *edata;
     293                 : 
     294                 :         /* Save error info in caller's context */
     295               8 :         MemoryContextSwitchTo(oldcontext);
     296               8 :         edata = CopyErrorData();
     297               8 :         FlushErrorState();
     298                 : 
     299                 :         /*
     300                 :          * Abort the failed transaction.  If this fails too, we'll just
     301                 :          * propagate the error out ... there's not that much we can do.
     302                 :          */
     303               8 :         AbortCurrentTransaction();
     304                 : 
     305                 :         /* ... and start a new one */
     306               8 :         StartTransactionCommand();
     307               8 :         if (chain)
     308 UBC           0 :             RestoreTransactionCharacteristics(&savetc);
     309                 : 
     310 CBC           8 :         MemoryContextSwitchTo(oldcontext);
     311                 : 
     312               8 :         _SPI_current->internal_xact = false;
     313                 : 
     314                 :         /* Now that we've cleaned up the transaction, re-throw the error */
     315               8 :         ReThrowError(edata);
     316                 :     }
     317            2115 :     PG_END_TRY();
     318            2115 : }
     319                 : 
     320                 : void
     321            2140 : SPI_commit(void)
     322                 : {
     323            2140 :     _SPI_commit(false);
     324            2113 : }
     325                 : 
     326                 : void
     327               2 : SPI_commit_and_chain(void)
     328                 : {
     329               2 :     _SPI_commit(true);
     330               2 : }
     331                 : 
     332                 : static void
     333              82 : _SPI_rollback(bool chain)
     334                 : {
     335              82 :     MemoryContext oldcontext = CurrentMemoryContext;
     336                 :     SavedTransactionCharacteristics savetc;
     337                 : 
     338                 :     /* see under SPI_commit() */
     339              82 :     if (_SPI_current->atomic)
     340 UBC           0 :         ereport(ERROR,
     341                 :                 (errcode(ERRCODE_INVALID_TRANSACTION_TERMINATION),
     342                 :                  errmsg("invalid transaction termination")));
     343                 : 
     344                 :     /* see under SPI_commit() */
     345 CBC          82 :     if (IsSubTransaction())
     346               2 :         ereport(ERROR,
     347                 :                 (errcode(ERRCODE_INVALID_TRANSACTION_TERMINATION),
     348                 :                  errmsg("cannot roll back while a subtransaction is active")));
     349                 : 
     350              80 :     if (chain)
     351               2 :         SaveTransactionCharacteristics(&savetc);
     352                 : 
     353                 :     /* Catch any error occurring during the ROLLBACK */
     354              80 :     PG_TRY();
     355                 :     {
     356                 :         /* Protect current SPI stack entry against deletion */
     357              80 :         _SPI_current->internal_xact = true;
     358                 : 
     359                 :         /*
     360                 :          * Hold any pinned portals that any PLs might be using.  We have to do
     361                 :          * this before changing transaction state, since this will run
     362                 :          * user-defined code that might throw an error, and in any case
     363                 :          * couldn't be run in an already-aborted transaction.
     364                 :          */
     365              80 :         HoldPinnedPortals();
     366                 : 
     367                 :         /* Release snapshots associated with portals */
     368              78 :         ForgetPortalSnapshots();
     369                 : 
     370                 :         /* Do the deed */
     371              78 :         AbortCurrentTransaction();
     372                 : 
     373                 :         /* Immediately start a new transaction */
     374              78 :         StartTransactionCommand();
     375              78 :         if (chain)
     376               2 :             RestoreTransactionCharacteristics(&savetc);
     377                 : 
     378              78 :         MemoryContextSwitchTo(oldcontext);
     379                 : 
     380              78 :         _SPI_current->internal_xact = false;
     381                 :     }
     382               2 :     PG_CATCH();
     383                 :     {
     384                 :         ErrorData  *edata;
     385                 : 
     386                 :         /* Save error info in caller's context */
     387               2 :         MemoryContextSwitchTo(oldcontext);
     388               2 :         edata = CopyErrorData();
     389               2 :         FlushErrorState();
     390                 : 
     391                 :         /*
     392                 :          * Try again to abort the failed transaction.  If this fails too,
     393                 :          * we'll just propagate the error out ... there's not that much we can
     394                 :          * do.
     395                 :          */
     396               2 :         AbortCurrentTransaction();
     397                 : 
     398                 :         /* ... and start a new one */
     399               2 :         StartTransactionCommand();
     400               2 :         if (chain)
     401 UBC           0 :             RestoreTransactionCharacteristics(&savetc);
     402                 : 
     403 CBC           2 :         MemoryContextSwitchTo(oldcontext);
     404                 : 
     405               2 :         _SPI_current->internal_xact = false;
     406                 : 
     407                 :         /* Now that we've cleaned up the transaction, re-throw the error */
     408               2 :         ReThrowError(edata);
     409                 :     }
     410              78 :     PG_END_TRY();
     411              78 : }
     412                 : 
     413                 : void
     414              80 : SPI_rollback(void)
     415                 : {
     416              80 :     _SPI_rollback(false);
     417              76 : }
     418                 : 
     419                 : void
     420               2 : SPI_rollback_and_chain(void)
     421                 : {
     422               2 :     _SPI_rollback(true);
     423               2 : }
     424                 : 
     425                 : /*
     426                 :  * Clean up SPI state at transaction commit or abort.
     427                 :  */
     428                 : void
     429          485859 : AtEOXact_SPI(bool isCommit)
     430                 : {
     431          485859 :     bool        found = false;
     432                 : 
     433                 :     /*
     434                 :      * Pop stack entries, stopping if we find one marked internal_xact (that
     435                 :      * one belongs to the caller of SPI_commit or SPI_abort).
     436                 :      */
     437          487001 :     while (_SPI_connected >= 0)
     438                 :     {
     439            3345 :         _SPI_connection *connection = &(_SPI_stack[_SPI_connected]);
     440                 : 
     441            3345 :         if (connection->internal_xact)
     442            2203 :             break;
     443                 : 
     444            1142 :         found = true;
     445                 : 
     446                 :         /*
     447                 :          * We need not release the procedure's memory contexts explicitly, as
     448                 :          * they'll go away automatically when their parent context does; see
     449                 :          * notes in SPI_connect_ext.
     450                 :          */
     451                 : 
     452                 :         /*
     453                 :          * Restore outer global variables and pop the stack entry.  Unlike
     454                 :          * SPI_finish(), we don't risk switching to memory contexts that might
     455                 :          * be already gone.
     456                 :          */
     457            1142 :         SPI_processed = connection->outer_processed;
     458            1142 :         SPI_tuptable = connection->outer_tuptable;
     459            1142 :         SPI_result = connection->outer_result;
     460                 : 
     461            1142 :         _SPI_connected--;
     462            1142 :         if (_SPI_connected < 0)
     463            1105 :             _SPI_current = NULL;
     464                 :         else
     465              37 :             _SPI_current = &(_SPI_stack[_SPI_connected]);
     466                 :     }
     467                 : 
     468                 :     /* We should only find entries to pop during an ABORT. */
     469          485859 :     if (found && isCommit)
     470 UBC           0 :         ereport(WARNING,
     471                 :                 (errcode(ERRCODE_WARNING),
     472                 :                  errmsg("transaction left non-empty SPI stack"),
     473                 :                  errhint("Check for missing \"SPI_finish\" calls.")));
     474 CBC      485859 : }
     475                 : 
     476                 : /*
     477                 :  * Clean up SPI state at subtransaction commit or abort.
     478                 :  *
     479                 :  * During commit, there shouldn't be any unclosed entries remaining from
     480                 :  * the current subtransaction; we emit a warning if any are found.
     481                 :  */
     482                 : void
     483            8785 : AtEOSubXact_SPI(bool isCommit, SubTransactionId mySubid)
     484                 : {
     485            8785 :     bool        found = false;
     486                 : 
     487            8891 :     while (_SPI_connected >= 0)
     488                 :     {
     489            6730 :         _SPI_connection *connection = &(_SPI_stack[_SPI_connected]);
     490                 : 
     491            6730 :         if (connection->connectSubid != mySubid)
     492            6624 :             break;              /* couldn't be any underneath it either */
     493                 : 
     494             106 :         if (connection->internal_xact)
     495 UBC           0 :             break;
     496                 : 
     497 CBC         106 :         found = true;
     498                 : 
     499                 :         /*
     500                 :          * Release procedure memory explicitly (see note in SPI_connect)
     501                 :          */
     502             106 :         if (connection->execCxt)
     503                 :         {
     504             106 :             MemoryContextDelete(connection->execCxt);
     505             106 :             connection->execCxt = NULL;
     506                 :         }
     507             106 :         if (connection->procCxt)
     508                 :         {
     509             106 :             MemoryContextDelete(connection->procCxt);
     510             106 :             connection->procCxt = NULL;
     511                 :         }
     512                 : 
     513                 :         /*
     514                 :          * Restore outer global variables and pop the stack entry.  Unlike
     515                 :          * SPI_finish(), we don't risk switching to memory contexts that might
     516                 :          * be already gone.
     517                 :          */
     518             106 :         SPI_processed = connection->outer_processed;
     519             106 :         SPI_tuptable = connection->outer_tuptable;
     520             106 :         SPI_result = connection->outer_result;
     521                 : 
     522             106 :         _SPI_connected--;
     523             106 :         if (_SPI_connected < 0)
     524              36 :             _SPI_current = NULL;
     525                 :         else
     526              70 :             _SPI_current = &(_SPI_stack[_SPI_connected]);
     527                 :     }
     528                 : 
     529            8785 :     if (found && isCommit)
     530 UBC           0 :         ereport(WARNING,
     531                 :                 (errcode(ERRCODE_WARNING),
     532                 :                  errmsg("subtransaction left non-empty SPI stack"),
     533                 :                  errhint("Check for missing \"SPI_finish\" calls.")));
     534                 : 
     535                 :     /*
     536                 :      * If we are aborting a subtransaction and there is an open SPI context
     537                 :      * surrounding the subxact, clean up to prevent memory leakage.
     538                 :      */
     539 CBC        8785 :     if (_SPI_current && !isCommit)
     540                 :     {
     541                 :         slist_mutable_iter siter;
     542                 : 
     543                 :         /*
     544                 :          * Throw away executor state if current executor operation was started
     545                 :          * within current subxact (essentially, force a _SPI_end_call(true)).
     546                 :          */
     547            3100 :         if (_SPI_current->execSubid >= mySubid)
     548                 :         {
     549            2708 :             _SPI_current->execSubid = InvalidSubTransactionId;
     550            2708 :             MemoryContextResetAndDeleteChildren(_SPI_current->execCxt);
     551                 :         }
     552                 : 
     553                 :         /* throw away any tuple tables created within current subxact */
     554            7582 :         slist_foreach_modify(siter, &_SPI_current->tuptables)
     555                 :         {
     556                 :             SPITupleTable *tuptable;
     557                 : 
     558            4482 :             tuptable = slist_container(SPITupleTable, next, siter.cur);
     559            4482 :             if (tuptable->subid >= mySubid)
     560                 :             {
     561                 :                 /*
     562                 :                  * If we used SPI_freetuptable() here, its internal search of
     563                 :                  * the tuptables list would make this operation O(N^2).
     564                 :                  * Instead, just free the tuptable manually.  This should
     565                 :                  * match what SPI_freetuptable() does.
     566                 :                  */
     567            2628 :                 slist_delete_current(&siter);
     568            2628 :                 if (tuptable == _SPI_current->tuptable)
     569            2625 :                     _SPI_current->tuptable = NULL;
     570            2628 :                 if (tuptable == SPI_tuptable)
     571               3 :                     SPI_tuptable = NULL;
     572            2628 :                 MemoryContextDelete(tuptable->tuptabcxt);
     573                 :             }
     574                 :         }
     575                 :     }
     576            8785 : }
     577                 : 
     578                 : /*
     579                 :  * Are we executing inside a procedure (that is, a nonatomic SPI context)?
     580                 :  */
     581                 : bool
     582          481965 : SPI_inside_nonatomic_context(void)
     583                 : {
     584          481965 :     if (_SPI_current == NULL)
     585          479762 :         return false;           /* not in any SPI context at all */
     586            2203 :     if (_SPI_current->atomic)
     587 UBC           0 :         return false;           /* it's atomic (ie function not procedure) */
     588 CBC        2203 :     return true;
     589                 : }
     590                 : 
     591                 : 
     592                 : /* Parse, plan, and execute a query string */
     593                 : int
     594             658 : SPI_execute(const char *src, bool read_only, long tcount)
     595                 : {
     596                 :     _SPI_plan   plan;
     597                 :     SPIExecuteOptions options;
     598                 :     int         res;
     599                 : 
     600             658 :     if (src == NULL || tcount < 0)
     601 UBC           0 :         return SPI_ERROR_ARGUMENT;
     602                 : 
     603 CBC         658 :     res = _SPI_begin_call(true);
     604             658 :     if (res < 0)
     605 UBC           0 :         return res;
     606                 : 
     607 CBC         658 :     memset(&plan, 0, sizeof(_SPI_plan));
     608             658 :     plan.magic = _SPI_PLAN_MAGIC;
     609             658 :     plan.parse_mode = RAW_PARSE_DEFAULT;
     610             658 :     plan.cursor_options = CURSOR_OPT_PARALLEL_OK;
     611                 : 
     612             658 :     _SPI_prepare_oneshot_plan(src, &plan);
     613                 : 
     614             650 :     memset(&options, 0, sizeof(options));
     615             650 :     options.read_only = read_only;
     616             650 :     options.tcount = tcount;
     617                 : 
     618             650 :     res = _SPI_execute_plan(&plan, &options,
     619                 :                             InvalidSnapshot, InvalidSnapshot,
     620                 :                             true);
     621                 : 
     622             623 :     _SPI_end_call(true);
     623             623 :     return res;
     624                 : }
     625                 : 
     626                 : /* Obsolete version of SPI_execute */
     627                 : int
     628             196 : SPI_exec(const char *src, long tcount)
     629                 : {
     630             196 :     return SPI_execute(src, false, tcount);
     631                 : }
     632                 : 
     633                 : /* Parse, plan, and execute a query string, with extensible options */
     634                 : int
     635            5355 : SPI_execute_extended(const char *src,
     636                 :                      const SPIExecuteOptions *options)
     637                 : {
     638                 :     int         res;
     639                 :     _SPI_plan   plan;
     640                 : 
     641            5355 :     if (src == NULL || options == NULL)
     642 UBC           0 :         return SPI_ERROR_ARGUMENT;
     643                 : 
     644 CBC        5355 :     res = _SPI_begin_call(true);
     645            5355 :     if (res < 0)
     646 UBC           0 :         return res;
     647                 : 
     648 CBC        5355 :     memset(&plan, 0, sizeof(_SPI_plan));
     649            5355 :     plan.magic = _SPI_PLAN_MAGIC;
     650            5355 :     plan.parse_mode = RAW_PARSE_DEFAULT;
     651            5355 :     plan.cursor_options = CURSOR_OPT_PARALLEL_OK;
     652            5355 :     if (options->params)
     653                 :     {
     654             285 :         plan.parserSetup = options->params->parserSetup;
     655             285 :         plan.parserSetupArg = options->params->parserSetupArg;
     656                 :     }
     657                 : 
     658            5355 :     _SPI_prepare_oneshot_plan(src, &plan);
     659                 : 
     660            5355 :     res = _SPI_execute_plan(&plan, options,
     661                 :                             InvalidSnapshot, InvalidSnapshot,
     662                 :                             true);
     663                 : 
     664            5302 :     _SPI_end_call(true);
     665            5302 :     return res;
     666                 : }
     667                 : 
     668                 : /* Execute a previously prepared plan */
     669                 : int
     670            1920 : SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls,
     671                 :                  bool read_only, long tcount)
     672                 : {
     673                 :     SPIExecuteOptions options;
     674                 :     int         res;
     675                 : 
     676            1920 :     if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC || tcount < 0)
     677 UBC           0 :         return SPI_ERROR_ARGUMENT;
     678                 : 
     679 CBC        1920 :     if (plan->nargs > 0 && Values == NULL)
     680 UBC           0 :         return SPI_ERROR_PARAM;
     681                 : 
     682 CBC        1920 :     res = _SPI_begin_call(true);
     683            1920 :     if (res < 0)
     684 UBC           0 :         return res;
     685                 : 
     686 CBC        1920 :     memset(&options, 0, sizeof(options));
     687            1920 :     options.params = _SPI_convert_params(plan->nargs, plan->argtypes,
     688                 :                                          Values, Nulls);
     689            1920 :     options.read_only = read_only;
     690            1920 :     options.tcount = tcount;
     691                 : 
     692            1920 :     res = _SPI_execute_plan(plan, &options,
     693                 :                             InvalidSnapshot, InvalidSnapshot,
     694                 :                             true);
     695                 : 
     696            1914 :     _SPI_end_call(true);
     697            1914 :     return res;
     698                 : }
     699                 : 
     700                 : /* Obsolete version of SPI_execute_plan */
     701                 : int
     702              93 : SPI_execp(SPIPlanPtr plan, Datum *Values, const char *Nulls, long tcount)
     703                 : {
     704              93 :     return SPI_execute_plan(plan, Values, Nulls, false, tcount);
     705                 : }
     706                 : 
     707                 : /* Execute a previously prepared plan */
     708                 : int
     709            1252 : SPI_execute_plan_extended(SPIPlanPtr plan,
     710                 :                           const SPIExecuteOptions *options)
     711                 : {
     712                 :     int         res;
     713                 : 
     714            1252 :     if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC || options == NULL)
     715 UBC           0 :         return SPI_ERROR_ARGUMENT;
     716                 : 
     717 CBC        1252 :     res = _SPI_begin_call(true);
     718            1252 :     if (res < 0)
     719 UBC           0 :         return res;
     720                 : 
     721 CBC        1252 :     res = _SPI_execute_plan(plan, options,
     722                 :                             InvalidSnapshot, InvalidSnapshot,
     723                 :                             true);
     724                 : 
     725            1248 :     _SPI_end_call(true);
     726            1248 :     return res;
     727                 : }
     728                 : 
     729                 : /* Execute a previously prepared plan */
     730                 : int
     731           29073 : SPI_execute_plan_with_paramlist(SPIPlanPtr plan, ParamListInfo params,
     732                 :                                 bool read_only, long tcount)
     733                 : {
     734                 :     SPIExecuteOptions options;
     735                 :     int         res;
     736                 : 
     737           29073 :     if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC || tcount < 0)
     738 UBC           0 :         return SPI_ERROR_ARGUMENT;
     739                 : 
     740 CBC       29073 :     res = _SPI_begin_call(true);
     741           29073 :     if (res < 0)
     742 UBC           0 :         return res;
     743                 : 
     744 CBC       29073 :     memset(&options, 0, sizeof(options));
     745           29073 :     options.params = params;
     746           29073 :     options.read_only = read_only;
     747           29073 :     options.tcount = tcount;
     748                 : 
     749           29073 :     res = _SPI_execute_plan(plan, &options,
     750                 :                             InvalidSnapshot, InvalidSnapshot,
     751                 :                             true);
     752                 : 
     753           26402 :     _SPI_end_call(true);
     754           26402 :     return res;
     755                 : }
     756                 : 
     757                 : /*
     758                 :  * SPI_execute_snapshot -- identical to SPI_execute_plan, except that we allow
     759                 :  * the caller to specify exactly which snapshots to use, which will be
     760                 :  * registered here.  Also, the caller may specify that AFTER triggers should be
     761                 :  * queued as part of the outer query rather than being fired immediately at the
     762                 :  * end of the command.
     763                 :  *
     764                 :  * This is currently not documented in spi.sgml because it is only intended
     765                 :  * for use by RI triggers.
     766                 :  *
     767                 :  * Passing snapshot == InvalidSnapshot will select the normal behavior of
     768                 :  * fetching a new snapshot for each query.
     769                 :  */
     770                 : int
     771            3414 : SPI_execute_snapshot(SPIPlanPtr plan,
     772                 :                      Datum *Values, const char *Nulls,
     773                 :                      Snapshot snapshot, Snapshot crosscheck_snapshot,
     774                 :                      bool read_only, bool fire_triggers, long tcount)
     775                 : {
     776                 :     SPIExecuteOptions options;
     777                 :     int         res;
     778                 : 
     779            3414 :     if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC || tcount < 0)
     780 UBC           0 :         return SPI_ERROR_ARGUMENT;
     781                 : 
     782 CBC        3414 :     if (plan->nargs > 0 && Values == NULL)
     783 UBC           0 :         return SPI_ERROR_PARAM;
     784                 : 
     785 CBC        3414 :     res = _SPI_begin_call(true);
     786            3414 :     if (res < 0)
     787 UBC           0 :         return res;
     788                 : 
     789 CBC        3414 :     memset(&options, 0, sizeof(options));
     790            3414 :     options.params = _SPI_convert_params(plan->nargs, plan->argtypes,
     791                 :                                          Values, Nulls);
     792            3414 :     options.read_only = read_only;
     793            3414 :     options.tcount = tcount;
     794                 : 
     795            3414 :     res = _SPI_execute_plan(plan, &options,
     796                 :                             snapshot, crosscheck_snapshot,
     797                 :                             fire_triggers);
     798                 : 
     799            3409 :     _SPI_end_call(true);
     800            3409 :     return res;
     801                 : }
     802                 : 
     803                 : /*
     804                 :  * SPI_execute_with_args -- plan and execute a query with supplied arguments
     805                 :  *
     806                 :  * This is functionally equivalent to SPI_prepare followed by
     807                 :  * SPI_execute_plan.
     808                 :  */
     809                 : int
     810 UBC           0 : SPI_execute_with_args(const char *src,
     811                 :                       int nargs, Oid *argtypes,
     812                 :                       Datum *Values, const char *Nulls,
     813                 :                       bool read_only, long tcount)
     814                 : {
     815                 :     int         res;
     816                 :     _SPI_plan   plan;
     817                 :     ParamListInfo paramLI;
     818                 :     SPIExecuteOptions options;
     819                 : 
     820               0 :     if (src == NULL || nargs < 0 || tcount < 0)
     821               0 :         return SPI_ERROR_ARGUMENT;
     822                 : 
     823               0 :     if (nargs > 0 && (argtypes == NULL || Values == NULL))
     824               0 :         return SPI_ERROR_PARAM;
     825                 : 
     826               0 :     res = _SPI_begin_call(true);
     827               0 :     if (res < 0)
     828               0 :         return res;
     829                 : 
     830               0 :     memset(&plan, 0, sizeof(_SPI_plan));
     831               0 :     plan.magic = _SPI_PLAN_MAGIC;
     832               0 :     plan.parse_mode = RAW_PARSE_DEFAULT;
     833               0 :     plan.cursor_options = CURSOR_OPT_PARALLEL_OK;
     834               0 :     plan.nargs = nargs;
     835               0 :     plan.argtypes = argtypes;
     836               0 :     plan.parserSetup = NULL;
     837               0 :     plan.parserSetupArg = NULL;
     838                 : 
     839               0 :     paramLI = _SPI_convert_params(nargs, argtypes,
     840                 :                                   Values, Nulls);
     841                 : 
     842               0 :     _SPI_prepare_oneshot_plan(src, &plan);
     843                 : 
     844               0 :     memset(&options, 0, sizeof(options));
     845               0 :     options.params = paramLI;
     846               0 :     options.read_only = read_only;
     847               0 :     options.tcount = tcount;
     848                 : 
     849               0 :     res = _SPI_execute_plan(&plan, &options,
     850                 :                             InvalidSnapshot, InvalidSnapshot,
     851                 :                             true);
     852                 : 
     853               0 :     _SPI_end_call(true);
     854               0 :     return res;
     855                 : }
     856                 : 
     857                 : SPIPlanPtr
     858 CBC        2380 : SPI_prepare(const char *src, int nargs, Oid *argtypes)
     859                 : {
     860            2380 :     return SPI_prepare_cursor(src, nargs, argtypes, 0);
     861                 : }
     862                 : 
     863                 : SPIPlanPtr
     864            2380 : SPI_prepare_cursor(const char *src, int nargs, Oid *argtypes,
     865                 :                    int cursorOptions)
     866                 : {
     867                 :     _SPI_plan   plan;
     868                 :     SPIPlanPtr  result;
     869                 : 
     870            2380 :     if (src == NULL || nargs < 0 || (nargs > 0 && argtypes == NULL))
     871                 :     {
     872 UBC           0 :         SPI_result = SPI_ERROR_ARGUMENT;
     873               0 :         return NULL;
     874                 :     }
     875                 : 
     876 CBC        2380 :     SPI_result = _SPI_begin_call(true);
     877            2380 :     if (SPI_result < 0)
     878 UBC           0 :         return NULL;
     879                 : 
     880 CBC        2380 :     memset(&plan, 0, sizeof(_SPI_plan));
     881            2380 :     plan.magic = _SPI_PLAN_MAGIC;
     882            2380 :     plan.parse_mode = RAW_PARSE_DEFAULT;
     883            2380 :     plan.cursor_options = cursorOptions;
     884            2380 :     plan.nargs = nargs;
     885            2380 :     plan.argtypes = argtypes;
     886            2380 :     plan.parserSetup = NULL;
     887            2380 :     plan.parserSetupArg = NULL;
     888                 : 
     889            2380 :     _SPI_prepare_plan(src, &plan);
     890                 : 
     891                 :     /* copy plan to procedure context */
     892            2379 :     result = _SPI_make_plan_non_temp(&plan);
     893                 : 
     894            2379 :     _SPI_end_call(true);
     895                 : 
     896            2379 :     return result;
     897                 : }
     898                 : 
     899                 : SPIPlanPtr
     900           11590 : SPI_prepare_extended(const char *src,
     901                 :                      const SPIPrepareOptions *options)
     902                 : {
     903                 :     _SPI_plan   plan;
     904                 :     SPIPlanPtr  result;
     905                 : 
     906           11590 :     if (src == NULL || options == NULL)
     907                 :     {
     908 UBC           0 :         SPI_result = SPI_ERROR_ARGUMENT;
     909               0 :         return NULL;
     910                 :     }
     911                 : 
     912 CBC       11590 :     SPI_result = _SPI_begin_call(true);
     913           11590 :     if (SPI_result < 0)
     914 UBC           0 :         return NULL;
     915                 : 
     916 CBC       11590 :     memset(&plan, 0, sizeof(_SPI_plan));
     917           11590 :     plan.magic = _SPI_PLAN_MAGIC;
     918           11590 :     plan.parse_mode = options->parseMode;
     919           11590 :     plan.cursor_options = options->cursorOptions;
     920           11590 :     plan.nargs = 0;
     921           11590 :     plan.argtypes = NULL;
     922           11590 :     plan.parserSetup = options->parserSetup;
     923           11590 :     plan.parserSetupArg = options->parserSetupArg;
     924                 : 
     925           11590 :     _SPI_prepare_plan(src, &plan);
     926                 : 
     927                 :     /* copy plan to procedure context */
     928           11547 :     result = _SPI_make_plan_non_temp(&plan);
     929                 : 
     930           11547 :     _SPI_end_call(true);
     931                 : 
     932           11547 :     return result;
     933                 : }
     934                 : 
     935                 : SPIPlanPtr
     936 UBC           0 : SPI_prepare_params(const char *src,
     937                 :                    ParserSetupHook parserSetup,
     938                 :                    void *parserSetupArg,
     939                 :                    int cursorOptions)
     940                 : {
     941                 :     _SPI_plan   plan;
     942                 :     SPIPlanPtr  result;
     943                 : 
     944               0 :     if (src == NULL)
     945                 :     {
     946               0 :         SPI_result = SPI_ERROR_ARGUMENT;
     947               0 :         return NULL;
     948                 :     }
     949                 : 
     950               0 :     SPI_result = _SPI_begin_call(true);
     951               0 :     if (SPI_result < 0)
     952               0 :         return NULL;
     953                 : 
     954               0 :     memset(&plan, 0, sizeof(_SPI_plan));
     955               0 :     plan.magic = _SPI_PLAN_MAGIC;
     956               0 :     plan.parse_mode = RAW_PARSE_DEFAULT;
     957               0 :     plan.cursor_options = cursorOptions;
     958               0 :     plan.nargs = 0;
     959               0 :     plan.argtypes = NULL;
     960               0 :     plan.parserSetup = parserSetup;
     961               0 :     plan.parserSetupArg = parserSetupArg;
     962                 : 
     963               0 :     _SPI_prepare_plan(src, &plan);
     964                 : 
     965                 :     /* copy plan to procedure context */
     966               0 :     result = _SPI_make_plan_non_temp(&plan);
     967                 : 
     968               0 :     _SPI_end_call(true);
     969                 : 
     970               0 :     return result;
     971                 : }
     972                 : 
     973                 : int
     974 CBC       13248 : SPI_keepplan(SPIPlanPtr plan)
     975                 : {
     976                 :     ListCell   *lc;
     977                 : 
     978           13248 :     if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC ||
     979           13248 :         plan->saved || plan->oneshot)
     980 UBC           0 :         return SPI_ERROR_ARGUMENT;
     981                 : 
     982                 :     /*
     983                 :      * Mark it saved, reparent it under CacheMemoryContext, and mark all the
     984                 :      * component CachedPlanSources as saved.  This sequence cannot fail
     985                 :      * partway through, so there's no risk of long-term memory leakage.
     986                 :      */
     987 CBC       13248 :     plan->saved = true;
     988           13248 :     MemoryContextSetParent(plan->plancxt, CacheMemoryContext);
     989                 : 
     990           26496 :     foreach(lc, plan->plancache_list)
     991                 :     {
     992           13248 :         CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc);
     993                 : 
     994           13248 :         SaveCachedPlan(plansource);
     995                 :     }
     996                 : 
     997           13248 :     return 0;
     998                 : }
     999                 : 
    1000                 : SPIPlanPtr
    1001 UBC           0 : SPI_saveplan(SPIPlanPtr plan)
    1002                 : {
    1003                 :     SPIPlanPtr  newplan;
    1004                 : 
    1005               0 :     if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC)
    1006                 :     {
    1007               0 :         SPI_result = SPI_ERROR_ARGUMENT;
    1008               0 :         return NULL;
    1009                 :     }
    1010                 : 
    1011               0 :     SPI_result = _SPI_begin_call(false);    /* don't change context */
    1012               0 :     if (SPI_result < 0)
    1013               0 :         return NULL;
    1014                 : 
    1015               0 :     newplan = _SPI_save_plan(plan);
    1016                 : 
    1017               0 :     SPI_result = _SPI_end_call(false);
    1018                 : 
    1019               0 :     return newplan;
    1020                 : }
    1021                 : 
    1022                 : int
    1023 CBC        2519 : SPI_freeplan(SPIPlanPtr plan)
    1024                 : {
    1025                 :     ListCell   *lc;
    1026                 : 
    1027            2519 :     if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC)
    1028 UBC           0 :         return SPI_ERROR_ARGUMENT;
    1029                 : 
    1030                 :     /* Release the plancache entries */
    1031 CBC        5038 :     foreach(lc, plan->plancache_list)
    1032                 :     {
    1033            2519 :         CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc);
    1034                 : 
    1035            2519 :         DropCachedPlan(plansource);
    1036                 :     }
    1037                 : 
    1038                 :     /* Now get rid of the _SPI_plan and subsidiary data in its plancxt */
    1039            2519 :     MemoryContextDelete(plan->plancxt);
    1040                 : 
    1041            2519 :     return 0;
    1042                 : }
    1043                 : 
    1044                 : HeapTuple
    1045            1026 : SPI_copytuple(HeapTuple tuple)
    1046                 : {
    1047                 :     MemoryContext oldcxt;
    1048                 :     HeapTuple   ctuple;
    1049                 : 
    1050            1026 :     if (tuple == NULL)
    1051                 :     {
    1052 UBC           0 :         SPI_result = SPI_ERROR_ARGUMENT;
    1053               0 :         return NULL;
    1054                 :     }
    1055                 : 
    1056 CBC        1026 :     if (_SPI_current == NULL)
    1057                 :     {
    1058 UBC           0 :         SPI_result = SPI_ERROR_UNCONNECTED;
    1059               0 :         return NULL;
    1060                 :     }
    1061                 : 
    1062 CBC        1026 :     oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
    1063                 : 
    1064            1026 :     ctuple = heap_copytuple(tuple);
    1065                 : 
    1066            1026 :     MemoryContextSwitchTo(oldcxt);
    1067                 : 
    1068            1026 :     return ctuple;
    1069                 : }
    1070                 : 
    1071                 : HeapTupleHeader
    1072            3046 : SPI_returntuple(HeapTuple tuple, TupleDesc tupdesc)
    1073                 : {
    1074                 :     MemoryContext oldcxt;
    1075                 :     HeapTupleHeader dtup;
    1076                 : 
    1077            3046 :     if (tuple == NULL || tupdesc == NULL)
    1078                 :     {
    1079 UBC           0 :         SPI_result = SPI_ERROR_ARGUMENT;
    1080               0 :         return NULL;
    1081                 :     }
    1082                 : 
    1083 CBC        3046 :     if (_SPI_current == NULL)
    1084                 :     {
    1085 UBC           0 :         SPI_result = SPI_ERROR_UNCONNECTED;
    1086               0 :         return NULL;
    1087                 :     }
    1088                 : 
    1089                 :     /* For RECORD results, make sure a typmod has been assigned */
    1090 CBC        3046 :     if (tupdesc->tdtypeid == RECORDOID &&
    1091            3038 :         tupdesc->tdtypmod < 0)
    1092 UBC           0 :         assign_record_type_typmod(tupdesc);
    1093                 : 
    1094 CBC        3046 :     oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
    1095                 : 
    1096            3046 :     dtup = DatumGetHeapTupleHeader(heap_copy_tuple_as_datum(tuple, tupdesc));
    1097                 : 
    1098            3046 :     MemoryContextSwitchTo(oldcxt);
    1099                 : 
    1100            3046 :     return dtup;
    1101                 : }
    1102                 : 
    1103                 : HeapTuple
    1104               6 : SPI_modifytuple(Relation rel, HeapTuple tuple, int natts, int *attnum,
    1105                 :                 Datum *Values, const char *Nulls)
    1106                 : {
    1107                 :     MemoryContext oldcxt;
    1108                 :     HeapTuple   mtuple;
    1109                 :     int         numberOfAttributes;
    1110                 :     Datum      *v;
    1111                 :     bool       *n;
    1112                 :     int         i;
    1113                 : 
    1114               6 :     if (rel == NULL || tuple == NULL || natts < 0 || attnum == NULL || Values == NULL)
    1115                 :     {
    1116 UBC           0 :         SPI_result = SPI_ERROR_ARGUMENT;
    1117               0 :         return NULL;
    1118                 :     }
    1119                 : 
    1120 CBC           6 :     if (_SPI_current == NULL)
    1121                 :     {
    1122 UBC           0 :         SPI_result = SPI_ERROR_UNCONNECTED;
    1123               0 :         return NULL;
    1124                 :     }
    1125                 : 
    1126 CBC           6 :     oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
    1127                 : 
    1128               6 :     SPI_result = 0;
    1129                 : 
    1130               6 :     numberOfAttributes = rel->rd_att->natts;
    1131               6 :     v = (Datum *) palloc(numberOfAttributes * sizeof(Datum));
    1132               6 :     n = (bool *) palloc(numberOfAttributes * sizeof(bool));
    1133                 : 
    1134                 :     /* fetch old values and nulls */
    1135               6 :     heap_deform_tuple(tuple, rel->rd_att, v, n);
    1136                 : 
    1137                 :     /* replace values and nulls */
    1138              12 :     for (i = 0; i < natts; i++)
    1139                 :     {
    1140               6 :         if (attnum[i] <= 0 || attnum[i] > numberOfAttributes)
    1141                 :             break;
    1142               6 :         v[attnum[i] - 1] = Values[i];
    1143               6 :         n[attnum[i] - 1] = (Nulls && Nulls[i] == 'n');
    1144                 :     }
    1145                 : 
    1146               6 :     if (i == natts)             /* no errors in *attnum */
    1147                 :     {
    1148               6 :         mtuple = heap_form_tuple(rel->rd_att, v, n);
    1149                 : 
    1150                 :         /*
    1151                 :          * copy the identification info of the old tuple: t_ctid, t_self, and
    1152                 :          * OID (if any)
    1153                 :          */
    1154               6 :         mtuple->t_data->t_ctid = tuple->t_data->t_ctid;
    1155               6 :         mtuple->t_self = tuple->t_self;
    1156               6 :         mtuple->t_tableOid = tuple->t_tableOid;
    1157                 :     }
    1158                 :     else
    1159                 :     {
    1160 UBC           0 :         mtuple = NULL;
    1161               0 :         SPI_result = SPI_ERROR_NOATTRIBUTE;
    1162                 :     }
    1163                 : 
    1164 CBC           6 :     pfree(v);
    1165               6 :     pfree(n);
    1166                 : 
    1167               6 :     MemoryContextSwitchTo(oldcxt);
    1168                 : 
    1169               6 :     return mtuple;
    1170                 : }
    1171                 : 
    1172                 : int
    1173            9132 : SPI_fnumber(TupleDesc tupdesc, const char *fname)
    1174                 : {
    1175                 :     int         res;
    1176                 :     const FormData_pg_attribute *sysatt;
    1177                 : 
    1178           48392 :     for (res = 0; res < tupdesc->natts; res++)
    1179                 :     {
    1180           48385 :         Form_pg_attribute attr = TupleDescAttr(tupdesc, res);
    1181                 : 
    1182           48385 :         if (namestrcmp(&attr->attname, fname) == 0 &&
    1183            9125 :             !attr->attisdropped)
    1184            9125 :             return res + 1;
    1185                 :     }
    1186                 : 
    1187               7 :     sysatt = SystemAttributeByName(fname);
    1188               7 :     if (sysatt != NULL)
    1189 UBC           0 :         return sysatt->attnum;
    1190                 : 
    1191                 :     /* SPI_ERROR_NOATTRIBUTE is different from all sys column numbers */
    1192 CBC           7 :     return SPI_ERROR_NOATTRIBUTE;
    1193                 : }
    1194                 : 
    1195                 : char *
    1196             486 : SPI_fname(TupleDesc tupdesc, int fnumber)
    1197                 : {
    1198                 :     const FormData_pg_attribute *att;
    1199                 : 
    1200             486 :     SPI_result = 0;
    1201                 : 
    1202             486 :     if (fnumber > tupdesc->natts || fnumber == 0 ||
    1203                 :         fnumber <= FirstLowInvalidHeapAttributeNumber)
    1204                 :     {
    1205 UBC           0 :         SPI_result = SPI_ERROR_NOATTRIBUTE;
    1206               0 :         return NULL;
    1207                 :     }
    1208                 : 
    1209 CBC         486 :     if (fnumber > 0)
    1210             486 :         att = TupleDescAttr(tupdesc, fnumber - 1);
    1211                 :     else
    1212 UBC           0 :         att = SystemAttributeDefinition(fnumber);
    1213                 : 
    1214 CBC         486 :     return pstrdup(NameStr(att->attname));
    1215                 : }
    1216                 : 
    1217                 : char *
    1218            3990 : SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber)
    1219                 : {
    1220                 :     Datum       val;
    1221                 :     bool        isnull;
    1222                 :     Oid         typoid,
    1223                 :                 foutoid;
    1224                 :     bool        typisvarlena;
    1225                 : 
    1226            3990 :     SPI_result = 0;
    1227                 : 
    1228            3990 :     if (fnumber > tupdesc->natts || fnumber == 0 ||
    1229                 :         fnumber <= FirstLowInvalidHeapAttributeNumber)
    1230                 :     {
    1231 UBC           0 :         SPI_result = SPI_ERROR_NOATTRIBUTE;
    1232               0 :         return NULL;
    1233                 :     }
    1234                 : 
    1235 CBC        3990 :     val = heap_getattr(tuple, fnumber, tupdesc, &isnull);
    1236            3990 :     if (isnull)
    1237              65 :         return NULL;
    1238                 : 
    1239            3925 :     if (fnumber > 0)
    1240            3925 :         typoid = TupleDescAttr(tupdesc, fnumber - 1)->atttypid;
    1241                 :     else
    1242 UBC           0 :         typoid = (SystemAttributeDefinition(fnumber))->atttypid;
    1243                 : 
    1244 CBC        3925 :     getTypeOutputInfo(typoid, &foutoid, &typisvarlena);
    1245                 : 
    1246            3925 :     return OidOutputFunctionCall(foutoid, val);
    1247                 : }
    1248                 : 
    1249                 : Datum
    1250           27165 : SPI_getbinval(HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool *isnull)
    1251                 : {
    1252           27165 :     SPI_result = 0;
    1253                 : 
    1254           27165 :     if (fnumber > tupdesc->natts || fnumber == 0 ||
    1255                 :         fnumber <= FirstLowInvalidHeapAttributeNumber)
    1256                 :     {
    1257 UBC           0 :         SPI_result = SPI_ERROR_NOATTRIBUTE;
    1258               0 :         *isnull = true;
    1259               0 :         return (Datum) NULL;
    1260                 :     }
    1261                 : 
    1262 CBC       27165 :     return heap_getattr(tuple, fnumber, tupdesc, isnull);
    1263                 : }
    1264                 : 
    1265                 : char *
    1266 UBC           0 : SPI_gettype(TupleDesc tupdesc, int fnumber)
    1267                 : {
    1268                 :     Oid         typoid;
    1269                 :     HeapTuple   typeTuple;
    1270                 :     char       *result;
    1271                 : 
    1272               0 :     SPI_result = 0;
    1273                 : 
    1274               0 :     if (fnumber > tupdesc->natts || fnumber == 0 ||
    1275                 :         fnumber <= FirstLowInvalidHeapAttributeNumber)
    1276                 :     {
    1277               0 :         SPI_result = SPI_ERROR_NOATTRIBUTE;
    1278               0 :         return NULL;
    1279                 :     }
    1280                 : 
    1281               0 :     if (fnumber > 0)
    1282               0 :         typoid = TupleDescAttr(tupdesc, fnumber - 1)->atttypid;
    1283                 :     else
    1284               0 :         typoid = (SystemAttributeDefinition(fnumber))->atttypid;
    1285                 : 
    1286               0 :     typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typoid));
    1287                 : 
    1288               0 :     if (!HeapTupleIsValid(typeTuple))
    1289                 :     {
    1290               0 :         SPI_result = SPI_ERROR_TYPUNKNOWN;
    1291               0 :         return NULL;
    1292                 :     }
    1293                 : 
    1294               0 :     result = pstrdup(NameStr(((Form_pg_type) GETSTRUCT(typeTuple))->typname));
    1295               0 :     ReleaseSysCache(typeTuple);
    1296               0 :     return result;
    1297                 : }
    1298                 : 
    1299                 : /*
    1300                 :  * Get the data type OID for a column.
    1301                 :  *
    1302                 :  * There's nothing similar for typmod and typcollation.  The rare consumers
    1303                 :  * thereof should inspect the TupleDesc directly.
    1304                 :  */
    1305                 : Oid
    1306 CBC         681 : SPI_gettypeid(TupleDesc tupdesc, int fnumber)
    1307                 : {
    1308             681 :     SPI_result = 0;
    1309                 : 
    1310             681 :     if (fnumber > tupdesc->natts || fnumber == 0 ||
    1311                 :         fnumber <= FirstLowInvalidHeapAttributeNumber)
    1312                 :     {
    1313 UBC           0 :         SPI_result = SPI_ERROR_NOATTRIBUTE;
    1314               0 :         return InvalidOid;
    1315                 :     }
    1316                 : 
    1317 CBC         681 :     if (fnumber > 0)
    1318             681 :         return TupleDescAttr(tupdesc, fnumber - 1)->atttypid;
    1319                 :     else
    1320 UBC           0 :         return (SystemAttributeDefinition(fnumber))->atttypid;
    1321                 : }
    1322                 : 
    1323                 : char *
    1324 CBC         234 : SPI_getrelname(Relation rel)
    1325                 : {
    1326             234 :     return pstrdup(RelationGetRelationName(rel));
    1327                 : }
    1328                 : 
    1329                 : char *
    1330             138 : SPI_getnspname(Relation rel)
    1331                 : {
    1332             138 :     return get_namespace_name(RelationGetNamespace(rel));
    1333                 : }
    1334                 : 
    1335                 : void *
    1336              19 : SPI_palloc(Size size)
    1337                 : {
    1338              19 :     if (_SPI_current == NULL)
    1339 UBC           0 :         elog(ERROR, "SPI_palloc called while not connected to SPI");
    1340                 : 
    1341 CBC          19 :     return MemoryContextAlloc(_SPI_current->savedcxt, size);
    1342                 : }
    1343                 : 
    1344                 : void *
    1345 UBC           0 : SPI_repalloc(void *pointer, Size size)
    1346                 : {
    1347                 :     /* No longer need to worry which context chunk was in... */
    1348               0 :     return repalloc(pointer, size);
    1349                 : }
    1350                 : 
    1351                 : void
    1352               0 : SPI_pfree(void *pointer)
    1353                 : {
    1354                 :     /* No longer need to worry which context chunk was in... */
    1355               0 :     pfree(pointer);
    1356               0 : }
    1357                 : 
    1358                 : Datum
    1359 CBC        2735 : SPI_datumTransfer(Datum value, bool typByVal, int typLen)
    1360                 : {
    1361                 :     MemoryContext oldcxt;
    1362                 :     Datum       result;
    1363                 : 
    1364            2735 :     if (_SPI_current == NULL)
    1365 UBC           0 :         elog(ERROR, "SPI_datumTransfer called while not connected to SPI");
    1366                 : 
    1367 CBC        2735 :     oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
    1368                 : 
    1369            2735 :     result = datumTransfer(value, typByVal, typLen);
    1370                 : 
    1371            2735 :     MemoryContextSwitchTo(oldcxt);
    1372                 : 
    1373            2735 :     return result;
    1374                 : }
    1375                 : 
    1376                 : void
    1377 UBC           0 : SPI_freetuple(HeapTuple tuple)
    1378                 : {
    1379                 :     /* No longer need to worry which context tuple was in... */
    1380               0 :     heap_freetuple(tuple);
    1381               0 : }
    1382                 : 
    1383                 : void
    1384 CBC       74695 : SPI_freetuptable(SPITupleTable *tuptable)
    1385                 : {
    1386           74695 :     bool        found = false;
    1387                 : 
    1388                 :     /* ignore call if NULL pointer */
    1389           74695 :     if (tuptable == NULL)
    1390           39220 :         return;
    1391                 : 
    1392                 :     /*
    1393                 :      * Search only the topmost SPI context for a matching tuple table.
    1394                 :      */
    1395           35475 :     if (_SPI_current != NULL)
    1396                 :     {
    1397                 :         slist_mutable_iter siter;
    1398                 : 
    1399                 :         /* find tuptable in active list, then remove it */
    1400           35475 :         slist_foreach_modify(siter, &_SPI_current->tuptables)
    1401                 :         {
    1402                 :             SPITupleTable *tt;
    1403                 : 
    1404           35475 :             tt = slist_container(SPITupleTable, next, siter.cur);
    1405           35475 :             if (tt == tuptable)
    1406                 :             {
    1407           35475 :                 slist_delete_current(&siter);
    1408           35475 :                 found = true;
    1409           35475 :                 break;
    1410                 :             }
    1411                 :         }
    1412                 :     }
    1413                 : 
    1414                 :     /*
    1415                 :      * Refuse the deletion if we didn't find it in the topmost SPI context.
    1416                 :      * This is primarily a guard against double deletion, but might prevent
    1417                 :      * other errors as well.  Since the worst consequence of not deleting a
    1418                 :      * tuptable would be a transient memory leak, this is just a WARNING.
    1419                 :      */
    1420           35475 :     if (!found)
    1421                 :     {
    1422 UBC           0 :         elog(WARNING, "attempt to delete invalid SPITupleTable %p", tuptable);
    1423               0 :         return;
    1424                 :     }
    1425                 : 
    1426                 :     /* for safety, reset global variables that might point at tuptable */
    1427 CBC       35475 :     if (tuptable == _SPI_current->tuptable)
    1428 UBC           0 :         _SPI_current->tuptable = NULL;
    1429 CBC       35475 :     if (tuptable == SPI_tuptable)
    1430           31673 :         SPI_tuptable = NULL;
    1431                 : 
    1432                 :     /* release all memory belonging to tuptable */
    1433           35475 :     MemoryContextDelete(tuptable->tuptabcxt);
    1434                 : }
    1435                 : 
    1436                 : 
    1437                 : /*
    1438                 :  * SPI_cursor_open()
    1439                 :  *
    1440                 :  *  Open a prepared SPI plan as a portal
    1441                 :  */
    1442                 : Portal
    1443             106 : SPI_cursor_open(const char *name, SPIPlanPtr plan,
    1444                 :                 Datum *Values, const char *Nulls,
    1445                 :                 bool read_only)
    1446                 : {
    1447                 :     Portal      portal;
    1448                 :     ParamListInfo paramLI;
    1449                 : 
    1450                 :     /* build transient ParamListInfo in caller's context */
    1451             106 :     paramLI = _SPI_convert_params(plan->nargs, plan->argtypes,
    1452                 :                                   Values, Nulls);
    1453                 : 
    1454             106 :     portal = SPI_cursor_open_internal(name, plan, paramLI, read_only);
    1455                 : 
    1456                 :     /* done with the transient ParamListInfo */
    1457             106 :     if (paramLI)
    1458               4 :         pfree(paramLI);
    1459                 : 
    1460             106 :     return portal;
    1461                 : }
    1462                 : 
    1463                 : 
    1464                 : /*
    1465                 :  * SPI_cursor_open_with_args()
    1466                 :  *
    1467                 :  * Parse and plan a query and open it as a portal.
    1468                 :  */
    1469                 : Portal
    1470 UBC           0 : SPI_cursor_open_with_args(const char *name,
    1471                 :                           const char *src,
    1472                 :                           int nargs, Oid *argtypes,
    1473                 :                           Datum *Values, const char *Nulls,
    1474                 :                           bool read_only, int cursorOptions)
    1475                 : {
    1476                 :     Portal      result;
    1477                 :     _SPI_plan   plan;
    1478                 :     ParamListInfo paramLI;
    1479                 : 
    1480               0 :     if (src == NULL || nargs < 0)
    1481               0 :         elog(ERROR, "SPI_cursor_open_with_args called with invalid arguments");
    1482                 : 
    1483               0 :     if (nargs > 0 && (argtypes == NULL || Values == NULL))
    1484               0 :         elog(ERROR, "SPI_cursor_open_with_args called with missing parameters");
    1485                 : 
    1486               0 :     SPI_result = _SPI_begin_call(true);
    1487               0 :     if (SPI_result < 0)
    1488               0 :         elog(ERROR, "SPI_cursor_open_with_args called while not connected");
    1489                 : 
    1490               0 :     memset(&plan, 0, sizeof(_SPI_plan));
    1491               0 :     plan.magic = _SPI_PLAN_MAGIC;
    1492               0 :     plan.parse_mode = RAW_PARSE_DEFAULT;
    1493               0 :     plan.cursor_options = cursorOptions;
    1494               0 :     plan.nargs = nargs;
    1495               0 :     plan.argtypes = argtypes;
    1496               0 :     plan.parserSetup = NULL;
    1497               0 :     plan.parserSetupArg = NULL;
    1498                 : 
    1499                 :     /* build transient ParamListInfo in executor context */
    1500               0 :     paramLI = _SPI_convert_params(nargs, argtypes,
    1501                 :                                   Values, Nulls);
    1502                 : 
    1503               0 :     _SPI_prepare_plan(src, &plan);
    1504                 : 
    1505                 :     /* We needn't copy the plan; SPI_cursor_open_internal will do so */
    1506                 : 
    1507               0 :     result = SPI_cursor_open_internal(name, &plan, paramLI, read_only);
    1508                 : 
    1509                 :     /* And clean up */
    1510               0 :     _SPI_end_call(true);
    1511                 : 
    1512               0 :     return result;
    1513                 : }
    1514                 : 
    1515                 : 
    1516                 : /*
    1517                 :  * SPI_cursor_open_with_paramlist()
    1518                 :  *
    1519                 :  *  Same as SPI_cursor_open except that parameters (if any) are passed
    1520                 :  *  as a ParamListInfo, which supports dynamic parameter set determination
    1521                 :  */
    1522                 : Portal
    1523 CBC        1231 : SPI_cursor_open_with_paramlist(const char *name, SPIPlanPtr plan,
    1524                 :                                ParamListInfo params, bool read_only)
    1525                 : {
    1526            1231 :     return SPI_cursor_open_internal(name, plan, params, read_only);
    1527                 : }
    1528                 : 
    1529                 : /* Parse a query and open it as a cursor */
    1530                 : Portal
    1531            4579 : SPI_cursor_parse_open(const char *name,
    1532                 :                       const char *src,
    1533                 :                       const SPIParseOpenOptions *options)
    1534                 : {
    1535                 :     Portal      result;
    1536                 :     _SPI_plan   plan;
    1537                 : 
    1538            4579 :     if (src == NULL || options == NULL)
    1539 UBC           0 :         elog(ERROR, "SPI_cursor_parse_open called with invalid arguments");
    1540                 : 
    1541 CBC        4579 :     SPI_result = _SPI_begin_call(true);
    1542            4579 :     if (SPI_result < 0)
    1543 UBC           0 :         elog(ERROR, "SPI_cursor_parse_open called while not connected");
    1544                 : 
    1545 CBC        4579 :     memset(&plan, 0, sizeof(_SPI_plan));
    1546            4579 :     plan.magic = _SPI_PLAN_MAGIC;
    1547            4579 :     plan.parse_mode = RAW_PARSE_DEFAULT;
    1548            4579 :     plan.cursor_options = options->cursorOptions;
    1549            4579 :     if (options->params)
    1550                 :     {
    1551               6 :         plan.parserSetup = options->params->parserSetup;
    1552               6 :         plan.parserSetupArg = options->params->parserSetupArg;
    1553                 :     }
    1554                 : 
    1555            4579 :     _SPI_prepare_plan(src, &plan);
    1556                 : 
    1557                 :     /* We needn't copy the plan; SPI_cursor_open_internal will do so */
    1558                 : 
    1559            4579 :     result = SPI_cursor_open_internal(name, &plan,
    1560            4579 :                                       options->params, options->read_only);
    1561                 : 
    1562                 :     /* And clean up */
    1563            4579 :     _SPI_end_call(true);
    1564                 : 
    1565            4579 :     return result;
    1566                 : }
    1567                 : 
    1568                 : 
    1569                 : /*
    1570                 :  * SPI_cursor_open_internal()
    1571                 :  *
    1572                 :  *  Common code for SPI_cursor_open variants
    1573                 :  */
    1574                 : static Portal
    1575            5916 : SPI_cursor_open_internal(const char *name, SPIPlanPtr plan,
    1576                 :                          ParamListInfo paramLI, bool read_only)
    1577                 : {
    1578                 :     CachedPlanSource *plansource;
    1579                 :     CachedPlan *cplan;
    1580                 :     List       *stmt_list;
    1581                 :     char       *query_string;
    1582                 :     Snapshot    snapshot;
    1583                 :     MemoryContext oldcontext;
    1584                 :     Portal      portal;
    1585                 :     SPICallbackArg spicallbackarg;
    1586                 :     ErrorContextCallback spierrcontext;
    1587                 : 
    1588                 :     /*
    1589                 :      * Check that the plan is something the Portal code will special-case as
    1590                 :      * returning one tupleset.
    1591                 :      */
    1592            5916 :     if (!SPI_is_cursor_plan(plan))
    1593                 :     {
    1594                 :         /* try to give a good error message */
    1595                 :         const char *cmdtag;
    1596                 : 
    1597 UBC           0 :         if (list_length(plan->plancache_list) != 1)
    1598               0 :             ereport(ERROR,
    1599                 :                     (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
    1600                 :                      errmsg("cannot open multi-query plan as cursor")));
    1601               0 :         plansource = (CachedPlanSource *) linitial(plan->plancache_list);
    1602                 :         /* A SELECT that fails SPI_is_cursor_plan() must be SELECT INTO */
    1603               0 :         if (plansource->commandTag == CMDTAG_SELECT)
    1604               0 :             cmdtag = "SELECT INTO";
    1605                 :         else
    1606               0 :             cmdtag = GetCommandTagName(plansource->commandTag);
    1607               0 :         ereport(ERROR,
    1608                 :                 (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
    1609                 :         /* translator: %s is name of a SQL command, eg INSERT */
    1610                 :                  errmsg("cannot open %s query as cursor", cmdtag)));
    1611                 :     }
    1612                 : 
    1613 CBC        5916 :     Assert(list_length(plan->plancache_list) == 1);
    1614            5916 :     plansource = (CachedPlanSource *) linitial(plan->plancache_list);
    1615                 : 
    1616                 :     /* Push the SPI stack */
    1617            5916 :     if (_SPI_begin_call(true) < 0)
    1618 UBC           0 :         elog(ERROR, "SPI_cursor_open called while not connected");
    1619                 : 
    1620                 :     /* Reset SPI result (note we deliberately don't touch lastoid) */
    1621 CBC        5916 :     SPI_processed = 0;
    1622            5916 :     SPI_tuptable = NULL;
    1623            5916 :     _SPI_current->processed = 0;
    1624            5916 :     _SPI_current->tuptable = NULL;
    1625                 : 
    1626                 :     /* Create the portal */
    1627            5916 :     if (name == NULL || name[0] == '\0')
    1628                 :     {
    1629                 :         /* Use a random nonconflicting name */
    1630            5892 :         portal = CreateNewPortal();
    1631                 :     }
    1632                 :     else
    1633                 :     {
    1634                 :         /* In this path, error if portal of same name already exists */
    1635              24 :         portal = CreatePortal(name, false, false);
    1636                 :     }
    1637                 : 
    1638                 :     /* Copy the plan's query string into the portal */
    1639            5916 :     query_string = MemoryContextStrdup(portal->portalContext,
    1640                 :                                        plansource->query_string);
    1641                 : 
    1642                 :     /*
    1643                 :      * Setup error traceback support for ereport(), in case GetCachedPlan
    1644                 :      * throws an error.
    1645                 :      */
    1646            5916 :     spicallbackarg.query = plansource->query_string;
    1647            5916 :     spicallbackarg.mode = plan->parse_mode;
    1648            5916 :     spierrcontext.callback = _SPI_error_callback;
    1649            5916 :     spierrcontext.arg = &spicallbackarg;
    1650            5916 :     spierrcontext.previous = error_context_stack;
    1651            5916 :     error_context_stack = &spierrcontext;
    1652                 : 
    1653                 :     /*
    1654                 :      * Note: for a saved plan, we mustn't have any failure occur between
    1655                 :      * GetCachedPlan and PortalDefineQuery; that would result in leaking our
    1656                 :      * plancache refcount.
    1657                 :      */
    1658                 : 
    1659                 :     /* Replan if needed, and increment plan refcount for portal */
    1660            5916 :     cplan = GetCachedPlan(plansource, paramLI, NULL, _SPI_current->queryEnv);
    1661            5916 :     stmt_list = cplan->stmt_list;
    1662                 : 
    1663            5916 :     if (!plan->saved)
    1664                 :     {
    1665                 :         /*
    1666                 :          * We don't want the portal to depend on an unsaved CachedPlanSource,
    1667                 :          * so must copy the plan into the portal's context.  An error here
    1668                 :          * will result in leaking our refcount on the plan, but it doesn't
    1669                 :          * matter because the plan is unsaved and hence transient anyway.
    1670                 :          */
    1671            4680 :         oldcontext = MemoryContextSwitchTo(portal->portalContext);
    1672            4680 :         stmt_list = copyObject(stmt_list);
    1673            4680 :         MemoryContextSwitchTo(oldcontext);
    1674            4680 :         ReleaseCachedPlan(cplan, NULL);
    1675            4680 :         cplan = NULL;           /* portal shouldn't depend on cplan */
    1676                 :     }
    1677                 : 
    1678                 :     /*
    1679                 :      * Set up the portal.
    1680                 :      */
    1681            5916 :     PortalDefineQuery(portal,
    1682                 :                       NULL,     /* no statement name */
    1683                 :                       query_string,
    1684                 :                       plansource->commandTag,
    1685                 :                       stmt_list,
    1686                 :                       cplan);
    1687                 : 
    1688                 :     /*
    1689                 :      * Set up options for portal.  Default SCROLL type is chosen the same way
    1690                 :      * as PerformCursorOpen does it.
    1691                 :      */
    1692            5916 :     portal->cursorOptions = plan->cursor_options;
    1693            5916 :     if (!(portal->cursorOptions & (CURSOR_OPT_SCROLL | CURSOR_OPT_NO_SCROLL)))
    1694                 :     {
    1695             209 :         if (list_length(stmt_list) == 1 &&
    1696             209 :             linitial_node(PlannedStmt, stmt_list)->commandType != CMD_UTILITY &&
    1697             417 :             linitial_node(PlannedStmt, stmt_list)->rowMarks == NIL &&
    1698             208 :             ExecSupportsBackwardScan(linitial_node(PlannedStmt, stmt_list)->planTree))
    1699             194 :             portal->cursorOptions |= CURSOR_OPT_SCROLL;
    1700                 :         else
    1701              15 :             portal->cursorOptions |= CURSOR_OPT_NO_SCROLL;
    1702                 :     }
    1703                 : 
    1704                 :     /*
    1705                 :      * Disallow SCROLL with SELECT FOR UPDATE.  This is not redundant with the
    1706                 :      * check in transformDeclareCursorStmt because the cursor options might
    1707                 :      * not have come through there.
    1708                 :      */
    1709            5916 :     if (portal->cursorOptions & CURSOR_OPT_SCROLL)
    1710                 :     {
    1711             206 :         if (list_length(stmt_list) == 1 &&
    1712             206 :             linitial_node(PlannedStmt, stmt_list)->commandType != CMD_UTILITY &&
    1713             206 :             linitial_node(PlannedStmt, stmt_list)->rowMarks != NIL)
    1714 UBC           0 :             ereport(ERROR,
    1715                 :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1716                 :                      errmsg("DECLARE SCROLL CURSOR ... FOR UPDATE/SHARE is not supported"),
    1717                 :                      errdetail("Scrollable cursors must be READ ONLY.")));
    1718                 :     }
    1719                 : 
    1720                 :     /* Make current query environment available to portal at execution time. */
    1721 CBC        5916 :     portal->queryEnv = _SPI_current->queryEnv;
    1722                 : 
    1723                 :     /*
    1724                 :      * If told to be read-only, we'd better check for read-only queries. This
    1725                 :      * can't be done earlier because we need to look at the finished, planned
    1726                 :      * queries.  (In particular, we don't want to do it between GetCachedPlan
    1727                 :      * and PortalDefineQuery, because throwing an error between those steps
    1728                 :      * would result in leaking our plancache refcount.)
    1729                 :      */
    1730            5916 :     if (read_only)
    1731                 :     {
    1732                 :         ListCell   *lc;
    1733                 : 
    1734             156 :         foreach(lc, stmt_list)
    1735                 :         {
    1736              78 :             PlannedStmt *pstmt = lfirst_node(PlannedStmt, lc);
    1737                 : 
    1738              78 :             if (!CommandIsReadOnly(pstmt))
    1739 UBC           0 :                 ereport(ERROR,
    1740                 :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1741                 :                 /* translator: %s is a SQL statement name */
    1742                 :                          errmsg("%s is not allowed in a non-volatile function",
    1743                 :                                 CreateCommandName((Node *) pstmt))));
    1744                 :         }
    1745                 :     }
    1746                 : 
    1747                 :     /* Set up the snapshot to use. */
    1748 CBC        5916 :     if (read_only)
    1749              78 :         snapshot = GetActiveSnapshot();
    1750                 :     else
    1751                 :     {
    1752            5838 :         CommandCounterIncrement();
    1753            5838 :         snapshot = GetTransactionSnapshot();
    1754                 :     }
    1755                 : 
    1756                 :     /*
    1757                 :      * If the plan has parameters, copy them into the portal.  Note that this
    1758                 :      * must be done after revalidating the plan, because in dynamic parameter
    1759                 :      * cases the set of parameters could have changed during re-parsing.
    1760                 :      */
    1761            5916 :     if (paramLI)
    1762                 :     {
    1763             347 :         oldcontext = MemoryContextSwitchTo(portal->portalContext);
    1764             347 :         paramLI = copyParamList(paramLI);
    1765             347 :         MemoryContextSwitchTo(oldcontext);
    1766                 :     }
    1767                 : 
    1768                 :     /*
    1769                 :      * Start portal execution.
    1770                 :      */
    1771            5916 :     PortalStart(portal, paramLI, 0, snapshot);
    1772                 : 
    1773            5916 :     Assert(portal->strategy != PORTAL_MULTI_QUERY);
    1774                 : 
    1775                 :     /* Pop the error context stack */
    1776            5916 :     error_context_stack = spierrcontext.previous;
    1777                 : 
    1778                 :     /* Pop the SPI stack */
    1779            5916 :     _SPI_end_call(true);
    1780                 : 
    1781                 :     /* Return the created portal */
    1782            5916 :     return portal;
    1783                 : }
    1784                 : 
    1785                 : 
    1786                 : /*
    1787                 :  * SPI_cursor_find()
    1788                 :  *
    1789                 :  *  Find the portal of an existing open cursor
    1790                 :  */
    1791                 : Portal
    1792             280 : SPI_cursor_find(const char *name)
    1793                 : {
    1794             280 :     return GetPortalByName(name);
    1795                 : }
    1796                 : 
    1797                 : 
    1798                 : /*
    1799                 :  * SPI_cursor_fetch()
    1800                 :  *
    1801                 :  *  Fetch rows in a cursor
    1802                 :  */
    1803                 : void
    1804           21526 : SPI_cursor_fetch(Portal portal, bool forward, long count)
    1805                 : {
    1806           21526 :     _SPI_cursor_operation(portal,
    1807           21526 :                           forward ? FETCH_FORWARD : FETCH_BACKWARD, count,
    1808                 :                           CreateDestReceiver(DestSPI));
    1809                 :     /* we know that the DestSPI receiver doesn't need a destroy call */
    1810           21523 : }
    1811                 : 
    1812                 : 
    1813                 : /*
    1814                 :  * SPI_cursor_move()
    1815                 :  *
    1816                 :  *  Move in a cursor
    1817                 :  */
    1818                 : void
    1819 UBC           0 : SPI_cursor_move(Portal portal, bool forward, long count)
    1820                 : {
    1821               0 :     _SPI_cursor_operation(portal,
    1822               0 :                           forward ? FETCH_FORWARD : FETCH_BACKWARD, count,
    1823                 :                           None_Receiver);
    1824               0 : }
    1825                 : 
    1826                 : 
    1827                 : /*
    1828                 :  * SPI_scroll_cursor_fetch()
    1829                 :  *
    1830                 :  *  Fetch rows in a scrollable cursor
    1831                 :  */
    1832                 : void
    1833 CBC         150 : SPI_scroll_cursor_fetch(Portal portal, FetchDirection direction, long count)
    1834                 : {
    1835             150 :     _SPI_cursor_operation(portal,
    1836                 :                           direction, count,
    1837                 :                           CreateDestReceiver(DestSPI));
    1838                 :     /* we know that the DestSPI receiver doesn't need a destroy call */
    1839             147 : }
    1840                 : 
    1841                 : 
    1842                 : /*
    1843                 :  * SPI_scroll_cursor_move()
    1844                 :  *
    1845                 :  *  Move in a scrollable cursor
    1846                 :  */
    1847                 : void
    1848              21 : SPI_scroll_cursor_move(Portal portal, FetchDirection direction, long count)
    1849                 : {
    1850              21 :     _SPI_cursor_operation(portal, direction, count, None_Receiver);
    1851              21 : }
    1852                 : 
    1853                 : 
    1854                 : /*
    1855                 :  * SPI_cursor_close()
    1856                 :  *
    1857                 :  *  Close a cursor
    1858                 :  */
    1859                 : void
    1860            5862 : SPI_cursor_close(Portal portal)
    1861                 : {
    1862            5862 :     if (!PortalIsValid(portal))
    1863 UBC           0 :         elog(ERROR, "invalid portal in SPI cursor operation");
    1864                 : 
    1865 CBC        5862 :     PortalDrop(portal, false);
    1866            5862 : }
    1867                 : 
    1868                 : /*
    1869                 :  * Returns the Oid representing the type id for argument at argIndex. First
    1870                 :  * parameter is at index zero.
    1871                 :  */
    1872                 : Oid
    1873 UBC           0 : SPI_getargtypeid(SPIPlanPtr plan, int argIndex)
    1874                 : {
    1875               0 :     if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC ||
    1876               0 :         argIndex < 0 || argIndex >= plan->nargs)
    1877                 :     {
    1878               0 :         SPI_result = SPI_ERROR_ARGUMENT;
    1879               0 :         return InvalidOid;
    1880                 :     }
    1881               0 :     return plan->argtypes[argIndex];
    1882                 : }
    1883                 : 
    1884                 : /*
    1885                 :  * Returns the number of arguments for the prepared plan.
    1886                 :  */
    1887                 : int
    1888               0 : SPI_getargcount(SPIPlanPtr plan)
    1889                 : {
    1890               0 :     if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC)
    1891                 :     {
    1892               0 :         SPI_result = SPI_ERROR_ARGUMENT;
    1893               0 :         return -1;
    1894                 :     }
    1895               0 :     return plan->nargs;
    1896                 : }
    1897                 : 
    1898                 : /*
    1899                 :  * Returns true if the plan contains exactly one command
    1900                 :  * and that command returns tuples to the caller (eg, SELECT or
    1901                 :  * INSERT ... RETURNING, but not SELECT ... INTO). In essence,
    1902                 :  * the result indicates if the command can be used with SPI_cursor_open
    1903                 :  *
    1904                 :  * Parameters
    1905                 :  *    plan: A plan previously prepared using SPI_prepare
    1906                 :  */
    1907                 : bool
    1908 CBC        5916 : SPI_is_cursor_plan(SPIPlanPtr plan)
    1909                 : {
    1910                 :     CachedPlanSource *plansource;
    1911                 : 
    1912            5916 :     if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC)
    1913                 :     {
    1914 UBC           0 :         SPI_result = SPI_ERROR_ARGUMENT;
    1915               0 :         return false;
    1916                 :     }
    1917                 : 
    1918 CBC        5916 :     if (list_length(plan->plancache_list) != 1)
    1919                 :     {
    1920 UBC           0 :         SPI_result = 0;
    1921               0 :         return false;           /* not exactly 1 pre-rewrite command */
    1922                 :     }
    1923 CBC        5916 :     plansource = (CachedPlanSource *) linitial(plan->plancache_list);
    1924                 : 
    1925                 :     /*
    1926                 :      * We used to force revalidation of the cached plan here, but that seems
    1927                 :      * unnecessary: invalidation could mean a change in the rowtype of the
    1928                 :      * tuples returned by a plan, but not whether it returns tuples at all.
    1929                 :      */
    1930            5916 :     SPI_result = 0;
    1931                 : 
    1932                 :     /* Does it return tuples? */
    1933            5916 :     if (plansource->resultDesc)
    1934            5916 :         return true;
    1935                 : 
    1936 UBC           0 :     return false;
    1937                 : }
    1938                 : 
    1939                 : /*
    1940                 :  * SPI_plan_is_valid --- test whether a SPI plan is currently valid
    1941                 :  * (that is, not marked as being in need of revalidation).
    1942                 :  *
    1943                 :  * See notes for CachedPlanIsValid before using this.
    1944                 :  */
    1945                 : bool
    1946 CBC        1537 : SPI_plan_is_valid(SPIPlanPtr plan)
    1947                 : {
    1948                 :     ListCell   *lc;
    1949                 : 
    1950            1537 :     Assert(plan->magic == _SPI_PLAN_MAGIC);
    1951                 : 
    1952            2935 :     foreach(lc, plan->plancache_list)
    1953                 :     {
    1954            1537 :         CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc);
    1955                 : 
    1956            1537 :         if (!CachedPlanIsValid(plansource))
    1957             139 :             return false;
    1958                 :     }
    1959            1398 :     return true;
    1960                 : }
    1961                 : 
    1962                 : /*
    1963                 :  * SPI_result_code_string --- convert any SPI return code to a string
    1964                 :  *
    1965                 :  * This is often useful in error messages.  Most callers will probably
    1966                 :  * only pass negative (error-case) codes, but for generality we recognize
    1967                 :  * the success codes too.
    1968                 :  */
    1969                 : const char *
    1970              59 : SPI_result_code_string(int code)
    1971                 : {
    1972                 :     static char buf[64];
    1973                 : 
    1974              59 :     switch (code)
    1975                 :     {
    1976 UBC           0 :         case SPI_ERROR_CONNECT:
    1977               0 :             return "SPI_ERROR_CONNECT";
    1978               0 :         case SPI_ERROR_COPY:
    1979               0 :             return "SPI_ERROR_COPY";
    1980               0 :         case SPI_ERROR_OPUNKNOWN:
    1981               0 :             return "SPI_ERROR_OPUNKNOWN";
    1982               0 :         case SPI_ERROR_UNCONNECTED:
    1983               0 :             return "SPI_ERROR_UNCONNECTED";
    1984               0 :         case SPI_ERROR_ARGUMENT:
    1985               0 :             return "SPI_ERROR_ARGUMENT";
    1986               0 :         case SPI_ERROR_PARAM:
    1987               0 :             return "SPI_ERROR_PARAM";
    1988 CBC           3 :         case SPI_ERROR_TRANSACTION:
    1989               3 :             return "SPI_ERROR_TRANSACTION";
    1990 UBC           0 :         case SPI_ERROR_NOATTRIBUTE:
    1991               0 :             return "SPI_ERROR_NOATTRIBUTE";
    1992               0 :         case SPI_ERROR_NOOUTFUNC:
    1993               0 :             return "SPI_ERROR_NOOUTFUNC";
    1994               0 :         case SPI_ERROR_TYPUNKNOWN:
    1995               0 :             return "SPI_ERROR_TYPUNKNOWN";
    1996               0 :         case SPI_ERROR_REL_DUPLICATE:
    1997               0 :             return "SPI_ERROR_REL_DUPLICATE";
    1998               0 :         case SPI_ERROR_REL_NOT_FOUND:
    1999               0 :             return "SPI_ERROR_REL_NOT_FOUND";
    2000               0 :         case SPI_OK_CONNECT:
    2001               0 :             return "SPI_OK_CONNECT";
    2002               0 :         case SPI_OK_FINISH:
    2003               0 :             return "SPI_OK_FINISH";
    2004               0 :         case SPI_OK_FETCH:
    2005               0 :             return "SPI_OK_FETCH";
    2006 CBC           1 :         case SPI_OK_UTILITY:
    2007               1 :             return "SPI_OK_UTILITY";
    2008              10 :         case SPI_OK_SELECT:
    2009              10 :             return "SPI_OK_SELECT";
    2010 UBC           0 :         case SPI_OK_SELINTO:
    2011               0 :             return "SPI_OK_SELINTO";
    2012 CBC          45 :         case SPI_OK_INSERT:
    2013              45 :             return "SPI_OK_INSERT";
    2014 UBC           0 :         case SPI_OK_DELETE:
    2015               0 :             return "SPI_OK_DELETE";
    2016               0 :         case SPI_OK_UPDATE:
    2017               0 :             return "SPI_OK_UPDATE";
    2018               0 :         case SPI_OK_CURSOR:
    2019               0 :             return "SPI_OK_CURSOR";
    2020               0 :         case SPI_OK_INSERT_RETURNING:
    2021               0 :             return "SPI_OK_INSERT_RETURNING";
    2022               0 :         case SPI_OK_DELETE_RETURNING:
    2023               0 :             return "SPI_OK_DELETE_RETURNING";
    2024               0 :         case SPI_OK_UPDATE_RETURNING:
    2025               0 :             return "SPI_OK_UPDATE_RETURNING";
    2026               0 :         case SPI_OK_REWRITTEN:
    2027               0 :             return "SPI_OK_REWRITTEN";
    2028               0 :         case SPI_OK_REL_REGISTER:
    2029               0 :             return "SPI_OK_REL_REGISTER";
    2030               0 :         case SPI_OK_REL_UNREGISTER:
    2031               0 :             return "SPI_OK_REL_UNREGISTER";
    2032               0 :         case SPI_OK_TD_REGISTER:
    2033               0 :             return "SPI_OK_TD_REGISTER";
    2034               0 :         case SPI_OK_MERGE:
    2035               0 :             return "SPI_OK_MERGE";
    2036                 :     }
    2037                 :     /* Unrecognized code ... return something useful ... */
    2038               0 :     sprintf(buf, "Unrecognized SPI code %d", code);
    2039               0 :     return buf;
    2040                 : }
    2041                 : 
    2042                 : /*
    2043                 :  * SPI_plan_get_plan_sources --- get a SPI plan's underlying list of
    2044                 :  * CachedPlanSources.
    2045                 :  *
    2046                 :  * This is exported so that PL/pgSQL can use it (this beats letting PL/pgSQL
    2047                 :  * look directly into the SPIPlan for itself).  It's not documented in
    2048                 :  * spi.sgml because we'd just as soon not have too many places using this.
    2049                 :  */
    2050                 : List *
    2051 CBC       12430 : SPI_plan_get_plan_sources(SPIPlanPtr plan)
    2052                 : {
    2053           12430 :     Assert(plan->magic == _SPI_PLAN_MAGIC);
    2054           12430 :     return plan->plancache_list;
    2055                 : }
    2056                 : 
    2057                 : /*
    2058                 :  * SPI_plan_get_cached_plan --- get a SPI plan's generic CachedPlan,
    2059                 :  * if the SPI plan contains exactly one CachedPlanSource.  If not,
    2060                 :  * return NULL.
    2061                 :  *
    2062                 :  * The plan's refcount is incremented (and logged in CurrentResourceOwner,
    2063                 :  * if it's a saved plan).  Caller is responsible for doing ReleaseCachedPlan.
    2064                 :  *
    2065                 :  * This is exported so that PL/pgSQL can use it (this beats letting PL/pgSQL
    2066                 :  * look directly into the SPIPlan for itself).  It's not documented in
    2067                 :  * spi.sgml because we'd just as soon not have too many places using this.
    2068                 :  */
    2069                 : CachedPlan *
    2070           12272 : SPI_plan_get_cached_plan(SPIPlanPtr plan)
    2071                 : {
    2072                 :     CachedPlanSource *plansource;
    2073                 :     CachedPlan *cplan;
    2074                 :     SPICallbackArg spicallbackarg;
    2075                 :     ErrorContextCallback spierrcontext;
    2076                 : 
    2077           12272 :     Assert(plan->magic == _SPI_PLAN_MAGIC);
    2078                 : 
    2079                 :     /* Can't support one-shot plans here */
    2080           12272 :     if (plan->oneshot)
    2081 UBC           0 :         return NULL;
    2082                 : 
    2083                 :     /* Must have exactly one CachedPlanSource */
    2084 CBC       12272 :     if (list_length(plan->plancache_list) != 1)
    2085 UBC           0 :         return NULL;
    2086 CBC       12272 :     plansource = (CachedPlanSource *) linitial(plan->plancache_list);
    2087                 : 
    2088                 :     /* Setup error traceback support for ereport() */
    2089           12272 :     spicallbackarg.query = plansource->query_string;
    2090           12272 :     spicallbackarg.mode = plan->parse_mode;
    2091           12272 :     spierrcontext.callback = _SPI_error_callback;
    2092           12272 :     spierrcontext.arg = &spicallbackarg;
    2093           12272 :     spierrcontext.previous = error_context_stack;
    2094           12272 :     error_context_stack = &spierrcontext;
    2095                 : 
    2096                 :     /* Get the generic plan for the query */
    2097           12272 :     cplan = GetCachedPlan(plansource, NULL,
    2098           12272 :                           plan->saved ? CurrentResourceOwner : NULL,
    2099           12272 :                           _SPI_current->queryEnv);
    2100           12256 :     Assert(cplan == plansource->gplan);
    2101                 : 
    2102                 :     /* Pop the error context stack */
    2103           12256 :     error_context_stack = spierrcontext.previous;
    2104                 : 
    2105           12256 :     return cplan;
    2106                 : }
    2107                 : 
    2108                 : 
    2109                 : /* =================== private functions =================== */
    2110                 : 
    2111                 : /*
    2112                 :  * spi_dest_startup
    2113                 :  *      Initialize to receive tuples from Executor into SPITupleTable
    2114                 :  *      of current SPI procedure
    2115                 :  */
    2116                 : void
    2117           43326 : spi_dest_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
    2118                 : {
    2119                 :     SPITupleTable *tuptable;
    2120                 :     MemoryContext oldcxt;
    2121                 :     MemoryContext tuptabcxt;
    2122                 : 
    2123           43326 :     if (_SPI_current == NULL)
    2124 UBC           0 :         elog(ERROR, "spi_dest_startup called while not connected to SPI");
    2125                 : 
    2126 CBC       43326 :     if (_SPI_current->tuptable != NULL)
    2127 UBC           0 :         elog(ERROR, "improper call to spi_dest_startup");
    2128                 : 
    2129                 :     /* We create the tuple table context as a child of procCxt */
    2130                 : 
    2131 CBC       43326 :     oldcxt = _SPI_procmem();    /* switch to procedure memory context */
    2132                 : 
    2133           43326 :     tuptabcxt = AllocSetContextCreate(CurrentMemoryContext,
    2134                 :                                       "SPI TupTable",
    2135                 :                                       ALLOCSET_DEFAULT_SIZES);
    2136           43326 :     MemoryContextSwitchTo(tuptabcxt);
    2137                 : 
    2138           43326 :     _SPI_current->tuptable = tuptable = (SPITupleTable *)
    2139           43326 :         palloc0(sizeof(SPITupleTable));
    2140           43326 :     tuptable->tuptabcxt = tuptabcxt;
    2141           43326 :     tuptable->subid = GetCurrentSubTransactionId();
    2142                 : 
    2143                 :     /*
    2144                 :      * The tuptable is now valid enough to be freed by AtEOSubXact_SPI, so put
    2145                 :      * it onto the SPI context's tuptables list.  This will ensure it's not
    2146                 :      * leaked even in the unlikely event the following few lines fail.
    2147                 :      */
    2148           43326 :     slist_push_head(&_SPI_current->tuptables, &tuptable->next);
    2149                 : 
    2150                 :     /* set up initial allocations */
    2151           43326 :     tuptable->alloced = 128;
    2152           43326 :     tuptable->vals = (HeapTuple *) palloc(tuptable->alloced * sizeof(HeapTuple));
    2153           43326 :     tuptable->numvals = 0;
    2154           43326 :     tuptable->tupdesc = CreateTupleDescCopy(typeinfo);
    2155                 : 
    2156           43326 :     MemoryContextSwitchTo(oldcxt);
    2157           43326 : }
    2158                 : 
    2159                 : /*
    2160                 :  * spi_printtup
    2161                 :  *      store tuple retrieved by Executor into SPITupleTable
    2162                 :  *      of current SPI procedure
    2163                 :  */
    2164                 : bool
    2165           52287 : spi_printtup(TupleTableSlot *slot, DestReceiver *self)
    2166                 : {
    2167                 :     SPITupleTable *tuptable;
    2168                 :     MemoryContext oldcxt;
    2169                 : 
    2170           52287 :     if (_SPI_current == NULL)
    2171 UBC           0 :         elog(ERROR, "spi_printtup called while not connected to SPI");
    2172                 : 
    2173 CBC       52287 :     tuptable = _SPI_current->tuptable;
    2174           52287 :     if (tuptable == NULL)
    2175 UBC           0 :         elog(ERROR, "improper call to spi_printtup");
    2176                 : 
    2177 CBC       52287 :     oldcxt = MemoryContextSwitchTo(tuptable->tuptabcxt);
    2178                 : 
    2179           52287 :     if (tuptable->numvals >= tuptable->alloced)
    2180                 :     {
    2181                 :         /* Double the size of the pointer array */
    2182 UBC           0 :         uint64      newalloced = tuptable->alloced * 2;
    2183                 : 
    2184               0 :         tuptable->vals = (HeapTuple *) repalloc_huge(tuptable->vals,
    2185                 :                                                      newalloced * sizeof(HeapTuple));
    2186               0 :         tuptable->alloced = newalloced;
    2187                 :     }
    2188                 : 
    2189 CBC       52287 :     tuptable->vals[tuptable->numvals] = ExecCopySlotHeapTuple(slot);
    2190           52287 :     (tuptable->numvals)++;
    2191                 : 
    2192           52287 :     MemoryContextSwitchTo(oldcxt);
    2193                 : 
    2194           52287 :     return true;
    2195                 : }
    2196                 : 
    2197                 : /*
    2198                 :  * Static functions
    2199                 :  */
    2200                 : 
    2201                 : /*
    2202                 :  * Parse and analyze a querystring.
    2203                 :  *
    2204                 :  * At entry, plan->argtypes and plan->nargs (or alternatively plan->parserSetup
    2205                 :  * and plan->parserSetupArg) must be valid, as must plan->parse_mode and
    2206                 :  * plan->cursor_options.
    2207                 :  *
    2208                 :  * Results are stored into *plan (specifically, plan->plancache_list).
    2209                 :  * Note that the result data is all in CurrentMemoryContext or child contexts
    2210                 :  * thereof; in practice this means it is in the SPI executor context, and
    2211                 :  * what we are creating is a "temporary" SPIPlan.  Cruft generated during
    2212                 :  * parsing is also left in CurrentMemoryContext.
    2213                 :  */
    2214                 : static void
    2215           18549 : _SPI_prepare_plan(const char *src, SPIPlanPtr plan)
    2216                 : {
    2217                 :     List       *raw_parsetree_list;
    2218                 :     List       *plancache_list;
    2219                 :     ListCell   *list_item;
    2220                 :     SPICallbackArg spicallbackarg;
    2221                 :     ErrorContextCallback spierrcontext;
    2222                 : 
    2223                 :     /*
    2224                 :      * Setup error traceback support for ereport()
    2225                 :      */
    2226           18549 :     spicallbackarg.query = src;
    2227           18549 :     spicallbackarg.mode = plan->parse_mode;
    2228           18549 :     spierrcontext.callback = _SPI_error_callback;
    2229           18549 :     spierrcontext.arg = &spicallbackarg;
    2230           18549 :     spierrcontext.previous = error_context_stack;
    2231           18549 :     error_context_stack = &spierrcontext;
    2232                 : 
    2233                 :     /*
    2234                 :      * Parse the request string into a list of raw parse trees.
    2235                 :      */
    2236           18549 :     raw_parsetree_list = raw_parser(src, plan->parse_mode);
    2237                 : 
    2238                 :     /*
    2239                 :      * Do parse analysis and rule rewrite for each raw parsetree, storing the
    2240                 :      * results into unsaved plancache entries.
    2241                 :      */
    2242           18549 :     plancache_list = NIL;
    2243                 : 
    2244           37054 :     foreach(list_item, raw_parsetree_list)
    2245                 :     {
    2246           18549 :         RawStmt    *parsetree = lfirst_node(RawStmt, list_item);
    2247                 :         List       *stmt_list;
    2248                 :         CachedPlanSource *plansource;
    2249                 : 
    2250                 :         /*
    2251                 :          * Create the CachedPlanSource before we do parse analysis, since it
    2252                 :          * needs to see the unmodified raw parse tree.
    2253                 :          */
    2254           18549 :         plansource = CreateCachedPlan(parsetree,
    2255                 :                                       src,
    2256                 :                                       CreateCommandTag(parsetree->stmt));
    2257                 : 
    2258                 :         /*
    2259                 :          * Parameter datatypes are driven by parserSetup hook if provided,
    2260                 :          * otherwise we use the fixed parameter list.
    2261                 :          */
    2262           18549 :         if (plan->parserSetup != NULL)
    2263                 :         {
    2264           11596 :             Assert(plan->nargs == 0);
    2265           11596 :             stmt_list = pg_analyze_and_rewrite_withcb(parsetree,
    2266                 :                                                       src,
    2267                 :                                                       plan->parserSetup,
    2268                 :                                                       plan->parserSetupArg,
    2269           11596 :                                                       _SPI_current->queryEnv);
    2270                 :         }
    2271                 :         else
    2272                 :         {
    2273            6953 :             stmt_list = pg_analyze_and_rewrite_fixedparams(parsetree,
    2274                 :                                                            src,
    2275            6953 :                                                            plan->argtypes,
    2276                 :                                                            plan->nargs,
    2277            6953 :                                                            _SPI_current->queryEnv);
    2278                 :         }
    2279                 : 
    2280                 :         /* Finish filling in the CachedPlanSource */
    2281           18505 :         CompleteCachedPlan(plansource,
    2282                 :                            stmt_list,
    2283                 :                            NULL,
    2284                 :                            plan->argtypes,
    2285                 :                            plan->nargs,
    2286                 :                            plan->parserSetup,
    2287                 :                            plan->parserSetupArg,
    2288                 :                            plan->cursor_options,
    2289                 :                            false);  /* not fixed result */
    2290                 : 
    2291           18505 :         plancache_list = lappend(plancache_list, plansource);
    2292                 :     }
    2293                 : 
    2294           18505 :     plan->plancache_list = plancache_list;
    2295           18505 :     plan->oneshot = false;
    2296                 : 
    2297                 :     /*
    2298                 :      * Pop the error context stack
    2299                 :      */
    2300           18505 :     error_context_stack = spierrcontext.previous;
    2301           18505 : }
    2302                 : 
    2303                 : /*
    2304                 :  * Parse, but don't analyze, a querystring.
    2305                 :  *
    2306                 :  * This is a stripped-down version of _SPI_prepare_plan that only does the
    2307                 :  * initial raw parsing.  It creates "one shot" CachedPlanSources
    2308                 :  * that still require parse analysis before execution is possible.
    2309                 :  *
    2310                 :  * The advantage of using the "one shot" form of CachedPlanSource is that
    2311                 :  * we eliminate data copying and invalidation overhead.  Postponing parse
    2312                 :  * analysis also prevents issues if some of the raw parsetrees are DDL
    2313                 :  * commands that affect validity of later parsetrees.  Both of these
    2314                 :  * attributes are good things for SPI_execute() and similar cases.
    2315                 :  *
    2316                 :  * Results are stored into *plan (specifically, plan->plancache_list).
    2317                 :  * Note that the result data is all in CurrentMemoryContext or child contexts
    2318                 :  * thereof; in practice this means it is in the SPI executor context, and
    2319                 :  * what we are creating is a "temporary" SPIPlan.  Cruft generated during
    2320                 :  * parsing is also left in CurrentMemoryContext.
    2321                 :  */
    2322                 : static void
    2323            6013 : _SPI_prepare_oneshot_plan(const char *src, SPIPlanPtr plan)
    2324                 : {
    2325                 :     List       *raw_parsetree_list;
    2326                 :     List       *plancache_list;
    2327                 :     ListCell   *list_item;
    2328                 :     SPICallbackArg spicallbackarg;
    2329                 :     ErrorContextCallback spierrcontext;
    2330                 : 
    2331                 :     /*
    2332                 :      * Setup error traceback support for ereport()
    2333                 :      */
    2334            6013 :     spicallbackarg.query = src;
    2335            6013 :     spicallbackarg.mode = plan->parse_mode;
    2336            6013 :     spierrcontext.callback = _SPI_error_callback;
    2337            6013 :     spierrcontext.arg = &spicallbackarg;
    2338            6013 :     spierrcontext.previous = error_context_stack;
    2339            6013 :     error_context_stack = &spierrcontext;
    2340                 : 
    2341                 :     /*
    2342                 :      * Parse the request string into a list of raw parse trees.
    2343                 :      */
    2344            6013 :     raw_parsetree_list = raw_parser(src, plan->parse_mode);
    2345                 : 
    2346                 :     /*
    2347                 :      * Construct plancache entries, but don't do parse analysis yet.
    2348                 :      */
    2349            6005 :     plancache_list = NIL;
    2350                 : 
    2351           12011 :     foreach(list_item, raw_parsetree_list)
    2352                 :     {
    2353            6006 :         RawStmt    *parsetree = lfirst_node(RawStmt, list_item);
    2354                 :         CachedPlanSource *plansource;
    2355                 : 
    2356            6006 :         plansource = CreateOneShotCachedPlan(parsetree,
    2357                 :                                              src,
    2358                 :                                              CreateCommandTag(parsetree->stmt));
    2359                 : 
    2360            6006 :         plancache_list = lappend(plancache_list, plansource);
    2361                 :     }
    2362                 : 
    2363            6005 :     plan->plancache_list = plancache_list;
    2364            6005 :     plan->oneshot = true;
    2365                 : 
    2366                 :     /*
    2367                 :      * Pop the error context stack
    2368                 :      */
    2369            6005 :     error_context_stack = spierrcontext.previous;
    2370            6005 : }
    2371                 : 
    2372                 : /*
    2373                 :  * _SPI_execute_plan: execute the given plan with the given options
    2374                 :  *
    2375                 :  * options contains options accessible from outside SPI:
    2376                 :  * params: parameter values to pass to query
    2377                 :  * read_only: true for read-only execution (no CommandCounterIncrement)
    2378                 :  * allow_nonatomic: true to allow nonatomic CALL/DO execution
    2379                 :  * must_return_tuples: throw error if query doesn't return tuples
    2380                 :  * tcount: execution tuple-count limit, or 0 for none
    2381                 :  * dest: DestReceiver to receive output, or NULL for normal SPI output
    2382                 :  * owner: ResourceOwner that will be used to hold refcount on plan;
    2383                 :  *      if NULL, CurrentResourceOwner is used (ignored for non-saved plan)
    2384                 :  *
    2385                 :  * Additional, only-internally-accessible options:
    2386                 :  * snapshot: query snapshot to use, or InvalidSnapshot for the normal
    2387                 :  *      behavior of taking a new snapshot for each query.
    2388                 :  * crosscheck_snapshot: for RI use, all others pass InvalidSnapshot
    2389                 :  * fire_triggers: true to fire AFTER triggers at end of query (normal case);
    2390                 :  *      false means any AFTER triggers are postponed to end of outer query
    2391                 :  */
    2392                 : static int
    2393           41664 : _SPI_execute_plan(SPIPlanPtr plan, const SPIExecuteOptions *options,
    2394                 :                   Snapshot snapshot, Snapshot crosscheck_snapshot,
    2395                 :                   bool fire_triggers)
    2396                 : {
    2397           41664 :     int         my_res = 0;
    2398           41664 :     uint64      my_processed = 0;
    2399           41664 :     SPITupleTable *my_tuptable = NULL;
    2400           41664 :     int         res = 0;
    2401           41664 :     bool        pushed_active_snap = false;
    2402           41664 :     ResourceOwner plan_owner = options->owner;
    2403                 :     SPICallbackArg spicallbackarg;
    2404                 :     ErrorContextCallback spierrcontext;
    2405           41664 :     CachedPlan *cplan = NULL;
    2406                 :     ListCell   *lc1;
    2407                 : 
    2408                 :     /*
    2409                 :      * Setup error traceback support for ereport()
    2410                 :      */
    2411           41664 :     spicallbackarg.query = NULL;    /* we'll fill this below */
    2412           41664 :     spicallbackarg.mode = plan->parse_mode;
    2413           41664 :     spierrcontext.callback = _SPI_error_callback;
    2414           41664 :     spierrcontext.arg = &spicallbackarg;
    2415           41664 :     spierrcontext.previous = error_context_stack;
    2416           41664 :     error_context_stack = &spierrcontext;
    2417                 : 
    2418                 :     /*
    2419                 :      * We support four distinct snapshot management behaviors:
    2420                 :      *
    2421                 :      * snapshot != InvalidSnapshot, read_only = true: use exactly the given
    2422                 :      * snapshot.
    2423                 :      *
    2424                 :      * snapshot != InvalidSnapshot, read_only = false: use the given snapshot,
    2425                 :      * modified by advancing its command ID before each querytree.
    2426                 :      *
    2427                 :      * snapshot == InvalidSnapshot, read_only = true: use the entry-time
    2428                 :      * ActiveSnapshot, if any (if there isn't one, we run with no snapshot).
    2429                 :      *
    2430                 :      * snapshot == InvalidSnapshot, read_only = false: take a full new
    2431                 :      * snapshot for each user command, and advance its command ID before each
    2432                 :      * querytree within the command.
    2433                 :      *
    2434                 :      * In the first two cases, we can just push the snap onto the stack once
    2435                 :      * for the whole plan list.
    2436                 :      *
    2437                 :      * Note that snapshot != InvalidSnapshot implies an atomic execution
    2438                 :      * context.
    2439                 :      */
    2440           41664 :     if (snapshot != InvalidSnapshot)
    2441                 :     {
    2442             516 :         Assert(!options->allow_nonatomic);
    2443             516 :         if (options->read_only)
    2444                 :         {
    2445             503 :             PushActiveSnapshot(snapshot);
    2446             503 :             pushed_active_snap = true;
    2447                 :         }
    2448                 :         else
    2449                 :         {
    2450                 :             /* Make sure we have a private copy of the snapshot to modify */
    2451              13 :             PushCopiedSnapshot(snapshot);
    2452              13 :             pushed_active_snap = true;
    2453                 :         }
    2454                 :     }
    2455                 : 
    2456                 :     /*
    2457                 :      * Ensure that we have a resource owner if plan is saved, and not if it
    2458                 :      * isn't.
    2459                 :      */
    2460           41664 :     if (!plan->saved)
    2461            6582 :         plan_owner = NULL;
    2462           35082 :     else if (plan_owner == NULL)
    2463           35036 :         plan_owner = CurrentResourceOwner;
    2464                 : 
    2465                 :     /*
    2466                 :      * We interpret must_return_tuples as "there must be at least one query,
    2467                 :      * and all of them must return tuples".  This is a bit laxer than
    2468                 :      * SPI_is_cursor_plan's check, but there seems no reason to enforce that
    2469                 :      * there be only one query.
    2470                 :      */
    2471           41664 :     if (options->must_return_tuples && plan->plancache_list == NIL)
    2472 UBC           0 :         ereport(ERROR,
    2473                 :                 (errcode(ERRCODE_SYNTAX_ERROR),
    2474                 :                  errmsg("empty query does not return tuples")));
    2475                 : 
    2476 CBC       80553 :     foreach(lc1, plan->plancache_list)
    2477                 :     {
    2478           41664 :         CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc1);
    2479                 :         List       *stmt_list;
    2480                 :         ListCell   *lc2;
    2481                 : 
    2482           41664 :         spicallbackarg.query = plansource->query_string;
    2483                 : 
    2484                 :         /*
    2485                 :          * If this is a one-shot plan, we still need to do parse analysis.
    2486                 :          */
    2487           41664 :         if (plan->oneshot)
    2488                 :         {
    2489            6005 :             RawStmt    *parsetree = plansource->raw_parse_tree;
    2490            6005 :             const char *src = plansource->query_string;
    2491                 :             List       *querytree_list;
    2492                 : 
    2493                 :             /*
    2494                 :              * Parameter datatypes are driven by parserSetup hook if provided,
    2495                 :              * otherwise we use the fixed parameter list.
    2496                 :              */
    2497            6005 :             if (parsetree == NULL)
    2498 UNC           0 :                 querytree_list = NIL;
    2499 CBC        6005 :             else if (plan->parserSetup != NULL)
    2500                 :             {
    2501             285 :                 Assert(plan->nargs == 0);
    2502 GNC         285 :                 querytree_list = pg_analyze_and_rewrite_withcb(parsetree,
    2503                 :                                                                src,
    2504                 :                                                                plan->parserSetup,
    2505                 :                                                                plan->parserSetupArg,
    2506             285 :                                                                _SPI_current->queryEnv);
    2507                 :             }
    2508                 :             else
    2509                 :             {
    2510            5720 :                 querytree_list = pg_analyze_and_rewrite_fixedparams(parsetree,
    2511                 :                                                                     src,
    2512            5720 :                                                                     plan->argtypes,
    2513                 :                                                                     plan->nargs,
    2514            5720 :                                                                     _SPI_current->queryEnv);
    2515                 :             }
    2516                 : 
    2517                 :             /* Finish filling in the CachedPlanSource */
    2518 CBC        5998 :             CompleteCachedPlan(plansource,
    2519                 :                                querytree_list,
    2520                 :                                NULL,
    2521                 :                                plan->argtypes,
    2522                 :                                plan->nargs,
    2523                 :                                plan->parserSetup,
    2524                 :                                plan->parserSetupArg,
    2525                 :                                plan->cursor_options,
    2526                 :                                false);  /* not fixed result */
    2527                 :         }
    2528                 : 
    2529                 :         /*
    2530                 :          * If asked to, complain when query does not return tuples.
    2531                 :          * (Replanning can't change this, so we can check it before that.
    2532                 :          * However, we can't check it till after parse analysis, so in the
    2533                 :          * case of a one-shot plan this is the earliest we could check.)
    2534                 :          */
    2535           41657 :         if (options->must_return_tuples && !plansource->resultDesc)
    2536                 :         {
    2537                 :             /* try to give a good error message */
    2538                 :             const char *cmdtag;
    2539                 : 
    2540                 :             /* A SELECT without resultDesc must be SELECT INTO */
    2541               6 :             if (plansource->commandTag == CMDTAG_SELECT)
    2542               6 :                 cmdtag = "SELECT INTO";
    2543                 :             else
    2544 UBC           0 :                 cmdtag = GetCommandTagName(plansource->commandTag);
    2545 CBC           6 :             ereport(ERROR,
    2546                 :                     (errcode(ERRCODE_SYNTAX_ERROR),
    2547                 :             /* translator: %s is name of a SQL command, eg INSERT */
    2548                 :                      errmsg("%s query does not return tuples", cmdtag)));
    2549                 :         }
    2550                 : 
    2551                 :         /*
    2552                 :          * Replan if needed, and increment plan refcount.  If it's a saved
    2553                 :          * plan, the refcount must be backed by the plan_owner.
    2554                 :          */
    2555           41651 :         cplan = GetCachedPlan(plansource, options->params,
    2556           41651 :                               plan_owner, _SPI_current->queryEnv);
    2557                 : 
    2558           41616 :         stmt_list = cplan->stmt_list;
    2559                 : 
    2560                 :         /*
    2561                 :          * If we weren't given a specific snapshot to use, and the statement
    2562                 :          * list requires a snapshot, set that up.
    2563                 :          */
    2564           82716 :         if (snapshot == InvalidSnapshot &&
    2565           82200 :             (list_length(stmt_list) > 1 ||
    2566           82200 :              (list_length(stmt_list) == 1 &&
    2567           41100 :               PlannedStmtRequiresSnapshot(linitial_node(PlannedStmt,
    2568                 :                                                         stmt_list)))))
    2569                 :         {
    2570                 :             /*
    2571                 :              * First, ensure there's a Portal-level snapshot.  This back-fills
    2572                 :              * the snapshot stack in case the previous operation was a COMMIT
    2573                 :              * or ROLLBACK inside a procedure or DO block.  (We can't put back
    2574                 :              * the Portal snapshot any sooner, or we'd break cases like doing
    2575                 :              * SET or LOCK just after COMMIT.)  It's enough to check once per
    2576                 :              * statement list, since COMMIT/ROLLBACK/CALL/DO can't appear
    2577                 :              * within a multi-statement list.
    2578                 :              */
    2579           35765 :             EnsurePortalSnapshotExists();
    2580                 : 
    2581                 :             /*
    2582                 :              * In the default non-read-only case, get a new per-statement-list
    2583                 :              * snapshot, replacing any that we pushed in a previous cycle.
    2584                 :              * Skip it when doing non-atomic execution, though (we rely
    2585                 :              * entirely on the Portal snapshot in that case).
    2586                 :              */
    2587           35765 :             if (!options->read_only && !options->allow_nonatomic)
    2588                 :             {
    2589           33669 :                 if (pushed_active_snap)
    2590 UBC           0 :                     PopActiveSnapshot();
    2591 CBC       33669 :                 PushActiveSnapshot(GetTransactionSnapshot());
    2592           33669 :                 pushed_active_snap = true;
    2593                 :             }
    2594                 :         }
    2595                 : 
    2596           80505 :         foreach(lc2, stmt_list)
    2597                 :         {
    2598           41616 :             PlannedStmt *stmt = lfirst_node(PlannedStmt, lc2);
    2599           41616 :             bool        canSetTag = stmt->canSetTag;
    2600                 :             DestReceiver *dest;
    2601                 : 
    2602                 :             /*
    2603                 :              * Reset output state.  (Note that if a non-SPI receiver is used,
    2604                 :              * _SPI_current->processed will stay zero, and that's what we'll
    2605                 :              * report to the caller.  It's the receiver's job to count tuples
    2606                 :              * in that case.)
    2607                 :              */
    2608           41616 :             _SPI_current->processed = 0;
    2609           41616 :             _SPI_current->tuptable = NULL;
    2610                 : 
    2611                 :             /* Check for unsupported cases. */
    2612           41616 :             if (stmt->utilityStmt)
    2613                 :             {
    2614            5938 :                 if (IsA(stmt->utilityStmt, CopyStmt))
    2615                 :                 {
    2616               9 :                     CopyStmt   *cstmt = (CopyStmt *) stmt->utilityStmt;
    2617                 : 
    2618               9 :                     if (cstmt->filename == NULL)
    2619                 :                     {
    2620               4 :                         my_res = SPI_ERROR_COPY;
    2621               9 :                         goto fail;
    2622                 :                     }
    2623                 :                 }
    2624            5929 :                 else if (IsA(stmt->utilityStmt, TransactionStmt))
    2625                 :                 {
    2626               5 :                     my_res = SPI_ERROR_TRANSACTION;
    2627               5 :                     goto fail;
    2628                 :                 }
    2629                 :             }
    2630                 : 
    2631           41607 :             if (options->read_only && !CommandIsReadOnly(stmt))
    2632 UBC           0 :                 ereport(ERROR,
    2633                 :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    2634                 :                 /* translator: %s is a SQL statement name */
    2635                 :                          errmsg("%s is not allowed in a non-volatile function",
    2636                 :                                 CreateCommandName((Node *) stmt))));
    2637                 : 
    2638                 :             /*
    2639                 :              * If not read-only mode, advance the command counter before each
    2640                 :              * command and update the snapshot.  (But skip it if the snapshot
    2641                 :              * isn't under our control.)
    2642                 :              */
    2643 CBC       41607 :             if (!options->read_only && pushed_active_snap)
    2644                 :             {
    2645           33678 :                 CommandCounterIncrement();
    2646           33678 :                 UpdateActiveSnapshotCommandId();
    2647                 :             }
    2648                 : 
    2649                 :             /*
    2650                 :              * Select appropriate tuple receiver.  Output from non-canSetTag
    2651                 :              * subqueries always goes to the bit bucket.
    2652                 :              */
    2653           41607 :             if (!canSetTag)
    2654 UBC           0 :                 dest = CreateDestReceiver(DestNone);
    2655 CBC       41607 :             else if (options->dest)
    2656            1327 :                 dest = options->dest;
    2657                 :             else
    2658           40280 :                 dest = CreateDestReceiver(DestSPI);
    2659                 : 
    2660           41607 :             if (stmt->utilityStmt == NULL)
    2661                 :             {
    2662                 :                 QueryDesc  *qdesc;
    2663                 :                 Snapshot    snap;
    2664                 : 
    2665           35678 :                 if (ActiveSnapshotSet())
    2666           35678 :                     snap = GetActiveSnapshot();
    2667                 :                 else
    2668 UBC           0 :                     snap = InvalidSnapshot;
    2669                 : 
    2670 CBC       35678 :                 qdesc = CreateQueryDesc(stmt,
    2671                 :                                         plansource->query_string,
    2672                 :                                         snap, crosscheck_snapshot,
    2673                 :                                         dest,
    2674           35678 :                                         options->params,
    2675           35678 :                                         _SPI_current->queryEnv,
    2676                 :                                         0);
    2677           35678 :                 res = _SPI_pquery(qdesc, fire_triggers,
    2678                 :                                   canSetTag ? options->tcount : 0);
    2679           33019 :                 FreeQueryDesc(qdesc);
    2680                 :             }
    2681                 :             else
    2682                 :             {
    2683                 :                 ProcessUtilityContext context;
    2684                 :                 QueryCompletion qc;
    2685                 : 
    2686                 :                 /*
    2687                 :                  * If the SPI context is atomic, or we were not told to allow
    2688                 :                  * nonatomic operations, tell ProcessUtility this is an atomic
    2689                 :                  * execution context.
    2690                 :                  */
    2691            5929 :                 if (_SPI_current->atomic || !options->allow_nonatomic)
    2692            5883 :                     context = PROCESS_UTILITY_QUERY;
    2693                 :                 else
    2694              46 :                     context = PROCESS_UTILITY_QUERY_NONATOMIC;
    2695                 : 
    2696            5929 :                 InitializeQueryCompletion(&qc);
    2697            5929 :                 ProcessUtility(stmt,
    2698                 :                                plansource->query_string,
    2699                 :                                true,    /* protect plancache's node tree */
    2700                 :                                context,
    2701            5929 :                                options->params,
    2702            5929 :                                _SPI_current->queryEnv,
    2703                 :                                dest,
    2704                 :                                &qc);
    2705                 : 
    2706                 :                 /* Update "processed" if stmt returned tuples */
    2707            5870 :                 if (_SPI_current->tuptable)
    2708              75 :                     _SPI_current->processed = _SPI_current->tuptable->numvals;
    2709                 : 
    2710            5870 :                 res = SPI_OK_UTILITY;
    2711                 : 
    2712                 :                 /*
    2713                 :                  * Some utility statements return a row count, even though the
    2714                 :                  * tuples are not returned to the caller.
    2715                 :                  */
    2716            5870 :                 if (IsA(stmt->utilityStmt, CreateTableAsStmt))
    2717                 :                 {
    2718              55 :                     CreateTableAsStmt *ctastmt = (CreateTableAsStmt *) stmt->utilityStmt;
    2719                 : 
    2720              55 :                     if (qc.commandTag == CMDTAG_SELECT)
    2721              52 :                         _SPI_current->processed = qc.nprocessed;
    2722                 :                     else
    2723                 :                     {
    2724                 :                         /*
    2725                 :                          * Must be an IF NOT EXISTS that did nothing, or a
    2726                 :                          * CREATE ... WITH NO DATA.
    2727                 :                          */
    2728               3 :                         Assert(ctastmt->if_not_exists ||
    2729                 :                                ctastmt->into->skipData);
    2730               3 :                         _SPI_current->processed = 0;
    2731                 :                     }
    2732                 : 
    2733                 :                     /*
    2734                 :                      * For historical reasons, if CREATE TABLE AS was spelled
    2735                 :                      * as SELECT INTO, return a special return code.
    2736                 :                      */
    2737              55 :                     if (ctastmt->is_select_into)
    2738 UBC           0 :                         res = SPI_OK_SELINTO;
    2739                 :                 }
    2740 CBC        5815 :                 else if (IsA(stmt->utilityStmt, CopyStmt))
    2741                 :                 {
    2742               5 :                     Assert(qc.commandTag == CMDTAG_COPY);
    2743               5 :                     _SPI_current->processed = qc.nprocessed;
    2744                 :                 }
    2745                 :             }
    2746                 : 
    2747                 :             /*
    2748                 :              * The last canSetTag query sets the status values returned to the
    2749                 :              * caller.  Be careful to free any tuptables not returned, to
    2750                 :              * avoid intra-transaction memory leak.
    2751                 :              */
    2752           38889 :             if (canSetTag)
    2753                 :             {
    2754           38889 :                 my_processed = _SPI_current->processed;
    2755           38889 :                 SPI_freetuptable(my_tuptable);
    2756           38889 :                 my_tuptable = _SPI_current->tuptable;
    2757           38889 :                 my_res = res;
    2758                 :             }
    2759                 :             else
    2760                 :             {
    2761 UBC           0 :                 SPI_freetuptable(_SPI_current->tuptable);
    2762               0 :                 _SPI_current->tuptable = NULL;
    2763                 :             }
    2764                 : 
    2765                 :             /*
    2766                 :              * We don't issue a destroy call to the receiver.  The SPI and
    2767                 :              * None receivers would ignore it anyway, while if the caller
    2768                 :              * supplied a receiver, it's not our job to destroy it.
    2769                 :              */
    2770                 : 
    2771 CBC       38889 :             if (res < 0)
    2772                 :             {
    2773 UBC           0 :                 my_res = res;
    2774               0 :                 goto fail;
    2775                 :             }
    2776                 :         }
    2777                 : 
    2778                 :         /* Done with this plan, so release refcount */
    2779 CBC       38889 :         ReleaseCachedPlan(cplan, plan_owner);
    2780           38889 :         cplan = NULL;
    2781                 : 
    2782                 :         /*
    2783                 :          * If not read-only mode, advance the command counter after the last
    2784                 :          * command.  This ensures that its effects are visible, in case it was
    2785                 :          * DDL that would affect the next CachedPlanSource.
    2786                 :          */
    2787           38889 :         if (!options->read_only)
    2788           36365 :             CommandCounterIncrement();
    2789                 :     }
    2790                 : 
    2791           38898 : fail:
    2792                 : 
    2793                 :     /* Pop the snapshot off the stack if we pushed one */
    2794           38898 :     if (pushed_active_snap)
    2795           31497 :         PopActiveSnapshot();
    2796                 : 
    2797                 :     /* We no longer need the cached plan refcount, if any */
    2798           38898 :     if (cplan)
    2799               9 :         ReleaseCachedPlan(cplan, plan_owner);
    2800                 : 
    2801                 :     /*
    2802                 :      * Pop the error context stack
    2803                 :      */
    2804           38898 :     error_context_stack = spierrcontext.previous;
    2805                 : 
    2806                 :     /* Save results for caller */
    2807           38898 :     SPI_processed = my_processed;
    2808           38898 :     SPI_tuptable = my_tuptable;
    2809                 : 
    2810                 :     /* tuptable now is caller's responsibility, not SPI's */
    2811           38898 :     _SPI_current->tuptable = NULL;
    2812                 : 
    2813                 :     /*
    2814                 :      * If none of the queries had canSetTag, return SPI_OK_REWRITTEN. Prior to
    2815                 :      * 8.4, we used return the last query's result code, but not its auxiliary
    2816                 :      * results, but that's confusing.
    2817                 :      */
    2818           38898 :     if (my_res == 0)
    2819 UBC           0 :         my_res = SPI_OK_REWRITTEN;
    2820                 : 
    2821 CBC       38898 :     return my_res;
    2822                 : }
    2823                 : 
    2824                 : /*
    2825                 :  * Convert arrays of query parameters to form wanted by planner and executor
    2826                 :  */
    2827                 : static ParamListInfo
    2828            5440 : _SPI_convert_params(int nargs, Oid *argtypes,
    2829                 :                     Datum *Values, const char *Nulls)
    2830                 : {
    2831                 :     ParamListInfo paramLI;
    2832                 : 
    2833            5440 :     if (nargs > 0)
    2834                 :     {
    2835            4748 :         paramLI = makeParamList(nargs);
    2836                 : 
    2837           11941 :         for (int i = 0; i < nargs; i++)
    2838                 :         {
    2839            7193 :             ParamExternData *prm = &paramLI->params[i];
    2840                 : 
    2841            7193 :             prm->value = Values[i];
    2842            7193 :             prm->isnull = (Nulls && Nulls[i] == 'n');
    2843            7193 :             prm->pflags = PARAM_FLAG_CONST;
    2844            7193 :             prm->ptype = argtypes[i];
    2845                 :         }
    2846                 :     }
    2847                 :     else
    2848             692 :         paramLI = NULL;
    2849            5440 :     return paramLI;
    2850                 : }
    2851                 : 
    2852                 : static int
    2853           35678 : _SPI_pquery(QueryDesc *queryDesc, bool fire_triggers, uint64 tcount)
    2854                 : {
    2855           35678 :     int         operation = queryDesc->operation;
    2856                 :     int         eflags;
    2857                 :     int         res;
    2858                 : 
    2859           35678 :     switch (operation)
    2860                 :     {
    2861           22401 :         case CMD_SELECT:
    2862           22401 :             if (queryDesc->dest->mydest == DestNone)
    2863                 :             {
    2864                 :                 /* Don't return SPI_OK_SELECT if we're discarding result */
    2865 UBC           0 :                 res = SPI_OK_UTILITY;
    2866                 :             }
    2867                 :             else
    2868 CBC       22401 :                 res = SPI_OK_SELECT;
    2869           22401 :             break;
    2870            8279 :         case CMD_INSERT:
    2871            8279 :             if (queryDesc->plannedstmt->hasReturning)
    2872             475 :                 res = SPI_OK_INSERT_RETURNING;
    2873                 :             else
    2874            7804 :                 res = SPI_OK_INSERT;
    2875            8279 :             break;
    2876            4233 :         case CMD_DELETE:
    2877            4233 :             if (queryDesc->plannedstmt->hasReturning)
    2878 UBC           0 :                 res = SPI_OK_DELETE_RETURNING;
    2879                 :             else
    2880 CBC        4233 :                 res = SPI_OK_DELETE;
    2881            4233 :             break;
    2882             753 :         case CMD_UPDATE:
    2883             753 :             if (queryDesc->plannedstmt->hasReturning)
    2884               2 :                 res = SPI_OK_UPDATE_RETURNING;
    2885                 :             else
    2886             751 :                 res = SPI_OK_UPDATE;
    2887             753 :             break;
    2888              12 :         case CMD_MERGE:
    2889              12 :             res = SPI_OK_MERGE;
    2890              12 :             break;
    2891 UBC           0 :         default:
    2892               0 :             return SPI_ERROR_OPUNKNOWN;
    2893                 :     }
    2894                 : 
    2895                 : #ifdef SPI_EXECUTOR_STATS
    2896                 :     if (ShowExecutorStats)
    2897                 :         ResetUsage();
    2898                 : #endif
    2899                 : 
    2900                 :     /* Select execution options */
    2901 CBC       35678 :     if (fire_triggers)
    2902           32264 :         eflags = 0;             /* default run-to-completion flags */
    2903                 :     else
    2904            3414 :         eflags = EXEC_FLAG_SKIP_TRIGGERS;
    2905                 : 
    2906           35678 :     ExecutorStart(queryDesc, eflags);
    2907                 : 
    2908           35678 :     ExecutorRun(queryDesc, ForwardScanDirection, tcount, true);
    2909                 : 
    2910           33020 :     _SPI_current->processed = queryDesc->estate->es_processed;
    2911                 : 
    2912           33020 :     if ((res == SPI_OK_SELECT || queryDesc->plannedstmt->hasReturning) &&
    2913           20242 :         queryDesc->dest->mydest == DestSPI)
    2914                 :     {
    2915           18945 :         if (_SPI_checktuples())
    2916 UBC           0 :             elog(ERROR, "consistency check on SPI tuple count failed");
    2917                 :     }
    2918                 : 
    2919 CBC       33020 :     ExecutorFinish(queryDesc);
    2920           33019 :     ExecutorEnd(queryDesc);
    2921                 :     /* FreeQueryDesc is done by the caller */
    2922                 : 
    2923                 : #ifdef SPI_EXECUTOR_STATS
    2924                 :     if (ShowExecutorStats)
    2925                 :         ShowUsage("SPI EXECUTOR STATS");
    2926                 : #endif
    2927                 : 
    2928           33019 :     return res;
    2929                 : }
    2930                 : 
    2931                 : /*
    2932                 :  * _SPI_error_callback
    2933                 :  *
    2934                 :  * Add context information when a query invoked via SPI fails
    2935                 :  */
    2936                 : static void
    2937            3137 : _SPI_error_callback(void *arg)
    2938                 : {
    2939            3137 :     SPICallbackArg *carg = (SPICallbackArg *) arg;
    2940            3137 :     const char *query = carg->query;
    2941                 :     int         syntaxerrposition;
    2942                 : 
    2943            3137 :     if (query == NULL)          /* in case arg wasn't set yet */
    2944 UBC           0 :         return;
    2945                 : 
    2946                 :     /*
    2947                 :      * If there is a syntax error position, convert to internal syntax error;
    2948                 :      * otherwise treat the query as an item of context stack
    2949                 :      */
    2950 CBC        3137 :     syntaxerrposition = geterrposition();
    2951            3137 :     if (syntaxerrposition > 0)
    2952                 :     {
    2953              50 :         errposition(0);
    2954              50 :         internalerrposition(syntaxerrposition);
    2955              50 :         internalerrquery(query);
    2956                 :     }
    2957                 :     else
    2958                 :     {
    2959                 :         /* Use the parse mode to decide how to describe the query */
    2960            3087 :         switch (carg->mode)
    2961                 :         {
    2962              16 :             case RAW_PARSE_PLPGSQL_EXPR:
    2963              16 :                 errcontext("SQL expression \"%s\"", query);
    2964              16 :                 break;
    2965               8 :             case RAW_PARSE_PLPGSQL_ASSIGN1:
    2966                 :             case RAW_PARSE_PLPGSQL_ASSIGN2:
    2967                 :             case RAW_PARSE_PLPGSQL_ASSIGN3:
    2968               8 :                 errcontext("PL/pgSQL assignment \"%s\"", query);
    2969               8 :                 break;
    2970            3063 :             default:
    2971            3063 :                 errcontext("SQL statement \"%s\"", query);
    2972            3063 :                 break;
    2973                 :         }
    2974                 :     }
    2975                 : }
    2976                 : 
    2977                 : /*
    2978                 :  * _SPI_cursor_operation()
    2979                 :  *
    2980                 :  *  Do a FETCH or MOVE in a cursor
    2981                 :  */
    2982                 : static void
    2983           21697 : _SPI_cursor_operation(Portal portal, FetchDirection direction, long count,
    2984                 :                       DestReceiver *dest)
    2985                 : {
    2986                 :     uint64      nfetched;
    2987                 : 
    2988                 :     /* Check that the portal is valid */
    2989           21697 :     if (!PortalIsValid(portal))
    2990 UBC           0 :         elog(ERROR, "invalid portal in SPI cursor operation");
    2991                 : 
    2992                 :     /* Push the SPI stack */
    2993 CBC       21697 :     if (_SPI_begin_call(true) < 0)
    2994 UBC           0 :         elog(ERROR, "SPI cursor operation called while not connected");
    2995                 : 
    2996                 :     /* Reset the SPI result (note we deliberately don't touch lastoid) */
    2997 CBC       21697 :     SPI_processed = 0;
    2998           21697 :     SPI_tuptable = NULL;
    2999           21697 :     _SPI_current->processed = 0;
    3000           21697 :     _SPI_current->tuptable = NULL;
    3001                 : 
    3002                 :     /* Run the cursor */
    3003           21697 :     nfetched = PortalRunFetch(portal,
    3004                 :                               direction,
    3005                 :                               count,
    3006                 :                               dest);
    3007                 : 
    3008                 :     /*
    3009                 :      * Think not to combine this store with the preceding function call. If
    3010                 :      * the portal contains calls to functions that use SPI, then _SPI_stack is
    3011                 :      * likely to move around while the portal runs.  When control returns,
    3012                 :      * _SPI_current will point to the correct stack entry... but the pointer
    3013                 :      * may be different than it was beforehand. So we must be sure to re-fetch
    3014                 :      * the pointer after the function call completes.
    3015                 :      */
    3016           21691 :     _SPI_current->processed = nfetched;
    3017                 : 
    3018           21691 :     if (dest->mydest == DestSPI && _SPI_checktuples())
    3019 UBC           0 :         elog(ERROR, "consistency check on SPI tuple count failed");
    3020                 : 
    3021                 :     /* Put the result into place for access by caller */
    3022 CBC       21691 :     SPI_processed = _SPI_current->processed;
    3023           21691 :     SPI_tuptable = _SPI_current->tuptable;
    3024                 : 
    3025                 :     /* tuptable now is caller's responsibility, not SPI's */
    3026           21691 :     _SPI_current->tuptable = NULL;
    3027                 : 
    3028                 :     /* Pop the SPI stack */
    3029           21691 :     _SPI_end_call(true);
    3030           21691 : }
    3031                 : 
    3032                 : 
    3033                 : static MemoryContext
    3034           87834 : _SPI_execmem(void)
    3035                 : {
    3036           87834 :     return MemoryContextSwitchTo(_SPI_current->execCxt);
    3037                 : }
    3038                 : 
    3039                 : static MemoryContext
    3040          128336 : _SPI_procmem(void)
    3041                 : {
    3042          128336 :     return MemoryContextSwitchTo(_SPI_current->procCxt);
    3043                 : }
    3044                 : 
    3045                 : /*
    3046                 :  * _SPI_begin_call: begin a SPI operation within a connected procedure
    3047                 :  *
    3048                 :  * use_exec is true if we intend to make use of the procedure's execCxt
    3049                 :  * during this SPI operation.  We'll switch into that context, and arrange
    3050                 :  * for it to be cleaned up at _SPI_end_call or if an error occurs.
    3051                 :  */
    3052                 : static int
    3053          135718 : _SPI_begin_call(bool use_exec)
    3054                 : {
    3055          135718 :     if (_SPI_current == NULL)
    3056 UBC           0 :         return SPI_ERROR_UNCONNECTED;
    3057                 : 
    3058 CBC      135718 :     if (use_exec)
    3059                 :     {
    3060                 :         /* remember when the Executor operation started */
    3061           87834 :         _SPI_current->execSubid = GetCurrentSubTransactionId();
    3062                 :         /* switch to the Executor memory context */
    3063           87834 :         _SPI_execmem();
    3064                 :     }
    3065                 : 
    3066          135718 :     return 0;
    3067                 : }
    3068                 : 
    3069                 : /*
    3070                 :  * _SPI_end_call: end a SPI operation within a connected procedure
    3071                 :  *
    3072                 :  * use_exec must be the same as in the previous _SPI_begin_call
    3073                 :  *
    3074                 :  * Note: this currently has no failure return cases, so callers don't check
    3075                 :  */
    3076                 : static int
    3077           85352 : _SPI_end_call(bool use_exec)
    3078                 : {
    3079           85352 :     if (use_exec)
    3080                 :     {
    3081                 :         /* switch to the procedure memory context */
    3082           85010 :         _SPI_procmem();
    3083                 :         /* mark Executor context no longer in use */
    3084           85010 :         _SPI_current->execSubid = InvalidSubTransactionId;
    3085                 :         /* and free Executor memory */
    3086           85010 :         MemoryContextResetAndDeleteChildren(_SPI_current->execCxt);
    3087                 :     }
    3088                 : 
    3089           85352 :     return 0;
    3090                 : }
    3091                 : 
    3092                 : static bool
    3093           40615 : _SPI_checktuples(void)
    3094                 : {
    3095           40615 :     uint64      processed = _SPI_current->processed;
    3096           40615 :     SPITupleTable *tuptable = _SPI_current->tuptable;
    3097           40615 :     bool        failed = false;
    3098                 : 
    3099           40615 :     if (tuptable == NULL)       /* spi_dest_startup was not called */
    3100 UBC           0 :         failed = true;
    3101 CBC       40615 :     else if (processed != tuptable->numvals)
    3102 UBC           0 :         failed = true;
    3103                 : 
    3104 CBC       40615 :     return failed;
    3105                 : }
    3106                 : 
    3107                 : /*
    3108                 :  * Convert a "temporary" SPIPlan into an "unsaved" plan.
    3109                 :  *
    3110                 :  * The passed _SPI_plan struct is on the stack, and all its subsidiary data
    3111                 :  * is in or under the current SPI executor context.  Copy the plan into the
    3112                 :  * SPI procedure context so it will survive _SPI_end_call().  To minimize
    3113                 :  * data copying, this destructively modifies the input plan, by taking the
    3114                 :  * plancache entries away from it and reparenting them to the new SPIPlan.
    3115                 :  */
    3116                 : static SPIPlanPtr
    3117           13926 : _SPI_make_plan_non_temp(SPIPlanPtr plan)
    3118                 : {
    3119                 :     SPIPlanPtr  newplan;
    3120           13926 :     MemoryContext parentcxt = _SPI_current->procCxt;
    3121                 :     MemoryContext plancxt;
    3122                 :     MemoryContext oldcxt;
    3123                 :     ListCell   *lc;
    3124                 : 
    3125                 :     /* Assert the input is a temporary SPIPlan */
    3126           13926 :     Assert(plan->magic == _SPI_PLAN_MAGIC);
    3127           13926 :     Assert(plan->plancxt == NULL);
    3128                 :     /* One-shot plans can't be saved */
    3129           13926 :     Assert(!plan->oneshot);
    3130                 : 
    3131                 :     /*
    3132                 :      * Create a memory context for the plan, underneath the procedure context.
    3133                 :      * We don't expect the plan to be very large.
    3134                 :      */
    3135           13926 :     plancxt = AllocSetContextCreate(parentcxt,
    3136                 :                                     "SPI Plan",
    3137                 :                                     ALLOCSET_SMALL_SIZES);
    3138           13926 :     oldcxt = MemoryContextSwitchTo(plancxt);
    3139                 : 
    3140                 :     /* Copy the _SPI_plan struct and subsidiary data into the new context */
    3141           13926 :     newplan = (SPIPlanPtr) palloc0(sizeof(_SPI_plan));
    3142           13926 :     newplan->magic = _SPI_PLAN_MAGIC;
    3143           13926 :     newplan->plancxt = plancxt;
    3144           13926 :     newplan->parse_mode = plan->parse_mode;
    3145           13926 :     newplan->cursor_options = plan->cursor_options;
    3146           13926 :     newplan->nargs = plan->nargs;
    3147           13926 :     if (plan->nargs > 0)
    3148                 :     {
    3149            1687 :         newplan->argtypes = (Oid *) palloc(plan->nargs * sizeof(Oid));
    3150            1687 :         memcpy(newplan->argtypes, plan->argtypes, plan->nargs * sizeof(Oid));
    3151                 :     }
    3152                 :     else
    3153           12239 :         newplan->argtypes = NULL;
    3154           13926 :     newplan->parserSetup = plan->parserSetup;
    3155           13926 :     newplan->parserSetupArg = plan->parserSetupArg;
    3156                 : 
    3157                 :     /*
    3158                 :      * Reparent all the CachedPlanSources into the procedure context.  In
    3159                 :      * theory this could fail partway through due to the pallocs, but we don't
    3160                 :      * care too much since both the procedure context and the executor context
    3161                 :      * would go away on error.
    3162                 :      */
    3163           27852 :     foreach(lc, plan->plancache_list)
    3164                 :     {
    3165           13926 :         CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc);
    3166                 : 
    3167           13926 :         CachedPlanSetParentContext(plansource, parentcxt);
    3168                 : 
    3169                 :         /* Build new list, with list cells in plancxt */
    3170           13926 :         newplan->plancache_list = lappend(newplan->plancache_list, plansource);
    3171                 :     }
    3172                 : 
    3173           13926 :     MemoryContextSwitchTo(oldcxt);
    3174                 : 
    3175                 :     /* For safety, unlink the CachedPlanSources from the temporary plan */
    3176           13926 :     plan->plancache_list = NIL;
    3177                 : 
    3178           13926 :     return newplan;
    3179                 : }
    3180                 : 
    3181                 : /*
    3182                 :  * Make a "saved" copy of the given plan.
    3183                 :  */
    3184                 : static SPIPlanPtr
    3185 UBC           0 : _SPI_save_plan(SPIPlanPtr plan)
    3186                 : {
    3187                 :     SPIPlanPtr  newplan;
    3188                 :     MemoryContext plancxt;
    3189                 :     MemoryContext oldcxt;
    3190                 :     ListCell   *lc;
    3191                 : 
    3192                 :     /* One-shot plans can't be saved */
    3193               0 :     Assert(!plan->oneshot);
    3194                 : 
    3195                 :     /*
    3196                 :      * Create a memory context for the plan.  We don't expect the plan to be
    3197                 :      * very large, so use smaller-than-default alloc parameters.  It's a
    3198                 :      * transient context until we finish copying everything.
    3199                 :      */
    3200               0 :     plancxt = AllocSetContextCreate(CurrentMemoryContext,
    3201                 :                                     "SPI Plan",
    3202                 :                                     ALLOCSET_SMALL_SIZES);
    3203               0 :     oldcxt = MemoryContextSwitchTo(plancxt);
    3204                 : 
    3205                 :     /* Copy the SPI plan into its own context */
    3206               0 :     newplan = (SPIPlanPtr) palloc0(sizeof(_SPI_plan));
    3207               0 :     newplan->magic = _SPI_PLAN_MAGIC;
    3208               0 :     newplan->plancxt = plancxt;
    3209               0 :     newplan->parse_mode = plan->parse_mode;
    3210               0 :     newplan->cursor_options = plan->cursor_options;
    3211               0 :     newplan->nargs = plan->nargs;
    3212               0 :     if (plan->nargs > 0)
    3213                 :     {
    3214               0 :         newplan->argtypes = (Oid *) palloc(plan->nargs * sizeof(Oid));
    3215               0 :         memcpy(newplan->argtypes, plan->argtypes, plan->nargs * sizeof(Oid));
    3216                 :     }
    3217                 :     else
    3218               0 :         newplan->argtypes = NULL;
    3219               0 :     newplan->parserSetup = plan->parserSetup;
    3220               0 :     newplan->parserSetupArg = plan->parserSetupArg;
    3221                 : 
    3222                 :     /* Copy all the plancache entries */
    3223               0 :     foreach(lc, plan->plancache_list)
    3224                 :     {
    3225               0 :         CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc);
    3226                 :         CachedPlanSource *newsource;
    3227                 : 
    3228               0 :         newsource = CopyCachedPlan(plansource);
    3229               0 :         newplan->plancache_list = lappend(newplan->plancache_list, newsource);
    3230                 :     }
    3231                 : 
    3232               0 :     MemoryContextSwitchTo(oldcxt);
    3233                 : 
    3234                 :     /*
    3235                 :      * Mark it saved, reparent it under CacheMemoryContext, and mark all the
    3236                 :      * component CachedPlanSources as saved.  This sequence cannot fail
    3237                 :      * partway through, so there's no risk of long-term memory leakage.
    3238                 :      */
    3239               0 :     newplan->saved = true;
    3240               0 :     MemoryContextSetParent(newplan->plancxt, CacheMemoryContext);
    3241                 : 
    3242               0 :     foreach(lc, newplan->plancache_list)
    3243                 :     {
    3244               0 :         CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc);
    3245                 : 
    3246               0 :         SaveCachedPlan(plansource);
    3247                 :     }
    3248                 : 
    3249               0 :     return newplan;
    3250                 : }
    3251                 : 
    3252                 : /*
    3253                 :  * Internal lookup of ephemeral named relation by name.
    3254                 :  */
    3255                 : static EphemeralNamedRelation
    3256 CBC         342 : _SPI_find_ENR_by_name(const char *name)
    3257                 : {
    3258                 :     /* internal static function; any error is bug in SPI itself */
    3259             342 :     Assert(name != NULL);
    3260                 : 
    3261                 :     /* fast exit if no tuplestores have been added */
    3262             342 :     if (_SPI_current->queryEnv == NULL)
    3263             267 :         return NULL;
    3264                 : 
    3265              75 :     return get_ENR(_SPI_current->queryEnv, name);
    3266                 : }
    3267                 : 
    3268                 : /*
    3269                 :  * Register an ephemeral named relation for use by the planner and executor on
    3270                 :  * subsequent calls using this SPI connection.
    3271                 :  */
    3272                 : int
    3273             342 : SPI_register_relation(EphemeralNamedRelation enr)
    3274                 : {
    3275                 :     EphemeralNamedRelation match;
    3276                 :     int         res;
    3277                 : 
    3278             342 :     if (enr == NULL || enr->md.name == NULL)
    3279 UBC           0 :         return SPI_ERROR_ARGUMENT;
    3280                 : 
    3281 CBC         342 :     res = _SPI_begin_call(false);   /* keep current memory context */
    3282             342 :     if (res < 0)
    3283 UBC           0 :         return res;
    3284                 : 
    3285 CBC         342 :     match = _SPI_find_ENR_by_name(enr->md.name);
    3286             342 :     if (match)
    3287 UBC           0 :         res = SPI_ERROR_REL_DUPLICATE;
    3288                 :     else
    3289                 :     {
    3290 CBC         342 :         if (_SPI_current->queryEnv == NULL)
    3291             267 :             _SPI_current->queryEnv = create_queryEnv();
    3292                 : 
    3293             342 :         register_ENR(_SPI_current->queryEnv, enr);
    3294             342 :         res = SPI_OK_REL_REGISTER;
    3295                 :     }
    3296                 : 
    3297             342 :     _SPI_end_call(false);
    3298                 : 
    3299             342 :     return res;
    3300                 : }
    3301                 : 
    3302                 : /*
    3303                 :  * Unregister an ephemeral named relation by name.  This will probably be a
    3304                 :  * rarely used function, since SPI_finish will clear it automatically.
    3305                 :  */
    3306                 : int
    3307 UBC           0 : SPI_unregister_relation(const char *name)
    3308                 : {
    3309                 :     EphemeralNamedRelation match;
    3310                 :     int         res;
    3311                 : 
    3312               0 :     if (name == NULL)
    3313               0 :         return SPI_ERROR_ARGUMENT;
    3314                 : 
    3315               0 :     res = _SPI_begin_call(false);   /* keep current memory context */
    3316               0 :     if (res < 0)
    3317               0 :         return res;
    3318                 : 
    3319               0 :     match = _SPI_find_ENR_by_name(name);
    3320               0 :     if (match)
    3321                 :     {
    3322               0 :         unregister_ENR(_SPI_current->queryEnv, match->md.name);
    3323               0 :         res = SPI_OK_REL_UNREGISTER;
    3324                 :     }
    3325                 :     else
    3326               0 :         res = SPI_ERROR_REL_NOT_FOUND;
    3327                 : 
    3328               0 :     _SPI_end_call(false);
    3329                 : 
    3330               0 :     return res;
    3331                 : }
    3332                 : 
    3333                 : /*
    3334                 :  * Register the transient relations from 'tdata' using this SPI connection.
    3335                 :  * This should be called by PL implementations' trigger handlers after
    3336                 :  * connecting, in order to make transition tables visible to any queries run
    3337                 :  * in this connection.
    3338                 :  */
    3339                 : int
    3340 CBC        7429 : SPI_register_trigger_data(TriggerData *tdata)
    3341                 : {
    3342            7429 :     if (tdata == NULL)
    3343 UBC           0 :         return SPI_ERROR_ARGUMENT;
    3344                 : 
    3345 CBC        7429 :     if (tdata->tg_newtable)
    3346                 :     {
    3347                 :         EphemeralNamedRelation enr =
    3348             192 :         palloc(sizeof(EphemeralNamedRelationData));
    3349                 :         int         rc;
    3350                 : 
    3351             192 :         enr->md.name = tdata->tg_trigger->tgnewtable;
    3352             192 :         enr->md.reliddesc = tdata->tg_relation->rd_id;
    3353             192 :         enr->md.tupdesc = NULL;
    3354             192 :         enr->md.enrtype = ENR_NAMED_TUPLESTORE;
    3355             192 :         enr->md.enrtuples = tuplestore_tuple_count(tdata->tg_newtable);
    3356             192 :         enr->reldata = tdata->tg_newtable;
    3357             192 :         rc = SPI_register_relation(enr);
    3358             192 :         if (rc != SPI_OK_REL_REGISTER)
    3359 UBC           0 :             return rc;
    3360                 :     }
    3361                 : 
    3362 CBC        7429 :     if (tdata->tg_oldtable)
    3363                 :     {
    3364                 :         EphemeralNamedRelation enr =
    3365             150 :         palloc(sizeof(EphemeralNamedRelationData));
    3366                 :         int         rc;
    3367                 : 
    3368             150 :         enr->md.name = tdata->tg_trigger->tgoldtable;
    3369             150 :         enr->md.reliddesc = tdata->tg_relation->rd_id;
    3370             150 :         enr->md.tupdesc = NULL;
    3371             150 :         enr->md.enrtype = ENR_NAMED_TUPLESTORE;
    3372             150 :         enr->md.enrtuples = tuplestore_tuple_count(tdata->tg_oldtable);
    3373             150 :         enr->reldata = tdata->tg_oldtable;
    3374             150 :         rc = SPI_register_relation(enr);
    3375             150 :         if (rc != SPI_OK_REL_REGISTER)
    3376 UBC           0 :             return rc;
    3377                 :     }
    3378                 : 
    3379 CBC        7429 :     return SPI_OK_TD_REGISTER;
    3380                 : }
        

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