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 3053 of file spi.c.

3054 {
3055  if (_SPI_current == NULL)
3056  return SPI_ERROR_UNCONNECTED;
3057 
3058  if (use_exec)
3059  {
3060  /* remember when the Executor operation started */
3062  /* switch to the Executor memory context */
3063  _SPI_execmem();
3064  }
3065 
3066  return 0;
3067 }
static _SPI_connection * _SPI_current
Definition: spi.c:50
static MemoryContext _SPI_execmem(void)
Definition: spi.c:3034
#define SPI_ERROR_UNCONNECTED
Definition: spi.h:71
SubTransactionId execSubid
Definition: spi_priv.h:29
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:780

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 3093 of file spi.c.

3094 {
3095  uint64 processed = _SPI_current->processed;
3096  SPITupleTable *tuptable = _SPI_current->tuptable;
3097  bool failed = false;
3098 
3099  if (tuptable == NULL) /* spi_dest_startup was not called */
3100  failed = true;
3101  else if (processed != tuptable->numvals)
3102  failed = true;
3103 
3104  return failed;
3105 }
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:1909
void FlushErrorState(void)
Definition: elog.c:1825
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
ErrorData * CopyErrorData(void)
Definition: elog.c:1720
#define PG_TRY(...)
Definition: elog.h:370
#define PG_END_TRY(...)
Definition: elog.h:395
#define ERROR
Definition: elog.h:39
#define PG_CATCH(...)
Definition: elog.h:380
#define ereport(elevel,...)
Definition: elog.h:149
MemoryContext CurrentMemoryContext
Definition: mcxt.c:135
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:138
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:3014
void RestoreTransactionCharacteristics(const SavedTransactionCharacteristics *s)
Definition: xact.c:3022
void StartTransactionCommand(void)
Definition: xact.c:2937
bool IsSubTransaction(void)
Definition: xact.c:4889
void CommitTransactionCommand(void)
Definition: xact.c:3034
void AbortCurrentTransaction(void)
Definition: xact.c:3305

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 2828 of file spi.c.

2830 {
2831  ParamListInfo paramLI;
2832 
2833  if (nargs > 0)
2834  {
2835  paramLI = makeParamList(nargs);
2836 
2837  for (int i = 0; i < nargs; i++)
2838  {
2839  ParamExternData *prm = &paramLI->params[i];
2840 
2841  prm->value = Values[i];
2842  prm->isnull = (Nulls && Nulls[i] == 'n');
2843  prm->pflags = PARAM_FLAG_CONST;
2844  prm->ptype = argtypes[i];
2845  }
2846  }
2847  else
2848  paramLI = NULL;
2849  return paramLI;
2850 }
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 2983 of file spi.c.

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

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 3077 of file spi.c.

3078 {
3079  if (use_exec)
3080  {
3081  /* switch to the procedure memory context */
3082  _SPI_procmem();
3083  /* mark Executor context no longer in use */
3085  /* and free Executor memory */
3087  }
3088 
3089  return 0;
3090 }
#define InvalidSubTransactionId
Definition: c.h:647
#define MemoryContextResetAndDeleteChildren(ctx)
Definition: memutils.h:70
static MemoryContext _SPI_procmem(void)
Definition: spi.c:3040
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 2937 of file spi.c.

2938 {
2939  SPICallbackArg *carg = (SPICallbackArg *) arg;
2940  const char *query = carg->query;
2941  int syntaxerrposition;
2942 
2943  if (query == NULL) /* in case arg wasn't set yet */
2944  return;
2945 
2946  /*
2947  * If there is a syntax error position, convert to internal syntax error;
2948  * otherwise treat the query as an item of context stack
2949  */
2950  syntaxerrposition = geterrposition();
2951  if (syntaxerrposition > 0)
2952  {
2953  errposition(0);
2954  internalerrposition(syntaxerrposition);
2955  internalerrquery(query);
2956  }
2957  else
2958  {
2959  /* Use the parse mode to decide how to describe the query */
2960  switch (carg->mode)
2961  {
2963  errcontext("SQL expression \"%s\"", query);
2964  break;
2968  errcontext("PL/pgSQL assignment \"%s\"", query);
2969  break;
2970  default:
2971  errcontext("SQL statement \"%s\"", query);
2972  break;
2973  }
2974  }
2975 }
int internalerrquery(const char *query)
Definition: elog.c:1481
int internalerrposition(int cursorpos)
Definition: elog.c:1461
int geterrposition(void)
Definition: elog.c:1577
int errposition(int cursorpos)
Definition: elog.c:1445
#define errcontext
Definition: elog.h:196
@ 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 3034 of file spi.c.

3035 {
3037 }

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 2393 of file spi.c.

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

References _SPI_current, _SPI_error_callback(), _SPI_pquery(), ActiveSnapshotSet(), ErrorContextCallback::arg, Assert(), _SPI_connection::atomic, ErrorContextCallback::callback, CommandCounterIncrement(), CommandIsReadOnly(), QueryCompletion::commandTag, CachedPlanSource::commandTag, CompleteCachedPlan(), CreateCommandName(), CreateDestReceiver(), CreateQueryDesc(), CurrentResourceOwner, 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, NIL, QueryCompletion::nprocessed, SPITupleTable::numvals, pg_analyze_and_rewrite_fixedparams(), pg_analyze_and_rewrite_withcb(), plan, 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, IntoClause::skipData, SPI_ERROR_COPY, SPI_ERROR_TRANSACTION, SPI_freetuptable(), SPI_OK_REWRITTEN, SPI_OK_SELINTO, SPI_OK_UTILITY, SPI_processed, SPI_tuptable, stmt, CachedPlan::stmt_list, _SPI_connection::tuptable, and UpdateActiveSnapshotCommandId().

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 3256 of file spi.c.

3257 {
3258  /* internal static function; any error is bug in SPI itself */
3259  Assert(name != NULL);
3260 
3261  /* fast exit if no tuplestores have been added */
3262  if (_SPI_current->queryEnv == NULL)
3263  return NULL;
3264 
3265  return get_ENR(_SPI_current->queryEnv, name);
3266 }
EphemeralNamedRelation get_ENR(QueryEnvironment *queryEnv, const char *name)
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 3117 of file spi.c.

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

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, palloc(), palloc0(), _SPI_plan::parse_mode, _SPI_plan::parserSetup, _SPI_plan::parserSetupArg, plan, _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 2853 of file spi.c.

2854 {
2855  int operation = queryDesc->operation;
2856  int eflags;
2857  int res;
2858 
2859  switch (operation)
2860  {
2861  case CMD_SELECT:
2862  if (queryDesc->dest->mydest == DestNone)
2863  {
2864  /* Don't return SPI_OK_SELECT if we're discarding result */
2865  res = SPI_OK_UTILITY;
2866  }
2867  else
2868  res = SPI_OK_SELECT;
2869  break;
2870  case CMD_INSERT:
2871  if (queryDesc->plannedstmt->hasReturning)
2873  else
2874  res = SPI_OK_INSERT;
2875  break;
2876  case CMD_DELETE:
2877  if (queryDesc->plannedstmt->hasReturning)
2879  else
2880  res = SPI_OK_DELETE;
2881  break;
2882  case CMD_UPDATE:
2883  if (queryDesc->plannedstmt->hasReturning)
2885  else
2886  res = SPI_OK_UPDATE;
2887  break;
2888  case CMD_MERGE:
2889  res = SPI_OK_MERGE;
2890  break;
2891  default:
2892  return SPI_ERROR_OPUNKNOWN;
2893  }
2894 
2895 #ifdef SPI_EXECUTOR_STATS
2896  if (ShowExecutorStats)
2897  ResetUsage();
2898 #endif
2899 
2900  /* Select execution options */
2901  if (fire_triggers)
2902  eflags = 0; /* default run-to-completion flags */
2903  else
2904  eflags = EXEC_FLAG_SKIP_TRIGGERS;
2905 
2906  ExecutorStart(queryDesc, eflags);
2907 
2908  ExecutorRun(queryDesc, ForwardScanDirection, tcount, true);
2909 
2910  _SPI_current->processed = queryDesc->estate->es_processed;
2911 
2912  if ((res == SPI_OK_SELECT || queryDesc->plannedstmt->hasReturning) &&
2913  queryDesc->dest->mydest == DestSPI)
2914  {
2915  if (_SPI_checktuples())
2916  elog(ERROR, "consistency check on SPI tuple count failed");
2917  }
2918 
2919  ExecutorFinish(queryDesc);
2920  ExecutorEnd(queryDesc);
2921  /* FreeQueryDesc is done by the caller */
2922 
2923 #ifdef SPI_EXECUTOR_STATS
2924  if (ShowExecutorStats)
2925  ShowUsage("SPI EXECUTOR STATS");
2926 #endif
2927 
2928  return res;
2929 }
void ExecutorEnd(QueryDesc *queryDesc)
Definition: execMain.c:469
void ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:409
void ExecutorStart(QueryDesc *queryDesc, int eflags)
Definition: execMain.c:132
void ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count, bool execute_once)
Definition: execMain.c:302
#define EXEC_FLAG_SKIP_TRIGGERS
Definition: executor.h:70
@ CMD_MERGE
Definition: nodes.h:280
@ CMD_INSERT
Definition: nodes.h:278
@ CMD_DELETE
Definition: nodes.h:279
@ CMD_UPDATE
Definition: nodes.h:277
@ CMD_SELECT
Definition: nodes.h:276
void ShowUsage(const char *title)
Definition: postgres.c:4972
void ResetUsage(void)
Definition: postgres.c:4965
@ ForwardScanDirection
Definition: sdir.h:28
#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:663
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:127

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 2323 of file spi.c.

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

References _SPI_error_callback(), ErrorContextCallback::arg, ErrorContextCallback::callback, CreateCommandTag(), CreateOneShotCachedPlan(), error_context_stack, lappend(), lfirst_node, SPICallbackArg::mode, NIL, plan, 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 2215 of file spi.c.

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

References _SPI_current, _SPI_error_callback(), ErrorContextCallback::arg, Assert(), ErrorContextCallback::callback, CompleteCachedPlan(), CreateCachedPlan(), CreateCommandTag(), error_context_stack, lappend(), lfirst_node, SPICallbackArg::mode, NIL, pg_analyze_and_rewrite_fixedparams(), pg_analyze_and_rewrite_withcb(), plan, 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 3040 of file spi.c.

3041 {
3043 }

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 3185 of file spi.c.

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

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, palloc(), palloc0(), _SPI_plan::parse_mode, _SPI_plan::parserSetup, _SPI_plan::parserSetupArg, plan, _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:1316
#define WARNING
Definition: elog.h:36
static void slist_delete_current(slist_mutable_iter *iter)
Definition: ilist.h:1084
#define slist_foreach_modify(iter, lhead)
Definition: ilist.h:1148
#define slist_container(type, membername, ptr)
Definition: ilist.h:1106
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:403
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_rollback).
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:986
return false
Definition: isn.c:131
MemoryContext TopTransactionContext
Definition: mcxt.c:146
MemoryContext TopMemoryContext
Definition: mcxt.c:141
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1476
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1021
MemoryContext PortalContext
Definition: mcxt.c:150
#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:768
#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:3193
@ FETCH_BACKWARD
Definition: parsenodes.h:3194
static void _SPI_cursor_operation(Portal portal, FetchDirection direction, long count, DestReceiver *dest)
Definition: spi.c:2983

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:1456
static ParamListInfo _SPI_convert_params(int nargs, Oid *argtypes, Datum *Values, const char *Nulls)
Definition: spi.c:2828
static Portal SPI_cursor_open_internal(const char *name, SPIPlanPtr plan, ParamListInfo paramLI, bool read_only)
Definition: spi.c:1575

References _SPI_convert_params(), name, Nulls, pfree(), plan, 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:1202
bool ExecSupportsBackwardScan(Plan *node)
Definition: execAmi.c:512
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1631
#define copyObject(obj)
Definition: nodes.h:244
@ CMD_UTILITY
Definition: nodes.h:281
ParamListInfo copyParamList(ParamListInfo from)
Definition: params.c:78
#define CURSOR_OPT_SCROLL
Definition: parsenodes.h:3156
#define CURSOR_OPT_NO_SCROLL
Definition: parsenodes.h:3157
#define linitial(l)
Definition: pg_list.h:178
@ 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, 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, plan, PORTAL_MULTI_QUERY, PortalData::portalContext, PortalDefineQuery(), PortalStart(), ErrorContextCallback::previous, _SPI_connection::processed, SPICallbackArg::query, CachedPlanSource::query_string, _SPI_connection::queryEnv, PortalData::queryEnv, ReleaseCachedPlan(), 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;
1492  plan.parse_mode = RAW_PARSE_DEFAULT;
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:2215

References _SPI_begin_call(), _SPI_convert_params(), _SPI_end_call(), _SPI_PLAN_MAGIC, _SPI_prepare_plan(), elog(), ERROR, name, Nulls, plan, 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, plan, 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;
1547  plan.parse_mode = RAW_PARSE_DEFAULT;
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(), elog(), ERROR, name, plan, 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 @148 value
uintptr_t Datum
Definition: postgres.h:64

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 2117 of file spi.c.

2118 {
2119  SPITupleTable *tuptable;
2120  MemoryContext oldcxt;
2121  MemoryContext tuptabcxt;
2122 
2123  if (_SPI_current == NULL)
2124  elog(ERROR, "spi_dest_startup called while not connected to SPI");
2125 
2126  if (_SPI_current->tuptable != NULL)
2127  elog(ERROR, "improper call to spi_dest_startup");
2128 
2129  /* We create the tuple table context as a child of procCxt */
2130 
2131  oldcxt = _SPI_procmem(); /* switch to procedure memory context */
2132 
2134  "SPI TupTable",
2136  MemoryContextSwitchTo(tuptabcxt);
2137 
2138  _SPI_current->tuptable = tuptable = (SPITupleTable *)
2139  palloc0(sizeof(SPITupleTable));
2140  tuptable->tuptabcxt = tuptabcxt;
2141  tuptable->subid = GetCurrentSubTransactionId();
2142 
2143  /*
2144  * The tuptable is now valid enough to be freed by AtEOSubXact_SPI, so put
2145  * it onto the SPI context's tuptables list. This will ensure it's not
2146  * leaked even in the unlikely event the following few lines fail.
2147  */
2148  slist_push_head(&_SPI_current->tuptables, &tuptable->next);
2149 
2150  /* set up initial allocations */
2151  tuptable->alloced = 128;
2152  tuptable->vals = (HeapTuple *) palloc(tuptable->alloced * sizeof(HeapTuple));
2153  tuptable->numvals = 0;
2154  tuptable->tupdesc = CreateTupleDescCopy(typeinfo);
2155 
2156  MemoryContextSwitchTo(oldcxt);
2157 }
static void slist_push_head(slist_head *head, slist_node *node)
Definition: ilist.h:1006
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, plan, 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;
609  plan.parse_mode = RAW_PARSE_DEFAULT;
610  plan.cursor_options = CURSOR_OPT_PARALLEL_OK;
611 
613 
614  memset(&options, 0, sizeof(options));
615  options.read_only = read_only;
616  options.tcount = tcount;
617 
620  true);
621 
622  _SPI_end_call(true);
623  return res;
624 }
#define CURSOR_OPT_PARALLEL_OK
Definition: parsenodes.h:3165
static char ** options
static int _SPI_execute_plan(SPIPlanPtr plan, const SPIExecuteOptions *options, Snapshot snapshot, Snapshot crosscheck_snapshot, bool fire_triggers)
Definition: spi.c:2393
static void _SPI_prepare_oneshot_plan(const char *src, SPIPlanPtr plan)
Definition: spi.c:2323

References _SPI_begin_call(), _SPI_end_call(), _SPI_execute_plan(), _SPI_PLAN_MAGIC, _SPI_prepare_oneshot_plan(), CURSOR_OPT_PARALLEL_OK, InvalidSnapshot, options, plan, 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(), SPI_exec(), and worker_spi_main().

◆ 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;
650  plan.parse_mode = RAW_PARSE_DEFAULT;
651  plan.cursor_options = CURSOR_OPT_PARALLEL_OK;
652  if (options->params)
653  {
654  plan.parserSetup = options->params->parserSetup;
655  plan.parserSetupArg = options->params->parserSetupArg;
656  }
657 
659 
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, InvalidSnapshot, plan, 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 
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, InvalidSnapshot, Nulls, options, plan, 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 
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, plan, 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 
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, options, plan, 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 
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, Nulls, options, plan, 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;
832  plan.parse_mode = RAW_PARSE_DEFAULT;
833  plan.cursor_options = CURSOR_OPT_PARALLEL_OK;
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 
843 
844  memset(&options, 0, sizeof(options));
845  options.params = paramLI;
846  options.read_only = read_only;
847  options.tcount = tcount;
848 
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(), CURSOR_OPT_PARALLEL_OK, InvalidSnapshot, Nulls, options, plan, 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(), worker_spi_main(), 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:735
const FormData_pg_attribute * SystemAttributeDefinition(AttrNumber attno)
Definition: heap.c:239
char * pstrdup(const char *in)
Definition: mcxt.c:1644
FormData_pg_attribute
Definition: pg_attribute.h:193
#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:209

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 */
1039  MemoryContextDelete(plan->plancxt);
1040 
1041  return 0;
1042 }
void DropCachedPlan(CachedPlanSource *plansource)
Definition: plancache.c:502

References _SPI_PLAN_MAGIC, DropCachedPlan(), lfirst, MemoryContextDelete(), plan, 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:1426

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, plan, 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, InvalidOid, plan, 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:792

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(), ttdummy(), and worker_spi_main().

◆ 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:3348
#define RelationGetNamespace(relation)
Definition: rel.h:545

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:653
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:252
#define SPI_ERROR_TYPUNKNOWN
Definition: spi.h:78
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:868
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:820
@ 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:1746
long val
Definition: informix.c:664
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:2889

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(), plan, 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, MemoryContextSetParent(), plan, SaveCachedPlan(), 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:1108
void heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *values, bool *isnull)
Definition: heaptuple.c:1337
int16 attnum
Definition: pg_attribute.h:74
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:161
TupleDesc rd_att
Definition: rel.h:112

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 2070 of file spi.c.

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

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 2051 of file spi.c.

2052 {
2053  Assert(plan->magic == _SPI_PLAN_MAGIC);
2054  return plan->plancache_list;
2055 }

References _SPI_PLAN_MAGIC, Assert(), and plan.

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:1604

References _SPI_PLAN_MAGIC, Assert(), CachedPlanIsValid(), lfirst, and plan.

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;
882  plan.parse_mode = RAW_PARSE_DEFAULT;
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:3117

References _SPI_begin_call(), _SPI_end_call(), _SPI_make_plan_non_temp(), _SPI_PLAN_MAGIC, _SPI_prepare_plan(), plan, 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(), plan, 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;
956  plan.parse_mode = RAW_PARSE_DEFAULT;
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(), plan, RAW_PARSE_DEFAULT, SPI_ERROR_ARGUMENT, and SPI_result.

◆ spi_printtup()

bool spi_printtup ( TupleTableSlot slot,
DestReceiver self 
)

Definition at line 2165 of file spi.c.

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

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 3273 of file spi.c.

3274 {
3275  EphemeralNamedRelation match;
3276  int res;
3277 
3278  if (enr == NULL || enr->md.name == NULL)
3279  return SPI_ERROR_ARGUMENT;
3280 
3281  res = _SPI_begin_call(false); /* keep current memory context */
3282  if (res < 0)
3283  return res;
3284 
3285  match = _SPI_find_ENR_by_name(enr->md.name);
3286  if (match)
3288  else
3289  {
3290  if (_SPI_current->queryEnv == NULL)
3292 
3295  }
3296 
3297  _SPI_end_call(false);
3298 
3299  return res;
3300 }
QueryEnvironment * create_queryEnv(void)
void register_ENR(QueryEnvironment *queryEnv, EphemeralNamedRelation enr)
static EphemeralNamedRelation _SPI_find_ENR_by_name(const char *name)
Definition: spi.c:3256
#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 3340 of file spi.c.

3341 {
3342  if (tdata == NULL)
3343  return SPI_ERROR_ARGUMENT;
3344 
3345  if (tdata->tg_newtable)
3346  {
3349  int rc;
3350 
3351  enr->md.name = tdata->tg_trigger->tgnewtable;
3352  enr->md.reliddesc = tdata->tg_relation->rd_id;
3353  enr->md.tupdesc = NULL;
3356  enr->reldata = tdata->tg_newtable;
3357  rc = SPI_register_relation(enr);
3358  if (rc != SPI_OK_REL_REGISTER)
3359  return rc;
3360  }
3361 
3362  if (tdata->tg_oldtable)
3363  {
3366  int rc;
3367 
3368  enr->md.name = tdata->tg_trigger->tgoldtable;
3369  enr->md.reliddesc = tdata->tg_relation->rd_id;
3370  enr->md.tupdesc = NULL;
3373  enr->reldata = tdata->tg_oldtable;
3374  rc = SPI_register_relation(enr);
3375  if (rc != SPI_OK_REL_REGISTER)
3376  return rc;
3377  }
3378 
3379  return SPI_OK_TD_REGISTER;
3380 }
@ ENR_NAMED_TUPLESTORE
int SPI_register_relation(EphemeralNamedRelation enr)
Definition: spi.c:3273
#define SPI_OK_TD_REGISTER
Definition: spi.h:98
EphemeralNameRelationType enrtype
Oid rd_id
Definition: rel.h:113
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  case SPI_OK_TD_REGISTER:
2033  return "SPI_OK_TD_REGISTER";
2034  case SPI_OK_MERGE:
2035  return "SPI_OK_MERGE";
2036  }
2037  /* Unrecognized code ... return something useful ... */
2038  sprintf(buf, "Unrecognized SPI code %d", code);
2039  return buf;
2040 }
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_MERGE, SPI_OK_REL_REGISTER, SPI_OK_REL_UNREGISTER, SPI_OK_REWRITTEN, SPI_OK_SELECT, SPI_OK_SELINTO, SPI_OK_TD_REGISTER, 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:1072
int32 tdtypmod
Definition: tupdesc.h:83
Oid tdtypeid
Definition: tupdesc.h:82
void assign_record_type_typmod(TupleDesc tupDesc)
Definition: typcache.c:1950

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:3185

References _SPI_begin_call(), _SPI_end_call(), _SPI_PLAN_MAGIC, _SPI_save_plan(), plan, 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 3307 of file spi.c.

3308 {
3309  EphemeralNamedRelation match;
3310  int res;
3311 
3312  if (name == NULL)
3313  return SPI_ERROR_ARGUMENT;
3314 
3315  res = _SPI_begin_call(false); /* keep current memory context */
3316  if (res < 0)
3317  return res;
3318 
3319  match = _SPI_find_ENR_by_name(name);
3320  if (match)
3321  {
3324  }
3325  else
3327 
3328  _SPI_end_call(false);
3329 
3330  return res;
3331 }
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