LCOV - code coverage report
Current view: top level - src/backend/executor - spi.c (source / functions) Hit Total Coverage
Test: PostgreSQL 15devel Lines: 872 1195 73.0 %
Date: 2021-12-03 03:09:03 Functions: 72 85 84.7 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14