PostgreSQL Source Code  git master
spi.c File Reference
#include "postgres.h"
#include "access/htup_details.h"
#include "access/printtup.h"
#include "access/sysattr.h"
#include "access/xact.h"
#include "catalog/heap.h"
#include "catalog/pg_type.h"
#include "commands/trigger.h"
#include "executor/executor.h"
#include "executor/spi_priv.h"
#include "miscadmin.h"
#include "tcop/pquery.h"
#include "tcop/utility.h"
#include "utils/builtins.h"
#include "utils/datum.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/rel.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
#include "utils/typcache.h"
Include dependency graph for spi.c:

Go to the source code of this file.

Data Structures

struct  SPICallbackArg
 

Typedefs

typedef struct SPICallbackArg SPICallbackArg
 

Functions

static Portal SPI_cursor_open_internal (const char *name, SPIPlanPtr plan, ParamListInfo paramLI, bool read_only)
 
static void _SPI_prepare_plan (const char *src, SPIPlanPtr plan)
 
static void _SPI_prepare_oneshot_plan (const char *src, SPIPlanPtr plan)
 
static int _SPI_execute_plan (SPIPlanPtr plan, const SPIExecuteOptions *options, Snapshot snapshot, Snapshot crosscheck_snapshot, bool fire_triggers)
 
static ParamListInfo _SPI_convert_params (int nargs, Oid *argtypes, Datum *Values, const char *Nulls)
 
static int _SPI_pquery (QueryDesc *queryDesc, bool fire_triggers, uint64 tcount)
 
static void _SPI_error_callback (void *arg)
 
static void _SPI_cursor_operation (Portal portal, FetchDirection direction, long count, DestReceiver *dest)
 
static SPIPlanPtr _SPI_make_plan_non_temp (SPIPlanPtr plan)
 
static SPIPlanPtr _SPI_save_plan (SPIPlanPtr plan)
 
static int _SPI_begin_call (bool use_exec)
 
static int _SPI_end_call (bool use_exec)
 
static MemoryContext _SPI_execmem (void)
 
static MemoryContext _SPI_procmem (void)
 
static bool _SPI_checktuples (void)
 
int SPI_connect (void)
 
int SPI_connect_ext (int options)
 
int SPI_finish (void)
 
void SPI_start_transaction (void)
 
static void _SPI_commit (bool chain)
 
void SPI_commit (void)
 
void SPI_commit_and_chain (void)
 
static void _SPI_rollback (bool chain)
 
void SPI_rollback (void)
 
void SPI_rollback_and_chain (void)
 
void AtEOXact_SPI (bool isCommit)
 
void AtEOSubXact_SPI (bool isCommit, SubTransactionId mySubid)
 
bool SPI_inside_nonatomic_context (void)
 
int SPI_execute (const char *src, bool read_only, long tcount)
 
int SPI_exec (const char *src, long tcount)
 
int SPI_execute_extended (const char *src, const SPIExecuteOptions *options)
 
int SPI_execute_plan (SPIPlanPtr plan, Datum *Values, const char *Nulls, bool read_only, long tcount)
 
int SPI_execp (SPIPlanPtr plan, Datum *Values, const char *Nulls, long tcount)
 
int SPI_execute_plan_extended (SPIPlanPtr plan, const SPIExecuteOptions *options)
 
int SPI_execute_plan_with_paramlist (SPIPlanPtr plan, ParamListInfo params, bool read_only, long tcount)
 
int SPI_execute_snapshot (SPIPlanPtr plan, Datum *Values, const char *Nulls, Snapshot snapshot, Snapshot crosscheck_snapshot, bool read_only, bool fire_triggers, long tcount)
 
int SPI_execute_with_args (const char *src, int nargs, Oid *argtypes, Datum *Values, const char *Nulls, bool read_only, long tcount)
 
SPIPlanPtr SPI_prepare (const char *src, int nargs, Oid *argtypes)
 
SPIPlanPtr SPI_prepare_cursor (const char *src, int nargs, Oid *argtypes, int cursorOptions)
 
SPIPlanPtr SPI_prepare_extended (const char *src, const SPIPrepareOptions *options)
 
SPIPlanPtr SPI_prepare_params (const char *src, ParserSetupHook parserSetup, void *parserSetupArg, int cursorOptions)
 
int SPI_keepplan (SPIPlanPtr plan)
 
SPIPlanPtr SPI_saveplan (SPIPlanPtr plan)
 
int SPI_freeplan (SPIPlanPtr plan)
 
HeapTuple SPI_copytuple (HeapTuple tuple)
 
HeapTupleHeader SPI_returntuple (HeapTuple tuple, TupleDesc tupdesc)
 
HeapTuple SPI_modifytuple (Relation rel, HeapTuple tuple, int natts, int *attnum, Datum *Values, const char *Nulls)
 
int SPI_fnumber (TupleDesc tupdesc, const char *fname)
 
char * SPI_fname (TupleDesc tupdesc, int fnumber)
 
char * SPI_getvalue (HeapTuple tuple, TupleDesc tupdesc, int fnumber)
 
Datum SPI_getbinval (HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool *isnull)
 
char * SPI_gettype (TupleDesc tupdesc, int fnumber)
 
Oid SPI_gettypeid (TupleDesc tupdesc, int fnumber)
 
char * SPI_getrelname (Relation rel)
 
char * SPI_getnspname (Relation rel)
 
void * SPI_palloc (Size size)
 
void * SPI_repalloc (void *pointer, Size size)
 
void SPI_pfree (void *pointer)
 
Datum SPI_datumTransfer (Datum value, bool typByVal, int typLen)
 
void SPI_freetuple (HeapTuple tuple)
 
void SPI_freetuptable (SPITupleTable *tuptable)
 
Portal SPI_cursor_open (const char *name, SPIPlanPtr plan, Datum *Values, const char *Nulls, bool read_only)
 
Portal SPI_cursor_open_with_args (const char *name, const char *src, int nargs, Oid *argtypes, Datum *Values, const char *Nulls, bool read_only, int cursorOptions)
 
Portal SPI_cursor_open_with_paramlist (const char *name, SPIPlanPtr plan, ParamListInfo params, bool read_only)
 
Portal SPI_cursor_parse_open (const char *name, const char *src, const SPIParseOpenOptions *options)
 
Portal SPI_cursor_find (const char *name)
 
void SPI_cursor_fetch (Portal portal, bool forward, long count)
 
void SPI_cursor_move (Portal portal, bool forward, long count)
 
void SPI_scroll_cursor_fetch (Portal portal, FetchDirection direction, long count)
 
void SPI_scroll_cursor_move (Portal portal, FetchDirection direction, long count)
 
void SPI_cursor_close (Portal portal)
 
Oid SPI_getargtypeid (SPIPlanPtr plan, int argIndex)
 
int SPI_getargcount (SPIPlanPtr plan)
 
bool SPI_is_cursor_plan (SPIPlanPtr plan)
 
bool SPI_plan_is_valid (SPIPlanPtr plan)
 
const char * SPI_result_code_string (int code)
 
ListSPI_plan_get_plan_sources (SPIPlanPtr plan)
 
CachedPlanSPI_plan_get_cached_plan (SPIPlanPtr plan)
 
void spi_dest_startup (DestReceiver *self, int operation, TupleDesc typeinfo)
 
bool spi_printtup (TupleTableSlot *slot, DestReceiver *self)
 
static EphemeralNamedRelation _SPI_find_ENR_by_name (const char *name)
 
int SPI_register_relation (EphemeralNamedRelation enr)
 
int SPI_unregister_relation (const char *name)
 
int SPI_register_trigger_data (TriggerData *tdata)
 

Variables

uint64 SPI_processed = 0
 
SPITupleTableSPI_tuptable = NULL
 
int SPI_result = 0
 
static _SPI_connection_SPI_stack = NULL
 
static _SPI_connection_SPI_current = NULL
 
static int _SPI_stack_depth = 0
 
static int _SPI_connected = -1
 

Typedef Documentation

◆ SPICallbackArg

Function Documentation

◆ _SPI_begin_call()

static int _SPI_begin_call ( bool  use_exec)
static

Definition at line 3049 of file spi.c.

3050 {
3051  if (_SPI_current == NULL)
3052  return SPI_ERROR_UNCONNECTED;
3053 
3054  if (use_exec)
3055  {
3056  /* remember when the Executor operation started */
3058  /* switch to the Executor memory context */
3059  _SPI_execmem();
3060  }
3061 
3062  return 0;
3063 }
static _SPI_connection * _SPI_current
Definition: spi.c:50
static MemoryContext _SPI_execmem(void)
Definition: spi.c:3030
#define SPI_ERROR_UNCONNECTED
Definition: spi.h:71
SubTransactionId execSubid
Definition: spi_priv.h:29
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:779

References _SPI_current, _SPI_execmem(), _SPI_connection::execSubid, GetCurrentSubTransactionId(), and SPI_ERROR_UNCONNECTED.

Referenced by _SPI_cursor_operation(), SPI_cursor_open_internal(), SPI_cursor_open_with_args(), SPI_cursor_parse_open(), SPI_execute(), SPI_execute_extended(), SPI_execute_plan(), SPI_execute_plan_extended(), SPI_execute_plan_with_paramlist(), SPI_execute_snapshot(), SPI_execute_with_args(), SPI_finish(), SPI_prepare_cursor(), SPI_prepare_extended(), SPI_prepare_params(), SPI_register_relation(), SPI_saveplan(), and SPI_unregister_relation().

◆ _SPI_checktuples()

static bool _SPI_checktuples ( void  )
static

Definition at line 3089 of file spi.c.

3090 {
3091  uint64 processed = _SPI_current->processed;
3092  SPITupleTable *tuptable = _SPI_current->tuptable;
3093  bool failed = false;
3094 
3095  if (tuptable == NULL) /* spi_dest_startup was not called */
3096  failed = true;
3097  else if (processed != tuptable->numvals)
3098  failed = true;
3099 
3100  return failed;
3101 }
uint64 numvals
Definition: spi.h:27
uint64 processed
Definition: spi_priv.h:25
SPITupleTable * tuptable
Definition: spi_priv.h:26

References _SPI_current, SPITupleTable::numvals, _SPI_connection::processed, and _SPI_connection::tuptable.

Referenced by _SPI_cursor_operation(), and _SPI_pquery().

◆ _SPI_commit()

static void _SPI_commit ( bool  chain)
static

Definition at line 228 of file spi.c.

229 {
230  MemoryContext oldcontext = CurrentMemoryContext;
232 
233  /*
234  * Complain if we are in a context that doesn't permit transaction
235  * termination. (Note: here and _SPI_rollback should be the only places
236  * that throw ERRCODE_INVALID_TRANSACTION_TERMINATION, so that callers can
237  * test for that with security that they know what happened.)
238  */
239  if (_SPI_current->atomic)
240  ereport(ERROR,
241  (errcode(ERRCODE_INVALID_TRANSACTION_TERMINATION),
242  errmsg("invalid transaction termination")));
243 
244  /*
245  * This restriction is required by PLs implemented on top of SPI. They
246  * use subtransactions to establish exception blocks that are supposed to
247  * be rolled back together if there is an error. Terminating the
248  * top-level transaction in such a block violates that idea. A future PL
249  * implementation might have different ideas about this, in which case
250  * this restriction would have to be refined or the check possibly be
251  * moved out of SPI into the PLs. Note however that the code below relies
252  * on not being within a subtransaction.
253  */
254  if (IsSubTransaction())
255  ereport(ERROR,
256  (errcode(ERRCODE_INVALID_TRANSACTION_TERMINATION),
257  errmsg("cannot commit while a subtransaction is active")));
258 
259  if (chain)
261 
262  /* Catch any error occurring during the COMMIT */
263  PG_TRY();
264  {
265  /* Protect current SPI stack entry against deletion */
266  _SPI_current->internal_xact = true;
267 
268  /*
269  * Hold any pinned portals that any PLs might be using. We have to do
270  * this before changing transaction state, since this will run
271  * user-defined code that might throw an error.
272  */
274 
275  /* Release snapshots associated with portals */
277 
278  /* Do the deed */
280 
281  /* Immediately start a new transaction */
283  if (chain)
285 
286  MemoryContextSwitchTo(oldcontext);
287 
288  _SPI_current->internal_xact = false;
289  }
290  PG_CATCH();
291  {
292  ErrorData *edata;
293 
294  /* Save error info in caller's context */
295  MemoryContextSwitchTo(oldcontext);
296  edata = CopyErrorData();
297  FlushErrorState();
298 
299  /*
300  * Abort the failed transaction. If this fails too, we'll just
301  * propagate the error out ... there's not that much we can do.
302  */
304 
305  /* ... and start a new one */
307  if (chain)
309 
310  MemoryContextSwitchTo(oldcontext);
311 
312  _SPI_current->internal_xact = false;
313 
314  /* Now that we've cleaned up the transaction, re-throw the error */
315  ReThrowError(edata);
316  }
317  PG_END_TRY();
318 }
void ReThrowError(ErrorData *edata)
Definition: elog.c:1735
void FlushErrorState(void)
Definition: elog.c:1651
int errcode(int sqlerrcode)
Definition: elog.c:695
int errmsg(const char *fmt,...)
Definition: elog.c:906
ErrorData * CopyErrorData(void)
Definition: elog.c:1557
#define PG_TRY(...)
Definition: elog.h:309
#define PG_END_TRY(...)
Definition: elog.h:334
#define ERROR
Definition: elog.h:35
#define PG_CATCH(...)
Definition: elog.h:319
#define ereport(elevel,...)
Definition: elog.h:145
MemoryContext CurrentMemoryContext
Definition: mcxt.c:124
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:135
void HoldPinnedPortals(void)
Definition: portalmem.c:1205
void ForgetPortalSnapshots(void)
Definition: portalmem.c:1254
bool internal_xact
Definition: spi_priv.h:42
void SaveTransactionCharacteristics(SavedTransactionCharacteristics *s)
Definition: xact.c:3002
void RestoreTransactionCharacteristics(const SavedTransactionCharacteristics *s)
Definition: xact.c:3010
void StartTransactionCommand(void)
Definition: xact.c:2925
bool IsSubTransaction(void)
Definition: xact.c:4869
void CommitTransactionCommand(void)
Definition: xact.c:3022
void AbortCurrentTransaction(void)
Definition: xact.c:3293

References _SPI_current, AbortCurrentTransaction(), _SPI_connection::atomic, CommitTransactionCommand(), CopyErrorData(), CurrentMemoryContext, ereport, errcode(), errmsg(), ERROR, FlushErrorState(), ForgetPortalSnapshots(), HoldPinnedPortals(), _SPI_connection::internal_xact, IsSubTransaction(), MemoryContextSwitchTo(), PG_CATCH, PG_END_TRY, PG_TRY, RestoreTransactionCharacteristics(), ReThrowError(), SaveTransactionCharacteristics(), and StartTransactionCommand().

Referenced by SPI_commit(), and SPI_commit_and_chain().

◆ _SPI_convert_params()

static ParamListInfo _SPI_convert_params ( int  nargs,
Oid argtypes,
Datum Values,
const char *  Nulls 
)
static

Definition at line 2824 of file spi.c.

2826 {
2827  ParamListInfo paramLI;
2828 
2829  if (nargs > 0)
2830  {
2831  paramLI = makeParamList(nargs);
2832 
2833  for (int i = 0; i < nargs; i++)
2834  {
2835  ParamExternData *prm = &paramLI->params[i];
2836 
2837  prm->value = Values[i];
2838  prm->isnull = (Nulls && Nulls[i] == 'n');
2839  prm->pflags = PARAM_FLAG_CONST;
2840  prm->ptype = argtypes[i];
2841  }
2842  }
2843  else
2844  paramLI = NULL;
2845  return paramLI;
2846 }
static bool Nulls[MAXATTR]
Definition: bootstrap.c:157
int i
Definition: isn.c:73
ParamListInfo makeParamList(int numParams)
Definition: params.c:44
#define PARAM_FLAG_CONST
Definition: params.h:88
bool isnull
Definition: params.h:93
uint16 pflags
Definition: params.h:94
Datum value
Definition: params.h:92
ParamExternData params[FLEXIBLE_ARRAY_MEMBER]
Definition: params.h:125

References i, ParamExternData::isnull, makeParamList(), Nulls, PARAM_FLAG_CONST, ParamListInfoData::params, ParamExternData::pflags, ParamExternData::ptype, and ParamExternData::value.

Referenced by SPI_cursor_open(), SPI_cursor_open_with_args(), SPI_execute_plan(), SPI_execute_snapshot(), and SPI_execute_with_args().

◆ _SPI_cursor_operation()

static void _SPI_cursor_operation ( Portal  portal,
FetchDirection  direction,
long  count,
DestReceiver dest 
)
static

Definition at line 2979 of file spi.c.

2981 {
2982  uint64 nfetched;
2983 
2984  /* Check that the portal is valid */
2985  if (!PortalIsValid(portal))
2986  elog(ERROR, "invalid portal in SPI cursor operation");
2987 
2988  /* Push the SPI stack */
2989  if (_SPI_begin_call(true) < 0)
2990  elog(ERROR, "SPI cursor operation called while not connected");
2991 
2992  /* Reset the SPI result (note we deliberately don't touch lastoid) */
2993  SPI_processed = 0;
2994  SPI_tuptable = NULL;
2995  _SPI_current->processed = 0;
2996  _SPI_current->tuptable = NULL;
2997 
2998  /* Run the cursor */
2999  nfetched = PortalRunFetch(portal,
3000  direction,
3001  count,
3002  dest);
3003 
3004  /*
3005  * Think not to combine this store with the preceding function call. If
3006  * the portal contains calls to functions that use SPI, then _SPI_stack is
3007  * likely to move around while the portal runs. When control returns,
3008  * _SPI_current will point to the correct stack entry... but the pointer
3009  * may be different than it was beforehand. So we must be sure to re-fetch
3010  * the pointer after the function call completes.
3011  */
3012  _SPI_current->processed = nfetched;
3013 
3014  if (dest->mydest == DestSPI && _SPI_checktuples())
3015  elog(ERROR, "consistency check on SPI tuple count failed");
3016 
3017  /* Put the result into place for access by caller */
3020 
3021  /* tuptable now is caller's responsibility, not SPI's */
3022  _SPI_current->tuptable = NULL;
3023 
3024  /* Pop the SPI stack */
3025  _SPI_end_call(true);
3026 }
@ DestSPI
Definition: dest.h:94
#define PortalIsValid(p)
Definition: portal.h:212
uint64 PortalRunFetch(Portal portal, FetchDirection fdirection, long count, DestReceiver *dest)
Definition: pquery.c:1391
static int _SPI_end_call(bool use_exec)
Definition: spi.c:3073
uint64 SPI_processed
Definition: spi.c:45
SPITupleTable * SPI_tuptable
Definition: spi.c:46
static int _SPI_begin_call(bool use_exec)
Definition: spi.c:3049
static bool _SPI_checktuples(void)
Definition: spi.c:3089

References _SPI_begin_call(), _SPI_checktuples(), _SPI_current, _SPI_end_call(), generate_unaccent_rules::dest, DestSPI, elog(), ERROR, PortalIsValid, PortalRunFetch(), _SPI_connection::processed, SPI_processed, SPI_tuptable, and _SPI_connection::tuptable.

Referenced by SPI_cursor_fetch(), SPI_cursor_move(), SPI_scroll_cursor_fetch(), and SPI_scroll_cursor_move().

◆ _SPI_end_call()

static int _SPI_end_call ( bool  use_exec)
static

Definition at line 3073 of file spi.c.

3074 {
3075  if (use_exec)
3076  {
3077  /* switch to the procedure memory context */
3078  _SPI_procmem();
3079  /* mark Executor context no longer in use */
3081  /* and free Executor memory */
3083  }
3084 
3085  return 0;
3086 }
#define InvalidSubTransactionId
Definition: c.h:594
#define MemoryContextResetAndDeleteChildren(ctx)
Definition: memutils.h:70
static MemoryContext _SPI_procmem(void)
Definition: spi.c:3036
MemoryContext execCxt
Definition: spi_priv.h:34

References _SPI_current, _SPI_procmem(), _SPI_connection::execCxt, _SPI_connection::execSubid, InvalidSubTransactionId, and MemoryContextResetAndDeleteChildren.

Referenced by _SPI_cursor_operation(), SPI_cursor_open_internal(), SPI_cursor_open_with_args(), SPI_cursor_parse_open(), SPI_execute(), SPI_execute_extended(), SPI_execute_plan(), SPI_execute_plan_extended(), SPI_execute_plan_with_paramlist(), SPI_execute_snapshot(), SPI_execute_with_args(), SPI_prepare_cursor(), SPI_prepare_extended(), SPI_prepare_params(), SPI_register_relation(), SPI_saveplan(), and SPI_unregister_relation().

◆ _SPI_error_callback()

static void _SPI_error_callback ( void *  arg)
static

Definition at line 2933 of file spi.c.

2934 {
2935  SPICallbackArg *carg = (SPICallbackArg *) arg;
2936  const char *query = carg->query;
2937  int syntaxerrposition;
2938 
2939  if (query == NULL) /* in case arg wasn't set yet */
2940  return;
2941 
2942  /*
2943  * If there is a syntax error position, convert to internal syntax error;
2944  * otherwise treat the query as an item of context stack
2945  */
2946  syntaxerrposition = geterrposition();
2947  if (syntaxerrposition > 0)
2948  {
2949  errposition(0);
2950  internalerrposition(syntaxerrposition);
2951  internalerrquery(query);
2952  }
2953  else
2954  {
2955  /* Use the parse mode to decide how to describe the query */
2956  switch (carg->mode)
2957  {
2959  errcontext("SQL expression \"%s\"", query);
2960  break;
2964  errcontext("PL/pgSQL assignment \"%s\"", query);
2965  break;
2966  default:
2967  errcontext("SQL statement \"%s\"", query);
2968  break;
2969  }
2970  }
2971 }
int internalerrquery(const char *query)
Definition: elog.c:1318
int internalerrposition(int cursorpos)
Definition: elog.c:1298
int geterrposition(void)
Definition: elog.c:1414
int errposition(int cursorpos)
Definition: elog.c:1282
#define errcontext
Definition: elog.h:192
@ RAW_PARSE_PLPGSQL_EXPR
Definition: parser.h:41
@ RAW_PARSE_PLPGSQL_ASSIGN2
Definition: parser.h:43
@ RAW_PARSE_PLPGSQL_ASSIGN1
Definition: parser.h:42
@ RAW_PARSE_PLPGSQL_ASSIGN3
Definition: parser.h:44
void * arg
const char * query
Definition: spi.c:56
RawParseMode mode
Definition: spi.c:57

References arg, errcontext, errposition(), geterrposition(), internalerrposition(), internalerrquery(), SPICallbackArg::mode, SPICallbackArg::query, RAW_PARSE_PLPGSQL_ASSIGN1, RAW_PARSE_PLPGSQL_ASSIGN2, RAW_PARSE_PLPGSQL_ASSIGN3, and RAW_PARSE_PLPGSQL_EXPR.

Referenced by _SPI_execute_plan(), _SPI_prepare_oneshot_plan(), _SPI_prepare_plan(), SPI_cursor_open_internal(), and SPI_plan_get_cached_plan().

◆ _SPI_execmem()

static MemoryContext _SPI_execmem ( void  )
static

Definition at line 3030 of file spi.c.

3031 {
3033 }

References _SPI_current, _SPI_connection::execCxt, and MemoryContextSwitchTo().

Referenced by _SPI_begin_call().

◆ _SPI_execute_plan()

static int _SPI_execute_plan ( SPIPlanPtr  plan,
const SPIExecuteOptions options,
Snapshot  snapshot,
Snapshot  crosscheck_snapshot,
bool  fire_triggers 
)
static

Definition at line 2389 of file spi.c.

2392 {
2393  int my_res = 0;
2394  uint64 my_processed = 0;
2395  SPITupleTable *my_tuptable = NULL;
2396  int res = 0;
2397  bool pushed_active_snap = false;
2398  ResourceOwner plan_owner = options->owner;
2399  SPICallbackArg spicallbackarg;
2400  ErrorContextCallback spierrcontext;
2401  CachedPlan *cplan = NULL;
2402  ListCell *lc1;
2403 
2404  /*
2405  * Setup error traceback support for ereport()
2406  */
2407  spicallbackarg.query = NULL; /* we'll fill this below */
2408  spicallbackarg.mode = plan->parse_mode;
2409  spierrcontext.callback = _SPI_error_callback;
2410  spierrcontext.arg = &spicallbackarg;
2411  spierrcontext.previous = error_context_stack;
2412  error_context_stack = &spierrcontext;
2413 
2414  /*
2415  * We support four distinct snapshot management behaviors:
2416  *
2417  * snapshot != InvalidSnapshot, read_only = true: use exactly the given
2418  * snapshot.
2419  *
2420  * snapshot != InvalidSnapshot, read_only = false: use the given snapshot,
2421  * modified by advancing its command ID before each querytree.
2422  *
2423  * snapshot == InvalidSnapshot, read_only = true: use the entry-time
2424  * ActiveSnapshot, if any (if there isn't one, we run with no snapshot).
2425  *
2426  * snapshot == InvalidSnapshot, read_only = false: take a full new
2427  * snapshot for each user command, and advance its command ID before each
2428  * querytree within the command.
2429  *
2430  * In the first two cases, we can just push the snap onto the stack once
2431  * for the whole plan list.
2432  *
2433  * Note that snapshot != InvalidSnapshot implies an atomic execution
2434  * context.
2435  */
2436  if (snapshot != InvalidSnapshot)
2437  {
2438  Assert(!options->allow_nonatomic);
2439  if (options->read_only)
2440  {
2441  PushActiveSnapshot(snapshot);
2442  pushed_active_snap = true;
2443  }
2444  else
2445  {
2446  /* Make sure we have a private copy of the snapshot to modify */
2447  PushCopiedSnapshot(snapshot);
2448  pushed_active_snap = true;
2449  }
2450  }
2451 
2452  /*
2453  * Ensure that we have a resource owner if plan is saved, and not if it
2454  * isn't.
2455  */
2456  if (!plan->saved)
2457  plan_owner = NULL;
2458  else if (plan_owner == NULL)
2459  plan_owner = CurrentResourceOwner;
2460 
2461  /*
2462  * We interpret must_return_tuples as "there must be at least one query,
2463  * and all of them must return tuples". This is a bit laxer than
2464  * SPI_is_cursor_plan's check, but there seems no reason to enforce that
2465  * there be only one query.
2466  */
2467  if (options->must_return_tuples && plan->plancache_list == NIL)
2468  ereport(ERROR,
2469  (errcode(ERRCODE_SYNTAX_ERROR),
2470  errmsg("empty query does not return tuples")));
2471 
2472  foreach(lc1, plan->plancache_list)
2473  {
2474  CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc1);
2475  List *stmt_list;
2476  ListCell *lc2;
2477 
2478  spicallbackarg.query = plansource->query_string;
2479 
2480  /*
2481  * If this is a one-shot plan, we still need to do parse analysis.
2482  */
2483  if (plan->oneshot)
2484  {
2485  RawStmt *parsetree = plansource->raw_parse_tree;
2486  const char *src = plansource->query_string;
2487  List *querytree_list;
2488 
2489  /*
2490  * Parameter datatypes are driven by parserSetup hook if provided,
2491  * otherwise we use the fixed parameter list.
2492  */
2493  if (parsetree == NULL)
2494  querytree_list = NIL;
2495  else if (plan->parserSetup != NULL)
2496  {
2497  Assert(plan->nargs == 0);
2498  querytree_list = pg_analyze_and_rewrite_withcb(parsetree,
2499  src,
2500  plan->parserSetup,
2501  plan->parserSetupArg,
2503  }
2504  else
2505  {
2506  querytree_list = pg_analyze_and_rewrite_fixedparams(parsetree,
2507  src,
2508  plan->argtypes,
2509  plan->nargs,
2511  }
2512 
2513  /* Finish filling in the CachedPlanSource */
2514  CompleteCachedPlan(plansource,
2515  querytree_list,
2516  NULL,
2517  plan->argtypes,
2518  plan->nargs,
2519  plan->parserSetup,
2520  plan->parserSetupArg,
2521  plan->cursor_options,
2522  false); /* not fixed result */
2523  }
2524 
2525  /*
2526  * If asked to, complain when query does not return tuples.
2527  * (Replanning can't change this, so we can check it before that.
2528  * However, we can't check it till after parse analysis, so in the
2529  * case of a one-shot plan this is the earliest we could check.)
2530  */
2531  if (options->must_return_tuples && !plansource->resultDesc)
2532  {
2533  /* try to give a good error message */
2534  const char *cmdtag;
2535 
2536  /* A SELECT without resultDesc must be SELECT INTO */
2537  if (plansource->commandTag == CMDTAG_SELECT)
2538  cmdtag = "SELECT INTO";
2539  else
2540  cmdtag = GetCommandTagName(plansource->commandTag);
2541  ereport(ERROR,
2542  (errcode(ERRCODE_SYNTAX_ERROR),
2543  /* translator: %s is name of a SQL command, eg INSERT */
2544  errmsg("%s query does not return tuples", cmdtag)));
2545  }
2546 
2547  /*
2548  * Replan if needed, and increment plan refcount. If it's a saved
2549  * plan, the refcount must be backed by the plan_owner.
2550  */
2551  cplan = GetCachedPlan(plansource, options->params,
2552  plan_owner, _SPI_current->queryEnv);
2553 
2554  stmt_list = cplan->stmt_list;
2555 
2556  /*
2557  * If we weren't given a specific snapshot to use, and the statement
2558  * list requires a snapshot, set that up.
2559  */
2560  if (snapshot == InvalidSnapshot &&
2561  (list_length(stmt_list) > 1 ||
2562  (list_length(stmt_list) == 1 &&
2564  stmt_list)))))
2565  {
2566  /*
2567  * First, ensure there's a Portal-level snapshot. This back-fills
2568  * the snapshot stack in case the previous operation was a COMMIT
2569  * or ROLLBACK inside a procedure or DO block. (We can't put back
2570  * the Portal snapshot any sooner, or we'd break cases like doing
2571  * SET or LOCK just after COMMIT.) It's enough to check once per
2572  * statement list, since COMMIT/ROLLBACK/CALL/DO can't appear
2573  * within a multi-statement list.
2574  */
2576 
2577  /*
2578  * In the default non-read-only case, get a new per-statement-list
2579  * snapshot, replacing any that we pushed in a previous cycle.
2580  * Skip it when doing non-atomic execution, though (we rely
2581  * entirely on the Portal snapshot in that case).
2582  */
2583  if (!options->read_only && !options->allow_nonatomic)
2584  {
2585  if (pushed_active_snap)
2588  pushed_active_snap = true;
2589  }
2590  }
2591 
2592  foreach(lc2, stmt_list)
2593  {
2594  PlannedStmt *stmt = lfirst_node(PlannedStmt, lc2);
2595  bool canSetTag = stmt->canSetTag;
2596  DestReceiver *dest;
2597 
2598  /*
2599  * Reset output state. (Note that if a non-SPI receiver is used,
2600  * _SPI_current->processed will stay zero, and that's what we'll
2601  * report to the caller. It's the receiver's job to count tuples
2602  * in that case.)
2603  */
2604  _SPI_current->processed = 0;
2605  _SPI_current->tuptable = NULL;
2606 
2607  /* Check for unsupported cases. */
2608  if (stmt->utilityStmt)
2609  {
2610  if (IsA(stmt->utilityStmt, CopyStmt))
2611  {
2612  CopyStmt *cstmt = (CopyStmt *) stmt->utilityStmt;
2613 
2614  if (cstmt->filename == NULL)
2615  {
2616  my_res = SPI_ERROR_COPY;
2617  goto fail;
2618  }
2619  }
2620  else if (IsA(stmt->utilityStmt, TransactionStmt))
2621  {
2622  my_res = SPI_ERROR_TRANSACTION;
2623  goto fail;
2624  }
2625  }
2626 
2627  if (options->read_only && !CommandIsReadOnly(stmt))
2628  ereport(ERROR,
2629  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2630  /* translator: %s is a SQL statement name */
2631  errmsg("%s is not allowed in a non-volatile function",
2632  CreateCommandName((Node *) stmt))));
2633 
2634  /*
2635  * If not read-only mode, advance the command counter before each
2636  * command and update the snapshot. (But skip it if the snapshot
2637  * isn't under our control.)
2638  */
2639  if (!options->read_only && pushed_active_snap)
2640  {
2643  }
2644 
2645  /*
2646  * Select appropriate tuple receiver. Output from non-canSetTag
2647  * subqueries always goes to the bit bucket.
2648  */
2649  if (!canSetTag)
2651  else if (options->dest)
2652  dest = options->dest;
2653  else
2655 
2656  if (stmt->utilityStmt == NULL)
2657  {
2658  QueryDesc *qdesc;
2659  Snapshot snap;
2660 
2661  if (ActiveSnapshotSet())
2662  snap = GetActiveSnapshot();
2663  else
2664  snap = InvalidSnapshot;
2665 
2666  qdesc = CreateQueryDesc(stmt,
2667  plansource->query_string,
2668  snap, crosscheck_snapshot,
2669  dest,
2670  options->params,
2672  0);
2673  res = _SPI_pquery(qdesc, fire_triggers,
2674  canSetTag ? options->tcount : 0);
2675  FreeQueryDesc(qdesc);
2676  }
2677  else
2678  {
2679  ProcessUtilityContext context;
2680  QueryCompletion qc;
2681 
2682  /*
2683  * If the SPI context is atomic, or we were not told to allow
2684  * nonatomic operations, tell ProcessUtility this is an atomic
2685  * execution context.
2686  */
2687  if (_SPI_current->atomic || !options->allow_nonatomic)
2688  context = PROCESS_UTILITY_QUERY;
2689  else
2691 
2693  ProcessUtility(stmt,
2694  plansource->query_string,
2695  true, /* protect plancache's node tree */
2696  context,
2697  options->params,
2699  dest,
2700  &qc);
2701 
2702  /* Update "processed" if stmt returned tuples */
2703  if (_SPI_current->tuptable)
2705 
2706  res = SPI_OK_UTILITY;
2707 
2708  /*
2709  * Some utility statements return a row count, even though the
2710  * tuples are not returned to the caller.
2711  */
2712  if (IsA(stmt->utilityStmt, CreateTableAsStmt))
2713  {
2714  CreateTableAsStmt *ctastmt = (CreateTableAsStmt *) stmt->utilityStmt;
2715 
2716  if (qc.commandTag == CMDTAG_SELECT)
2718  else
2719  {
2720  /*
2721  * Must be an IF NOT EXISTS that did nothing, or a
2722  * CREATE ... WITH NO DATA.
2723  */
2724  Assert(ctastmt->if_not_exists ||
2725  ctastmt->into->skipData);
2726  _SPI_current->processed = 0;
2727  }
2728 
2729  /*
2730  * For historical reasons, if CREATE TABLE AS was spelled
2731  * as SELECT INTO, return a special return code.
2732  */
2733  if (ctastmt->is_select_into)
2734  res = SPI_OK_SELINTO;
2735  }
2736  else if (IsA(stmt->utilityStmt, CopyStmt))
2737  {
2738  Assert(qc.commandTag == CMDTAG_COPY);
2740  }
2741  }
2742 
2743  /*
2744  * The last canSetTag query sets the status values returned to the
2745  * caller. Be careful to free any tuptables not returned, to
2746  * avoid intra-transaction memory leak.
2747  */
2748  if (canSetTag)
2749  {
2750  my_processed = _SPI_current->processed;
2751  SPI_freetuptable(my_tuptable);
2752  my_tuptable = _SPI_current->tuptable;
2753  my_res = res;
2754  }
2755  else
2756  {
2758  _SPI_current->tuptable = NULL;
2759  }
2760 
2761  /*
2762  * We don't issue a destroy call to the receiver. The SPI and
2763  * None receivers would ignore it anyway, while if the caller
2764  * supplied a receiver, it's not our job to destroy it.
2765  */
2766 
2767  if (res < 0)
2768  {
2769  my_res = res;
2770  goto fail;
2771  }
2772  }
2773 
2774  /* Done with this plan, so release refcount */
2775  ReleaseCachedPlan(cplan, plan_owner);
2776  cplan = NULL;
2777 
2778  /*
2779  * If not read-only mode, advance the command counter after the last
2780  * command. This ensures that its effects are visible, in case it was
2781  * DDL that would affect the next CachedPlanSource.
2782  */
2783  if (!options->read_only)
2785  }
2786 
2787 fail:
2788 
2789  /* Pop the snapshot off the stack if we pushed one */
2790  if (pushed_active_snap)
2792 
2793  /* We no longer need the cached plan refcount, if any */
2794  if (cplan)
2795  ReleaseCachedPlan(cplan, plan_owner);
2796 
2797  /*
2798  * Pop the error context stack
2799  */
2800  error_context_stack = spierrcontext.previous;
2801 
2802  /* Save results for caller */
2803  SPI_processed = my_processed;
2804  SPI_tuptable = my_tuptable;
2805 
2806  /* tuptable now is caller's responsibility, not SPI's */
2807  _SPI_current->tuptable = NULL;
2808 
2809  /*
2810  * If none of the queries had canSetTag, return SPI_OK_REWRITTEN. Prior to
2811  * 8.4, we used return the last query's result code, but not its auxiliary
2812  * results, but that's confusing.
2813  */
2814  if (my_res == 0)
2815  my_res = SPI_OK_REWRITTEN;
2816 
2817  return my_res;
2818 }
void InitializeQueryCompletion(QueryCompletion *qc)
Definition: cmdtag.c:38
const char * GetCommandTagName(CommandTag commandTag)
Definition: cmdtag.c:45
DestReceiver * CreateDestReceiver(CommandDest dest)
Definition: dest.c:113
@ DestNone
Definition: dest.h:89
ErrorContextCallback * error_context_stack
Definition: elog.c:94
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
Assert(fmt[strlen(fmt) - 1] !='\n')
#define IsA(nodeptr, _type_)
Definition: nodes.h:168
#define lfirst(lc)
Definition: pg_list.h:170
#define lfirst_node(type, lc)
Definition: pg_list.h:174
static int list_length(const List *l)
Definition: pg_list.h:150
#define linitial_node(type, l)
Definition: pg_list.h:179
#define NIL
Definition: pg_list.h:66
void CompleteCachedPlan(CachedPlanSource *plansource, List *querytree_list, MemoryContext querytree_context, Oid *param_types, int num_params, ParserSetupHook parserSetup, void *parserSetupArg, int cursor_options, bool fixed_result)
Definition: plancache.c:338
CachedPlan * GetCachedPlan(CachedPlanSource *plansource, ParamListInfo boundParams, ResourceOwner owner, QueryEnvironment *queryEnv)
Definition: plancache.c:1141
void ReleaseCachedPlan(CachedPlan *plan, ResourceOwner owner)
Definition: plancache.c:1264
List * pg_analyze_and_rewrite_withcb(RawStmt *parsetree, const char *query_string, ParserSetupHook parserSetup, void *parserSetupArg, QueryEnvironment *queryEnv)
Definition: postgres.c:731
List * pg_analyze_and_rewrite_fixedparams(RawStmt *parsetree, const char *query_string, const Oid *paramTypes, int numParams, QueryEnvironment *queryEnv)
Definition: postgres.c:638
void FreeQueryDesc(QueryDesc *qdesc)
Definition: pquery.c:105
bool PlannedStmtRequiresSnapshot(PlannedStmt *pstmt)
Definition: pquery.c:1732
void EnsurePortalSnapshotExists(void)
Definition: pquery.c:1780
QueryDesc * CreateQueryDesc(PlannedStmt *plannedstmt, const char *sourceText, Snapshot snapshot, Snapshot crosscheck_snapshot, DestReceiver *dest, ParamListInfo params, QueryEnvironment *queryEnv, int instrument_options)
Definition: pquery.c:67
ResourceOwner CurrentResourceOwner
Definition: resowner.c:146
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:251
void PushActiveSnapshot(Snapshot snapshot)
Definition: snapmgr.c:683
void UpdateActiveSnapshotCommandId(void)
Definition: snapmgr.c:747
bool ActiveSnapshotSet(void)
Definition: snapmgr.c:817
void PopActiveSnapshot(void)
Definition: snapmgr.c:778
void PushCopiedSnapshot(Snapshot snapshot)
Definition: snapmgr.c:735
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:805
#define InvalidSnapshot
Definition: snapshot.h:123
static void _SPI_error_callback(void *arg)
Definition: spi.c:2933
static int _SPI_pquery(QueryDesc *queryDesc, bool fire_triggers, uint64 tcount)
Definition: spi.c:2849
void SPI_freetuptable(SPITupleTable *tuptable)
Definition: spi.c:1384
#define SPI_ERROR_TRANSACTION
Definition: spi.h:75
#define SPI_OK_UTILITY
Definition: spi.h:85
#define SPI_OK_REWRITTEN
Definition: spi.h:95
#define SPI_OK_SELINTO
Definition: spi.h:87
#define SPI_ERROR_COPY
Definition: spi.h:69
CommandTag commandTag
Definition: plancache.h:101
const char * query_string
Definition: plancache.h:100
struct RawStmt * raw_parse_tree
Definition: plancache.h:99
TupleDesc resultDesc
Definition: plancache.h:108
List * stmt_list
Definition: plancache.h:150
char * filename
Definition: parsenodes.h:2204
IntoClause * into
Definition: parsenodes.h:3500
struct ErrorContextCallback * previous
Definition: elog.h:234
void(* callback)(void *arg)
Definition: elog.h:235
bool skipData
Definition: primnodes.h:135
Definition: pg_list.h:52
Definition: nodes.h:118
bool canSetTag
Definition: plannodes.h:61
Node * utilityStmt
Definition: plannodes.h:96
uint64 nprocessed
Definition: cmdtag.h:31
CommandTag commandTag
Definition: cmdtag.h:30
QueryEnvironment * queryEnv
Definition: spi_priv.h:37
ParserSetupHook parserSetup
Definition: spi_priv.h:101
List * plancache_list
Definition: spi_priv.h:95
bool oneshot
Definition: spi_priv.h:94
bool saved
Definition: spi_priv.h:93
int cursor_options
Definition: spi_priv.h:98
Oid * argtypes
Definition: spi_priv.h:100
int nargs
Definition: spi_priv.h:99
RawParseMode parse_mode
Definition: spi_priv.h:97
void * parserSetupArg
Definition: spi_priv.h:102
void ProcessUtility(PlannedStmt *pstmt, const char *queryString, bool readOnlyTree, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *qc)
Definition: utility.c:506
bool CommandIsReadOnly(PlannedStmt *pstmt)
Definition: utility.c:101
static const char * CreateCommandName(Node *parsetree)
Definition: utility.h:103
ProcessUtilityContext
Definition: utility.h:21
@ PROCESS_UTILITY_QUERY_NONATOMIC
Definition: utility.h:24
@ PROCESS_UTILITY_QUERY
Definition: utility.h:23
void CommandCounterIncrement(void)
Definition: xact.c:1077

References _SPI_current, _SPI_error_callback(), _SPI_pquery(), ActiveSnapshotSet(), ErrorContextCallback::arg, _SPI_plan::argtypes, Assert(), _SPI_connection::atomic, ErrorContextCallback::callback, PlannedStmt::canSetTag, CommandCounterIncrement(), CommandIsReadOnly(), QueryCompletion::commandTag, CachedPlanSource::commandTag, CompleteCachedPlan(), CreateCommandName(), CreateDestReceiver(), CreateQueryDesc(), CurrentResourceOwner, _SPI_plan::cursor_options, generate_unaccent_rules::dest, DestNone, DestSPI, EnsurePortalSnapshotExists(), ereport, errcode(), errmsg(), ERROR, error_context_stack, CopyStmt::filename, FreeQueryDesc(), GetActiveSnapshot(), GetCachedPlan(), GetCommandTagName(), GetTransactionSnapshot(), if(), CreateTableAsStmt::if_not_exists, InitializeQueryCompletion(), CreateTableAsStmt::into, InvalidSnapshot, CreateTableAsStmt::is_select_into, IsA, lfirst, lfirst_node, linitial_node, list_length(), SPICallbackArg::mode, _SPI_plan::nargs, NIL, QueryCompletion::nprocessed, SPITupleTable::numvals, _SPI_plan::oneshot, _SPI_plan::parse_mode, _SPI_plan::parserSetup, _SPI_plan::parserSetupArg, pg_analyze_and_rewrite_fixedparams(), pg_analyze_and_rewrite_withcb(), _SPI_plan::plancache_list, PlannedStmtRequiresSnapshot(), PopActiveSnapshot(), ErrorContextCallback::previous, PROCESS_UTILITY_QUERY, PROCESS_UTILITY_QUERY_NONATOMIC, _SPI_connection::processed, ProcessUtility(), PushActiveSnapshot(), PushCopiedSnapshot(), SPICallbackArg::query, CachedPlanSource::query_string, _SPI_connection::queryEnv, CachedPlanSource::raw_parse_tree, ReleaseCachedPlan(), res, CachedPlanSource::resultDesc, _SPI_plan::saved, IntoClause::skipData, SPI_ERROR_COPY, SPI_ERROR_TRANSACTION, SPI_freetuptable(), SPI_OK_REWRITTEN, SPI_OK_SELINTO, SPI_OK_UTILITY, SPI_processed, SPI_tuptable, CachedPlan::stmt_list, _SPI_connection::tuptable, UpdateActiveSnapshotCommandId(), and PlannedStmt::utilityStmt.

Referenced by SPI_execute(), SPI_execute_extended(), SPI_execute_plan(), SPI_execute_plan_extended(), SPI_execute_plan_with_paramlist(), SPI_execute_snapshot(), and SPI_execute_with_args().

◆ _SPI_find_ENR_by_name()

static EphemeralNamedRelation _SPI_find_ENR_by_name ( const char *  name)
static

Definition at line 3252 of file spi.c.

3253 {
3254  /* internal static function; any error is bug in SPI itself */
3255  Assert(name != NULL);
3256 
3257  /* fast exit if no tuplestores have been added */
3258  if (_SPI_current->queryEnv == NULL)
3259  return NULL;
3260 
3261  return get_ENR(_SPI_current->queryEnv, name);
3262 }
const char * name
Definition: encode.c:561
EphemeralNamedRelation get_ENR(QueryEnvironment *queryEnv, const char *name)

References _SPI_current, Assert(), get_ENR(), name, and _SPI_connection::queryEnv.

Referenced by SPI_register_relation(), and SPI_unregister_relation().

◆ _SPI_make_plan_non_temp()

static SPIPlanPtr _SPI_make_plan_non_temp ( SPIPlanPtr  plan)
static

Definition at line 3113 of file spi.c.

3114 {
3115  SPIPlanPtr newplan;
3116  MemoryContext parentcxt = _SPI_current->procCxt;
3117  MemoryContext plancxt;
3118  MemoryContext oldcxt;
3119  ListCell *lc;
3120 
3121  /* Assert the input is a temporary SPIPlan */
3122  Assert(plan->magic == _SPI_PLAN_MAGIC);
3123  Assert(plan->plancxt == NULL);
3124  /* One-shot plans can't be saved */
3125  Assert(!plan->oneshot);
3126 
3127  /*
3128  * Create a memory context for the plan, underneath the procedure context.
3129  * We don't expect the plan to be very large.
3130  */
3131  plancxt = AllocSetContextCreate(parentcxt,
3132  "SPI Plan",
3134  oldcxt = MemoryContextSwitchTo(plancxt);
3135 
3136  /* Copy the _SPI_plan struct and subsidiary data into the new context */
3137  newplan = (SPIPlanPtr) palloc0(sizeof(_SPI_plan));
3138  newplan->magic = _SPI_PLAN_MAGIC;
3139  newplan->plancxt = plancxt;
3140  newplan->parse_mode = plan->parse_mode;
3141  newplan->cursor_options = plan->cursor_options;
3142  newplan->nargs = plan->nargs;
3143  if (plan->nargs > 0)
3144  {
3145  newplan->argtypes = (Oid *) palloc(plan->nargs * sizeof(Oid));
3146  memcpy(newplan->argtypes, plan->argtypes, plan->nargs * sizeof(Oid));
3147  }
3148  else
3149  newplan->argtypes = NULL;
3150  newplan->parserSetup = plan->parserSetup;
3151  newplan->parserSetupArg = plan->parserSetupArg;
3152 
3153  /*
3154  * Reparent all the CachedPlanSources into the procedure context. In
3155  * theory this could fail partway through due to the pallocs, but we don't
3156  * care too much since both the procedure context and the executor context
3157  * would go away on error.
3158  */
3159  foreach(lc, plan->plancache_list)
3160  {
3161  CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc);
3162 
3163  CachedPlanSetParentContext(plansource, parentcxt);
3164 
3165  /* Build new list, with list cells in plancxt */
3166  newplan->plancache_list = lappend(newplan->plancache_list, plansource);
3167  }
3168 
3169  MemoryContextSwitchTo(oldcxt);
3170 
3171  /* For safety, unlink the CachedPlanSources from the temporary plan */
3172  plan->plancache_list = NIL;
3173 
3174  return newplan;
3175 }
List * lappend(List *list, void *datum)
Definition: list.c:338
void * palloc0(Size size)
Definition: mcxt.c:1230
void * palloc(Size size)
Definition: mcxt.c:1199
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:163
void CachedPlanSetParentContext(CachedPlanSource *plansource, MemoryContext newcontext)
Definition: plancache.c:1469
unsigned int Oid
Definition: postgres_ext.h:31
struct _SPI_plan * SPIPlanPtr
Definition: spi.h:66
#define _SPI_PLAN_MAGIC
Definition: spi_priv.h:20
MemoryContext procCxt
Definition: spi_priv.h:33
int magic
Definition: spi_priv.h:92
MemoryContext plancxt
Definition: spi_priv.h:96

References _SPI_current, _SPI_PLAN_MAGIC, ALLOCSET_SMALL_SIZES, AllocSetContextCreate, _SPI_plan::argtypes, Assert(), CachedPlanSetParentContext(), _SPI_plan::cursor_options, lappend(), lfirst, _SPI_plan::magic, MemoryContextSwitchTo(), _SPI_plan::nargs, NIL, _SPI_plan::oneshot, palloc(), palloc0(), _SPI_plan::parse_mode, _SPI_plan::parserSetup, _SPI_plan::parserSetupArg, _SPI_plan::plancache_list, _SPI_plan::plancxt, and _SPI_connection::procCxt.

Referenced by SPI_prepare_cursor(), SPI_prepare_extended(), and SPI_prepare_params().

◆ _SPI_pquery()

static int _SPI_pquery ( QueryDesc queryDesc,
bool  fire_triggers,
uint64  tcount 
)
static

Definition at line 2849 of file spi.c.

2850 {
2851  int operation = queryDesc->operation;
2852  int eflags;
2853  int res;
2854 
2855  switch (operation)
2856  {
2857  case CMD_SELECT:
2858  if (queryDesc->dest->mydest == DestNone)
2859  {
2860  /* Don't return SPI_OK_SELECT if we're discarding result */
2861  res = SPI_OK_UTILITY;
2862  }
2863  else
2864  res = SPI_OK_SELECT;
2865  break;
2866  case CMD_INSERT:
2867  if (queryDesc->plannedstmt->hasReturning)
2869  else
2870  res = SPI_OK_INSERT;
2871  break;
2872  case CMD_DELETE:
2873  if (queryDesc->plannedstmt->hasReturning)
2875  else
2876  res = SPI_OK_DELETE;
2877  break;
2878  case CMD_UPDATE:
2879  if (queryDesc->plannedstmt->hasReturning)
2881  else
2882  res = SPI_OK_UPDATE;
2883  break;
2884  case CMD_MERGE:
2885  res = SPI_OK_MERGE;
2886  break;
2887  default:
2888  return SPI_ERROR_OPUNKNOWN;
2889  }
2890 
2891 #ifdef SPI_EXECUTOR_STATS
2892  if (ShowExecutorStats)
2893  ResetUsage();
2894 #endif
2895 
2896  /* Select execution options */
2897  if (fire_triggers)
2898  eflags = 0; /* default run-to-completion flags */
2899  else
2900  eflags = EXEC_FLAG_SKIP_TRIGGERS;
2901 
2902  ExecutorStart(queryDesc, eflags);
2903 
2904  ExecutorRun(queryDesc, ForwardScanDirection, tcount, true);
2905 
2906  _SPI_current->processed = queryDesc->estate->es_processed;
2907 
2908  if ((res == SPI_OK_SELECT || queryDesc->plannedstmt->hasReturning) &&
2909  queryDesc->dest->mydest == DestSPI)
2910  {
2911  if (_SPI_checktuples())
2912  elog(ERROR, "consistency check on SPI tuple count failed");
2913  }
2914 
2915  ExecutorFinish(queryDesc);
2916  ExecutorEnd(queryDesc);
2917  /* FreeQueryDesc is done by the caller */
2918 
2919 #ifdef SPI_EXECUTOR_STATS
2920  if (ShowExecutorStats)
2921  ShowUsage("SPI EXECUTOR STATS");
2922 #endif
2923 
2924  return res;
2925 }
void ExecutorEnd(QueryDesc *queryDesc)
Definition: execMain.c:461
void ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:401
void ExecutorStart(QueryDesc *queryDesc, int eflags)
Definition: execMain.c:131
void ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count, bool execute_once)
Definition: execMain.c:300
#define EXEC_FLAG_SKIP_TRIGGERS
Definition: executor.h:60
@ CMD_MERGE
Definition: nodes.h:269
@ CMD_INSERT
Definition: nodes.h:267
@ CMD_DELETE
Definition: nodes.h:268
@ CMD_UPDATE
Definition: nodes.h:266
@ CMD_SELECT
Definition: nodes.h:265
void ShowUsage(const char *title)
Definition: postgres.c:4856
void ResetUsage(void)
Definition: postgres.c:4849
@ ForwardScanDirection
Definition: sdir.h:26
#define SPI_OK_INSERT
Definition: spi.h:88
#define SPI_OK_UPDATE
Definition: spi.h:90
#define SPI_OK_MERGE
Definition: spi.h:99
#define SPI_ERROR_OPUNKNOWN
Definition: spi.h:70
#define SPI_OK_UPDATE_RETURNING
Definition: spi.h:94
#define SPI_OK_DELETE
Definition: spi.h:89
#define SPI_OK_INSERT_RETURNING
Definition: spi.h:92
#define SPI_OK_DELETE_RETURNING
Definition: spi.h:93
#define SPI_OK_SELECT
Definition: spi.h:86
uint64 es_processed
Definition: execnodes.h:659
bool hasReturning
Definition: plannodes.h:57
DestReceiver * dest
Definition: execdesc.h:41
EState * estate
Definition: execdesc.h:48
CmdType operation
Definition: execdesc.h:36
PlannedStmt * plannedstmt
Definition: execdesc.h:37
CommandDest mydest
Definition: dest.h:129

References _SPI_checktuples(), _SPI_current, CMD_DELETE, CMD_INSERT, CMD_MERGE, CMD_SELECT, CMD_UPDATE, QueryDesc::dest, DestNone, DestSPI, elog(), ERROR, EState::es_processed, QueryDesc::estate, EXEC_FLAG_SKIP_TRIGGERS, ExecutorEnd(), ExecutorFinish(), ExecutorRun(), ExecutorStart(), ForwardScanDirection, PlannedStmt::hasReturning, _DestReceiver::mydest, QueryDesc::operation, QueryDesc::plannedstmt, _SPI_connection::processed, res, ResetUsage(), ShowUsage(), SPI_ERROR_OPUNKNOWN, SPI_OK_DELETE, SPI_OK_DELETE_RETURNING, SPI_OK_INSERT, SPI_OK_INSERT_RETURNING, SPI_OK_MERGE, SPI_OK_SELECT, SPI_OK_UPDATE, SPI_OK_UPDATE_RETURNING, and SPI_OK_UTILITY.

Referenced by _SPI_execute_plan().

◆ _SPI_prepare_oneshot_plan()

static void _SPI_prepare_oneshot_plan ( const char *  src,
SPIPlanPtr  plan 
)
static

Definition at line 2319 of file spi.c.

2320 {
2321  List *raw_parsetree_list;
2322  List *plancache_list;
2323  ListCell *list_item;
2324  SPICallbackArg spicallbackarg;
2325  ErrorContextCallback spierrcontext;
2326 
2327  /*
2328  * Setup error traceback support for ereport()
2329  */
2330  spicallbackarg.query = src;
2331  spicallbackarg.mode = plan->parse_mode;
2332  spierrcontext.callback = _SPI_error_callback;
2333  spierrcontext.arg = &spicallbackarg;
2334  spierrcontext.previous = error_context_stack;
2335  error_context_stack = &spierrcontext;
2336 
2337  /*
2338  * Parse the request string into a list of raw parse trees.
2339  */
2340  raw_parsetree_list = raw_parser(src, plan->parse_mode);
2341 
2342  /*
2343  * Construct plancache entries, but don't do parse analysis yet.
2344  */
2345  plancache_list = NIL;
2346 
2347  foreach(list_item, raw_parsetree_list)
2348  {
2349  RawStmt *parsetree = lfirst_node(RawStmt, list_item);
2350  CachedPlanSource *plansource;
2351 
2352  plansource = CreateOneShotCachedPlan(parsetree,
2353  src,
2354  CreateCommandTag(parsetree->stmt));
2355 
2356  plancache_list = lappend(plancache_list, plansource);
2357  }
2358 
2359  plan->plancache_list = plancache_list;
2360  plan->oneshot = true;
2361 
2362  /*
2363  * Pop the error context stack
2364  */
2365  error_context_stack = spierrcontext.previous;
2366 }
List * raw_parser(const char *str, RawParseMode mode)
Definition: parser.c:42
CachedPlanSource * CreateOneShotCachedPlan(RawStmt *raw_parse_tree, const char *query_string, CommandTag commandTag)
Definition: plancache.c:248
Node * stmt
Definition: parsenodes.h:1631
CommandTag CreateCommandTag(Node *parsetree)
Definition: utility.c:2353

References _SPI_error_callback(), ErrorContextCallback::arg, ErrorContextCallback::callback, CreateCommandTag(), CreateOneShotCachedPlan(), error_context_stack, lappend(), lfirst_node, SPICallbackArg::mode, NIL, _SPI_plan::oneshot, _SPI_plan::parse_mode, _SPI_plan::plancache_list, ErrorContextCallback::previous, SPICallbackArg::query, raw_parser(), and RawStmt::stmt.

Referenced by SPI_execute(), SPI_execute_extended(), and SPI_execute_with_args().

◆ _SPI_prepare_plan()

static void _SPI_prepare_plan ( const char *  src,
SPIPlanPtr  plan 
)
static

Definition at line 2211 of file spi.c.

2212 {
2213  List *raw_parsetree_list;
2214  List *plancache_list;
2215  ListCell *list_item;
2216  SPICallbackArg spicallbackarg;
2217  ErrorContextCallback spierrcontext;
2218 
2219  /*
2220  * Setup error traceback support for ereport()
2221  */
2222  spicallbackarg.query = src;
2223  spicallbackarg.mode = plan->parse_mode;
2224  spierrcontext.callback = _SPI_error_callback;
2225  spierrcontext.arg = &spicallbackarg;
2226  spierrcontext.previous = error_context_stack;
2227  error_context_stack = &spierrcontext;
2228 
2229  /*
2230  * Parse the request string into a list of raw parse trees.
2231  */
2232  raw_parsetree_list = raw_parser(src, plan->parse_mode);
2233 
2234  /*
2235  * Do parse analysis and rule rewrite for each raw parsetree, storing the
2236  * results into unsaved plancache entries.
2237  */
2238  plancache_list = NIL;
2239 
2240  foreach(list_item, raw_parsetree_list)
2241  {
2242  RawStmt *parsetree = lfirst_node(RawStmt, list_item);
2243  List *stmt_list;
2244  CachedPlanSource *plansource;
2245 
2246  /*
2247  * Create the CachedPlanSource before we do parse analysis, since it
2248  * needs to see the unmodified raw parse tree.
2249  */
2250  plansource = CreateCachedPlan(parsetree,
2251  src,
2252  CreateCommandTag(parsetree->stmt));
2253 
2254  /*
2255  * Parameter datatypes are driven by parserSetup hook if provided,
2256  * otherwise we use the fixed parameter list.
2257  */
2258  if (plan->parserSetup != NULL)
2259  {
2260  Assert(plan->nargs == 0);
2261  stmt_list = pg_analyze_and_rewrite_withcb(parsetree,
2262  src,
2263  plan->parserSetup,
2264  plan->parserSetupArg,
2266  }
2267  else
2268  {
2269  stmt_list = pg_analyze_and_rewrite_fixedparams(parsetree,
2270  src,
2271  plan->argtypes,
2272  plan->nargs,
2274  }
2275 
2276  /* Finish filling in the CachedPlanSource */
2277  CompleteCachedPlan(plansource,
2278  stmt_list,
2279  NULL,
2280  plan->argtypes,
2281  plan->nargs,
2282  plan->parserSetup,
2283  plan->parserSetupArg,
2284  plan->cursor_options,
2285  false); /* not fixed result */
2286 
2287  plancache_list = lappend(plancache_list, plansource);
2288  }
2289 
2290  plan->plancache_list = plancache_list;
2291  plan->oneshot = false;
2292 
2293  /*
2294  * Pop the error context stack
2295  */
2296  error_context_stack = spierrcontext.previous;
2297 }
CachedPlanSource * CreateCachedPlan(RawStmt *raw_parse_tree, const char *query_string, CommandTag commandTag)
Definition: plancache.c:164

References _SPI_current, _SPI_error_callback(), ErrorContextCallback::arg, _SPI_plan::argtypes, Assert(), ErrorContextCallback::callback, CompleteCachedPlan(), CreateCachedPlan(), CreateCommandTag(), _SPI_plan::cursor_options, error_context_stack, lappend(), lfirst_node, SPICallbackArg::mode, _SPI_plan::nargs, NIL, _SPI_plan::oneshot, _SPI_plan::parse_mode, _SPI_plan::parserSetup, _SPI_plan::parserSetupArg, pg_analyze_and_rewrite_fixedparams(), pg_analyze_and_rewrite_withcb(), _SPI_plan::plancache_list, ErrorContextCallback::previous, SPICallbackArg::query, _SPI_connection::queryEnv, raw_parser(), and RawStmt::stmt.

Referenced by SPI_cursor_open_with_args(), SPI_cursor_parse_open(), SPI_prepare_cursor(), SPI_prepare_extended(), and SPI_prepare_params().

◆ _SPI_procmem()

static MemoryContext _SPI_procmem ( void  )
static

Definition at line 3036 of file spi.c.

3037 {
3039 }

References _SPI_current, MemoryContextSwitchTo(), and _SPI_connection::procCxt.

Referenced by _SPI_end_call(), and spi_dest_startup().

◆ _SPI_rollback()

static void _SPI_rollback ( bool  chain)
static

Definition at line 333 of file spi.c.

334 {
335  MemoryContext oldcontext = CurrentMemoryContext;
337 
338  /* see under SPI_commit() */
339  if (_SPI_current->atomic)
340  ereport(ERROR,
341  (errcode(ERRCODE_INVALID_TRANSACTION_TERMINATION),
342  errmsg("invalid transaction termination")));
343 
344  /* see under SPI_commit() */
345  if (IsSubTransaction())
346  ereport(ERROR,
347  (errcode(ERRCODE_INVALID_TRANSACTION_TERMINATION),
348  errmsg("cannot roll back while a subtransaction is active")));
349 
350  if (chain)
352 
353  /* Catch any error occurring during the ROLLBACK */
354  PG_TRY();
355  {
356  /* Protect current SPI stack entry against deletion */
357  _SPI_current->internal_xact = true;
358 
359  /*
360  * Hold any pinned portals that any PLs might be using. We have to do
361  * this before changing transaction state, since this will run
362  * user-defined code that might throw an error, and in any case
363  * couldn't be run in an already-aborted transaction.
364  */
366 
367  /* Release snapshots associated with portals */
369 
370  /* Do the deed */
372 
373  /* Immediately start a new transaction */
375  if (chain)
377 
378  MemoryContextSwitchTo(oldcontext);
379 
380  _SPI_current->internal_xact = false;
381  }
382  PG_CATCH();
383  {
384  ErrorData *edata;
385 
386  /* Save error info in caller's context */
387  MemoryContextSwitchTo(oldcontext);
388  edata = CopyErrorData();
389  FlushErrorState();
390 
391  /*
392  * Try again to abort the failed transaction. If this fails too,
393  * we'll just propagate the error out ... there's not that much we can
394  * do.
395  */
397 
398  /* ... and start a new one */
400  if (chain)
402 
403  MemoryContextSwitchTo(oldcontext);
404 
405  _SPI_current->internal_xact = false;
406 
407  /* Now that we've cleaned up the transaction, re-throw the error */
408  ReThrowError(edata);
409  }
410  PG_END_TRY();
411 }

References _SPI_current, AbortCurrentTransaction(), _SPI_connection::atomic, CopyErrorData(), CurrentMemoryContext, ereport, errcode(), errmsg(), ERROR, FlushErrorState(), ForgetPortalSnapshots(), HoldPinnedPortals(), _SPI_connection::internal_xact, IsSubTransaction(), MemoryContextSwitchTo(), PG_CATCH, PG_END_TRY, PG_TRY, RestoreTransactionCharacteristics(), ReThrowError(), SaveTransactionCharacteristics(), and StartTransactionCommand().

Referenced by SPI_rollback(), and SPI_rollback_and_chain().

◆ _SPI_save_plan()

static SPIPlanPtr _SPI_save_plan ( SPIPlanPtr  plan)
static

Definition at line 3181 of file spi.c.

3182 {
3183  SPIPlanPtr newplan;
3184  MemoryContext plancxt;
3185  MemoryContext oldcxt;
3186  ListCell *lc;
3187 
3188  /* One-shot plans can't be saved */
3189  Assert(!plan->oneshot);
3190 
3191  /*
3192  * Create a memory context for the plan. We don't expect the plan to be
3193  * very large, so use smaller-than-default alloc parameters. It's a
3194  * transient context until we finish copying everything.
3195  */
3197  "SPI Plan",
3199  oldcxt = MemoryContextSwitchTo(plancxt);
3200 
3201  /* Copy the SPI plan into its own context */
3202  newplan = (SPIPlanPtr) palloc0(sizeof(_SPI_plan));
3203  newplan->magic = _SPI_PLAN_MAGIC;
3204  newplan->plancxt = plancxt;
3205  newplan->parse_mode = plan->parse_mode;
3206  newplan->cursor_options = plan->cursor_options;
3207  newplan->nargs = plan->nargs;
3208  if (plan->nargs > 0)
3209  {
3210  newplan->argtypes = (Oid *) palloc(plan->nargs * sizeof(Oid));
3211  memcpy(newplan->argtypes, plan->argtypes, plan->nargs * sizeof(Oid));
3212  }
3213  else
3214  newplan->argtypes = NULL;
3215  newplan->parserSetup = plan->parserSetup;
3216  newplan->parserSetupArg = plan->parserSetupArg;
3217 
3218  /* Copy all the plancache entries */
3219  foreach(lc, plan->plancache_list)
3220  {
3221  CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc);
3222  CachedPlanSource *newsource;
3223 
3224  newsource = CopyCachedPlan(plansource);
3225  newplan->plancache_list = lappend(newplan->plancache_list, newsource);
3226  }
3227 
3228  MemoryContextSwitchTo(oldcxt);
3229 
3230  /*
3231  * Mark it saved, reparent it under CacheMemoryContext, and mark all the
3232  * component CachedPlanSources as saved. This sequence cannot fail
3233  * partway through, so there's no risk of long-term memory leakage.
3234  */
3235  newplan->saved = true;
3237 
3238  foreach(lc, newplan->plancache_list)
3239  {
3240  CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc);
3241 
3242  SaveCachedPlan(plansource);
3243  }
3244 
3245  return newplan;
3246 }
void MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
Definition: mcxt.c:519
MemoryContext CacheMemoryContext
Definition: mcxt.c:133
void SaveCachedPlan(CachedPlanSource *plansource)
Definition: plancache.c:454
CachedPlanSource * CopyCachedPlan(CachedPlanSource *plansource)
Definition: plancache.c:1507

References _SPI_PLAN_MAGIC, ALLOCSET_SMALL_SIZES, AllocSetContextCreate, _SPI_plan::argtypes, Assert(), CacheMemoryContext, CopyCachedPlan(), CurrentMemoryContext, _SPI_plan::cursor_options, lappend(), lfirst, _SPI_plan::magic, MemoryContextSetParent(), MemoryContextSwitchTo(), _SPI_plan::nargs, _SPI_plan::oneshot, palloc(), palloc0(), _SPI_plan::parse_mode, _SPI_plan::parserSetup, _SPI_plan::parserSetupArg, _SPI_plan::plancache_list, _SPI_plan::plancxt, SaveCachedPlan(), and _SPI_plan::saved.

Referenced by SPI_saveplan().

◆ AtEOSubXact_SPI()

void AtEOSubXact_SPI ( bool  isCommit,
SubTransactionId  mySubid 
)

Definition at line 483 of file spi.c.

484 {
485  bool found = false;
486 
487  while (_SPI_connected >= 0)
488  {
490 
491  if (connection->connectSubid != mySubid)
492  break; /* couldn't be any underneath it either */
493 
494  if (connection->internal_xact)
495  break;
496 
497  found = true;
498 
499  /*
500  * Release procedure memory explicitly (see note in SPI_connect)
501  */
502  if (connection->execCxt)
503  {
505  connection->execCxt = NULL;
506  }
507  if (connection->procCxt)
508  {
510  connection->procCxt = NULL;
511  }
512 
513  /*
514  * Restore outer global variables and pop the stack entry. Unlike
515  * SPI_finish(), we don't risk switching to memory contexts that might
516  * be already gone.
517  */
518  SPI_processed = connection->outer_processed;
519  SPI_tuptable = connection->outer_tuptable;
520  SPI_result = connection->outer_result;
521 
522  _SPI_connected--;
523  if (_SPI_connected < 0)
524  _SPI_current = NULL;
525  else
527  }
528 
529  if (found && isCommit)
531  (errcode(ERRCODE_WARNING),
532  errmsg("subtransaction left non-empty SPI stack"),
533  errhint("Check for missing \"SPI_finish\" calls.")));
534 
535  /*
536  * If we are aborting a subtransaction and there is an open SPI context
537  * surrounding the subxact, clean up to prevent memory leakage.
538  */
539  if (_SPI_current && !isCommit)
540  {
541  slist_mutable_iter siter;
542 
543  /*
544  * Throw away executor state if current executor operation was started
545  * within current subxact (essentially, force a _SPI_end_call(true)).
546  */
547  if (_SPI_current->execSubid >= mySubid)
548  {
551  }
552 
553  /* throw away any tuple tables created within current subxact */
555  {
556  SPITupleTable *tuptable;
557 
558  tuptable = slist_container(SPITupleTable, next, siter.cur);
559  if (tuptable->subid >= mySubid)
560  {
561  /*
562  * If we used SPI_freetuptable() here, its internal search of
563  * the tuptables list would make this operation O(N^2).
564  * Instead, just free the tuptable manually. This should
565  * match what SPI_freetuptable() does.
566  */
567  slist_delete_current(&siter);
568  if (tuptable == _SPI_current->tuptable)
569  _SPI_current->tuptable = NULL;
570  if (tuptable == SPI_tuptable)
571  SPI_tuptable = NULL;
572  MemoryContextDelete(tuptable->tuptabcxt);
573  }
574  }
575  }
576 }
static int32 next
Definition: blutils.c:219
int errhint(const char *fmt,...)
Definition: elog.c:1153
#define WARNING
Definition: elog.h:32
static void slist_delete_current(slist_mutable_iter *iter)
Definition: ilist.h:1021
#define slist_foreach_modify(iter, lhead)
Definition: ilist.h:1085
#define slist_container(type, membername, ptr)
Definition: ilist.h:1043
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:376
static int _SPI_connected
Definition: spi.c:52
static _SPI_connection * _SPI_stack
Definition: spi.c:49
int SPI_result
Definition: spi.c:47
MemoryContext tuptabcxt
Definition: spi.h:31
SubTransactionId subid
Definition: spi.h:33
slist_head tuptables
Definition: spi_priv.h:32
slist_node * cur
Definition: ilist.h:274

References _SPI_connected, _SPI_current, _SPI_stack, slist_mutable_iter::cur, ereport, errcode(), errhint(), errmsg(), _SPI_connection::execCxt, _SPI_connection::execSubid, InvalidSubTransactionId, MemoryContextDelete(), MemoryContextResetAndDeleteChildren, next, slist_container, slist_delete_current(), slist_foreach_modify, SPI_processed, SPI_result, SPI_tuptable, SPITupleTable::subid, SPITupleTable::tuptabcxt, _SPI_connection::tuptable, _SPI_connection::tuptables, and WARNING.

Referenced by AbortSubTransaction(), and CommitSubTransaction().

◆ AtEOXact_SPI()

void AtEOXact_SPI ( bool  isCommit)

Definition at line 429 of file spi.c.

430 {
431  bool found = false;
432 
433  /*
434  * Pop stack entries, stopping if we find one marked internal_xact (that
435  * one belongs to the caller of SPI_commit or SPI_abort).
436  */
437  while (_SPI_connected >= 0)
438  {
440 
441  if (connection->internal_xact)
442  break;
443 
444  found = true;
445 
446  /*
447  * We need not release the procedure's memory contexts explicitly, as
448  * they'll go away automatically when their parent context does; see
449  * notes in SPI_connect_ext.
450  */
451 
452  /*
453  * Restore outer global variables and pop the stack entry. Unlike
454  * SPI_finish(), we don't risk switching to memory contexts that might
455  * be already gone.
456  */
457  SPI_processed = connection->outer_processed;
458  SPI_tuptable = connection->outer_tuptable;
459  SPI_result = connection->outer_result;
460 
461  _SPI_connected--;
462  if (_SPI_connected < 0)
463  _SPI_current = NULL;
464  else
466  }
467 
468  /* We should only find entries to pop during an ABORT. */
469  if (found && isCommit)
471  (errcode(ERRCODE_WARNING),
472  errmsg("transaction left non-empty SPI stack"),
473  errhint("Check for missing \"SPI_finish\" calls.")));
474 }

References _SPI_connected, _SPI_current, _SPI_stack, ereport, errcode(), errhint(), errmsg(), SPI_processed, SPI_result, SPI_tuptable, and WARNING.

Referenced by AbortTransaction(), CommitTransaction(), and PrepareTransaction().

◆ SPI_commit()

void SPI_commit ( void  )

Definition at line 321 of file spi.c.

322 {
323  _SPI_commit(false);
324 }
static void _SPI_commit(bool chain)
Definition: spi.c:228

References _SPI_commit().

Referenced by exec_stmt_commit(), plperl_spi_commit(), pltcl_commit(), and PLy_commit().

◆ SPI_commit_and_chain()

void SPI_commit_and_chain ( void  )

Definition at line 327 of file spi.c.

328 {
329  _SPI_commit(true);
330 }

References _SPI_commit().

Referenced by exec_stmt_commit().

◆ SPI_connect()

◆ SPI_connect_ext()

int SPI_connect_ext ( int  options)

Definition at line 101 of file spi.c.

102 {
103  int newdepth;
104 
105  /* Enlarge stack if necessary */
106  if (_SPI_stack == NULL)
107  {
108  if (_SPI_connected != -1 || _SPI_stack_depth != 0)
109  elog(ERROR, "SPI stack corrupted");
110  newdepth = 16;
113  newdepth * sizeof(_SPI_connection));
114  _SPI_stack_depth = newdepth;
115  }
116  else
117  {
119  elog(ERROR, "SPI stack corrupted");
120  if (_SPI_stack_depth == _SPI_connected + 1)
121  {
122  newdepth = _SPI_stack_depth * 2;
125  newdepth * sizeof(_SPI_connection));
126  _SPI_stack_depth = newdepth;
127  }
128  }
129 
130  /* Enter new stack level */
131  _SPI_connected++;
133 
135  _SPI_current->processed = 0;
136  _SPI_current->tuptable = NULL;
139  _SPI_current->procCxt = NULL; /* in case we fail to create 'em */
140  _SPI_current->execCxt = NULL;
142  _SPI_current->queryEnv = NULL;
144  _SPI_current->internal_xact = false;
148 
149  /*
150  * Create memory contexts for this procedure
151  *
152  * In atomic contexts (the normal case), we use TopTransactionContext,
153  * otherwise PortalContext, so that it lives across transaction
154  * boundaries.
155  *
156  * XXX It could be better to use PortalContext as the parent context in
157  * all cases, but we may not be inside a portal (consider deferred-trigger
158  * execution). Perhaps CurTransactionContext could be an option? For now
159  * it doesn't matter because we clean up explicitly in AtEOSubXact_SPI();
160  * but see also AtEOXact_SPI().
161  */
163  "SPI Proc",
166  "SPI Exec",
168  /* ... and switch to procedure's context */
170 
171  /*
172  * Reset API global variables so that current caller cannot accidentally
173  * depend on state of an outer caller.
174  */
175  SPI_processed = 0;
176  SPI_tuptable = NULL;
177  SPI_result = 0;
178 
179  return SPI_OK_CONNECT;
180 }
static void slist_init(slist_head *head)
Definition: ilist.h:923
return false
Definition: isn.c:131
MemoryContext TopTransactionContext
Definition: mcxt.c:135
MemoryContext TopMemoryContext
Definition: mcxt.c:130
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1321
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:994
MemoryContext PortalContext
Definition: mcxt.c:139
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:153
static int _SPI_stack_depth
Definition: spi.c:51
#define SPI_OPT_NONATOMIC
Definition: spi.h:101
#define SPI_OK_CONNECT
Definition: spi.h:82
SubTransactionId connectSubid
Definition: spi_priv.h:36
SPITupleTable * outer_tuptable
Definition: spi_priv.h:47
int outer_result
Definition: spi_priv.h:48
uint64 outer_processed
Definition: spi_priv.h:46
MemoryContext savedcxt
Definition: spi_priv.h:35

References _SPI_connected, _SPI_current, _SPI_stack, _SPI_stack_depth, ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert(), _SPI_connection::atomic, _SPI_connection::connectSubid, elog(), ERROR, _SPI_connection::execCxt, _SPI_connection::execSubid, false, GetCurrentSubTransactionId(), _SPI_connection::internal_xact, InvalidSubTransactionId, MemoryContextAlloc(), MemoryContextSwitchTo(), _SPI_connection::outer_processed, _SPI_connection::outer_result, _SPI_connection::outer_tuptable, PortalContext, _SPI_connection::procCxt, _SPI_connection::processed, _SPI_connection::queryEnv, repalloc(), _SPI_connection::savedcxt, slist_init(), SPI_OK_CONNECT, SPI_OPT_NONATOMIC, SPI_processed, SPI_result, SPI_tuptable, TopMemoryContext, TopTransactionContext, _SPI_connection::tuptable, and _SPI_connection::tuptables.

Referenced by plperl_func_handler(), plperl_inline_handler(), plpgsql_call_handler(), plpgsql_inline_handler(), plpython3_call_handler(), plpython3_inline_handler(), pltcl_func_handler(), and SPI_connect().

◆ SPI_copytuple()

HeapTuple SPI_copytuple ( HeapTuple  tuple)

Definition at line 1045 of file spi.c.

1046 {
1047  MemoryContext oldcxt;
1048  HeapTuple ctuple;
1049 
1050  if (tuple == NULL)
1051  {
1053  return NULL;
1054  }
1055 
1056  if (_SPI_current == NULL)
1057  {
1059  return NULL;
1060  }
1061 
1063 
1064  ctuple = heap_copytuple(tuple);
1065 
1066  MemoryContextSwitchTo(oldcxt);
1067 
1068  return ctuple;
1069 }
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:680
#define SPI_ERROR_ARGUMENT
Definition: spi.h:73

References _SPI_current, heap_copytuple(), MemoryContextSwitchTo(), _SPI_connection::savedcxt, SPI_ERROR_ARGUMENT, SPI_ERROR_UNCONNECTED, and SPI_result.

Referenced by get_tuple_of_interest(), and plpgsql_exec_trigger().

◆ SPI_cursor_close()

void SPI_cursor_close ( Portal  portal)

Definition at line 1860 of file spi.c.

1861 {
1862  if (!PortalIsValid(portal))
1863  elog(ERROR, "invalid portal in SPI cursor operation");
1864 
1865  PortalDrop(portal, false);
1866 }
void PortalDrop(Portal portal, bool isTopCommit)
Definition: portalmem.c:469

References elog(), ERROR, PortalDrop(), and PortalIsValid.

Referenced by exec_stmt_close(), exec_stmt_dynfors(), exec_stmt_forc(), exec_stmt_fors(), plperl_spi_cursor_close(), plperl_spi_fetchrow(), PLy_cursor_close(), PLy_cursor_dealloc(), query_to_xml_and_xmlschema(), query_to_xmlschema(), ts_stat_sql(), and tsquery_rewrite_query().

◆ SPI_cursor_fetch()

void SPI_cursor_fetch ( Portal  portal,
bool  forward,
long  count 
)

Definition at line 1804 of file spi.c.

1805 {
1806  _SPI_cursor_operation(portal,
1807  forward ? FETCH_FORWARD : FETCH_BACKWARD, count,
1809  /* we know that the DestSPI receiver doesn't need a destroy call */
1810 }
@ FETCH_FORWARD
Definition: parsenodes.h:2936
@ FETCH_BACKWARD
Definition: parsenodes.h:2937
static void _SPI_cursor_operation(Portal portal, FetchDirection direction, long count, DestReceiver *dest)
Definition: spi.c:2979

References _SPI_cursor_operation(), CreateDestReceiver(), DestSPI, FETCH_BACKWARD, and FETCH_FORWARD.

Referenced by cursor_to_xml(), exec_for_query(), plperl_spi_fetchrow(), PLy_cursor_fetch(), PLy_cursor_iternext(), ts_stat_sql(), and tsquery_rewrite_query().

◆ SPI_cursor_find()

Portal SPI_cursor_find ( const char *  name)

Definition at line 1792 of file spi.c.

1793 {
1794  return GetPortalByName(name);
1795 }
Portal GetPortalByName(const char *name)
Definition: portalmem.c:131

References GetPortalByName(), and name.

Referenced by cursor_to_xml(), cursor_to_xmlschema(), exec_stmt_close(), exec_stmt_fetch(), exec_stmt_forc(), exec_stmt_open(), plperl_spi_cursor_close(), and plperl_spi_fetchrow().

◆ SPI_cursor_move()

void SPI_cursor_move ( Portal  portal,
bool  forward,
long  count 
)

Definition at line 1819 of file spi.c.

1820 {
1821  _SPI_cursor_operation(portal,
1822  forward ? FETCH_FORWARD : FETCH_BACKWARD, count,
1823  None_Receiver);
1824 }
DestReceiver * None_Receiver
Definition: dest.c:96

References _SPI_cursor_operation(), FETCH_BACKWARD, FETCH_FORWARD, and None_Receiver.

◆ SPI_cursor_open()

Portal SPI_cursor_open ( const char *  name,
SPIPlanPtr  plan,
Datum Values,
const char *  Nulls,
bool  read_only 
)

Definition at line 1443 of file spi.c.

1446 {
1447  Portal portal;
1448  ParamListInfo paramLI;
1449 
1450  /* build transient ParamListInfo in caller's context */
1451  paramLI = _SPI_convert_params(plan->nargs, plan->argtypes,
1452  Values, Nulls);
1453 
1454  portal = SPI_cursor_open_internal(name, plan, paramLI, read_only);
1455 
1456  /* done with the transient ParamListInfo */
1457  if (paramLI)
1458  pfree(paramLI);
1459 
1460  return portal;
1461 }
void pfree(void *pointer)
Definition: mcxt.c:1306
static ParamListInfo _SPI_convert_params(int nargs, Oid *argtypes, Datum *Values, const char *Nulls)
Definition: spi.c:2824
static Portal SPI_cursor_open_internal(const char *name, SPIPlanPtr plan, ParamListInfo paramLI, bool read_only)
Definition: spi.c:1575

References _SPI_convert_params(), _SPI_plan::argtypes, name, _SPI_plan::nargs, Nulls, pfree(), and SPI_cursor_open_internal().

Referenced by plperl_spi_query(), plperl_spi_query_prepared(), PLy_cursor_plan(), PLy_cursor_query(), query_to_xml_and_xmlschema(), query_to_xmlschema(), ts_stat_sql(), and tsquery_rewrite_query().

◆ SPI_cursor_open_internal()

static Portal SPI_cursor_open_internal ( const char *  name,
SPIPlanPtr  plan,
ParamListInfo  paramLI,
bool  read_only 
)
static

Definition at line 1575 of file spi.c.

1577 {
1578  CachedPlanSource *plansource;
1579  CachedPlan *cplan;
1580  List *stmt_list;
1581  char *query_string;
1582  Snapshot snapshot;
1583  MemoryContext oldcontext;
1584  Portal portal;
1585  SPICallbackArg spicallbackarg;
1586  ErrorContextCallback spierrcontext;
1587 
1588  /*
1589  * Check that the plan is something the Portal code will special-case as
1590  * returning one tupleset.
1591  */
1592  if (!SPI_is_cursor_plan(plan))
1593  {
1594  /* try to give a good error message */
1595  const char *cmdtag;
1596 
1597  if (list_length(plan->plancache_list) != 1)
1598  ereport(ERROR,
1599  (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
1600  errmsg("cannot open multi-query plan as cursor")));
1601  plansource = (CachedPlanSource *) linitial(plan->plancache_list);
1602  /* A SELECT that fails SPI_is_cursor_plan() must be SELECT INTO */
1603  if (plansource->commandTag == CMDTAG_SELECT)
1604  cmdtag = "SELECT INTO";
1605  else
1606  cmdtag = GetCommandTagName(plansource->commandTag);
1607  ereport(ERROR,
1608  (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
1609  /* translator: %s is name of a SQL command, eg INSERT */
1610  errmsg("cannot open %s query as cursor", cmdtag)));
1611  }
1612 
1613  Assert(list_length(plan->plancache_list) == 1);
1614  plansource = (CachedPlanSource *) linitial(plan->plancache_list);
1615 
1616  /* Push the SPI stack */
1617  if (_SPI_begin_call(true) < 0)
1618  elog(ERROR, "SPI_cursor_open called while not connected");
1619 
1620  /* Reset SPI result (note we deliberately don't touch lastoid) */
1621  SPI_processed = 0;
1622  SPI_tuptable = NULL;
1623  _SPI_current->processed = 0;
1624  _SPI_current->tuptable = NULL;
1625 
1626  /* Create the portal */
1627  if (name == NULL || name[0] == '\0')
1628  {
1629  /* Use a random nonconflicting name */
1630  portal = CreateNewPortal();
1631  }
1632  else
1633  {
1634  /* In this path, error if portal of same name already exists */
1635  portal = CreatePortal(name, false, false);
1636  }
1637 
1638  /* Copy the plan's query string into the portal */
1639  query_string = MemoryContextStrdup(portal->portalContext,
1640  plansource->query_string);
1641 
1642  /*
1643  * Setup error traceback support for ereport(), in case GetCachedPlan
1644  * throws an error.
1645  */
1646  spicallbackarg.query = plansource->query_string;
1647  spicallbackarg.mode = plan->parse_mode;
1648  spierrcontext.callback = _SPI_error_callback;
1649  spierrcontext.arg = &spicallbackarg;
1650  spierrcontext.previous = error_context_stack;
1651  error_context_stack = &spierrcontext;
1652 
1653  /*
1654  * Note: for a saved plan, we mustn't have any failure occur between
1655  * GetCachedPlan and PortalDefineQuery; that would result in leaking our
1656  * plancache refcount.
1657  */
1658 
1659  /* Replan if needed, and increment plan refcount for portal */
1660  cplan = GetCachedPlan(plansource, paramLI, NULL, _SPI_current->queryEnv);
1661  stmt_list = cplan->stmt_list;
1662 
1663  if (!plan->saved)
1664  {
1665  /*
1666  * We don't want the portal to depend on an unsaved CachedPlanSource,
1667  * so must copy the plan into the portal's context. An error here
1668  * will result in leaking our refcount on the plan, but it doesn't
1669  * matter because the plan is unsaved and hence transient anyway.
1670  */
1671  oldcontext = MemoryContextSwitchTo(portal->portalContext);
1672  stmt_list = copyObject(stmt_list);
1673  MemoryContextSwitchTo(oldcontext);
1674  ReleaseCachedPlan(cplan, NULL);
1675  cplan = NULL; /* portal shouldn't depend on cplan */
1676  }
1677 
1678  /*
1679  * Set up the portal.
1680  */
1681  PortalDefineQuery(portal,
1682  NULL, /* no statement name */
1683  query_string,
1684  plansource->commandTag,
1685  stmt_list,
1686  cplan);
1687 
1688  /*
1689  * Set up options for portal. Default SCROLL type is chosen the same way
1690  * as PerformCursorOpen does it.
1691  */
1692  portal->cursorOptions = plan->cursor_options;
1694  {
1695  if (list_length(stmt_list) == 1 &&
1696  linitial_node(PlannedStmt, stmt_list)->commandType != CMD_UTILITY &&
1697  linitial_node(PlannedStmt, stmt_list)->rowMarks == NIL &&
1698  ExecSupportsBackwardScan(linitial_node(PlannedStmt, stmt_list)->planTree))
1699  portal->cursorOptions |= CURSOR_OPT_SCROLL;
1700  else
1702  }
1703 
1704  /*
1705  * Disallow SCROLL with SELECT FOR UPDATE. This is not redundant with the
1706  * check in transformDeclareCursorStmt because the cursor options might
1707  * not have come through there.
1708  */
1709  if (portal->cursorOptions & CURSOR_OPT_SCROLL)
1710  {
1711  if (list_length(stmt_list) == 1 &&
1712  linitial_node(PlannedStmt, stmt_list)->commandType != CMD_UTILITY &&
1713  linitial_node(PlannedStmt, stmt_list)->rowMarks != NIL)
1714  ereport(ERROR,
1715  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1716  errmsg("DECLARE SCROLL CURSOR ... FOR UPDATE/SHARE is not supported"),
1717  errdetail("Scrollable cursors must be READ ONLY.")));
1718  }
1719 
1720  /* Make current query environment available to portal at execution time. */
1721  portal->queryEnv = _SPI_current->queryEnv;
1722 
1723  /*
1724  * If told to be read-only, we'd better check for read-only queries. This
1725  * can't be done earlier because we need to look at the finished, planned
1726  * queries. (In particular, we don't want to do it between GetCachedPlan
1727  * and PortalDefineQuery, because throwing an error between those steps
1728  * would result in leaking our plancache refcount.)
1729  */
1730  if (read_only)
1731  {
1732  ListCell *lc;
1733 
1734  foreach(lc, stmt_list)
1735  {
1736  PlannedStmt *pstmt = lfirst_node(PlannedStmt, lc);
1737 
1738  if (!CommandIsReadOnly(pstmt))
1739  ereport(ERROR,
1740  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1741  /* translator: %s is a SQL statement name */
1742  errmsg("%s is not allowed in a non-volatile function",
1743  CreateCommandName((Node *) pstmt))));
1744  }
1745  }
1746 
1747  /* Set up the snapshot to use. */
1748  if (read_only)
1749  snapshot = GetActiveSnapshot();
1750  else
1751  {
1753  snapshot = GetTransactionSnapshot();
1754  }
1755 
1756  /*
1757  * If the plan has parameters, copy them into the portal. Note that this
1758  * must be done after revalidating the plan, because in dynamic parameter
1759  * cases the set of parameters could have changed during re-parsing.
1760  */
1761  if (paramLI)
1762  {
1763  oldcontext = MemoryContextSwitchTo(portal->portalContext);
1764  paramLI = copyParamList(paramLI);
1765  MemoryContextSwitchTo(oldcontext);
1766  }
1767 
1768  /*
1769  * Start portal execution.
1770  */
1771  PortalStart(portal, paramLI, 0, snapshot);
1772 
1773  Assert(portal->strategy != PORTAL_MULTI_QUERY);
1774 
1775  /* Pop the error context stack */
1776  error_context_stack = spierrcontext.previous;
1777 
1778  /* Pop the SPI stack */
1779  _SPI_end_call(true);
1780 
1781  /* Return the created portal */
1782  return portal;
1783 }
int errdetail(const char *fmt,...)
Definition: elog.c:1039
bool ExecSupportsBackwardScan(Plan *node)
Definition: execAmi.c:512
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1470
#define copyObject(obj)
Definition: nodes.h:233
@ CMD_UTILITY
Definition: nodes.h:270
ParamListInfo copyParamList(ParamListInfo from)
Definition: params.c:78
#define CURSOR_OPT_SCROLL
Definition: parsenodes.h:2899
#define CURSOR_OPT_NO_SCROLL
Definition: parsenodes.h:2900
#define linitial(l)
Definition: pg_list.h:176
@ PORTAL_MULTI_QUERY
Definition: portal.h:95
Portal CreateNewPortal(void)
Definition: portalmem.c:236
void PortalDefineQuery(Portal portal, const char *prepStmtName, const char *sourceText, CommandTag commandTag, List *stmts, CachedPlan *cplan)
Definition: portalmem.c:283
Portal CreatePortal(const char *name, bool allowDup, bool dupSilent)
Definition: portalmem.c:176
void PortalStart(Portal portal, ParamListInfo params, int eflags, Snapshot snapshot)
Definition: pquery.c:433
bool SPI_is_cursor_plan(SPIPlanPtr plan)
Definition: spi.c:1908
QueryEnvironment * queryEnv
Definition: portal.h:143
MemoryContext portalContext
Definition: portal.h:120
int cursorOptions
Definition: portal.h:147
PortalStrategy strategy
Definition: portal.h:146

References _SPI_begin_call(), _SPI_current, _SPI_end_call(), _SPI_error_callback(), ErrorContextCallback::arg, Assert(), ErrorContextCallback::callback, CMD_UTILITY, CommandCounterIncrement(), CommandIsReadOnly(), CachedPlanSource::commandTag, copyObject, copyParamList(), CreateCommandName(), CreateNewPortal(), CreatePortal(), CURSOR_OPT_NO_SCROLL, CURSOR_OPT_SCROLL, _SPI_plan::cursor_options, PortalData::cursorOptions, elog(), ereport, errcode(), errdetail(), errmsg(), ERROR, error_context_stack, ExecSupportsBackwardScan(), GetActiveSnapshot(), GetCachedPlan(), GetCommandTagName(), GetTransactionSnapshot(), lfirst_node, linitial, linitial_node, list_length(), MemoryContextStrdup(), MemoryContextSwitchTo(), SPICallbackArg::mode, name, NIL, _SPI_plan::parse_mode, _SPI_plan::plancache_list, PORTAL_MULTI_QUERY, PortalData::portalContext, PortalDefineQuery(), PortalStart(), ErrorContextCallback::previous, _SPI_connection::processed, SPICallbackArg::query, CachedPlanSource::query_string, _SPI_connection::queryEnv, PortalData::queryEnv, ReleaseCachedPlan(), _SPI_plan::saved, SPI_is_cursor_plan(), SPI_processed, SPI_tuptable, CachedPlan::stmt_list, PortalData::strategy, and _SPI_connection::tuptable.

Referenced by SPI_cursor_open(), SPI_cursor_open_with_args(), SPI_cursor_open_with_paramlist(), and SPI_cursor_parse_open().

◆ SPI_cursor_open_with_args()

Portal SPI_cursor_open_with_args ( const char *  name,
const char *  src,
int  nargs,
Oid argtypes,
Datum Values,
const char *  Nulls,
bool  read_only,
int  cursorOptions 
)

Definition at line 1470 of file spi.c.

1475 {
1476  Portal result;
1477  _SPI_plan plan;
1478  ParamListInfo paramLI;
1479 
1480  if (src == NULL || nargs < 0)
1481  elog(ERROR, "SPI_cursor_open_with_args called with invalid arguments");
1482 
1483  if (nargs > 0 && (argtypes == NULL || Values == NULL))
1484  elog(ERROR, "SPI_cursor_open_with_args called with missing parameters");
1485 
1486  SPI_result = _SPI_begin_call(true);
1487  if (SPI_result < 0)
1488  elog(ERROR, "SPI_cursor_open_with_args called while not connected");
1489 
1490  memset(&plan, 0, sizeof(_SPI_plan));
1491  plan.magic = _SPI_PLAN_MAGIC;
1493  plan.cursor_options = cursorOptions;
1494  plan.nargs = nargs;
1495  plan.argtypes = argtypes;
1496  plan.parserSetup = NULL;
1497  plan.parserSetupArg = NULL;
1498 
1499  /* build transient ParamListInfo in executor context */
1500  paramLI = _SPI_convert_params(nargs, argtypes,
1501  Values, Nulls);
1502 
1503  _SPI_prepare_plan(src, &plan);
1504 
1505  /* We needn't copy the plan; SPI_cursor_open_internal will do so */
1506 
1507  result = SPI_cursor_open_internal(name, &plan, paramLI, read_only);
1508 
1509  /* And clean up */
1510  _SPI_end_call(true);
1511 
1512  return result;
1513 }
@ RAW_PARSE_DEFAULT
Definition: parser.h:39
static void _SPI_prepare_plan(const char *src, SPIPlanPtr plan)
Definition: spi.c:2211

References _SPI_begin_call(), _SPI_convert_params(), _SPI_end_call(), _SPI_PLAN_MAGIC, _SPI_prepare_plan(), _SPI_plan::argtypes, _SPI_plan::cursor_options, elog(), ERROR, _SPI_plan::magic, name, _SPI_plan::nargs, Nulls, _SPI_plan::parse_mode, _SPI_plan::parserSetup, _SPI_plan::parserSetupArg, RAW_PARSE_DEFAULT, SPI_cursor_open_internal(), and SPI_result.

◆ SPI_cursor_open_with_paramlist()

Portal SPI_cursor_open_with_paramlist ( const char *  name,
SPIPlanPtr  plan,
ParamListInfo  params,
bool  read_only 
)

Definition at line 1523 of file spi.c.

1525 {
1526  return SPI_cursor_open_internal(name, plan, params, read_only);
1527 }

References name, and SPI_cursor_open_internal().

Referenced by exec_run_select(), exec_stmt_forc(), and exec_stmt_open().

◆ SPI_cursor_parse_open()

Portal SPI_cursor_parse_open ( const char *  name,
const char *  src,
const SPIParseOpenOptions options 
)

Definition at line 1531 of file spi.c.

1534 {
1535  Portal result;
1536  _SPI_plan plan;
1537 
1538  if (src == NULL || options == NULL)
1539  elog(ERROR, "SPI_cursor_parse_open called with invalid arguments");
1540 
1541  SPI_result = _SPI_begin_call(true);
1542  if (SPI_result < 0)
1543  elog(ERROR, "SPI_cursor_parse_open called while not connected");
1544 
1545  memset(&plan, 0, sizeof(_SPI_plan));
1546  plan.magic = _SPI_PLAN_MAGIC;
1548  plan.cursor_options = options->cursorOptions;
1549  if (options->params)
1550  {
1551  plan.parserSetup = options->params->parserSetup;
1552  plan.parserSetupArg = options->params->parserSetupArg;
1553  }
1554 
1555  _SPI_prepare_plan(src, &plan);
1556 
1557  /* We needn't copy the plan; SPI_cursor_open_internal will do so */
1558 
1559  result = SPI_cursor_open_internal(name, &plan,
1560  options->params, options->read_only);
1561 
1562  /* And clean up */
1563  _SPI_end_call(true);
1564 
1565  return result;
1566 }

References _SPI_begin_call(), _SPI_end_call(), _SPI_PLAN_MAGIC, _SPI_prepare_plan(), _SPI_plan::cursor_options, elog(), ERROR, _SPI_plan::magic, name, _SPI_plan::parse_mode, _SPI_plan::parserSetup, _SPI_plan::parserSetupArg, RAW_PARSE_DEFAULT, SPI_cursor_open_internal(), and SPI_result.

Referenced by exec_dynquery_with_params().

◆ SPI_datumTransfer()

Datum SPI_datumTransfer ( Datum  value,
bool  typByVal,
int  typLen 
)

Definition at line 1359 of file spi.c.

1360 {
1361  MemoryContext oldcxt;
1362  Datum result;
1363 
1364  if (_SPI_current == NULL)
1365  elog(ERROR, "SPI_datumTransfer called while not connected to SPI");
1366 
1368 
1369  result = datumTransfer(value, typByVal, typLen);
1370 
1371  MemoryContextSwitchTo(oldcxt);
1372 
1373  return result;
1374 }
Datum datumTransfer(Datum value, bool typByVal, int typLen)
Definition: datum.c:194
static struct @143 value
uintptr_t Datum
Definition: postgres.h:412

References _SPI_current, datumTransfer(), elog(), ERROR, MemoryContextSwitchTo(), _SPI_connection::savedcxt, and value.

Referenced by coerce_function_result_tuple(), and plpgsql_exec_function().

◆ spi_dest_startup()

void spi_dest_startup ( DestReceiver self,
int  operation,
TupleDesc  typeinfo 
)

Definition at line 2113 of file spi.c.

2114 {
2115  SPITupleTable *tuptable;
2116  MemoryContext oldcxt;
2117  MemoryContext tuptabcxt;
2118 
2119  if (_SPI_current == NULL)
2120  elog(ERROR, "spi_dest_startup called while not connected to SPI");
2121 
2122  if (_SPI_current->tuptable != NULL)
2123  elog(ERROR, "improper call to spi_dest_startup");
2124 
2125  /* We create the tuple table context as a child of procCxt */
2126 
2127  oldcxt = _SPI_procmem(); /* switch to procedure memory context */
2128 
2130  "SPI TupTable",
2132  MemoryContextSwitchTo(tuptabcxt);
2133 
2134  _SPI_current->tuptable = tuptable = (SPITupleTable *)
2135  palloc0(sizeof(SPITupleTable));
2136  tuptable->tuptabcxt = tuptabcxt;
2137  tuptable->subid = GetCurrentSubTransactionId();
2138 
2139  /*
2140  * The tuptable is now valid enough to be freed by AtEOSubXact_SPI, so put
2141  * it onto the SPI context's tuptables list. This will ensure it's not
2142  * leaked even in the unlikely event the following few lines fail.
2143  */
2144  slist_push_head(&_SPI_current->tuptables, &tuptable->next);
2145 
2146  /* set up initial allocations */
2147  tuptable->alloced = 128;
2148  tuptable->vals = (HeapTuple *) palloc(tuptable->alloced * sizeof(HeapTuple));
2149  tuptable->numvals = 0;
2150  tuptable->tupdesc = CreateTupleDescCopy(typeinfo);
2151 
2152  MemoryContextSwitchTo(oldcxt);
2153 }
static void slist_push_head(slist_head *head, slist_node *node)
Definition: ilist.h:943
uint64 alloced
Definition: spi.h:30
TupleDesc tupdesc
Definition: spi.h:25
HeapTuple * vals
Definition: spi.h:26
slist_node next
Definition: spi.h:32
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:111

References _SPI_current, _SPI_procmem(), SPITupleTable::alloced, ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, CreateTupleDescCopy(), CurrentMemoryContext, elog(), ERROR, GetCurrentSubTransactionId(), MemoryContextSwitchTo(), SPITupleTable::next, SPITupleTable::numvals, palloc(), palloc0(), slist_push_head(), SPITupleTable::subid, SPITupleTable::tupdesc, SPITupleTable::tuptabcxt, _SPI_connection::tuptable, _SPI_connection::tuptables, and SPITupleTable::vals.

◆ SPI_exec()

int SPI_exec ( const char *  src,
long  tcount 
)

Definition at line 628 of file spi.c.

629 {
630  return SPI_execute(src, false, tcount);
631 }
int SPI_execute(const char *src, bool read_only, long tcount)
Definition: spi.c:594

References SPI_execute().

Referenced by get_tuple_of_interest(), refresh_by_match_merge(), and xpath_table().

◆ SPI_execp()

int SPI_execp ( SPIPlanPtr  plan,
Datum Values,
const char *  Nulls,
long  tcount 
)

Definition at line 702 of file spi.c.

703 {
704  return SPI_execute_plan(plan, Values, Nulls, false, tcount);
705 }
int SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls, bool read_only, long tcount)
Definition: spi.c:670

References Nulls, and SPI_execute_plan().

Referenced by check_foreign_key(), check_primary_key(), and ttdummy().

◆ SPI_execute()

int SPI_execute ( const char *  src,
bool  read_only,
long  tcount 
)

Definition at line 594 of file spi.c.

595 {
596  _SPI_plan plan;
598  int res;
599 
600  if (src == NULL || tcount < 0)
601  return SPI_ERROR_ARGUMENT;
602 
603  res = _SPI_begin_call(true);
604  if (res < 0)
605  return res;
606 
607  memset(&plan, 0, sizeof(_SPI_plan));
608  plan.magic = _SPI_PLAN_MAGIC;
611 
612  _SPI_prepare_oneshot_plan(src, &plan);
613 
614  memset(&options, 0, sizeof(options));
615  options.read_only = read_only;
616  options.tcount = tcount;
617 
618  res = _SPI_execute_plan(&plan, &options,
620  true);
621 
622  _SPI_end_call(true);
623  return res;
624 }
#define CURSOR_OPT_PARALLEL_OK
Definition: parsenodes.h:2908
static char ** options
static int _SPI_execute_plan(SPIPlanPtr plan, const SPIExecuteOptions *options, Snapshot snapshot, Snapshot crosscheck_snapshot, bool fire_triggers)
Definition: spi.c:2389
static void _SPI_prepare_oneshot_plan(const char *src, SPIPlanPtr plan)
Definition: spi.c:2319

References _SPI_begin_call(), _SPI_end_call(), _SPI_execute_plan(), _SPI_PLAN_MAGIC, _SPI_prepare_oneshot_plan(), CURSOR_OPT_PARALLEL_OK, _SPI_plan::cursor_options, InvalidSnapshot, _SPI_plan::magic, options, _SPI_plan::parse_mode, RAW_PARSE_DEFAULT, res, and SPI_ERROR_ARGUMENT.

Referenced by build_tuplestore_recursively(), crosstab(), get_crosstab_tuplestore(), initialize_worker_spi(), load_categories_hash(), plperl_spi_exec(), pltcl_SPI_execute(), PLy_spi_execute_query(), query_to_oid_list(), query_to_xml_internal(), refresh_by_match_merge(), and SPI_exec().

◆ SPI_execute_extended()

int SPI_execute_extended ( const char *  src,
const SPIExecuteOptions options 
)

Definition at line 635 of file spi.c.

637 {
638  int res;
639  _SPI_plan plan;
640 
641  if (src == NULL || options == NULL)
642  return SPI_ERROR_ARGUMENT;
643 
644  res = _SPI_begin_call(true);
645  if (res < 0)
646  return res;
647 
648  memset(&plan, 0, sizeof(_SPI_plan));
649  plan.magic = _SPI_PLAN_MAGIC;
652  if (options->params)
653  {
654  plan.parserSetup = options->params->parserSetup;
655  plan.parserSetupArg = options->params->parserSetupArg;
656  }
657 
658  _SPI_prepare_oneshot_plan(src, &plan);
659 
660  res = _SPI_execute_plan(&plan, options,
662  true);
663 
664  _SPI_end_call(true);
665  return res;
666 }

References _SPI_begin_call(), _SPI_end_call(), _SPI_execute_plan(), _SPI_PLAN_MAGIC, _SPI_prepare_oneshot_plan(), CURSOR_OPT_PARALLEL_OK, _SPI_plan::cursor_options, InvalidSnapshot, _SPI_plan::magic, _SPI_plan::parse_mode, _SPI_plan::parserSetup, _SPI_plan::parserSetupArg, RAW_PARSE_DEFAULT, res, and SPI_ERROR_ARGUMENT.

Referenced by exec_stmt_dynexecute(), and exec_stmt_return_query().

◆ SPI_execute_plan()

int SPI_execute_plan ( SPIPlanPtr  plan,
Datum Values,
const char *  Nulls,
bool  read_only,
long  tcount 
)

Definition at line 670 of file spi.c.

672 {
674  int res;
675 
676  if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC || tcount < 0)
677  return SPI_ERROR_ARGUMENT;
678 
679  if (plan->nargs > 0 && Values == NULL)
680  return SPI_ERROR_PARAM;
681 
682  res = _SPI_begin_call(true);
683  if (res < 0)
684  return res;
685 
686  memset(&options, 0, sizeof(options));
687  options.params = _SPI_convert_params(plan->nargs, plan->argtypes,
688  Values, Nulls);
689  options.read_only = read_only;
690  options.tcount = tcount;
691 
692  res = _SPI_execute_plan(plan, &options,
694  true);
695 
696  _SPI_end_call(true);
697  return res;
698 }
#define SPI_ERROR_PARAM
Definition: spi.h:74

References _SPI_begin_call(), _SPI_convert_params(), _SPI_end_call(), _SPI_execute_plan(), _SPI_PLAN_MAGIC, _SPI_plan::argtypes, InvalidSnapshot, _SPI_plan::magic, _SPI_plan::nargs, Nulls, options, res, SPI_ERROR_ARGUMENT, and SPI_ERROR_PARAM.

Referenced by pg_get_ruledef_worker(), pg_get_viewdef_worker(), plperl_spi_exec_prepared(), pltcl_SPI_execute_plan(), PLy_spi_execute_plan(), SPI_execp(), and test_predtest().

◆ SPI_execute_plan_extended()

int SPI_execute_plan_extended ( SPIPlanPtr  plan,
const SPIExecuteOptions options 
)

Definition at line 709 of file spi.c.

711 {
712  int res;
713 
714  if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC || options == NULL)
715  return SPI_ERROR_ARGUMENT;
716 
717  res = _SPI_begin_call(true);
718  if (res < 0)
719  return res;
720 
721  res = _SPI_execute_plan(plan, options,
723  true);
724 
725  _SPI_end_call(true);
726  return res;
727 }

References _SPI_begin_call(), _SPI_end_call(), _SPI_execute_plan(), _SPI_PLAN_MAGIC, InvalidSnapshot, _SPI_plan::magic, res, and SPI_ERROR_ARGUMENT.

Referenced by exec_stmt_call(), and exec_stmt_return_query().

◆ SPI_execute_plan_with_paramlist()

int SPI_execute_plan_with_paramlist ( SPIPlanPtr  plan,
ParamListInfo  params,
bool  read_only,
long  tcount 
)

Definition at line 731 of file spi.c.

733 {
735  int res;
736 
737  if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC || tcount < 0)
738  return SPI_ERROR_ARGUMENT;
739 
740  res = _SPI_begin_call(true);
741  if (res < 0)
742  return res;
743 
744  memset(&options, 0, sizeof(options));
745  options.params = params;
746  options.read_only = read_only;
747  options.tcount = tcount;
748 
749  res = _SPI_execute_plan(plan, &options,
751  true);
752 
753  _SPI_end_call(true);
754  return res;
755 }

References _SPI_begin_call(), _SPI_end_call(), _SPI_execute_plan(), _SPI_PLAN_MAGIC, InvalidSnapshot, _SPI_plan::magic, options, res, and SPI_ERROR_ARGUMENT.

Referenced by exec_run_select(), and exec_stmt_execsql().

◆ SPI_execute_snapshot()

int SPI_execute_snapshot ( SPIPlanPtr  plan,
Datum Values,
const char *  Nulls,
Snapshot  snapshot,
Snapshot  crosscheck_snapshot,
bool  read_only,
bool  fire_triggers,
long  tcount 
)

Definition at line 771 of file spi.c.

775 {
777  int res;
778 
779  if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC || tcount < 0)
780  return SPI_ERROR_ARGUMENT;
781 
782  if (plan->nargs > 0 && Values == NULL)
783  return SPI_ERROR_PARAM;
784 
785  res = _SPI_begin_call(true);
786  if (res < 0)
787  return res;
788 
789  memset(&options, 0, sizeof(options));
790  options.params = _SPI_convert_params(plan->nargs, plan->argtypes,
791  Values, Nulls);
792  options.read_only = read_only;
793  options.tcount = tcount;
794 
795  res = _SPI_execute_plan(plan, &options,
796  snapshot, crosscheck_snapshot,
797  fire_triggers);
798 
799  _SPI_end_call(true);
800  return res;
801 }

References _SPI_begin_call(), _SPI_convert_params(), _SPI_end_call(), _SPI_execute_plan(), _SPI_PLAN_MAGIC, _SPI_plan::argtypes, _SPI_plan::magic, _SPI_plan::nargs, Nulls, options, res, SPI_ERROR_ARGUMENT, and SPI_ERROR_PARAM.

Referenced by RI_Initial_Check(), RI_PartitionRemove_Check(), and ri_PerformCheck().

◆ SPI_execute_with_args()

int SPI_execute_with_args ( const char *  src,
int  nargs,
Oid argtypes,
Datum Values,
const char *  Nulls,
bool  read_only,
long  tcount 
)

Definition at line 810 of file spi.c.

814 {
815  int res;
816  _SPI_plan plan;
817  ParamListInfo paramLI;
819 
820  if (src == NULL || nargs < 0 || tcount < 0)
821  return SPI_ERROR_ARGUMENT;
822 
823  if (nargs > 0 && (argtypes == NULL || Values == NULL))
824  return SPI_ERROR_PARAM;
825 
826  res = _SPI_begin_call(true);
827  if (res < 0)
828  return res;
829 
830  memset(&plan, 0, sizeof(_SPI_plan));
831  plan.magic = _SPI_PLAN_MAGIC;
834  plan.nargs = nargs;
835  plan.argtypes = argtypes;
836  plan.parserSetup = NULL;
837  plan.parserSetupArg = NULL;
838 
839  paramLI = _SPI_convert_params(nargs, argtypes,
840  Values, Nulls);
841 
842  _SPI_prepare_oneshot_plan(src, &plan);
843 
844  memset(&options, 0, sizeof(options));
845  options.params = paramLI;
846  options.read_only = read_only;
847  options.tcount = tcount;
848 
849  res = _SPI_execute_plan(&plan, &options,
851  true);
852 
853  _SPI_end_call(true);
854  return res;
855 }

References _SPI_begin_call(), _SPI_convert_params(), _SPI_end_call(), _SPI_execute_plan(), _SPI_PLAN_MAGIC, _SPI_prepare_oneshot_plan(), _SPI_plan::argtypes, CURSOR_OPT_PARALLEL_OK, _SPI_plan::cursor_options, InvalidSnapshot, _SPI_plan::magic, _SPI_plan::nargs, Nulls, options, _SPI_plan::parse_mode, _SPI_plan::parserSetup, _SPI_plan::parserSetupArg, RAW_PARSE_DEFAULT, res, SPI_ERROR_ARGUMENT, and SPI_ERROR_PARAM.

◆ SPI_finish()

int SPI_finish ( void  )

Definition at line 183 of file spi.c.

184 {
185  int res;
186 
187  res = _SPI_begin_call(false); /* just check we're connected */
188  if (res < 0)
189  return res;
190 
191  /* Restore memory context as it was before procedure call */
193 
194  /* Release memory used in procedure call (including tuptables) */
196  _SPI_current->execCxt = NULL;
198  _SPI_current->procCxt = NULL;
199 
200  /*
201  * Restore outer API variables, especially SPI_tuptable which is probably
202  * pointing at a just-deleted tuptable
203  */
207 
208  /* Exit stack level */
209  _SPI_connected--;
210  if (_SPI_connected < 0)
211  _SPI_current = NULL;
212  else
214 
215  return SPI_OK_FINISH;
216 }
#define SPI_OK_FINISH
Definition: spi.h:83

References _SPI_begin_call(), _SPI_connected, _SPI_current, _SPI_stack, _SPI_connection::execCxt, MemoryContextDelete(), MemoryContextSwitchTo(), _SPI_connection::outer_processed, _SPI_connection::outer_result, _SPI_connection::outer_tuptable, _SPI_connection::procCxt, res, _SPI_connection::savedcxt, SPI_OK_FINISH, SPI_processed, SPI_result, and SPI_tuptable.

Referenced by check_foreign_key(), check_primary_key(), connectby(), crosstab(), cursor_to_xml(), cursor_to_xmlschema(), database_to_xml_internal(), database_to_xmlschema_internal(), get_crosstab_tuplestore(), get_tuple_of_interest(), initialize_worker_spi(), load_categories_hash(), pg_get_ruledef_worker(), pg_get_viewdef_worker(), plperl_event_trigger_handler(), plperl_func_handler(), plperl_inline_handler(), plperl_trigger_handler(), plpgsql_call_handler(), plpgsql_inline_handler(), plpgsql_validator(), plsample_trigger_handler(), pltcl_event_trigger_handler(), pltcl_func_handler(), pltcl_trigger_handler(), PLy_exec_function(), PLy_exec_trigger(), query_to_xml_and_xmlschema(), query_to_xml_internal(), query_to_xmlschema(), refresh_by_match_merge(), ri_Check_Pk_Match(), RI_FKey_cascade_del(), RI_FKey_cascade_upd(), RI_FKey_check(), RI_Initial_Check(), RI_PartitionRemove_Check(), ri_restrict(), ri_set(), schema_to_xml_internal(), schema_to_xmlschema_internal(), test_predtest(), ts_stat1(), ts_stat2(), tsquery_rewrite_query(), ttdummy(), and xpath_table().

◆ SPI_fname()

char* SPI_fname ( TupleDesc  tupdesc,
int  fnumber 
)

Definition at line 1196 of file spi.c.

1197 {
1198  const FormData_pg_attribute *att;
1199 
1200  SPI_result = 0;
1201 
1202  if (fnumber > tupdesc->natts || fnumber == 0 ||
1204  {
1206  return NULL;
1207  }
1208 
1209  if (fnumber > 0)
1210  att = TupleDescAttr(tupdesc, fnumber - 1);
1211  else
1212  att = SystemAttributeDefinition(fnumber);
1213 
1214  return pstrdup(NameStr(att->attname));
1215 }
#define NameStr(name)
Definition: c.h:682
const FormData_pg_attribute * SystemAttributeDefinition(AttrNumber attno)
Definition: heap.c:239
char * pstrdup(const char *in)
Definition: mcxt.c:1483
FormData_pg_attribute
Definition: pg_attribute.h:191
#define SPI_ERROR_NOATTRIBUTE
Definition: spi.h:76
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92

References FirstLowInvalidHeapAttributeNumber, FormData_pg_attribute, NameStr, TupleDescData::natts, pstrdup(), SPI_ERROR_NOATTRIBUTE, SPI_result, SystemAttributeDefinition(), and TupleDescAttr.

Referenced by get_pkey_attnames(), and SPI_sql_row_to_xmlelement().

◆ SPI_fnumber()

int SPI_fnumber ( TupleDesc  tupdesc,
const char *  fname 
)

Definition at line 1173 of file spi.c.

1174 {
1175  int res;
1176  const FormData_pg_attribute *sysatt;
1177 
1178  for (res = 0; res < tupdesc->natts; res++)
1179  {
1180  Form_pg_attribute attr = TupleDescAttr(tupdesc, res);
1181 
1182  if (namestrcmp(&attr->attname, fname) == 0 &&
1183  !attr->attisdropped)
1184  return res + 1;
1185  }
1186 
1187  sysatt = SystemAttributeByName(fname);
1188  if (sysatt != NULL)
1189  return sysatt->attnum;
1190 
1191  /* SPI_ERROR_NOATTRIBUTE is different from all sys column numbers */
1192  return SPI_ERROR_NOATTRIBUTE;
1193 }
const FormData_pg_attribute * SystemAttributeByName(const char *attname)
Definition: heap.c:251
int namestrcmp(Name name, const char *str)
Definition: name.c:247
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:207

References FormData_pg_attribute, namestrcmp(), TupleDescData::natts, res, SPI_ERROR_NOATTRIBUTE, SystemAttributeByName(), and TupleDescAttr.

Referenced by autoinc(), check_foreign_key(), check_primary_key(), insert_username(), lo_manage(), make_ruledef(), make_viewdef(), moddatetime(), plperl_build_tuple_result(), plperl_modify_tuple(), pltcl_build_tuple_result(), PLy_modify_tuple(), tsvector_update_trigger(), and ttdummy().

◆ SPI_freeplan()

int SPI_freeplan ( SPIPlanPtr  plan)

Definition at line 1023 of file spi.c.

1024 {
1025  ListCell *lc;
1026 
1027  if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC)
1028  return SPI_ERROR_ARGUMENT;
1029 
1030  /* Release the plancache entries */
1031  foreach(lc, plan->plancache_list)
1032  {
1033  CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc);
1034 
1035  DropCachedPlan(plansource);
1036  }
1037 
1038  /* Now get rid of the _SPI_plan and subsidiary data in its plancxt */
1040 
1041  return 0;
1042 }
void DropCachedPlan(CachedPlanSource *plansource)
Definition: plancache.c:498

References _SPI_PLAN_MAGIC, DropCachedPlan(), lfirst, _SPI_plan::magic, MemoryContextDelete(), _SPI_plan::plancache_list, _SPI_plan::plancxt, and SPI_ERROR_ARGUMENT.

Referenced by free_expr(), plperl_spi_freeplan(), plperl_spi_prepare(), plperl_spi_query(), PLy_cursor_query(), PLy_plan_dealloc(), ri_FetchPreparedPlan(), ts_stat_sql(), and tsquery_rewrite_query().

◆ SPI_freetuple()

void SPI_freetuple ( HeapTuple  tuple)

Definition at line 1377 of file spi.c.

1378 {
1379  /* No longer need to worry which context tuple was in... */
1380  heap_freetuple(tuple);
1381 }
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338

References heap_freetuple().

◆ SPI_freetuptable()

void SPI_freetuptable ( SPITupleTable tuptable)

Definition at line 1384 of file spi.c.

1385 {
1386  bool found = false;
1387 
1388  /* ignore call if NULL pointer */
1389  if (tuptable == NULL)
1390  return;
1391 
1392  /*
1393  * Search only the topmost SPI context for a matching tuple table.
1394  */
1395  if (_SPI_current != NULL)
1396  {
1397  slist_mutable_iter siter;
1398 
1399  /* find tuptable in active list, then remove it */
1401  {
1402  SPITupleTable *tt;
1403 
1404  tt = slist_container(SPITupleTable, next, siter.cur);
1405  if (tt == tuptable)
1406  {
1407  slist_delete_current(&siter);
1408  found = true;
1409  break;
1410  }
1411  }
1412  }
1413 
1414  /*
1415  * Refuse the deletion if we didn't find it in the topmost SPI context.
1416  * This is primarily a guard against double deletion, but might prevent
1417  * other errors as well. Since the worst consequence of not deleting a
1418  * tuptable would be a transient memory leak, this is just a WARNING.
1419  */
1420  if (!found)
1421  {
1422  elog(WARNING, "attempt to delete invalid SPITupleTable %p", tuptable);
1423  return;
1424  }
1425 
1426  /* for safety, reset global variables that might point at tuptable */
1427  if (tuptable == _SPI_current->tuptable)
1428  _SPI_current->tuptable = NULL;
1429  if (tuptable == SPI_tuptable)
1430  SPI_tuptable = NULL;
1431 
1432  /* release all memory belonging to tuptable */
1433  MemoryContextDelete(tuptable->tuptabcxt);
1434 }

References _SPI_current, slist_mutable_iter::cur, elog(), MemoryContextDelete(), next, slist_container, slist_delete_current(), slist_foreach_modify, SPI_tuptable, SPITupleTable::tuptabcxt, _SPI_connection::tuptable, _SPI_connection::tuptables, and WARNING.

Referenced by _SPI_execute_plan(), exec_eval_cleanup(), exec_for_query(), exec_stmt_call(), exec_stmt_dynexecute(), exec_stmt_execsql(), exec_stmt_fetch(), plperl_spi_execute_fetch_result(), plperl_spi_fetchrow(), pltcl_process_SPI_result(), PLy_cursor_fetch(), PLy_cursor_iternext(), PLy_spi_execute_fetch_result(), ts_stat_sql(), and tsquery_rewrite_query().

◆ SPI_getargcount()

int SPI_getargcount ( SPIPlanPtr  plan)

Definition at line 1888 of file spi.c.

1889 {
1890  if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC)
1891  {
1893  return -1;
1894  }
1895  return plan->nargs;
1896 }

References _SPI_PLAN_MAGIC, _SPI_plan::magic, _SPI_plan::nargs, SPI_ERROR_ARGUMENT, and SPI_result.

◆ SPI_getargtypeid()

Oid SPI_getargtypeid ( SPIPlanPtr  plan,
int  argIndex 
)

Definition at line 1873 of file spi.c.

1874 {
1875  if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC ||
1876  argIndex < 0 || argIndex >= plan->nargs)
1877  {
1879  return InvalidOid;
1880  }
1881  return plan->argtypes[argIndex];
1882 }
#define InvalidOid
Definition: postgres_ext.h:36

References _SPI_PLAN_MAGIC, _SPI_plan::argtypes, InvalidOid, _SPI_plan::magic, _SPI_plan::nargs, SPI_ERROR_ARGUMENT, and SPI_result.

◆ SPI_getbinval()

Datum SPI_getbinval ( HeapTuple  tuple,
TupleDesc  tupdesc,
int  fnumber,
bool isnull 
)

Definition at line 1250 of file spi.c.

1251 {
1252  SPI_result = 0;
1253 
1254  if (fnumber > tupdesc->natts || fnumber == 0 ||
1256  {
1258  *isnull = true;
1259  return (Datum) NULL;
1260  }
1261 
1262  return heap_getattr(tuple, fnumber, tupdesc, isnull);
1263 }
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:788

References FirstLowInvalidHeapAttributeNumber, heap_getattr(), TupleDescData::natts, SPI_ERROR_NOATTRIBUTE, and SPI_result.

Referenced by autoinc(), check_foreign_key(), check_primary_key(), exec_eval_expr(), initialize_worker_spi(), make_ruledef(), make_viewdef(), query_to_oid_list(), SPI_sql_row_to_xmlelement(), test_predtest(), ts_stat_sql(), tsquery_rewrite_query(), tsvector_update_trigger(), and ttdummy().

◆ SPI_getnspname()

char* SPI_getnspname ( Relation  rel)

Definition at line 1330 of file spi.c.

1331 {
1333 }
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3331
#define RelationGetNamespace(relation)
Definition: rel.h:542

References get_namespace_name(), and RelationGetNamespace.

Referenced by plperl_trigger_build_args(), plsample_trigger_handler(), pltcl_trigger_handler(), and PLy_trigger_build_args().

◆ SPI_getrelname()

char* SPI_getrelname ( Relation  rel)

◆ SPI_gettype()

char* SPI_gettype ( TupleDesc  tupdesc,
int  fnumber 
)

Definition at line 1266 of file spi.c.

1267 {
1268  Oid typoid;
1269  HeapTuple typeTuple;
1270  char *result;
1271 
1272  SPI_result = 0;
1273 
1274  if (fnumber > tupdesc->natts || fnumber == 0 ||
1276  {
1278  return NULL;
1279  }
1280 
1281  if (fnumber > 0)
1282  typoid = TupleDescAttr(tupdesc, fnumber - 1)->atttypid;
1283  else
1284  typoid = (SystemAttributeDefinition(fnumber))->atttypid;
1285 
1286  typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typoid));
1287 
1288  if (!HeapTupleIsValid(typeTuple))
1289  {
1291  return NULL;
1292  }
1293 
1294  result = pstrdup(NameStr(((Form_pg_type) GETSTRUCT(typeTuple))->typname));
1295  ReleaseSysCache(typeTuple);
1296  return result;
1297 }
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:649
FormData_pg_type * Form_pg_type
Definition: pg_type.h:261
NameData typname
Definition: pg_type.h:41
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:600
#define SPI_ERROR_TYPUNKNOWN
Definition: spi.h:78
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1221
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1173
@ TYPEOID
Definition: syscache.h:114

References FirstLowInvalidHeapAttributeNumber, GETSTRUCT, HeapTupleIsValid, NameStr, TupleDescData::natts, ObjectIdGetDatum(), pstrdup(), ReleaseSysCache(), SearchSysCache1(), SPI_ERROR_NOATTRIBUTE, SPI_ERROR_TYPUNKNOWN, SPI_result, SystemAttributeDefinition(), TupleDescAttr, TYPEOID, and typname.

Referenced by check_foreign_key().

◆ SPI_gettypeid()

Oid SPI_gettypeid ( TupleDesc  tupdesc,
int  fnumber 
)

Definition at line 1306 of file spi.c.

1307 {
1308  SPI_result = 0;
1309 
1310  if (fnumber > tupdesc->natts || fnumber == 0 ||
1312  {
1314  return InvalidOid;
1315  }
1316 
1317  if (fnumber > 0)
1318  return TupleDescAttr(tupdesc, fnumber - 1)->atttypid;
1319  else
1320  return (SystemAttributeDefinition(fnumber))->atttypid;
1321 }

References FirstLowInvalidHeapAttributeNumber, InvalidOid, TupleDescData::natts, SPI_ERROR_NOATTRIBUTE, SPI_result, SystemAttributeDefinition(), and TupleDescAttr.

Referenced by autoinc(), check_foreign_key(), check_primary_key(), insert_username(), moddatetime(), SPI_sql_row_to_xmlelement(), ts_stat_sql(), tsquery_rewrite_query(), tsvector_update_trigger(), and ttdummy().

◆ SPI_getvalue()

char* SPI_getvalue ( HeapTuple  tuple,
TupleDesc  tupdesc,
int  fnumber 
)

Definition at line 1218 of file spi.c.

1219 {
1220  Datum val;
1221  bool isnull;
1222  Oid typoid,
1223  foutoid;
1224  bool typisvarlena;
1225 
1226  SPI_result = 0;
1227 
1228  if (fnumber > tupdesc->natts || fnumber == 0 ||
1230  {
1232  return NULL;
1233  }
1234 
1235  val = heap_getattr(tuple, fnumber, tupdesc, &isnull);
1236  if (isnull)
1237  return NULL;
1238 
1239  if (fnumber > 0)
1240  typoid = TupleDescAttr(tupdesc, fnumber - 1)->atttypid;
1241  else
1242  typoid = (SystemAttributeDefinition(fnumber))->atttypid;
1243 
1244  getTypeOutputInfo(typoid, &foutoid, &typisvarlena);
1245 
1246  return OidOutputFunctionCall(foutoid, val);
1247 }
char * OidOutputFunctionCall(Oid functionId, Datum val)
Definition: fmgr.c:1639
long val
Definition: informix.c:664
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:2865

References FirstLowInvalidHeapAttributeNumber, getTypeOutputInfo(), heap_getattr(), TupleDescData::natts, OidOutputFunctionCall(), SPI_ERROR_NOATTRIBUTE, SPI_result, SystemAttributeDefinition(), TupleDescAttr, and val.

Referenced by build_tuplestore_recursively(), check_foreign_key(), crosstab(), get_crosstab_tuplestore(), get_sql_insert(), get_sql_update(), lo_manage(), load_categories_hash(), make_ruledef(), make_viewdef(), refresh_by_match_merge(), triggered_change_notification(), and xpath_table().

◆ SPI_inside_nonatomic_context()

bool SPI_inside_nonatomic_context ( void  )

Definition at line 582 of file spi.c.

583 {
584  if (_SPI_current == NULL)
585  return false; /* not in any SPI context at all */
586  if (_SPI_current->atomic)
587  return false; /* it's atomic (ie function not procedure) */
588  return true;
589 }

References _SPI_current, and _SPI_connection::atomic.

Referenced by StartTransaction().

◆ SPI_is_cursor_plan()

bool SPI_is_cursor_plan ( SPIPlanPtr  plan)

Definition at line 1908 of file spi.c.

1909 {
1910  CachedPlanSource *plansource;
1911 
1912  if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC)
1913  {
1915  return false;
1916  }
1917 
1918  if (list_length(plan->plancache_list) != 1)
1919  {
1920  SPI_result = 0;
1921  return false; /* not exactly 1 pre-rewrite command */
1922  }
1923  plansource = (CachedPlanSource *) linitial(plan->plancache_list);
1924 
1925  /*
1926  * We used to force revalidation of the cached plan here, but that seems
1927  * unnecessary: invalidation could mean a change in the rowtype of the
1928  * tuples returned by a plan, but not whether it returns tuples at all.
1929  */
1930  SPI_result = 0;
1931 
1932  /* Does it return tuples? */
1933  if (plansource->resultDesc)
1934  return true;
1935 
1936  return false;
1937 }

References _SPI_PLAN_MAGIC, linitial, list_length(), _SPI_plan::magic, _SPI_plan::plancache_list, CachedPlanSource::resultDesc, SPI_ERROR_ARGUMENT, and SPI_result.

Referenced by SPI_cursor_open_internal().

◆ SPI_keepplan()

int SPI_keepplan ( SPIPlanPtr  plan)

Definition at line 974 of file spi.c.

975 {
976  ListCell *lc;
977 
978  if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC ||
979  plan->saved || plan->oneshot)
980  return SPI_ERROR_ARGUMENT;
981 
982  /*
983  * Mark it saved, reparent it under CacheMemoryContext, and mark all the
984  * component CachedPlanSources as saved. This sequence cannot fail
985  * partway through, so there's no risk of long-term memory leakage.
986  */
987  plan->saved = true;
989 
990  foreach(lc, plan->plancache_list)
991  {
992  CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc);
993 
994  SaveCachedPlan(plansource);
995  }
996 
997  return 0;
998 }

References _SPI_PLAN_MAGIC, CacheMemoryContext, lfirst, _SPI_plan::magic, MemoryContextSetParent(), _SPI_plan::oneshot, _SPI_plan::plancache_list, _SPI_plan::plancxt, SaveCachedPlan(), _SPI_plan::saved, and SPI_ERROR_ARGUMENT.

Referenced by check_foreign_key(), check_primary_key(), exec_prepare_plan(), pg_get_ruledef_worker(), pg_get_viewdef_worker(), plperl_spi_prepare(), pltcl_SPI_prepare(), PLy_spi_prepare(), ri_PlanCheck(), and ttdummy().

◆ SPI_modifytuple()

HeapTuple SPI_modifytuple ( Relation  rel,
HeapTuple  tuple,
int  natts,
int *  attnum,
Datum Values,
const char *  Nulls 
)

Definition at line 1104 of file spi.c.

1106 {
1107  MemoryContext oldcxt;
1108  HeapTuple mtuple;
1109  int numberOfAttributes;
1110  Datum *v;
1111  bool *n;
1112  int i;
1113 
1114  if (rel == NULL || tuple == NULL || natts < 0 || attnum == NULL || Values == NULL)
1115  {
1117  return NULL;
1118  }
1119 
1120  if (_SPI_current == NULL)
1121  {
1123  return NULL;
1124  }
1125 
1127 
1128  SPI_result = 0;
1129 
1130  numberOfAttributes = rel->rd_att->natts;
1131  v = (Datum *) palloc(numberOfAttributes * sizeof(Datum));
1132  n = (bool *) palloc(numberOfAttributes * sizeof(bool));
1133 
1134  /* fetch old values and nulls */
1135  heap_deform_tuple(tuple, rel->rd_att, v, n);
1136 
1137  /* replace values and nulls */
1138  for (i = 0; i < natts; i++)
1139  {
1140  if (attnum[i] <= 0 || attnum[i] > numberOfAttributes)
1141  break;
1142  v[attnum[i] - 1] = Values[i];
1143  n[attnum[i] - 1] = (Nulls && Nulls[i] == 'n');
1144  }
1145 
1146  if (i == natts) /* no errors in *attnum */
1147  {
1148  mtuple = heap_form_tuple(rel->rd_att, v, n);
1149 
1150  /*
1151  * copy the identification info of the old tuple: t_ctid, t_self, and
1152  * OID (if any)
1153  */
1154  mtuple->t_data->t_ctid = tuple->t_data->t_ctid;
1155  mtuple->t_self = tuple->t_self;
1156  mtuple->t_tableOid = tuple->t_tableOid;
1157  }
1158  else
1159  {
1160  mtuple = NULL;
1162  }
1163 
1164  pfree(v);
1165  pfree(n);
1166 
1167  MemoryContextSwitchTo(oldcxt);
1168 
1169  return mtuple;
1170 }
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
void heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *values, bool *isnull)
Definition: heaptuple.c:1249
int16 attnum
Definition: pg_attribute.h:83
ItemPointerData t_self
Definition: htup.h:65
HeapTupleHeader t_data
Definition: htup.h:68
Oid t_tableOid
Definition: htup.h:66
ItemPointerData t_ctid
Definition: htup_details.h:160
TupleDesc rd_att
Definition: rel.h:111

References _SPI_current, attnum, heap_deform_tuple(), heap_form_tuple(), i, MemoryContextSwitchTo(), TupleDescData::natts, Nulls, palloc(), pfree(), RelationData::rd_att, _SPI_connection::savedcxt, SPI_ERROR_ARGUMENT, SPI_ERROR_NOATTRIBUTE, SPI_ERROR_UNCONNECTED, SPI_result, HeapTupleHeaderData::t_ctid, HeapTupleData::t_data, HeapTupleData::t_self, and HeapTupleData::t_tableOid.

Referenced by ttdummy().

◆ SPI_palloc()

void* SPI_palloc ( Size  size)

Definition at line 1336 of file spi.c.

1337 {
1338  if (_SPI_current == NULL)
1339  elog(ERROR, "SPI_palloc called while not connected to SPI");
1340 
1341  return MemoryContextAlloc(_SPI_current->savedcxt, size);
1342 }

References _SPI_current, elog(), ERROR, MemoryContextAlloc(), and _SPI_connection::savedcxt.

Referenced by _SPI_strdup(), and coerce_function_result_tuple().

◆ SPI_pfree()

void SPI_pfree ( void *  pointer)

Definition at line 1352 of file spi.c.

1353 {
1354  /* No longer need to worry which context chunk was in... */
1355  pfree(pointer);
1356 }

References pfree().

◆ SPI_plan_get_cached_plan()

CachedPlan* SPI_plan_get_cached_plan ( SPIPlanPtr  plan)

Definition at line 2066 of file spi.c.

2067 {
2068  CachedPlanSource *plansource;
2069  CachedPlan *cplan;
2070  SPICallbackArg spicallbackarg;
2071  ErrorContextCallback spierrcontext;
2072 
2073  Assert(plan->magic == _SPI_PLAN_MAGIC);
2074 
2075  /* Can't support one-shot plans here */
2076  if (plan->oneshot)
2077  return NULL;
2078 
2079  /* Must have exactly one CachedPlanSource */
2080  if (list_length(plan->plancache_list) != 1)
2081  return NULL;
2082  plansource = (CachedPlanSource *) linitial(plan->plancache_list);
2083 
2084  /* Setup error traceback support for ereport() */
2085  spicallbackarg.query = plansource->query_string;
2086  spicallbackarg.mode = plan->parse_mode;
2087  spierrcontext.callback = _SPI_error_callback;
2088  spierrcontext.arg = &spicallbackarg;
2089  spierrcontext.previous = error_context_stack;
2090  error_context_stack = &spierrcontext;
2091 
2092  /* Get the generic plan for the query */
2093  cplan = GetCachedPlan(plansource, NULL,
2094  plan->saved ? CurrentResourceOwner : NULL,
2096  Assert(cplan == plansource->gplan);
2097 
2098  /* Pop the error context stack */
2099  error_context_stack = spierrcontext.previous;
2100 
2101  return cplan;
2102 }
struct CachedPlan * gplan
Definition: plancache.h:121

References _SPI_current, _SPI_error_callback(), _SPI_PLAN_MAGIC, ErrorContextCallback::arg, Assert(), ErrorContextCallback::callback, CurrentResourceOwner, error_context_stack, GetCachedPlan(), CachedPlanSource::gplan, linitial, list_length(), _SPI_plan::magic, SPICallbackArg::mode, _SPI_plan::oneshot, _SPI_plan::parse_mode, _SPI_plan::plancache_list, ErrorContextCallback::previous, SPICallbackArg::query, CachedPlanSource::query_string, _SPI_connection::queryEnv, and _SPI_plan::saved.

Referenced by exec_eval_simple_expr(), exec_simple_check_plan(), and test_predtest().

◆ SPI_plan_get_plan_sources()

List* SPI_plan_get_plan_sources ( SPIPlanPtr  plan)

Definition at line 2047 of file spi.c.

2048 {
2049  Assert(plan->magic == _SPI_PLAN_MAGIC);
2050  return plan->plancache_list;
2051 }

References _SPI_PLAN_MAGIC, Assert(), _SPI_plan::magic, and _SPI_plan::plancache_list.

Referenced by exec_simple_check_plan(), exec_stmt_execsql(), and make_callstmt_target().

◆ SPI_plan_is_valid()

bool SPI_plan_is_valid ( SPIPlanPtr  plan)

Definition at line 1946 of file spi.c.

1947 {
1948  ListCell *lc;
1949 
1950  Assert(plan->magic == _SPI_PLAN_MAGIC);
1951 
1952  foreach(lc, plan->plancache_list)
1953  {
1954  CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc);
1955 
1956  if (!CachedPlanIsValid(plansource))
1957  return false;
1958  }
1959  return true;
1960 }
bool CachedPlanIsValid(CachedPlanSource *plansource)
Definition: plancache.c:1598

References _SPI_PLAN_MAGIC, Assert(), CachedPlanIsValid(), lfirst, _SPI_plan::magic, and _SPI_plan::plancache_list.

Referenced by ri_FetchPreparedPlan().

◆ SPI_prepare()

SPIPlanPtr SPI_prepare ( const char *  src,
int  nargs,
Oid argtypes 
)

◆ SPI_prepare_cursor()

SPIPlanPtr SPI_prepare_cursor ( const char *  src,
int  nargs,
Oid argtypes,
int  cursorOptions 
)

Definition at line 864 of file spi.c.

866 {
867  _SPI_plan plan;
868  SPIPlanPtr result;
869 
870  if (src == NULL || nargs < 0 || (nargs > 0 && argtypes == NULL))
871  {
873  return NULL;
874  }
875 
876  SPI_result = _SPI_begin_call(true);
877  if (SPI_result < 0)
878  return NULL;
879 
880  memset(&plan, 0, sizeof(_SPI_plan));
881  plan.magic = _SPI_PLAN_MAGIC;
883  plan.cursor_options = cursorOptions;
884  plan.nargs = nargs;
885  plan.argtypes = argtypes;
886  plan.parserSetup = NULL;
887  plan.parserSetupArg = NULL;
888 
889  _SPI_prepare_plan(src, &plan);
890 
891  /* copy plan to procedure context */
892  result = _SPI_make_plan_non_temp(&plan);
893 
894  _SPI_end_call(true);
895 
896  return result;
897 }
static SPIPlanPtr _SPI_make_plan_non_temp(SPIPlanPtr plan)
Definition: spi.c:3113

References _SPI_begin_call(), _SPI_end_call(), _SPI_make_plan_non_temp(), _SPI_PLAN_MAGIC, _SPI_prepare_plan(), _SPI_plan::argtypes, _SPI_plan::cursor_options, _SPI_plan::magic, _SPI_plan::nargs, _SPI_plan::parse_mode, _SPI_plan::parserSetup, _SPI_plan::parserSetupArg, RAW_PARSE_DEFAULT, SPI_ERROR_ARGUMENT, and SPI_result.

Referenced by SPI_prepare().

◆ SPI_prepare_extended()

SPIPlanPtr SPI_prepare_extended ( const char *  src,
const SPIPrepareOptions options 
)

Definition at line 900 of file spi.c.

902 {
903  _SPI_plan plan;
904  SPIPlanPtr result;
905 
906  if (src == NULL || options == NULL)
907  {
909  return NULL;
910  }
911 
912  SPI_result = _SPI_begin_call(true);
913  if (SPI_result < 0)
914  return NULL;
915 
916  memset(&plan, 0, sizeof(_SPI_plan));
917  plan.magic = _SPI_PLAN_MAGIC;
918  plan.parse_mode = options->parseMode;
919  plan.cursor_options = options->cursorOptions;
920  plan.nargs = 0;
921  plan.argtypes = NULL;
922  plan.parserSetup = options->parserSetup;
923  plan.parserSetupArg = options->parserSetupArg;
924 
925  _SPI_prepare_plan(src, &plan);
926 
927  /* copy plan to procedure context */
928  result = _SPI_make_plan_non_temp(&plan);
929 
930  _SPI_end_call(true);
931 
932  return result;
933 }

References _SPI_begin_call(), _SPI_end_call(), _SPI_make_plan_non_temp(), _SPI_PLAN_MAGIC, _SPI_prepare_plan(), _SPI_plan::argtypes, _SPI_plan::cursor_options, _SPI_plan::magic, _SPI_plan::nargs, _SPI_plan::parse_mode, _SPI_plan::parserSetup, _SPI_plan::parserSetupArg, SPI_ERROR_ARGUMENT, and SPI_result.

Referenced by exec_prepare_plan().

◆ SPI_prepare_params()

SPIPlanPtr SPI_prepare_params ( const char *  src,
ParserSetupHook  parserSetup,
void *  parserSetupArg,
int  cursorOptions 
)

Definition at line 936 of file spi.c.

940 {
941  _SPI_plan plan;
942  SPIPlanPtr result;
943 
944  if (src == NULL)
945  {
947  return NULL;
948  }
949 
950  SPI_result = _SPI_begin_call(true);
951  if (SPI_result < 0)
952  return NULL;
953 
954  memset(&plan, 0, sizeof(_SPI_plan));
955  plan.magic = _SPI_PLAN_MAGIC;
957  plan.cursor_options = cursorOptions;
958  plan.nargs = 0;
959  plan.argtypes = NULL;
960  plan.parserSetup = parserSetup;
961  plan.parserSetupArg = parserSetupArg;
962 
963  _SPI_prepare_plan(src, &plan);
964 
965  /* copy plan to procedure context */
966  result = _SPI_make_plan_non_temp(&plan);
967 
968  _SPI_end_call(true);
969 
970  return result;
971 }

References _SPI_begin_call(), _SPI_end_call(), _SPI_make_plan_non_temp(), _SPI_PLAN_MAGIC, _SPI_prepare_plan(), _SPI_plan::argtypes, _SPI_plan::cursor_options, _SPI_plan::magic, _SPI_plan::nargs, _SPI_plan::parse_mode, _SPI_plan::parserSetup, _SPI_plan::parserSetupArg, RAW_PARSE_DEFAULT, SPI_ERROR_ARGUMENT, and SPI_result.

◆ spi_printtup()

bool spi_printtup ( TupleTableSlot slot,
DestReceiver self 
)

Definition at line 2161 of file spi.c.

2162 {
2163  SPITupleTable *tuptable;
2164  MemoryContext oldcxt;
2165 
2166  if (_SPI_current == NULL)
2167  elog(ERROR, "spi_printtup called while not connected to SPI");
2168 
2169  tuptable = _SPI_current->tuptable;
2170  if (tuptable == NULL)
2171  elog(ERROR, "improper call to spi_printtup");
2172 
2173  oldcxt = MemoryContextSwitchTo(tuptable->tuptabcxt);
2174 
2175  if (tuptable->numvals >= tuptable->alloced)
2176  {
2177  /* Double the size of the pointer array */
2178  uint64 newalloced = tuptable->alloced * 2;
2179 
2180  tuptable->vals = (HeapTuple *) repalloc_huge(tuptable->vals,
2181  newalloced * sizeof(HeapTuple));
2182  tuptable->alloced = newalloced;
2183  }
2184 
2185  tuptable->vals[tuptable->numvals] = ExecCopySlotHeapTuple(slot);
2186  (tuptable->numvals)++;
2187 
2188  MemoryContextSwitchTo(oldcxt);
2189 
2190  return true;
2191 }
void * repalloc_huge(void *pointer, Size size)
Definition: mcxt.c:1459
static HeapTuple ExecCopySlotHeapTuple(TupleTableSlot *slot)
Definition: tuptable.h:460

References _SPI_current, SPITupleTable::alloced, elog(), ERROR, ExecCopySlotHeapTuple(), MemoryContextSwitchTo(), SPITupleTable::numvals, repalloc_huge(), SPITupleTable::tuptabcxt, _SPI_connection::tuptable, and SPITupleTable::vals.

◆ SPI_register_relation()

int SPI_register_relation ( EphemeralNamedRelation  enr)

Definition at line 3269 of file spi.c.

3270 {
3271  EphemeralNamedRelation match;
3272  int res;
3273 
3274  if (enr == NULL || enr->md.name == NULL)
3275  return SPI_ERROR_ARGUMENT;
3276 
3277  res = _SPI_begin_call(false); /* keep current memory context */
3278  if (res < 0)
3279  return res;
3280 
3281  match = _SPI_find_ENR_by_name(enr->md.name);
3282  if (match)
3284  else
3285  {
3286  if (_SPI_current->queryEnv == NULL)
3288 
3291  }
3292 
3293  _SPI_end_call(false);
3294 
3295  return res;
3296 }
QueryEnvironment * create_queryEnv(void)
void register_ENR(QueryEnvironment *queryEnv, EphemeralNamedRelation enr)
static EphemeralNamedRelation _SPI_find_ENR_by_name(const char *name)
Definition: spi.c:3252
#define SPI_ERROR_REL_DUPLICATE
Definition: spi.h:79
#define SPI_OK_REL_REGISTER
Definition: spi.h:96
EphemeralNamedRelationMetadataData md

References _SPI_begin_call(), _SPI_current, _SPI_end_call(), _SPI_find_ENR_by_name(), create_queryEnv(), EphemeralNamedRelationData::md, EphemeralNamedRelationMetadataData::name, _SPI_connection::queryEnv, register_ENR(), res, SPI_ERROR_ARGUMENT, SPI_ERROR_REL_DUPLICATE, and SPI_OK_REL_REGISTER.

Referenced by SPI_register_trigger_data().

◆ SPI_register_trigger_data()

int SPI_register_trigger_data ( TriggerData tdata)

Definition at line 3336 of file spi.c.

3337 {
3338  if (tdata == NULL)
3339  return SPI_ERROR_ARGUMENT;
3340 
3341  if (tdata->tg_newtable)
3342  {
3345  int rc;
3346 
3347  enr->md.name = tdata->tg_trigger->tgnewtable;
3348  enr->md.reliddesc = tdata->tg_relation->rd_id;
3349  enr->md.tupdesc = NULL;
3352  enr->reldata = tdata->tg_newtable;
3353  rc = SPI_register_relation(enr);
3354  if (rc != SPI_OK_REL_REGISTER)
3355  return rc;
3356  }
3357 
3358  if (tdata->tg_oldtable)
3359  {
3362  int rc;
3363 
3364  enr->md.name = tdata->tg_trigger->tgoldtable;
3365  enr->md.reliddesc = tdata->tg_relation->rd_id;
3366  enr->md.tupdesc = NULL;
3369  enr->reldata = tdata->tg_oldtable;
3370  rc = SPI_register_relation(enr);
3371  if (rc != SPI_OK_REL_REGISTER)
3372  return rc;
3373  }
3374 
3375  return SPI_OK_TD_REGISTER;
3376 }
@ ENR_NAMED_TUPLESTORE
int SPI_register_relation(EphemeralNamedRelation enr)
Definition: spi.c:3269
#define SPI_OK_TD_REGISTER
Definition: spi.h:98
EphemeralNameRelationType enrtype
Oid rd_id
Definition: rel.h:112
Tuplestorestate * tg_oldtable
Definition: trigger.h:41
Relation tg_relation
Definition: trigger.h:35
Tuplestorestate * tg_newtable
Definition: trigger.h:42
Trigger * tg_trigger
Definition: trigger.h:38
char * tgoldtable
Definition: reltrigger.h:43
char * tgnewtable
Definition: reltrigger.h:44
int64 tuplestore_tuple_count(Tuplestorestate *state)
Definition: tuplestore.c:546

References ENR_NAMED_TUPLESTORE, EphemeralNamedRelationMetadataData::enrtuples, EphemeralNamedRelationMetadataData::enrtype, EphemeralNamedRelationData::md, EphemeralNamedRelationMetadataData::name, palloc(), RelationData::rd_id, EphemeralNamedRelationData::reldata, EphemeralNamedRelationMetadataData::reliddesc, SPI_ERROR_ARGUMENT, SPI_OK_REL_REGISTER, SPI_OK_TD_REGISTER, SPI_register_relation(), TriggerData::tg_newtable, TriggerData::tg_oldtable, TriggerData::tg_relation, TriggerData::tg_trigger, Trigger::tgnewtable, Trigger::tgoldtable, EphemeralNamedRelationMetadataData::tupdesc, and tuplestore_tuple_count().

Referenced by plperl_trigger_handler(), plpgsql_exec_trigger(), plsample_trigger_handler(), pltcl_trigger_handler(), and PLy_exec_trigger().

◆ SPI_repalloc()

void* SPI_repalloc ( void *  pointer,
Size  size 
)

Definition at line 1345 of file spi.c.

1346 {
1347  /* No longer need to worry which context chunk was in... */
1348  return repalloc(pointer, size);
1349 }

References repalloc().

◆ SPI_result_code_string()

const char* SPI_result_code_string ( int  code)

Definition at line 1970 of file spi.c.

1971 {
1972  static char buf[64];
1973 
1974  switch (code)
1975  {
1976  case SPI_ERROR_CONNECT:
1977  return "SPI_ERROR_CONNECT";
1978  case SPI_ERROR_COPY:
1979  return "SPI_ERROR_COPY";
1980  case SPI_ERROR_OPUNKNOWN:
1981  return "SPI_ERROR_OPUNKNOWN";
1982  case SPI_ERROR_UNCONNECTED:
1983  return "SPI_ERROR_UNCONNECTED";
1984  case SPI_ERROR_ARGUMENT:
1985  return "SPI_ERROR_ARGUMENT";
1986  case SPI_ERROR_PARAM:
1987  return "SPI_ERROR_PARAM";
1988  case SPI_ERROR_TRANSACTION:
1989  return "SPI_ERROR_TRANSACTION";
1990  case SPI_ERROR_NOATTRIBUTE:
1991  return "SPI_ERROR_NOATTRIBUTE";
1992  case SPI_ERROR_NOOUTFUNC:
1993  return "SPI_ERROR_NOOUTFUNC";
1994  case SPI_ERROR_TYPUNKNOWN:
1995  return "SPI_ERROR_TYPUNKNOWN";
1997  return "SPI_ERROR_REL_DUPLICATE";
1999  return "SPI_ERROR_REL_NOT_FOUND";
2000  case SPI_OK_CONNECT:
2001  return "SPI_OK_CONNECT";
2002  case SPI_OK_FINISH:
2003  return "SPI_OK_FINISH";
2004  case SPI_OK_FETCH:
2005  return "SPI_OK_FETCH";
2006  case SPI_OK_UTILITY:
2007  return "SPI_OK_UTILITY";
2008  case SPI_OK_SELECT:
2009  return "SPI_OK_SELECT";
2010  case SPI_OK_SELINTO:
2011  return "SPI_OK_SELINTO";
2012  case SPI_OK_INSERT:
2013  return "SPI_OK_INSERT";
2014  case SPI_OK_DELETE:
2015  return "SPI_OK_DELETE";
2016  case SPI_OK_UPDATE:
2017  return "SPI_OK_UPDATE";
2018  case SPI_OK_CURSOR:
2019  return "SPI_OK_CURSOR";
2021  return "SPI_OK_INSERT_RETURNING";
2023  return "SPI_OK_DELETE_RETURNING";
2025  return "SPI_OK_UPDATE_RETURNING";
2026  case SPI_OK_REWRITTEN:
2027  return "SPI_OK_REWRITTEN";
2028  case SPI_OK_REL_REGISTER:
2029  return "SPI_OK_REL_REGISTER";
2030  case SPI_OK_REL_UNREGISTER:
2031  return "SPI_OK_REL_UNREGISTER";
2032  }
2033  /* Unrecognized code ... return something useful ... */
2034  sprintf(buf, "Unrecognized SPI code %d", code);
2035  return buf;
2036 }
static char * buf
Definition: pg_test_fsync.c:67
#define sprintf
Definition: port.h:240
#define SPI_ERROR_REL_NOT_FOUND
Definition: spi.h:80
#define SPI_OK_CURSOR
Definition: spi.h:91
#define SPI_OK_FETCH
Definition: spi.h:84
#define SPI_OK_REL_UNREGISTER
Definition: spi.h:97
#define SPI_ERROR_NOOUTFUNC
Definition: spi.h:77
#define SPI_ERROR_CONNECT
Definition: spi.h:68

References buf, SPI_ERROR_ARGUMENT, SPI_ERROR_CONNECT, SPI_ERROR_COPY, SPI_ERROR_NOATTRIBUTE, SPI_ERROR_NOOUTFUNC, SPI_ERROR_OPUNKNOWN, SPI_ERROR_PARAM, SPI_ERROR_REL_DUPLICATE, SPI_ERROR_REL_NOT_FOUND, SPI_ERROR_TRANSACTION, SPI_ERROR_TYPUNKNOWN, SPI_ERROR_UNCONNECTED, SPI_OK_CONNECT, SPI_OK_CURSOR, SPI_OK_DELETE, SPI_OK_DELETE_RETURNING, SPI_OK_FETCH, SPI_OK_FINISH, SPI_OK_INSERT, SPI_OK_INSERT_RETURNING, SPI_OK_REL_REGISTER, SPI_OK_REL_UNREGISTER, SPI_OK_REWRITTEN, SPI_OK_SELECT, SPI_OK_SELINTO, SPI_OK_UPDATE, SPI_OK_UPDATE_RETURNING, SPI_OK_UTILITY, and sprintf.

Referenced by check_foreign_key(), check_primary_key(), exec_dynquery_with_params(), exec_prepare_plan(), exec_run_select(), exec_stmt_call(), exec_stmt_dynexecute(), exec_stmt_execsql(), exec_stmt_forc(), exec_stmt_open(), exec_stmt_return_query(), plperl_spi_execute_fetch_result(), plperl_spi_prepare(), plperl_spi_query(), plperl_spi_query_prepared(), plpgsql_call_handler(), plpgsql_inline_handler(), plpgsql_validator(), pltcl_process_SPI_result(), PLy_cursor_plan(), PLy_cursor_query(), PLy_spi_execute_plan(), PLy_spi_execute_query(), PLy_spi_prepare(), query_to_oid_list(), RI_Initial_Check(), RI_PartitionRemove_Check(), ri_PerformCheck(), ri_PlanCheck(), and ttdummy().

◆ SPI_returntuple()

HeapTupleHeader SPI_returntuple ( HeapTuple  tuple,
TupleDesc  tupdesc 
)

Definition at line 1072 of file spi.c.

1073 {
1074  MemoryContext oldcxt;
1075  HeapTupleHeader dtup;
1076 
1077  if (tuple == NULL || tupdesc == NULL)
1078  {
1080  return NULL;
1081  }
1082 
1083  if (_SPI_current == NULL)
1084  {
1086  return NULL;
1087  }
1088 
1089  /* For RECORD results, make sure a typmod has been assigned */
1090  if (tupdesc->tdtypeid == RECORDOID &&
1091  tupdesc->tdtypmod < 0)
1092  assign_record_type_typmod(tupdesc);
1093 
1095 
1096  dtup = DatumGetHeapTupleHeader(heap_copy_tuple_as_datum(tuple, tupdesc));
1097 
1098  MemoryContextSwitchTo(oldcxt);
1099 
1100  return dtup;
1101 }
#define DatumGetHeapTupleHeader(X)
Definition: fmgr.h:295
Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
Definition: heaptuple.c:984
int32 tdtypmod
Definition: tupdesc.h:83
Oid tdtypeid
Definition: tupdesc.h:82
void assign_record_type_typmod(TupleDesc tupDesc)
Definition: typcache.c:1944

References _SPI_current, assign_record_type_typmod(), DatumGetHeapTupleHeader, heap_copy_tuple_as_datum(), MemoryContextSwitchTo(), _SPI_connection::savedcxt, SPI_ERROR_ARGUMENT, SPI_ERROR_UNCONNECTED, SPI_result, TupleDescData::tdtypeid, and TupleDescData::tdtypmod.

Referenced by coerce_function_result_tuple().

◆ SPI_rollback()

void SPI_rollback ( void  )

Definition at line 414 of file spi.c.

415 {
416  _SPI_rollback(false);
417 }
static void _SPI_rollback(bool chain)
Definition: spi.c:333

References _SPI_rollback().

Referenced by exec_stmt_rollback(), plperl_spi_rollback(), pltcl_rollback(), and PLy_rollback().

◆ SPI_rollback_and_chain()

void SPI_rollback_and_chain ( void  )

Definition at line 420 of file spi.c.

421 {
422  _SPI_rollback(true);
423 }

References _SPI_rollback().

Referenced by exec_stmt_rollback().

◆ SPI_saveplan()

SPIPlanPtr SPI_saveplan ( SPIPlanPtr  plan)

Definition at line 1001 of file spi.c.

1002 {
1003  SPIPlanPtr newplan;
1004 
1005  if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC)
1006  {
1008  return NULL;
1009  }
1010 
1011  SPI_result = _SPI_begin_call(false); /* don't change context */
1012  if (SPI_result < 0)
1013  return NULL;
1014 
1015  newplan = _SPI_save_plan(plan);
1016 
1017  SPI_result = _SPI_end_call(false);
1018 
1019  return newplan;
1020 }
static SPIPlanPtr _SPI_save_plan(SPIPlanPtr plan)
Definition: spi.c:3181

References _SPI_begin_call(), _SPI_end_call(), _SPI_PLAN_MAGIC, _SPI_save_plan(), _SPI_plan::magic, SPI_ERROR_ARGUMENT, and SPI_result.

◆ SPI_scroll_cursor_fetch()

void SPI_scroll_cursor_fetch ( Portal  portal,
FetchDirection  direction,
long  count 
)

Definition at line 1833 of file spi.c.

1834 {
1835  _SPI_cursor_operation(portal,
1836  direction, count,
1838  /* we know that the DestSPI receiver doesn't need a destroy call */
1839 }

References _SPI_cursor_operation(), CreateDestReceiver(), and DestSPI.

Referenced by exec_stmt_fetch().

◆ SPI_scroll_cursor_move()

void SPI_scroll_cursor_move ( Portal  portal,
FetchDirection  direction,
long  count 
)

Definition at line 1848 of file spi.c.

1849 {
1850  _SPI_cursor_operation(portal, direction, count, None_Receiver);
1851 }

References _SPI_cursor_operation(), and None_Receiver.

Referenced by exec_stmt_fetch().

◆ SPI_start_transaction()

void SPI_start_transaction ( void  )

Definition at line 223 of file spi.c.

224 {
225 }

◆ SPI_unregister_relation()

int SPI_unregister_relation ( const char *  name)

Definition at line 3303 of file spi.c.

3304 {
3305  EphemeralNamedRelation match;
3306  int res;
3307 
3308  if (name == NULL)
3309  return SPI_ERROR_ARGUMENT;
3310 
3311  res = _SPI_begin_call(false); /* keep current memory context */
3312  if (res < 0)
3313  return res;
3314 
3315  match = _SPI_find_ENR_by_name(name);
3316  if (match)
3317  {
3320  }
3321  else
3323 
3324  _SPI_end_call(false);
3325 
3326  return res;
3327 }
void unregister_ENR(QueryEnvironment *queryEnv, const char *name)

References _SPI_begin_call(), _SPI_current, _SPI_end_call(), _SPI_find_ENR_by_name(), EphemeralNamedRelationData::md, name, EphemeralNamedRelationMetadataData::name, _SPI_connection::queryEnv, res, SPI_ERROR_ARGUMENT, SPI_ERROR_REL_NOT_FOUND, SPI_OK_REL_UNREGISTER, and unregister_ENR().

Variable Documentation

◆ _SPI_connected

int _SPI_connected = -1
static

Definition at line 52 of file spi.c.

Referenced by AtEOSubXact_SPI(), AtEOXact_SPI(), SPI_connect_ext(), and SPI_finish().

◆ _SPI_current

◆ _SPI_stack

_SPI_connection* _SPI_stack = NULL
static

Definition at line 49 of file spi.c.

Referenced by AtEOSubXact_SPI(), AtEOXact_SPI(), SPI_connect_ext(), and SPI_finish().

◆ _SPI_stack_depth

int _SPI_stack_depth = 0
static

Definition at line 51 of file spi.c.

Referenced by SPI_connect_ext().

◆ SPI_processed

◆ SPI_result

◆ SPI_tuptable