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.

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, ParamListInfo paramLI, Snapshot snapshot, Snapshot crosscheck_snapshot, bool read_only, bool fire_triggers, uint64 tcount)
 
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 SPICleanup (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_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_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_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_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
 

Function Documentation

◆ _SPI_begin_call()

static int _SPI_begin_call ( bool  use_exec)
static

Definition at line 2649 of file spi.c.

References _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_execute(), SPI_execute_plan(), SPI_execute_plan_with_paramlist(), SPI_execute_snapshot(), SPI_execute_with_args(), SPI_finish(), SPI_prepare_cursor(), SPI_prepare_params(), SPI_register_relation(), SPI_saveplan(), and SPI_unregister_relation().

2650 {
2651  if (_SPI_current == NULL)
2652  return SPI_ERROR_UNCONNECTED;
2653 
2654  if (use_exec)
2655  {
2656  /* remember when the Executor operation started */
2658  /* switch to the Executor memory context */
2659  _SPI_execmem();
2660  }
2661 
2662  return 0;
2663 }
#define SPI_ERROR_UNCONNECTED
Definition: spi.h:42
SubTransactionId execSubid
Definition: spi_priv.h:29
static _SPI_connection * _SPI_current
Definition: spi.c:50
static MemoryContext _SPI_execmem(void)
Definition: spi.c:2630
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:708

◆ _SPI_checktuples()

static bool _SPI_checktuples ( void  )
static

Definition at line 2689 of file spi.c.

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

Referenced by _SPI_cursor_operation(), and _SPI_pquery().

2690 {
2691  uint64 processed = _SPI_current->processed;
2692  SPITupleTable *tuptable = _SPI_current->tuptable;
2693  bool failed = false;
2694 
2695  if (tuptable == NULL) /* spi_dest_startup was not called */
2696  failed = true;
2697  else if (processed != tuptable->numvals)
2698  failed = true;
2699 
2700  return failed;
2701 }
static _SPI_connection * _SPI_current
Definition: spi.c:50
uint64 numvals
Definition: spi.h:27
SPITupleTable * tuptable
Definition: spi_priv.h:26
uint64 processed
Definition: spi_priv.h:25

◆ _SPI_commit()

static void _SPI_commit ( bool  chain)
static

Definition at line 221 of file spi.c.

References ActiveSnapshotSet(), _SPI_connection::atomic, CommitTransactionCommand(), CurrentMemoryContext, ereport, errcode(), errmsg(), ERROR, HoldPinnedPortals(), _SPI_connection::internal_xact, IsSubTransaction(), MemoryContextSwitchTo(), PopActiveSnapshot(), RestoreTransactionCharacteristics(), SaveTransactionCharacteristics(), and StartTransactionCommand().

Referenced by SPI_commit(), and SPI_commit_and_chain().

222 {
223  MemoryContext oldcontext = CurrentMemoryContext;
224 
225  if (_SPI_current->atomic)
226  ereport(ERROR,
227  (errcode(ERRCODE_INVALID_TRANSACTION_TERMINATION),
228  errmsg("invalid transaction termination")));
229 
230  /*
231  * This restriction is required by PLs implemented on top of SPI. They
232  * use subtransactions to establish exception blocks that are supposed to
233  * be rolled back together if there is an error. Terminating the
234  * top-level transaction in such a block violates that idea. A future PL
235  * implementation might have different ideas about this, in which case
236  * this restriction would have to be refined or the check possibly be
237  * moved out of SPI into the PLs.
238  */
239  if (IsSubTransaction())
240  ereport(ERROR,
241  (errcode(ERRCODE_INVALID_TRANSACTION_TERMINATION),
242  errmsg("cannot commit while a subtransaction is active")));
243 
244  /*
245  * Hold any pinned portals that any PLs might be using. We have to do
246  * this before changing transaction state, since this will run
247  * user-defined code that might throw an error.
248  */
250 
251  /* Start the actual commit */
252  _SPI_current->internal_xact = true;
253 
254  /*
255  * Before committing, pop all active snapshots to avoid error about
256  * "snapshot %p still active".
257  */
258  while (ActiveSnapshotSet())
260 
261  if (chain)
263 
265 
266  if (chain)
267  {
270  }
271 
272  MemoryContextSwitchTo(oldcontext);
273 
274  _SPI_current->internal_xact = false;
275 }
bool internal_xact
Definition: spi_priv.h:42
void CommitTransactionCommand(void)
Definition: xact.c:2895
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int errcode(int sqlerrcode)
Definition: elog.c:570
static _SPI_connection * _SPI_current
Definition: spi.c:50
void PopActiveSnapshot(void)
Definition: snapmgr.c:814
#define ERROR
Definition: elog.h:43
void SaveTransactionCharacteristics(void)
Definition: xact.c:2875
bool ActiveSnapshotSet(void)
Definition: snapmgr.c:853
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
#define ereport(elevel, rest)
Definition: elog.h:141
void StartTransactionCommand(void)
Definition: xact.c:2794
void RestoreTransactionCharacteristics(void)
Definition: xact.c:2883
bool IsSubTransaction(void)
Definition: xact.c:4682
int errmsg(const char *fmt,...)
Definition: elog.c:784
void HoldPinnedPortals(void)
Definition: portalmem.c:1244

◆ _SPI_convert_params()

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

Definition at line 2444 of file spi.c.

References i, ParamExternData::isnull, makeParamList(), 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().

2446 {
2447  ParamListInfo paramLI;
2448 
2449  if (nargs > 0)
2450  {
2451  paramLI = makeParamList(nargs);
2452 
2453  for (int i = 0; i < nargs; i++)
2454  {
2455  ParamExternData *prm = &paramLI->params[i];
2456 
2457  prm->value = Values[i];
2458  prm->isnull = (Nulls && Nulls[i] == 'n');
2459  prm->pflags = PARAM_FLAG_CONST;
2460  prm->ptype = argtypes[i];
2461  }
2462  }
2463  else
2464  paramLI = NULL;
2465  return paramLI;
2466 }
ParamExternData params[FLEXIBLE_ARRAY_MEMBER]
Definition: params.h:124
Datum value
Definition: params.h:92
ParamListInfo makeParamList(int numParams)
Definition: params.c:32
uint16 pflags
Definition: params.h:94
int i
bool isnull
Definition: params.h:93
#define PARAM_FLAG_CONST
Definition: params.h:88
static bool Nulls[MAXATTR]
Definition: bootstrap.c:168

◆ _SPI_cursor_operation()

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

Definition at line 2579 of file spi.c.

References _SPI_begin_call(), _SPI_checktuples(), _SPI_end_call(), DestSPI, elog, ERROR, _DestReceiver::mydest, PortalIsValid, PortalRunFetch(), _SPI_connection::processed, SPI_processed, and _SPI_connection::tuptable.

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

2581 {
2582  uint64 nfetched;
2583 
2584  /* Check that the portal is valid */
2585  if (!PortalIsValid(portal))
2586  elog(ERROR, "invalid portal in SPI cursor operation");
2587 
2588  /* Push the SPI stack */
2589  if (_SPI_begin_call(true) < 0)
2590  elog(ERROR, "SPI cursor operation called while not connected");
2591 
2592  /* Reset the SPI result (note we deliberately don't touch lastoid) */
2593  SPI_processed = 0;
2594  SPI_tuptable = NULL;
2595  _SPI_current->processed = 0;
2596  _SPI_current->tuptable = NULL;
2597 
2598  /* Run the cursor */
2599  nfetched = PortalRunFetch(portal,
2600  direction,
2601  count,
2602  dest);
2603 
2604  /*
2605  * Think not to combine this store with the preceding function call. If
2606  * the portal contains calls to functions that use SPI, then _SPI_stack is
2607  * likely to move around while the portal runs. When control returns,
2608  * _SPI_current will point to the correct stack entry... but the pointer
2609  * may be different than it was beforehand. So we must be sure to re-fetch
2610  * the pointer after the function call completes.
2611  */
2612  _SPI_current->processed = nfetched;
2613 
2614  if (dest->mydest == DestSPI && _SPI_checktuples())
2615  elog(ERROR, "consistency check on SPI tuple count failed");
2616 
2617  /* Put the result into place for access by caller */
2620 
2621  /* tuptable now is caller's responsibility, not SPI's */
2622  _SPI_current->tuptable = NULL;
2623 
2624  /* Pop the SPI stack */
2625  _SPI_end_call(true);
2626 }
Definition: dest.h:93
CommandDest mydest
Definition: dest.h:128
uint64 PortalRunFetch(Portal portal, FetchDirection fdirection, long count, DestReceiver *dest)
Definition: pquery.c:1392
SPITupleTable * SPI_tuptable
Definition: spi.c:46
static _SPI_connection * _SPI_current
Definition: spi.c:50
uint64 SPI_processed
Definition: spi.c:45
static int _SPI_begin_call(bool use_exec)
Definition: spi.c:2649
static bool _SPI_checktuples(void)
Definition: spi.c:2689
#define ERROR
Definition: elog.h:43
SPITupleTable * tuptable
Definition: spi_priv.h:26
static int _SPI_end_call(bool use_exec)
Definition: spi.c:2673
#define PortalIsValid(p)
Definition: portal.h:201
uint64 processed
Definition: spi_priv.h:25
#define elog(elevel,...)
Definition: elog.h:226

◆ _SPI_end_call()

static int _SPI_end_call ( bool  use_exec)
static

Definition at line 2673 of file spi.c.

References _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_execute(), SPI_execute_plan(), SPI_execute_plan_with_paramlist(), SPI_execute_snapshot(), SPI_execute_with_args(), SPI_prepare_cursor(), SPI_prepare_params(), SPI_register_relation(), SPI_saveplan(), and SPI_unregister_relation().

2674 {
2675  if (use_exec)
2676  {
2677  /* switch to the procedure memory context */
2678  _SPI_procmem();
2679  /* mark Executor context no longer in use */
2681  /* and free Executor memory */
2683  }
2684 
2685  return 0;
2686 }
SubTransactionId execSubid
Definition: spi_priv.h:29
static _SPI_connection * _SPI_current
Definition: spi.c:50
#define MemoryContextResetAndDeleteChildren(ctx)
Definition: memutils.h:67
MemoryContext execCxt
Definition: spi_priv.h:34
#define InvalidSubTransactionId
Definition: c.h:513
static MemoryContext _SPI_procmem(void)
Definition: spi.c:2636

◆ _SPI_error_callback()

static void _SPI_error_callback ( void *  arg)
static

Definition at line 2550 of file spi.c.

References errcontext, errposition(), geterrposition(), internalerrposition(), and internalerrquery().

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

2551 {
2552  const char *query = (const char *) arg;
2553  int syntaxerrposition;
2554 
2555  if (query == NULL) /* in case arg wasn't set yet */
2556  return;
2557 
2558  /*
2559  * If there is a syntax error position, convert to internal syntax error;
2560  * otherwise treat the query as an item of context stack
2561  */
2562  syntaxerrposition = geterrposition();
2563  if (syntaxerrposition > 0)
2564  {
2565  errposition(0);
2566  internalerrposition(syntaxerrposition);
2567  internalerrquery(query);
2568  }
2569  else
2570  errcontext("SQL statement \"%s\"", query);
2571 }
int geterrposition(void)
Definition: elog.c:1244
int internalerrquery(const char *query)
Definition: elog.c:1148
#define errcontext
Definition: elog.h:183
void * arg
int errposition(int cursorpos)
Definition: elog.c:1112
int internalerrposition(int cursorpos)
Definition: elog.c:1128

◆ _SPI_execmem()

static MemoryContext _SPI_execmem ( void  )
static

Definition at line 2630 of file spi.c.

References _SPI_connection::execCxt, and MemoryContextSwitchTo().

Referenced by _SPI_begin_call().

2631 {
2633 }
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static _SPI_connection * _SPI_current
Definition: spi.c:50
MemoryContext execCxt
Definition: spi_priv.h:34

◆ _SPI_execute_plan()

static int _SPI_execute_plan ( SPIPlanPtr  plan,
ParamListInfo  paramLI,
Snapshot  snapshot,
Snapshot  crosscheck_snapshot,
bool  read_only,
bool  fire_triggers,
uint64  tcount 
)
static

Definition at line 2101 of file spi.c.

References _SPI_error_callback(), _SPI_pquery(), ActiveSnapshotSet(), ErrorContextCallback::arg, _SPI_plan::argtypes, Assert, _SPI_connection::atomic, ErrorContextCallback::callback, PlannedStmt::canSetTag, CommandCounterIncrement(), CommandIsReadOnly(), CompleteCachedPlan(), COMPLETION_TAG_BUFSIZE, CreateCommandTag(), CreateDestReceiver(), CreateQueryDesc(), _SPI_plan::cursor_options, generate_unaccent_rules::dest, DestNone, DestSPI, ereport, errcode(), errmsg(), ERROR, error_context_stack, CopyStmt::filename, FreeQueryDesc(), GetActiveSnapshot(), GetCachedPlan(), GetTransactionSnapshot(), CreateTableAsStmt::if_not_exists, CreateTableAsStmt::into, InvalidSnapshot, CreateTableAsStmt::is_select_into, IsA, IsInParallelMode(), lfirst, lfirst_node, _SPI_plan::nargs, NIL, _SPI_plan::no_snapshots, SPITupleTable::numvals, _SPI_plan::oneshot, _SPI_plan::parserSetup, _SPI_plan::parserSetupArg, pg_analyze_and_rewrite(), pg_analyze_and_rewrite_params(), pg_strtouint64(), _SPI_plan::plancache_list, PopActiveSnapshot(), PreventCommandIfParallelMode(), ErrorContextCallback::previous, PROCESS_UTILITY_QUERY, PROCESS_UTILITY_QUERY_NONATOMIC, _SPI_connection::processed, ProcessUtility(), PushActiveSnapshot(), PushCopiedSnapshot(), CachedPlanSource::query_string, _SPI_connection::queryEnv, CachedPlanSource::raw_parse_tree, ReleaseCachedPlan(), _SPI_plan::saved, IntoClause::skipData, SPI_ERROR_COPY, SPI_ERROR_TRANSACTION, SPI_freetuptable(), SPI_OK_REWRITTEN, SPI_OK_SELINTO, SPI_OK_UTILITY, SPI_processed, CachedPlan::stmt_list, _SPI_connection::tuptable, unconstify, UpdateActiveSnapshotCommandId(), and PlannedStmt::utilityStmt.

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

2104 {
2105  int my_res = 0;
2106  uint64 my_processed = 0;
2107  SPITupleTable *my_tuptable = NULL;
2108  int res = 0;
2109  bool pushed_active_snap = false;
2110  ErrorContextCallback spierrcontext;
2111  CachedPlan *cplan = NULL;
2112  ListCell *lc1;
2113 
2114  /*
2115  * Setup error traceback support for ereport()
2116  */
2117  spierrcontext.callback = _SPI_error_callback;
2118  spierrcontext.arg = NULL; /* we'll fill this below */
2119  spierrcontext.previous = error_context_stack;
2120  error_context_stack = &spierrcontext;
2121 
2122  /*
2123  * We support four distinct snapshot management behaviors:
2124  *
2125  * snapshot != InvalidSnapshot, read_only = true: use exactly the given
2126  * snapshot.
2127  *
2128  * snapshot != InvalidSnapshot, read_only = false: use the given snapshot,
2129  * modified by advancing its command ID before each querytree.
2130  *
2131  * snapshot == InvalidSnapshot, read_only = true: use the entry-time
2132  * ActiveSnapshot, if any (if there isn't one, we run with no snapshot).
2133  *
2134  * snapshot == InvalidSnapshot, read_only = false: take a full new
2135  * snapshot for each user command, and advance its command ID before each
2136  * querytree within the command.
2137  *
2138  * In the first two cases, we can just push the snap onto the stack once
2139  * for the whole plan list.
2140  *
2141  * But if the plan has no_snapshots set to true, then don't manage
2142  * snapshots at all. The caller should then take care of that.
2143  */
2144  if (snapshot != InvalidSnapshot && !plan->no_snapshots)
2145  {
2146  if (read_only)
2147  {
2148  PushActiveSnapshot(snapshot);
2149  pushed_active_snap = true;
2150  }
2151  else
2152  {
2153  /* Make sure we have a private copy of the snapshot to modify */
2154  PushCopiedSnapshot(snapshot);
2155  pushed_active_snap = true;
2156  }
2157  }
2158 
2159  foreach(lc1, plan->plancache_list)
2160  {
2161  CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc1);
2162  List *stmt_list;
2163  ListCell *lc2;
2164 
2165  spierrcontext.arg = unconstify(char *, plansource->query_string);
2166 
2167  /*
2168  * If this is a one-shot plan, we still need to do parse analysis.
2169  */
2170  if (plan->oneshot)
2171  {
2172  RawStmt *parsetree = plansource->raw_parse_tree;
2173  const char *src = plansource->query_string;
2174  List *stmt_list;
2175 
2176  /*
2177  * Parameter datatypes are driven by parserSetup hook if provided,
2178  * otherwise we use the fixed parameter list.
2179  */
2180  if (parsetree == NULL)
2181  stmt_list = NIL;
2182  else if (plan->parserSetup != NULL)
2183  {
2184  Assert(plan->nargs == 0);
2185  stmt_list = pg_analyze_and_rewrite_params(parsetree,
2186  src,
2187  plan->parserSetup,
2188  plan->parserSetupArg,
2190  }
2191  else
2192  {
2193  stmt_list = pg_analyze_and_rewrite(parsetree,
2194  src,
2195  plan->argtypes,
2196  plan->nargs,
2198  }
2199 
2200  /* Finish filling in the CachedPlanSource */
2201  CompleteCachedPlan(plansource,
2202  stmt_list,
2203  NULL,
2204  plan->argtypes,
2205  plan->nargs,
2206  plan->parserSetup,
2207  plan->parserSetupArg,
2208  plan->cursor_options,
2209  false); /* not fixed result */
2210  }
2211 
2212  /*
2213  * Replan if needed, and increment plan refcount. If it's a saved
2214  * plan, the refcount must be backed by the CurrentResourceOwner.
2215  */
2216  cplan = GetCachedPlan(plansource, paramLI, plan->saved, _SPI_current->queryEnv);
2217  stmt_list = cplan->stmt_list;
2218 
2219  /*
2220  * In the default non-read-only case, get a new snapshot, replacing
2221  * any that we pushed in a previous cycle.
2222  */
2223  if (snapshot == InvalidSnapshot && !read_only && !plan->no_snapshots)
2224  {
2225  if (pushed_active_snap)
2228  pushed_active_snap = true;
2229  }
2230 
2231  foreach(lc2, stmt_list)
2232  {
2233  PlannedStmt *stmt = lfirst_node(PlannedStmt, lc2);
2234  bool canSetTag = stmt->canSetTag;
2235  DestReceiver *dest;
2236 
2237  _SPI_current->processed = 0;
2238  _SPI_current->tuptable = NULL;
2239 
2240  if (stmt->utilityStmt)
2241  {
2242  if (IsA(stmt->utilityStmt, CopyStmt))
2243  {
2244  CopyStmt *cstmt = (CopyStmt *) stmt->utilityStmt;
2245 
2246  if (cstmt->filename == NULL)
2247  {
2248  my_res = SPI_ERROR_COPY;
2249  goto fail;
2250  }
2251  }
2252  else if (IsA(stmt->utilityStmt, TransactionStmt))
2253  {
2254  my_res = SPI_ERROR_TRANSACTION;
2255  goto fail;
2256  }
2257  }
2258 
2259  if (read_only && !CommandIsReadOnly(stmt))
2260  ereport(ERROR,
2261  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2262  /* translator: %s is a SQL statement name */
2263  errmsg("%s is not allowed in a non-volatile function",
2264  CreateCommandTag((Node *) stmt))));
2265 
2266  if (IsInParallelMode() && !CommandIsReadOnly(stmt))
2268 
2269  /*
2270  * If not read-only mode, advance the command counter before each
2271  * command and update the snapshot.
2272  */
2273  if (!read_only && !plan->no_snapshots)
2274  {
2277  }
2278 
2279  dest = CreateDestReceiver(canSetTag ? DestSPI : DestNone);
2280 
2281  if (stmt->utilityStmt == NULL)
2282  {
2283  QueryDesc *qdesc;
2284  Snapshot snap;
2285 
2286  if (ActiveSnapshotSet())
2287  snap = GetActiveSnapshot();
2288  else
2289  snap = InvalidSnapshot;
2290 
2291  qdesc = CreateQueryDesc(stmt,
2292  plansource->query_string,
2293  snap, crosscheck_snapshot,
2294  dest,
2295  paramLI, _SPI_current->queryEnv,
2296  0);
2297  res = _SPI_pquery(qdesc, fire_triggers,
2298  canSetTag ? tcount : 0);
2299  FreeQueryDesc(qdesc);
2300  }
2301  else
2302  {
2303  char completionTag[COMPLETION_TAG_BUFSIZE];
2304  ProcessUtilityContext context;
2305 
2306  /*
2307  * If the SPI context is atomic, or we are asked to manage
2308  * snapshots, then we are in an atomic execution context.
2309  * Conversely, to propagate a nonatomic execution context, the
2310  * caller must be in a nonatomic SPI context and manage
2311  * snapshots itself.
2312  */
2313  if (_SPI_current->atomic || !plan->no_snapshots)
2314  context = PROCESS_UTILITY_QUERY;
2315  else
2317 
2318  ProcessUtility(stmt,
2319  plansource->query_string,
2320  context,
2321  paramLI,
2323  dest,
2324  completionTag);
2325 
2326  /* Update "processed" if stmt returned tuples */
2327  if (_SPI_current->tuptable)
2329 
2330  res = SPI_OK_UTILITY;
2331 
2332  /*
2333  * Some utility statements return a row count, even though the
2334  * tuples are not returned to the caller.
2335  */
2336  if (IsA(stmt->utilityStmt, CreateTableAsStmt))
2337  {
2338  CreateTableAsStmt *ctastmt = (CreateTableAsStmt *) stmt->utilityStmt;
2339 
2340  if (strncmp(completionTag, "SELECT ", 7) == 0)
2342  pg_strtouint64(completionTag + 7, NULL, 10);
2343  else
2344  {
2345  /*
2346  * Must be an IF NOT EXISTS that did nothing, or a
2347  * CREATE ... WITH NO DATA.
2348  */
2349  Assert(ctastmt->if_not_exists ||
2350  ctastmt->into->skipData);
2351  _SPI_current->processed = 0;
2352  }
2353 
2354  /*
2355  * For historical reasons, if CREATE TABLE AS was spelled
2356  * as SELECT INTO, return a special return code.
2357  */
2358  if (ctastmt->is_select_into)
2359  res = SPI_OK_SELINTO;
2360  }
2361  else if (IsA(stmt->utilityStmt, CopyStmt))
2362  {
2363  Assert(strncmp(completionTag, "COPY ", 5) == 0);
2364  _SPI_current->processed = pg_strtouint64(completionTag + 5,
2365  NULL, 10);
2366  }
2367  }
2368 
2369  /*
2370  * The last canSetTag query sets the status values returned to the
2371  * caller. Be careful to free any tuptables not returned, to
2372  * avoid intra-transaction memory leak.
2373  */
2374  if (canSetTag)
2375  {
2376  my_processed = _SPI_current->processed;
2377  SPI_freetuptable(my_tuptable);
2378  my_tuptable = _SPI_current->tuptable;
2379  my_res = res;
2380  }
2381  else
2382  {
2384  _SPI_current->tuptable = NULL;
2385  }
2386  /* we know that the receiver doesn't need a destroy call */
2387  if (res < 0)
2388  {
2389  my_res = res;
2390  goto fail;
2391  }
2392  }
2393 
2394  /* Done with this plan, so release refcount */
2395  ReleaseCachedPlan(cplan, plan->saved);
2396  cplan = NULL;
2397 
2398  /*
2399  * If not read-only mode, advance the command counter after the last
2400  * command. This ensures that its effects are visible, in case it was
2401  * DDL that would affect the next CachedPlanSource.
2402  */
2403  if (!read_only)
2405  }
2406 
2407 fail:
2408 
2409  /* Pop the snapshot off the stack if we pushed one */
2410  if (pushed_active_snap)
2412 
2413  /* We no longer need the cached plan refcount, if any */
2414  if (cplan)
2415  ReleaseCachedPlan(cplan, plan->saved);
2416 
2417  /*
2418  * Pop the error context stack
2419  */
2420  error_context_stack = spierrcontext.previous;
2421 
2422  /* Save results for caller */
2423  SPI_processed = my_processed;
2424  SPI_tuptable = my_tuptable;
2425 
2426  /* tuptable now is caller's responsibility, not SPI's */
2427  _SPI_current->tuptable = NULL;
2428 
2429  /*
2430  * If none of the queries had canSetTag, return SPI_OK_REWRITTEN. Prior to
2431  * 8.4, we used return the last query's result code, but not its auxiliary
2432  * results, but that's confusing.
2433  */
2434  if (my_res == 0)
2435  my_res = SPI_OK_REWRITTEN;
2436 
2437  return my_res;
2438 }
#define NIL
Definition: pg_list.h:65
Oid * argtypes
Definition: spi_priv.h:100
bool CommandIsReadOnly(PlannedStmt *pstmt)
Definition: utility.c:100
void UpdateActiveSnapshotCommandId(void)
Definition: snapmgr.c:783
#define IsA(nodeptr, _type_)
Definition: nodes.h:575
List * plancache_list
Definition: spi_priv.h:96
CachedPlan * GetCachedPlan(CachedPlanSource *plansource, ParamListInfo boundParams, bool useResOwner, QueryEnvironment *queryEnv)
Definition: plancache.c:1138
void PreventCommandIfParallelMode(const char *cmdname)
Definition: utility.c:257
void FreeQueryDesc(QueryDesc *qdesc)
Definition: pquery.c:105
Definition: dest.h:93
#define SPI_ERROR_COPY
Definition: spi.h:40
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:841
SPITupleTable * SPI_tuptable
Definition: spi.c:46
Definition: nodes.h:524
void ProcessUtility(PlannedStmt *pstmt, const char *queryString, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, char *completionTag)
Definition: utility.c:338
int errcode(int sqlerrcode)
Definition: elog.c:570
ProcessUtilityContext
Definition: utility.h:19
static _SPI_connection * _SPI_current
Definition: spi.c:50
void PopActiveSnapshot(void)
Definition: snapmgr.c:814
bool skipData
Definition: primnodes.h:119
List * pg_analyze_and_rewrite(RawStmt *parsetree, const char *query_string, Oid *paramTypes, int numParams, QueryEnvironment *queryEnv)
Definition: postgres.c:680
void(* callback)(void *arg)
Definition: elog.h:254
struct ErrorContextCallback * previous
Definition: elog.h:253
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:306
uint64 SPI_processed
Definition: spi.c:45
ErrorContextCallback * error_context_stack
Definition: elog.c:88
static void _SPI_error_callback(void *arg)
Definition: spi.c:2550
bool IsInParallelMode(void)
Definition: xact.c:994
uint64 numvals
Definition: spi.h:27
#define ERROR
Definition: elog.h:43
bool no_snapshots
Definition: spi_priv.h:95
QueryEnvironment * queryEnv
Definition: spi_priv.h:37
SPITupleTable * tuptable
Definition: spi_priv.h:26
void PushCopiedSnapshot(Snapshot snapshot)
Definition: snapmgr.c:771
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
#define lfirst_node(type, lc)
Definition: pg_list.h:193
static int _SPI_pquery(QueryDesc *queryDesc, bool fire_triggers, uint64 tcount)
Definition: spi.c:2469
Definition: dest.h:88
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:735
DestReceiver * CreateDestReceiver(CommandDest dest)
Definition: dest.c:113
#define SPI_OK_UTILITY
Definition: spi.h:56
Node * utilityStmt
Definition: plannodes.h:90
void ReleaseCachedPlan(CachedPlan *plan, bool useResOwner)
Definition: plancache.c:1259
bool ActiveSnapshotSet(void)
Definition: snapmgr.c:853
#define SPI_OK_REWRITTEN
Definition: spi.h:66
#define ereport(elevel, rest)
Definition: elog.h:141
const char * CreateCommandTag(Node *parsetree)
Definition: utility.c:2100
#define SPI_ERROR_TRANSACTION
Definition: spi.h:46
#define SPI_OK_SELINTO
Definition: spi.h:58
#define unconstify(underlying_type, expr)
Definition: c.h:1163
void SPI_freetuptable(SPITupleTable *tuptable)
Definition: spi.c:1162
#define InvalidSnapshot
Definition: snapshot.h:123
uint64 pg_strtouint64(const char *str, char **endptr, int base)
Definition: numutils.c:558
bool canSetTag
Definition: plannodes.h:54
void CommandCounterIncrement(void)
Definition: xact.c:1003
bool saved
Definition: spi_priv.h:93
int nargs
Definition: spi_priv.h:99
IntoClause * into
Definition: parsenodes.h:3228
#define COMPLETION_TAG_BUFSIZE
Definition: dest.h:74
uint64 processed
Definition: spi_priv.h:25
#define Assert(condition)
Definition: c.h:732
#define lfirst(lc)
Definition: pg_list.h:190
ParserSetupHook parserSetup
Definition: spi_priv.h:101
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:336
bool oneshot
Definition: spi_priv.h:94
const char * query_string
Definition: plancache.h:97
void * parserSetupArg
Definition: spi_priv.h:102
List * pg_analyze_and_rewrite_params(RawStmt *parsetree, const char *query_string, ParserSetupHook parserSetup, void *parserSetupArg, QueryEnvironment *queryEnv)
Definition: postgres.c:717
struct RawStmt * raw_parse_tree
Definition: plancache.h:96
int errmsg(const char *fmt,...)
Definition: elog.c:784
char * filename
Definition: parsenodes.h:1994
List * stmt_list
Definition: plancache.h:146
int cursor_options
Definition: spi_priv.h:98
Definition: pg_list.h:50

◆ _SPI_find_ENR_by_name()

static EphemeralNamedRelation _SPI_find_ENR_by_name ( const char *  name)
static

Definition at line 2850 of file spi.c.

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

Referenced by SPI_register_relation(), and SPI_unregister_relation().

2851 {
2852  /* internal static function; any error is bug in SPI itself */
2853  Assert(name != NULL);
2854 
2855  /* fast exit if no tuplestores have been added */
2856  if (_SPI_current->queryEnv == NULL)
2857  return NULL;
2858 
2859  return get_ENR(_SPI_current->queryEnv, name);
2860 }
static _SPI_connection * _SPI_current
Definition: spi.c:50
QueryEnvironment * queryEnv
Definition: spi_priv.h:37
#define Assert(condition)
Definition: c.h:732
const char * name
Definition: encode.c:521
EphemeralNamedRelation get_ENR(QueryEnvironment *queryEnv, const char *name)

◆ _SPI_make_plan_non_temp()

static SPIPlanPtr _SPI_make_plan_non_temp ( SPIPlanPtr  plan)
static

Definition at line 2713 of file spi.c.

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

Referenced by SPI_prepare_cursor(), and SPI_prepare_params().

2714 {
2715  SPIPlanPtr newplan;
2716  MemoryContext parentcxt = _SPI_current->procCxt;
2717  MemoryContext plancxt;
2718  MemoryContext oldcxt;
2719  ListCell *lc;
2720 
2721  /* Assert the input is a temporary SPIPlan */
2722  Assert(plan->magic == _SPI_PLAN_MAGIC);
2723  Assert(plan->plancxt == NULL);
2724  /* One-shot plans can't be saved */
2725  Assert(!plan->oneshot);
2726 
2727  /*
2728  * Create a memory context for the plan, underneath the procedure context.
2729  * We don't expect the plan to be very large.
2730  */
2731  plancxt = AllocSetContextCreate(parentcxt,
2732  "SPI Plan",
2734  oldcxt = MemoryContextSwitchTo(plancxt);
2735 
2736  /* Copy the _SPI_plan struct and subsidiary data into the new context */
2737  newplan = (SPIPlanPtr) palloc0(sizeof(_SPI_plan));
2738  newplan->magic = _SPI_PLAN_MAGIC;
2739  newplan->plancxt = plancxt;
2740  newplan->cursor_options = plan->cursor_options;
2741  newplan->nargs = plan->nargs;
2742  if (plan->nargs > 0)
2743  {
2744  newplan->argtypes = (Oid *) palloc(plan->nargs * sizeof(Oid));
2745  memcpy(newplan->argtypes, plan->argtypes, plan->nargs * sizeof(Oid));
2746  }
2747  else
2748  newplan->argtypes = NULL;
2749  newplan->parserSetup = plan->parserSetup;
2750  newplan->parserSetupArg = plan->parserSetupArg;
2751 
2752  /*
2753  * Reparent all the CachedPlanSources into the procedure context. In
2754  * theory this could fail partway through due to the pallocs, but we don't
2755  * care too much since both the procedure context and the executor context
2756  * would go away on error.
2757  */
2758  foreach(lc, plan->plancache_list)
2759  {
2760  CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc);
2761 
2762  CachedPlanSetParentContext(plansource, parentcxt);
2763 
2764  /* Build new list, with list cells in plancxt */
2765  newplan->plancache_list = lappend(newplan->plancache_list, plansource);
2766  }
2767 
2768  MemoryContextSwitchTo(oldcxt);
2769 
2770  /* For safety, unlink the CachedPlanSources from the temporary plan */
2771  plan->plancache_list = NIL;
2772 
2773  return newplan;
2774 }
#define NIL
Definition: pg_list.h:65
Oid * argtypes
Definition: spi_priv.h:100
#define AllocSetContextCreate
Definition: memutils.h:169
List * plancache_list
Definition: spi_priv.h:96
#define _SPI_PLAN_MAGIC
Definition: spi_priv.h:20
int magic
Definition: spi_priv.h:92
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:201
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static _SPI_connection * _SPI_current
Definition: spi.c:50
unsigned int Oid
Definition: postgres_ext.h:31
void CachedPlanSetParentContext(CachedPlanSource *plansource, MemoryContext newcontext)
Definition: plancache.c:1287
MemoryContext plancxt
Definition: spi_priv.h:97
List * lappend(List *list, void *datum)
Definition: list.c:321
void * palloc0(Size size)
Definition: mcxt.c:955
MemoryContext procCxt
Definition: spi_priv.h:33
int nargs
Definition: spi_priv.h:99
#define Assert(condition)
Definition: c.h:732
#define lfirst(lc)
Definition: pg_list.h:190
ParserSetupHook parserSetup
Definition: spi_priv.h:101
bool oneshot
Definition: spi_priv.h:94
void * parserSetupArg
Definition: spi_priv.h:102
void * palloc(Size size)
Definition: mcxt.c:924
struct _SPI_plan * SPIPlanPtr
Definition: spi.h:37
int cursor_options
Definition: spi_priv.h:98

◆ _SPI_pquery()

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

Definition at line 2469 of file spi.c.

References _SPI_checktuples(), CMD_DELETE, CMD_INSERT, CMD_SELECT, CMD_UPDATE, QueryDesc::dest, 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, ResetUsage(), ShowUsage(), SPI_ERROR_OPUNKNOWN, SPI_OK_DELETE, SPI_OK_DELETE_RETURNING, SPI_OK_INSERT, SPI_OK_INSERT_RETURNING, SPI_OK_SELECT, SPI_OK_UPDATE, SPI_OK_UPDATE_RETURNING, and SPI_OK_UTILITY.

Referenced by _SPI_execute_plan().

2470 {
2471  int operation = queryDesc->operation;
2472  int eflags;
2473  int res;
2474 
2475  switch (operation)
2476  {
2477  case CMD_SELECT:
2478  if (queryDesc->dest->mydest != DestSPI)
2479  {
2480  /* Don't return SPI_OK_SELECT if we're discarding result */
2481  res = SPI_OK_UTILITY;
2482  }
2483  else
2484  res = SPI_OK_SELECT;
2485  break;
2486  case CMD_INSERT:
2487  if (queryDesc->plannedstmt->hasReturning)
2489  else
2490  res = SPI_OK_INSERT;
2491  break;
2492  case CMD_DELETE:
2493  if (queryDesc->plannedstmt->hasReturning)
2495  else
2496  res = SPI_OK_DELETE;
2497  break;
2498  case CMD_UPDATE:
2499  if (queryDesc->plannedstmt->hasReturning)
2501  else
2502  res = SPI_OK_UPDATE;
2503  break;
2504  default:
2505  return SPI_ERROR_OPUNKNOWN;
2506  }
2507 
2508 #ifdef SPI_EXECUTOR_STATS
2509  if (ShowExecutorStats)
2510  ResetUsage();
2511 #endif
2512 
2513  /* Select execution options */
2514  if (fire_triggers)
2515  eflags = 0; /* default run-to-completion flags */
2516  else
2517  eflags = EXEC_FLAG_SKIP_TRIGGERS;
2518 
2519  ExecutorStart(queryDesc, eflags);
2520 
2521  ExecutorRun(queryDesc, ForwardScanDirection, tcount, true);
2522 
2523  _SPI_current->processed = queryDesc->estate->es_processed;
2524 
2525  if ((res == SPI_OK_SELECT || queryDesc->plannedstmt->hasReturning) &&
2526  queryDesc->dest->mydest == DestSPI)
2527  {
2528  if (_SPI_checktuples())
2529  elog(ERROR, "consistency check on SPI tuple count failed");
2530  }
2531 
2532  ExecutorFinish(queryDesc);
2533  ExecutorEnd(queryDesc);
2534  /* FreeQueryDesc is done by the caller */
2535 
2536 #ifdef SPI_EXECUTOR_STATS
2537  if (ShowExecutorStats)
2538  ShowUsage("SPI EXECUTOR STATS");
2539 #endif
2540 
2541  return res;
2542 }
EState * estate
Definition: execdesc.h:48
#define SPI_OK_DELETE_RETURNING
Definition: spi.h:64
Definition: dest.h:93
void ShowUsage(const char *title)
Definition: postgres.c:4559
#define SPI_OK_DELETE
Definition: spi.h:60
CommandDest mydest
Definition: dest.h:128
void ExecutorStart(QueryDesc *queryDesc, int eflags)
Definition: execMain.c:144
#define SPI_ERROR_OPUNKNOWN
Definition: spi.h:41
static _SPI_connection * _SPI_current
Definition: spi.c:50
static bool _SPI_checktuples(void)
Definition: spi.c:2689
void ExecutorEnd(QueryDesc *queryDesc)
Definition: execMain.c:463
void ResetUsage(void)
Definition: postgres.c:4552
#define ERROR
Definition: elog.h:43
void ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count, bool execute_once)
Definition: execMain.c:302
#define SPI_OK_INSERT_RETURNING
Definition: spi.h:63
bool hasReturning
Definition: plannodes.h:50
#define SPI_OK_UTILITY
Definition: spi.h:56
#define SPI_OK_UPDATE_RETURNING
Definition: spi.h:65
void ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:403
CmdType operation
Definition: execdesc.h:36
#define SPI_OK_SELECT
Definition: spi.h:57
uint64 processed
Definition: spi_priv.h:25
uint64 es_processed
Definition: execnodes.h:554
#define EXEC_FLAG_SKIP_TRIGGERS
Definition: executor.h:60
DestReceiver * dest
Definition: execdesc.h:41
#define SPI_OK_UPDATE
Definition: spi.h:61
#define elog(elevel,...)
Definition: elog.h:226
#define SPI_OK_INSERT
Definition: spi.h:59
PlannedStmt * plannedstmt
Definition: execdesc.h:37

◆ _SPI_prepare_oneshot_plan()

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

Definition at line 2043 of file spi.c.

References _SPI_error_callback(), ErrorContextCallback::arg, ErrorContextCallback::callback, CreateCommandTag(), CreateOneShotCachedPlan(), error_context_stack, lappend(), lfirst_node, NIL, _SPI_plan::oneshot, pg_parse_query(), _SPI_plan::plancache_list, ErrorContextCallback::previous, RawStmt::stmt, and unconstify.

Referenced by SPI_execute(), and SPI_execute_with_args().

2044 {
2045  List *raw_parsetree_list;
2046  List *plancache_list;
2047  ListCell *list_item;
2048  ErrorContextCallback spierrcontext;
2049 
2050  /*
2051  * Setup error traceback support for ereport()
2052  */
2053  spierrcontext.callback = _SPI_error_callback;
2054  spierrcontext.arg = unconstify(char *, src);
2055  spierrcontext.previous = error_context_stack;
2056  error_context_stack = &spierrcontext;
2057 
2058  /*
2059  * Parse the request string into a list of raw parse trees.
2060  */
2061  raw_parsetree_list = pg_parse_query(src);
2062 
2063  /*
2064  * Construct plancache entries, but don't do parse analysis yet.
2065  */
2066  plancache_list = NIL;
2067 
2068  foreach(list_item, raw_parsetree_list)
2069  {
2070  RawStmt *parsetree = lfirst_node(RawStmt, list_item);
2071  CachedPlanSource *plansource;
2072 
2073  plansource = CreateOneShotCachedPlan(parsetree,
2074  src,
2075  CreateCommandTag(parsetree->stmt));
2076 
2077  plancache_list = lappend(plancache_list, plansource);
2078  }
2079 
2080  plan->plancache_list = plancache_list;
2081  plan->oneshot = true;
2082 
2083  /*
2084  * Pop the error context stack
2085  */
2086  error_context_stack = spierrcontext.previous;
2087 }
#define NIL
Definition: pg_list.h:65
List * plancache_list
Definition: spi_priv.h:96
CachedPlanSource * CreateOneShotCachedPlan(RawStmt *raw_parse_tree, const char *query_string, const char *commandTag)
Definition: plancache.c:247
void(* callback)(void *arg)
Definition: elog.h:254
struct ErrorContextCallback * previous
Definition: elog.h:253
ErrorContextCallback * error_context_stack
Definition: elog.c:88
static void _SPI_error_callback(void *arg)
Definition: spi.c:2550
List * pg_parse_query(const char *query_string)
Definition: postgres.c:632
#define lfirst_node(type, lc)
Definition: pg_list.h:193
Node * stmt
Definition: parsenodes.h:1485
const char * CreateCommandTag(Node *parsetree)
Definition: utility.c:2100
List * lappend(List *list, void *datum)
Definition: list.c:321
#define unconstify(underlying_type, expr)
Definition: c.h:1163
bool oneshot
Definition: spi_priv.h:94
Definition: pg_list.h:50

◆ _SPI_prepare_plan()

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

Definition at line 1938 of file spi.c.

References _SPI_error_callback(), ErrorContextCallback::arg, _SPI_plan::argtypes, Assert, ErrorContextCallback::callback, CompleteCachedPlan(), CreateCachedPlan(), CreateCommandTag(), _SPI_plan::cursor_options, error_context_stack, lappend(), lfirst_node, _SPI_plan::nargs, NIL, _SPI_plan::oneshot, _SPI_plan::parserSetup, _SPI_plan::parserSetupArg, pg_analyze_and_rewrite(), pg_analyze_and_rewrite_params(), pg_parse_query(), _SPI_plan::plancache_list, ErrorContextCallback::previous, _SPI_connection::queryEnv, RawStmt::stmt, and unconstify.

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

1939 {
1940  List *raw_parsetree_list;
1941  List *plancache_list;
1942  ListCell *list_item;
1943  ErrorContextCallback spierrcontext;
1944 
1945  /*
1946  * Setup error traceback support for ereport()
1947  */
1948  spierrcontext.callback = _SPI_error_callback;
1949  spierrcontext.arg = unconstify(char *, src);
1950  spierrcontext.previous = error_context_stack;
1951  error_context_stack = &spierrcontext;
1952 
1953  /*
1954  * Parse the request string into a list of raw parse trees.
1955  */
1956  raw_parsetree_list = pg_parse_query(src);
1957 
1958  /*
1959  * Do parse analysis and rule rewrite for each raw parsetree, storing the
1960  * results into unsaved plancache entries.
1961  */
1962  plancache_list = NIL;
1963 
1964  foreach(list_item, raw_parsetree_list)
1965  {
1966  RawStmt *parsetree = lfirst_node(RawStmt, list_item);
1967  List *stmt_list;
1968  CachedPlanSource *plansource;
1969 
1970  /*
1971  * Create the CachedPlanSource before we do parse analysis, since it
1972  * needs to see the unmodified raw parse tree.
1973  */
1974  plansource = CreateCachedPlan(parsetree,
1975  src,
1976  CreateCommandTag(parsetree->stmt));
1977 
1978  /*
1979  * Parameter datatypes are driven by parserSetup hook if provided,
1980  * otherwise we use the fixed parameter list.
1981  */
1982  if (plan->parserSetup != NULL)
1983  {
1984  Assert(plan->nargs == 0);
1985  stmt_list = pg_analyze_and_rewrite_params(parsetree,
1986  src,
1987  plan->parserSetup,
1988  plan->parserSetupArg,
1990  }
1991  else
1992  {
1993  stmt_list = pg_analyze_and_rewrite(parsetree,
1994  src,
1995  plan->argtypes,
1996  plan->nargs,
1998  }
1999 
2000  /* Finish filling in the CachedPlanSource */
2001  CompleteCachedPlan(plansource,
2002  stmt_list,
2003  NULL,
2004  plan->argtypes,
2005  plan->nargs,
2006  plan->parserSetup,
2007  plan->parserSetupArg,
2008  plan->cursor_options,
2009  false); /* not fixed result */
2010 
2011  plancache_list = lappend(plancache_list, plansource);
2012  }
2013 
2014  plan->plancache_list = plancache_list;
2015  plan->oneshot = false;
2016 
2017  /*
2018  * Pop the error context stack
2019  */
2020  error_context_stack = spierrcontext.previous;
2021 }
#define NIL
Definition: pg_list.h:65
Oid * argtypes
Definition: spi_priv.h:100
List * plancache_list
Definition: spi_priv.h:96
static _SPI_connection * _SPI_current
Definition: spi.c:50
List * pg_analyze_and_rewrite(RawStmt *parsetree, const char *query_string, Oid *paramTypes, int numParams, QueryEnvironment *queryEnv)
Definition: postgres.c:680
void(* callback)(void *arg)
Definition: elog.h:254
struct ErrorContextCallback * previous
Definition: elog.h:253
ErrorContextCallback * error_context_stack
Definition: elog.c:88
static void _SPI_error_callback(void *arg)
Definition: spi.c:2550
QueryEnvironment * queryEnv
Definition: spi_priv.h:37
List * pg_parse_query(const char *query_string)
Definition: postgres.c:632
#define lfirst_node(type, lc)
Definition: pg_list.h:193
Node * stmt
Definition: parsenodes.h:1485
CachedPlanSource * CreateCachedPlan(RawStmt *raw_parse_tree, const char *query_string, const char *commandTag)
Definition: plancache.c:164
const char * CreateCommandTag(Node *parsetree)
Definition: utility.c:2100
List * lappend(List *list, void *datum)
Definition: list.c:321
#define unconstify(underlying_type, expr)
Definition: c.h:1163
int nargs
Definition: spi_priv.h:99
#define Assert(condition)
Definition: c.h:732
ParserSetupHook parserSetup
Definition: spi_priv.h:101
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:336
bool oneshot
Definition: spi_priv.h:94
void * parserSetupArg
Definition: spi_priv.h:102
List * pg_analyze_and_rewrite_params(RawStmt *parsetree, const char *query_string, ParserSetupHook parserSetup, void *parserSetupArg, QueryEnvironment *queryEnv)
Definition: postgres.c:717
int cursor_options
Definition: spi_priv.h:98
Definition: pg_list.h:50

◆ _SPI_procmem()

static MemoryContext _SPI_procmem ( void  )
static

Definition at line 2636 of file spi.c.

References MemoryContextSwitchTo(), and _SPI_connection::procCxt.

Referenced by _SPI_end_call(), and spi_dest_startup().

2637 {
2639 }
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static _SPI_connection * _SPI_current
Definition: spi.c:50
MemoryContext procCxt
Definition: spi_priv.h:33

◆ _SPI_rollback()

static void _SPI_rollback ( bool  chain)
static

Definition at line 290 of file spi.c.

References AbortCurrentTransaction(), _SPI_connection::atomic, CurrentMemoryContext, ereport, errcode(), errmsg(), ERROR, HoldPinnedPortals(), _SPI_connection::internal_xact, IsSubTransaction(), MemoryContextSwitchTo(), RestoreTransactionCharacteristics(), SaveTransactionCharacteristics(), and StartTransactionCommand().

Referenced by SPI_rollback(), and SPI_rollback_and_chain().

291 {
292  MemoryContext oldcontext = CurrentMemoryContext;
293 
294  if (_SPI_current->atomic)
295  ereport(ERROR,
296  (errcode(ERRCODE_INVALID_TRANSACTION_TERMINATION),
297  errmsg("invalid transaction termination")));
298 
299  /* see under SPI_commit() */
300  if (IsSubTransaction())
301  ereport(ERROR,
302  (errcode(ERRCODE_INVALID_TRANSACTION_TERMINATION),
303  errmsg("cannot roll back while a subtransaction is active")));
304 
305  /*
306  * Hold any pinned portals that any PLs might be using. We have to do
307  * this before changing transaction state, since this will run
308  * user-defined code that might throw an error, and in any case couldn't
309  * be run in an already-aborted transaction.
310  */
312 
313  /* Start the actual rollback */
314  _SPI_current->internal_xact = true;
315 
316  if (chain)
318 
320 
321  if (chain)
322  {
325  }
326 
327  MemoryContextSwitchTo(oldcontext);
328 
329  _SPI_current->internal_xact = false;
330 }
void AbortCurrentTransaction(void)
Definition: xact.c:3159
bool internal_xact
Definition: spi_priv.h:42
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int errcode(int sqlerrcode)
Definition: elog.c:570
static _SPI_connection * _SPI_current
Definition: spi.c:50
#define ERROR
Definition: elog.h:43
void SaveTransactionCharacteristics(void)
Definition: xact.c:2875
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
#define ereport(elevel, rest)
Definition: elog.h:141
void StartTransactionCommand(void)
Definition: xact.c:2794
void RestoreTransactionCharacteristics(void)
Definition: xact.c:2883
bool IsSubTransaction(void)
Definition: xact.c:4682
int errmsg(const char *fmt,...)
Definition: elog.c:784
void HoldPinnedPortals(void)
Definition: portalmem.c:1244

◆ _SPI_save_plan()

static SPIPlanPtr _SPI_save_plan ( SPIPlanPtr  plan)
static

Definition at line 2780 of file spi.c.

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

Referenced by SPI_saveplan().

2781 {
2782  SPIPlanPtr newplan;
2783  MemoryContext plancxt;
2784  MemoryContext oldcxt;
2785  ListCell *lc;
2786 
2787  /* One-shot plans can't be saved */
2788  Assert(!plan->oneshot);
2789 
2790  /*
2791  * Create a memory context for the plan. We don't expect the plan to be
2792  * very large, so use smaller-than-default alloc parameters. It's a
2793  * transient context until we finish copying everything.
2794  */
2796  "SPI Plan",
2798  oldcxt = MemoryContextSwitchTo(plancxt);
2799 
2800  /* Copy the SPI plan into its own context */
2801  newplan = (SPIPlanPtr) palloc0(sizeof(_SPI_plan));
2802  newplan->magic = _SPI_PLAN_MAGIC;
2803  newplan->plancxt = plancxt;
2804  newplan->cursor_options = plan->cursor_options;
2805  newplan->nargs = plan->nargs;
2806  if (plan->nargs > 0)
2807  {
2808  newplan->argtypes = (Oid *) palloc(plan->nargs * sizeof(Oid));
2809  memcpy(newplan->argtypes, plan->argtypes, plan->nargs * sizeof(Oid));
2810  }
2811  else
2812  newplan->argtypes = NULL;
2813  newplan->parserSetup = plan->parserSetup;
2814  newplan->parserSetupArg = plan->parserSetupArg;
2815 
2816  /* Copy all the plancache entries */
2817  foreach(lc, plan->plancache_list)
2818  {
2819  CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc);
2820  CachedPlanSource *newsource;
2821 
2822  newsource = CopyCachedPlan(plansource);
2823  newplan->plancache_list = lappend(newplan->plancache_list, newsource);
2824  }
2825 
2826  MemoryContextSwitchTo(oldcxt);
2827 
2828  /*
2829  * Mark it saved, reparent it under CacheMemoryContext, and mark all the
2830  * component CachedPlanSources as saved. This sequence cannot fail
2831  * partway through, so there's no risk of long-term memory leakage.
2832  */
2833  newplan->saved = true;
2835 
2836  foreach(lc, newplan->plancache_list)
2837  {
2838  CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc);
2839 
2840  SaveCachedPlan(plansource);
2841  }
2842 
2843  return newplan;
2844 }
Oid * argtypes
Definition: spi_priv.h:100
#define AllocSetContextCreate
Definition: memutils.h:169
List * plancache_list
Definition: spi_priv.h:96
#define _SPI_PLAN_MAGIC
Definition: spi_priv.h:20
void MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
Definition: mcxt.c:354
int magic
Definition: spi_priv.h:92
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:201
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
unsigned int Oid
Definition: postgres_ext.h:31
CachedPlanSource * CopyCachedPlan(CachedPlanSource *plansource)
Definition: plancache.c:1325
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
MemoryContext plancxt
Definition: spi_priv.h:97
List * lappend(List *list, void *datum)
Definition: list.c:321
void * palloc0(Size size)
Definition: mcxt.c:955
bool saved
Definition: spi_priv.h:93
int nargs
Definition: spi_priv.h:99
void SaveCachedPlan(CachedPlanSource *plansource)
Definition: plancache.c:452
#define Assert(condition)
Definition: c.h:732
#define lfirst(lc)
Definition: pg_list.h:190
ParserSetupHook parserSetup
Definition: spi_priv.h:101
bool oneshot
Definition: spi_priv.h:94
void * parserSetupArg
Definition: spi_priv.h:102
void * palloc(Size size)
Definition: mcxt.c:924
struct _SPI_plan * SPIPlanPtr
Definition: spi.h:37
int cursor_options
Definition: spi_priv.h:98
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ AtEOSubXact_SPI()

void AtEOSubXact_SPI ( bool  isCommit,
SubTransactionId  mySubid 
)

Definition at line 385 of file spi.c.

References _SPI_connected, _SPI_connection::connectSubid, slist_mutable_iter::cur, ereport, errcode(), errhint(), errmsg(), _SPI_connection::execCxt, _SPI_connection::execSubid, _SPI_connection::internal_xact, InvalidSubTransactionId, MemoryContextDelete(), MemoryContextResetAndDeleteChildren, next, _SPI_connection::outer_processed, _SPI_connection::outer_result, _SPI_connection::outer_tuptable, _SPI_connection::procCxt, slist_container, slist_delete_current(), slist_foreach_modify, SPI_processed, SPI_result, SPITupleTable::subid, SPITupleTable::tuptabcxt, _SPI_connection::tuptable, _SPI_connection::tuptables, and WARNING.

Referenced by AbortSubTransaction(), and CommitSubTransaction().

386 {
387  bool found = false;
388 
389  while (_SPI_connected >= 0)
390  {
392 
393  if (connection->connectSubid != mySubid)
394  break; /* couldn't be any underneath it either */
395 
396  if (connection->internal_xact)
397  break;
398 
399  found = true;
400 
401  /*
402  * Release procedure memory explicitly (see note in SPI_connect)
403  */
404  if (connection->execCxt)
405  {
406  MemoryContextDelete(connection->execCxt);
407  connection->execCxt = NULL;
408  }
409  if (connection->procCxt)
410  {
411  MemoryContextDelete(connection->procCxt);
412  connection->procCxt = NULL;
413  }
414 
415  /*
416  * Restore outer global variables and pop the stack entry. Unlike
417  * SPI_finish(), we don't risk switching to memory contexts that might
418  * be already gone.
419  */
420  SPI_processed = connection->outer_processed;
421  SPI_tuptable = connection->outer_tuptable;
422  SPI_result = connection->outer_result;
423 
424  _SPI_connected--;
425  if (_SPI_connected < 0)
426  _SPI_current = NULL;
427  else
429  }
430 
431  if (found && isCommit)
433  (errcode(ERRCODE_WARNING),
434  errmsg("subtransaction left non-empty SPI stack"),
435  errhint("Check for missing \"SPI_finish\" calls.")));
436 
437  /*
438  * If we are aborting a subtransaction and there is an open SPI context
439  * surrounding the subxact, clean up to prevent memory leakage.
440  */
441  if (_SPI_current && !isCommit)
442  {
443  slist_mutable_iter siter;
444 
445  /*
446  * Throw away executor state if current executor operation was started
447  * within current subxact (essentially, force a _SPI_end_call(true)).
448  */
449  if (_SPI_current->execSubid >= mySubid)
450  {
453  }
454 
455  /* throw away any tuple tables created within current subxact */
457  {
458  SPITupleTable *tuptable;
459 
460  tuptable = slist_container(SPITupleTable, next, siter.cur);
461  if (tuptable->subid >= mySubid)
462  {
463  /*
464  * If we used SPI_freetuptable() here, its internal search of
465  * the tuptables list would make this operation O(N^2).
466  * Instead, just free the tuptable manually. This should
467  * match what SPI_freetuptable() does.
468  */
469  slist_delete_current(&siter);
470  if (tuptable == _SPI_current->tuptable)
471  _SPI_current->tuptable = NULL;
472  if (tuptable == SPI_tuptable)
473  SPI_tuptable = NULL;
474  MemoryContextDelete(tuptable->tuptabcxt);
475  }
476  }
477  }
478 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
int errhint(const char *fmt,...)
Definition: elog.c:974
static int32 next
Definition: blutils.c:213
bool internal_xact
Definition: spi_priv.h:42
slist_node * cur
Definition: ilist.h:241
SPITupleTable * SPI_tuptable
Definition: spi.c:46
int errcode(int sqlerrcode)
Definition: elog.c:570
static int _SPI_connected
Definition: spi.c:52
SubTransactionId execSubid
Definition: spi_priv.h:29
static _SPI_connection * _SPI_current
Definition: spi.c:50
uint64 SPI_processed
Definition: spi.c:45
SPITupleTable * outer_tuptable
Definition: spi_priv.h:47
#define slist_foreach_modify(iter, lhead)
Definition: ilist.h:716
int SPI_result
Definition: spi.c:47
SubTransactionId connectSubid
Definition: spi_priv.h:36
SPITupleTable * tuptable
Definition: spi_priv.h:26
static _SPI_connection * _SPI_stack
Definition: spi.c:49
#define ereport(elevel, rest)
Definition: elog.h:141
#define WARNING
Definition: elog.h:40
uint64 outer_processed
Definition: spi_priv.h:46
#define MemoryContextResetAndDeleteChildren(ctx)
Definition: memutils.h:67
#define slist_container(type, membername, ptr)
Definition: ilist.h:674
MemoryContext procCxt
Definition: spi_priv.h:33
MemoryContext execCxt
Definition: spi_priv.h:34
int outer_result
Definition: spi_priv.h:48
#define InvalidSubTransactionId
Definition: c.h:513
int errmsg(const char *fmt,...)
Definition: elog.c:784
static void slist_delete_current(slist_mutable_iter *iter)
Definition: ilist.h:652
SubTransactionId subid
Definition: spi.h:33
slist_head tuptables
Definition: spi_priv.h:32
MemoryContext tuptabcxt
Definition: spi.h:31

◆ AtEOXact_SPI()

void AtEOXact_SPI ( bool  isCommit)

Definition at line 363 of file spi.c.

References _SPI_connected, ereport, errcode(), errhint(), errmsg(), _SPI_connection::internal_xact, SPICleanup(), and WARNING.

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

364 {
365  /* Do nothing if the transaction end was initiated by SPI. */
367  return;
368 
369  if (isCommit && _SPI_connected != -1)
371  (errcode(ERRCODE_WARNING),
372  errmsg("transaction left non-empty SPI stack"),
373  errhint("Check for missing \"SPI_finish\" calls.")));
374 
375  SPICleanup();
376 }
int errhint(const char *fmt,...)
Definition: elog.c:974
bool internal_xact
Definition: spi_priv.h:42
void SPICleanup(void)
Definition: spi.c:349
int errcode(int sqlerrcode)
Definition: elog.c:570
static int _SPI_connected
Definition: spi.c:52
static _SPI_connection * _SPI_current
Definition: spi.c:50
#define ereport(elevel, rest)
Definition: elog.h:141
#define WARNING
Definition: elog.h:40
int errmsg(const char *fmt,...)
Definition: elog.c:784

◆ SPI_commit()

void SPI_commit ( void  )

Definition at line 278 of file spi.c.

References _SPI_commit().

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

279 {
280  _SPI_commit(false);
281 }
static void _SPI_commit(bool chain)
Definition: spi.c:221

◆ SPI_commit_and_chain()

void SPI_commit_and_chain ( void  )

Definition at line 284 of file spi.c.

References _SPI_commit().

Referenced by exec_stmt_commit().

285 {
286  _SPI_commit(true);
287 }
static void _SPI_commit(bool chain)
Definition: spi.c:221

◆ SPI_connect()

◆ SPI_connect_ext()

int SPI_connect_ext ( int  options)

Definition at line 95 of file spi.c.

References _SPI_connected, _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(), plpython_call_handler(), plpython_inline_handler(), pltcl_func_handler(), and SPI_connect().

96 {
97  int newdepth;
98 
99  /* Enlarge stack if necessary */
100  if (_SPI_stack == NULL)
101  {
102  if (_SPI_connected != -1 || _SPI_stack_depth != 0)
103  elog(ERROR, "SPI stack corrupted");
104  newdepth = 16;
107  newdepth * sizeof(_SPI_connection));
108  _SPI_stack_depth = newdepth;
109  }
110  else
111  {
113  elog(ERROR, "SPI stack corrupted");
114  if (_SPI_stack_depth == _SPI_connected + 1)
115  {
116  newdepth = _SPI_stack_depth * 2;
119  newdepth * sizeof(_SPI_connection));
120  _SPI_stack_depth = newdepth;
121  }
122  }
123 
124  /* Enter new stack level */
125  _SPI_connected++;
127 
129  _SPI_current->processed = 0;
130  _SPI_current->tuptable = NULL;
133  _SPI_current->procCxt = NULL; /* in case we fail to create 'em */
134  _SPI_current->execCxt = NULL;
136  _SPI_current->queryEnv = NULL;
138  _SPI_current->internal_xact = false;
142 
143  /*
144  * Create memory contexts for this procedure
145  *
146  * In atomic contexts (the normal case), we use TopTransactionContext,
147  * otherwise PortalContext, so that it lives across transaction
148  * boundaries.
149  *
150  * XXX It could be better to use PortalContext as the parent context in
151  * all cases, but we may not be inside a portal (consider deferred-trigger
152  * execution). Perhaps CurTransactionContext could be an option? For now
153  * it doesn't matter because we clean up explicitly in AtEOSubXact_SPI().
154  */
156  "SPI Proc",
159  "SPI Exec",
161  /* ... and switch to procedure's context */
163 
164  /*
165  * Reset API global variables so that current caller cannot accidentally
166  * depend on state of an outer caller.
167  */
168  SPI_processed = 0;
169  SPI_tuptable = NULL;
170  SPI_result = 0;
171 
172  return SPI_OK_CONNECT;
173 }
#define SPI_OK_CONNECT
Definition: spi.h:53
#define AllocSetContextCreate
Definition: memutils.h:169
MemoryContext TopTransactionContext
Definition: mcxt.c:49
static int _SPI_stack_depth
Definition: spi.c:51
bool internal_xact
Definition: spi_priv.h:42
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
SPITupleTable * SPI_tuptable
Definition: spi.c:46
static int _SPI_connected
Definition: spi.c:52
SubTransactionId execSubid
Definition: spi_priv.h:29
static _SPI_connection * _SPI_current
Definition: spi.c:50
#define false
Definition: c.h:316
uint64 SPI_processed
Definition: spi.c:45
SPITupleTable * outer_tuptable
Definition: spi_priv.h:47
MemoryContext PortalContext
Definition: mcxt.c:53
int SPI_result
Definition: spi.c:47
SubTransactionId connectSubid
Definition: spi_priv.h:36
static void slist_init(slist_head *head)
Definition: ilist.h:554
#define ERROR
Definition: elog.h:43
QueryEnvironment * queryEnv
Definition: spi_priv.h:37
#define SPI_OPT_NONATOMIC
Definition: spi.h:71
SPITupleTable * tuptable
Definition: spi_priv.h:26
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:191
static _SPI_connection * _SPI_stack
Definition: spi.c:49
MemoryContext TopMemoryContext
Definition: mcxt.c:44
MemoryContext savedcxt
Definition: spi_priv.h:35
uint64 outer_processed
Definition: spi_priv.h:46
MemoryContext procCxt
Definition: spi_priv.h:33
MemoryContext execCxt
Definition: spi_priv.h:34
uint64 processed
Definition: spi_priv.h:25
#define Assert(condition)
Definition: c.h:732
int outer_result
Definition: spi_priv.h:48
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:708
#define InvalidSubTransactionId
Definition: c.h:513
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1044
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:771
#define elog(elevel,...)
Definition: elog.h:226
slist_head tuptables
Definition: spi_priv.h:32

◆ SPI_copytuple()

HeapTuple SPI_copytuple ( HeapTuple  tuple)

Definition at line 823 of file spi.c.

References 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().

824 {
825  MemoryContext oldcxt;
826  HeapTuple ctuple;
827 
828  if (tuple == NULL)
829  {
831  return NULL;
832  }
833 
834  if (_SPI_current == NULL)
835  {
837  return NULL;
838  }
839 
841 
842  ctuple = heap_copytuple(tuple);
843 
844  MemoryContextSwitchTo(oldcxt);
845 
846  return ctuple;
847 }
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:680
#define SPI_ERROR_UNCONNECTED
Definition: spi.h:42
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static _SPI_connection * _SPI_current
Definition: spi.c:50
int SPI_result
Definition: spi.c:47
#define SPI_ERROR_ARGUMENT
Definition: spi.h:44
MemoryContext savedcxt
Definition: spi_priv.h:35

◆ SPI_cursor_close()

void SPI_cursor_close ( Portal  portal)

Definition at line 1595 of file spi.c.

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

Referenced by exec_stmt_close(), exec_stmt_dynfors(), exec_stmt_forc(), exec_stmt_fors(), exec_stmt_return_query(), 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().

1596 {
1597  if (!PortalIsValid(portal))
1598  elog(ERROR, "invalid portal in SPI cursor operation");
1599 
1600  PortalDrop(portal, false);
1601 }
#define ERROR
Definition: elog.h:43
#define PortalIsValid(p)
Definition: portal.h:201
void PortalDrop(Portal portal, bool isTopCommit)
Definition: portalmem.c:465
#define elog(elevel,...)
Definition: elog.h:226

◆ SPI_cursor_fetch()

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

Definition at line 1539 of file spi.c.

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

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

1540 {
1541  _SPI_cursor_operation(portal,
1542  forward ? FETCH_FORWARD : FETCH_BACKWARD, count,
1544  /* we know that the DestSPI receiver doesn't need a destroy call */
1545 }
Definition: dest.h:93
DestReceiver * CreateDestReceiver(CommandDest dest)
Definition: dest.c:113
static void _SPI_cursor_operation(Portal portal, FetchDirection direction, long count, DestReceiver *dest)
Definition: spi.c:2579

◆ SPI_cursor_find()

Portal SPI_cursor_find ( const char *  name)

Definition at line 1527 of file spi.c.

References GetPortalByName().

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().

1528 {
1529  return GetPortalByName(name);
1530 }
Portal GetPortalByName(const char *name)
Definition: portalmem.c:130
const char * name
Definition: encode.c:521

◆ SPI_cursor_move()

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

Definition at line 1554 of file spi.c.

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

1555 {
1556  _SPI_cursor_operation(portal,
1557  forward ? FETCH_FORWARD : FETCH_BACKWARD, count,
1558  None_Receiver);
1559 }
DestReceiver * None_Receiver
Definition: dest.c:96
static void _SPI_cursor_operation(Portal portal, FetchDirection direction, long count, DestReceiver *dest)
Definition: spi.c:2579

◆ SPI_cursor_open()

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

Definition at line 1221 of file spi.c.

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

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

1224 {
1225  Portal portal;
1226  ParamListInfo paramLI;
1227 
1228  /* build transient ParamListInfo in caller's context */
1229  paramLI = _SPI_convert_params(plan->nargs, plan->argtypes,
1230  Values, Nulls);
1231 
1232  portal = SPI_cursor_open_internal(name, plan, paramLI, read_only);
1233 
1234  /* done with the transient ParamListInfo */
1235  if (paramLI)
1236  pfree(paramLI);
1237 
1238  return portal;
1239 }
Oid * argtypes
Definition: spi_priv.h:100
void pfree(void *pointer)
Definition: mcxt.c:1031
int nargs
Definition: spi_priv.h:99
const char * name
Definition: encode.c:521
static Portal SPI_cursor_open_internal(const char *name, SPIPlanPtr plan, ParamListInfo paramLI, bool read_only)
Definition: spi.c:1313
static ParamListInfo _SPI_convert_params(int nargs, Oid *argtypes, Datum *Values, const char *Nulls)
Definition: spi.c:2444
static bool Nulls[MAXATTR]
Definition: bootstrap.c:168

◆ SPI_cursor_open_internal()

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

Definition at line 1313 of file spi.c.

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

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

1315 {
1316  CachedPlanSource *plansource;
1317  CachedPlan *cplan;
1318  List *stmt_list;
1319  char *query_string;
1320  Snapshot snapshot;
1321  MemoryContext oldcontext;
1322  Portal portal;
1323  ErrorContextCallback spierrcontext;
1324 
1325  /*
1326  * Check that the plan is something the Portal code will special-case as
1327  * returning one tupleset.
1328  */
1329  if (!SPI_is_cursor_plan(plan))
1330  {
1331  /* try to give a good error message */
1332  if (list_length(plan->plancache_list) != 1)
1333  ereport(ERROR,
1334  (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
1335  errmsg("cannot open multi-query plan as cursor")));
1336  plansource = (CachedPlanSource *) linitial(plan->plancache_list);
1337  ereport(ERROR,
1338  (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
1339  /* translator: %s is name of a SQL command, eg INSERT */
1340  errmsg("cannot open %s query as cursor",
1341  plansource->commandTag)));
1342  }
1343 
1344  Assert(list_length(plan->plancache_list) == 1);
1345  plansource = (CachedPlanSource *) linitial(plan->plancache_list);
1346 
1347  /* Push the SPI stack */
1348  if (_SPI_begin_call(true) < 0)
1349  elog(ERROR, "SPI_cursor_open called while not connected");
1350 
1351  /* Reset SPI result (note we deliberately don't touch lastoid) */
1352  SPI_processed = 0;
1353  SPI_tuptable = NULL;
1354  _SPI_current->processed = 0;
1355  _SPI_current->tuptable = NULL;
1356 
1357  /* Create the portal */
1358  if (name == NULL || name[0] == '\0')
1359  {
1360  /* Use a random nonconflicting name */
1361  portal = CreateNewPortal();
1362  }
1363  else
1364  {
1365  /* In this path, error if portal of same name already exists */
1366  portal = CreatePortal(name, false, false);
1367  }
1368 
1369  /* Copy the plan's query string into the portal */
1370  query_string = MemoryContextStrdup(portal->portalContext,
1371  plansource->query_string);
1372 
1373  /*
1374  * Setup error traceback support for ereport(), in case GetCachedPlan
1375  * throws an error.
1376  */
1377  spierrcontext.callback = _SPI_error_callback;
1378  spierrcontext.arg = unconstify(char *, plansource->query_string);
1379  spierrcontext.previous = error_context_stack;
1380  error_context_stack = &spierrcontext;
1381 
1382  /*
1383  * Note: for a saved plan, we mustn't have any failure occur between
1384  * GetCachedPlan and PortalDefineQuery; that would result in leaking our
1385  * plancache refcount.
1386  */
1387 
1388  /* Replan if needed, and increment plan refcount for portal */
1389  cplan = GetCachedPlan(plansource, paramLI, false, _SPI_current->queryEnv);
1390  stmt_list = cplan->stmt_list;
1391 
1392  if (!plan->saved)
1393  {
1394  /*
1395  * We don't want the portal to depend on an unsaved CachedPlanSource,
1396  * so must copy the plan into the portal's context. An error here
1397  * will result in leaking our refcount on the plan, but it doesn't
1398  * matter because the plan is unsaved and hence transient anyway.
1399  */
1400  oldcontext = MemoryContextSwitchTo(portal->portalContext);
1401  stmt_list = copyObject(stmt_list);
1402  MemoryContextSwitchTo(oldcontext);
1403  ReleaseCachedPlan(cplan, false);
1404  cplan = NULL; /* portal shouldn't depend on cplan */
1405  }
1406 
1407  /*
1408  * Set up the portal.
1409  */
1410  PortalDefineQuery(portal,
1411  NULL, /* no statement name */
1412  query_string,
1413  plansource->commandTag,
1414  stmt_list,
1415  cplan);
1416 
1417  /*
1418  * Set up options for portal. Default SCROLL type is chosen the same way
1419  * as PerformCursorOpen does it.
1420  */
1421  portal->cursorOptions = plan->cursor_options;
1423  {
1424  if (list_length(stmt_list) == 1 &&
1425  linitial_node(PlannedStmt, stmt_list)->commandType != CMD_UTILITY &&
1426  linitial_node(PlannedStmt, stmt_list)->rowMarks == NIL &&
1427  ExecSupportsBackwardScan(linitial_node(PlannedStmt, stmt_list)->planTree))
1428  portal->cursorOptions |= CURSOR_OPT_SCROLL;
1429  else
1431  }
1432 
1433  /*
1434  * Disallow SCROLL with SELECT FOR UPDATE. This is not redundant with the
1435  * check in transformDeclareCursorStmt because the cursor options might
1436  * not have come through there.
1437  */
1438  if (portal->cursorOptions & CURSOR_OPT_SCROLL)
1439  {
1440  if (list_length(stmt_list) == 1 &&
1441  linitial_node(PlannedStmt, stmt_list)->commandType != CMD_UTILITY &&
1442  linitial_node(PlannedStmt, stmt_list)->rowMarks != NIL)
1443  ereport(ERROR,
1444  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1445  errmsg("DECLARE SCROLL CURSOR ... FOR UPDATE/SHARE is not supported"),
1446  errdetail("Scrollable cursors must be READ ONLY.")));
1447  }
1448 
1449  /* Make current query environment available to portal at execution time. */
1450  portal->queryEnv = _SPI_current->queryEnv;
1451 
1452  /*
1453  * If told to be read-only, or in parallel mode, verify that this query is
1454  * in fact read-only. This can't be done earlier because we need to look
1455  * at the finished, planned queries. (In particular, we don't want to do
1456  * it between GetCachedPlan and PortalDefineQuery, because throwing an
1457  * error between those steps would result in leaking our plancache
1458  * refcount.)
1459  */
1460  if (read_only || IsInParallelMode())
1461  {
1462  ListCell *lc;
1463 
1464  foreach(lc, stmt_list)
1465  {
1466  PlannedStmt *pstmt = lfirst_node(PlannedStmt, lc);
1467 
1468  if (!CommandIsReadOnly(pstmt))
1469  {
1470  if (read_only)
1471  ereport(ERROR,
1472  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1473  /* translator: %s is a SQL statement name */
1474  errmsg("%s is not allowed in a non-volatile function",
1475  CreateCommandTag((Node *) pstmt))));
1476  else
1478  }
1479  }
1480  }
1481 
1482  /* Set up the snapshot to use. */
1483  if (read_only)
1484  snapshot = GetActiveSnapshot();
1485  else
1486  {
1488  snapshot = GetTransactionSnapshot();
1489  }
1490 
1491  /*
1492  * If the plan has parameters, copy them into the portal. Note that this
1493  * must be done after revalidating the plan, because in dynamic parameter
1494  * cases the set of parameters could have changed during re-parsing.
1495  */
1496  if (paramLI)
1497  {
1498  oldcontext = MemoryContextSwitchTo(portal->portalContext);
1499  paramLI = copyParamList(paramLI);
1500  MemoryContextSwitchTo(oldcontext);
1501  }
1502 
1503  /*
1504  * Start portal execution.
1505  */
1506  PortalStart(portal, paramLI, 0, snapshot);
1507 
1508  Assert(portal->strategy != PORTAL_MULTI_QUERY);
1509 
1510  /* Pop the error context stack */
1511  error_context_stack = spierrcontext.previous;
1512 
1513  /* Pop the SPI stack */
1514  _SPI_end_call(true);
1515 
1516  /* Return the created portal */
1517  return portal;
1518 }
ParamListInfo copyParamList(ParamListInfo from)
Definition: params.c:63
#define NIL
Definition: pg_list.h:65
bool CommandIsReadOnly(PlannedStmt *pstmt)
Definition: utility.c:100
Portal CreatePortal(const char *name, bool allowDup, bool dupSilent)
Definition: portalmem.c:175
List * plancache_list
Definition: spi_priv.h:96
CachedPlan * GetCachedPlan(CachedPlanSource *plansource, ParamListInfo boundParams, bool useResOwner, QueryEnvironment *queryEnv)
Definition: plancache.c:1138
Portal CreateNewPortal(void)
Definition: portalmem.c:234
void PortalStart(Portal portal, ParamListInfo params, int eflags, Snapshot snapshot)
Definition: pquery.c:443
void PreventCommandIfParallelMode(const char *cmdname)
Definition: utility.c:257
void PortalDefineQuery(Portal portal, const char *prepStmtName, const char *sourceText, const char *commandTag, List *stmts, CachedPlan *cplan)
Definition: portalmem.c:281
bool SPI_is_cursor_plan(SPIPlanPtr plan)
Definition: spi.c:1643
const char * commandTag
Definition: plancache.h:98
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:841
SPITupleTable * SPI_tuptable
Definition: spi.c:46
Definition: nodes.h:524
int errcode(int sqlerrcode)
Definition: elog.c:570
static _SPI_connection * _SPI_current
Definition: spi.c:50
#define linitial_node(type, l)
Definition: pg_list.h:198
void(* callback)(void *arg)
Definition: elog.h:254
struct ErrorContextCallback * previous
Definition: elog.h:253
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:306
MemoryContext portalContext
Definition: portal.h:119
#define CURSOR_OPT_NO_SCROLL
Definition: parsenodes.h:2685
uint64 SPI_processed
Definition: spi.c:45
static int _SPI_begin_call(bool use_exec)
Definition: spi.c:2649
ErrorContextCallback * error_context_stack
Definition: elog.c:88
static void _SPI_error_callback(void *arg)
Definition: spi.c:2550
bool IsInParallelMode(void)
Definition: xact.c:994
#define linitial(l)
Definition: pg_list.h:195
#define ERROR
Definition: elog.h:43
QueryEnvironment * queryEnv
Definition: spi_priv.h:37
SPITupleTable * tuptable
Definition: spi_priv.h:26
#define lfirst_node(type, lc)
Definition: pg_list.h:193
int errdetail(const char *fmt,...)
Definition: elog.c:860
void ReleaseCachedPlan(CachedPlan *plan, bool useResOwner)
Definition: plancache.c:1259
PortalStrategy strategy
Definition: portal.h:143
#define ereport(elevel, rest)
Definition: elog.h:141
const char * CreateCommandTag(Node *parsetree)
Definition: utility.c:2100
static int _SPI_end_call(bool use_exec)
Definition: spi.c:2673
#define unconstify(underlying_type, expr)
Definition: c.h:1163
void CommandCounterIncrement(void)
Definition: xact.c:1003
bool ExecSupportsBackwardScan(Plan *node)
Definition: execAmi.c:496
bool saved
Definition: spi_priv.h:93
uint64 processed
Definition: spi_priv.h:25
#define Assert(condition)
Definition: c.h:732
const char * query_string
Definition: plancache.h:97
static int list_length(const List *l)
Definition: pg_list.h:169
const char * name
Definition: encode.c:521
QueryEnvironment * queryEnv
Definition: portal.h:140
int errmsg(const char *fmt,...)
Definition: elog.c:784
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1148
#define elog(elevel,...)
Definition: elog.h:226
#define CURSOR_OPT_SCROLL
Definition: parsenodes.h:2684
List * stmt_list
Definition: plancache.h:146
int cursor_options
Definition: spi_priv.h:98
int cursorOptions
Definition: portal.h:144
#define copyObject(obj)
Definition: nodes.h:640
Definition: pg_list.h:50

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

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

Referenced by exec_dynquery_with_params().

1253 {
1254  Portal result;
1255  _SPI_plan plan;
1256  ParamListInfo paramLI;
1257 
1258  if (src == NULL || nargs < 0)
1259  elog(ERROR, "SPI_cursor_open_with_args called with invalid arguments");
1260 
1261  if (nargs > 0 && (argtypes == NULL || Values == NULL))
1262  elog(ERROR, "SPI_cursor_open_with_args called with missing parameters");
1263 
1264  SPI_result = _SPI_begin_call(true);
1265  if (SPI_result < 0)
1266  elog(ERROR, "SPI_cursor_open_with_args called while not connected");
1267 
1268  memset(&plan, 0, sizeof(_SPI_plan));
1269  plan.magic = _SPI_PLAN_MAGIC;
1270  plan.cursor_options = cursorOptions;
1271  plan.nargs = nargs;
1272  plan.argtypes = argtypes;
1273  plan.parserSetup = NULL;
1274  plan.parserSetupArg = NULL;
1275 
1276  /* build transient ParamListInfo in executor context */
1277  paramLI = _SPI_convert_params(nargs, argtypes,
1278  Values, Nulls);
1279 
1280  _SPI_prepare_plan(src, &plan);
1281 
1282  /* We needn't copy the plan; SPI_cursor_open_internal will do so */
1283 
1284  result = SPI_cursor_open_internal(name, &plan, paramLI, read_only);
1285 
1286  /* And clean up */
1287  _SPI_end_call(true);
1288 
1289  return result;
1290 }
static void _SPI_prepare_plan(const char *src, SPIPlanPtr plan)
Definition: spi.c:1938
Oid * argtypes
Definition: spi_priv.h:100
#define _SPI_PLAN_MAGIC
Definition: spi_priv.h:20
int magic
Definition: spi_priv.h:92
static int _SPI_begin_call(bool use_exec)
Definition: spi.c:2649
int SPI_result
Definition: spi.c:47
#define ERROR
Definition: elog.h:43
static int _SPI_end_call(bool use_exec)
Definition: spi.c:2673
int nargs
Definition: spi_priv.h:99
ParserSetupHook parserSetup
Definition: spi_priv.h:101
void * parserSetupArg
Definition: spi_priv.h:102
const char * name
Definition: encode.c:521
static Portal SPI_cursor_open_internal(const char *name, SPIPlanPtr plan, ParamListInfo paramLI, bool read_only)
Definition: spi.c:1313
#define elog(elevel,...)
Definition: elog.h:226
int cursor_options
Definition: spi_priv.h:98
static ParamListInfo _SPI_convert_params(int nargs, Oid *argtypes, Datum *Values, const char *Nulls)
Definition: spi.c:2444
static bool Nulls[MAXATTR]
Definition: bootstrap.c:168

◆ SPI_cursor_open_with_paramlist()

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

Definition at line 1300 of file spi.c.

References SPI_cursor_open_internal().

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

1302 {
1303  return SPI_cursor_open_internal(name, plan, params, read_only);
1304 }
const char * name
Definition: encode.c:521
static Portal SPI_cursor_open_internal(const char *name, SPIPlanPtr plan, ParamListInfo paramLI, bool read_only)
Definition: spi.c:1313

◆ SPI_datumTransfer()

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

Definition at line 1137 of file spi.c.

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

Referenced by coerce_function_result_tuple(), and plpgsql_exec_function().

1138 {
1139  MemoryContext oldcxt;
1140  Datum result;
1141 
1142  if (_SPI_current == NULL)
1143  elog(ERROR, "SPI_datumTransfer called while not connected to SPI");
1144 
1146 
1147  result = datumTransfer(value, typByVal, typLen);
1148 
1149  MemoryContextSwitchTo(oldcxt);
1150 
1151  return result;
1152 }
static struct @144 value
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static _SPI_connection * _SPI_current
Definition: spi.c:50
#define ERROR
Definition: elog.h:43
MemoryContext savedcxt
Definition: spi_priv.h:35
uintptr_t Datum
Definition: postgres.h:367
Datum datumTransfer(Datum value, bool typByVal, int typLen)
Definition: datum.c:192
#define elog(elevel,...)
Definition: elog.h:226

◆ spi_dest_startup()

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

Definition at line 1841 of file spi.c.

References _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.

1842 {
1843  SPITupleTable *tuptable;
1844  MemoryContext oldcxt;
1845  MemoryContext tuptabcxt;
1846 
1847  if (_SPI_current == NULL)
1848  elog(ERROR, "spi_dest_startup called while not connected to SPI");
1849 
1850  if (_SPI_current->tuptable != NULL)
1851  elog(ERROR, "improper call to spi_dest_startup");
1852 
1853  /* We create the tuple table context as a child of procCxt */
1854 
1855  oldcxt = _SPI_procmem(); /* switch to procedure memory context */
1856 
1858  "SPI TupTable",
1860  MemoryContextSwitchTo(tuptabcxt);
1861 
1862  _SPI_current->tuptable = tuptable = (SPITupleTable *)
1863  palloc0(sizeof(SPITupleTable));
1864  tuptable->tuptabcxt = tuptabcxt;
1865  tuptable->subid = GetCurrentSubTransactionId();
1866 
1867  /*
1868  * The tuptable is now valid enough to be freed by AtEOSubXact_SPI, so put
1869  * it onto the SPI context's tuptables list. This will ensure it's not
1870  * leaked even in the unlikely event the following few lines fail.
1871  */
1872  slist_push_head(&_SPI_current->tuptables, &tuptable->next);
1873 
1874  /* set up initial allocations */
1875  tuptable->alloced = 128;
1876  tuptable->vals = (HeapTuple *) palloc(tuptable->alloced * sizeof(HeapTuple));
1877  tuptable->numvals = 0;
1878  tuptable->tupdesc = CreateTupleDescCopy(typeinfo);
1879 
1880  MemoryContextSwitchTo(oldcxt);
1881 }
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:110
#define AllocSetContextCreate
Definition: memutils.h:169
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static void slist_push_head(slist_head *head, slist_node *node)
Definition: ilist.h:574
slist_node next
Definition: spi.h:32
static _SPI_connection * _SPI_current
Definition: spi.c:50
HeapTuple * vals
Definition: spi.h:26
uint64 numvals
Definition: spi.h:27
#define ERROR
Definition: elog.h:43
SPITupleTable * tuptable
Definition: spi_priv.h:26
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:191
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
void * palloc0(Size size)
Definition: mcxt.c:955
TupleDesc tupdesc
Definition: spi.h:25
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:708
void * palloc(Size size)
Definition: mcxt.c:924
#define elog(elevel,...)
Definition: elog.h:226
uint64 alloced
Definition: spi.h:30
static MemoryContext _SPI_procmem(void)
Definition: spi.c:2636
SubTransactionId subid
Definition: spi.h:33
slist_head tuptables
Definition: spi_priv.h:32
MemoryContext tuptabcxt
Definition: spi.h:31

◆ SPI_exec()

int SPI_exec ( const char *  src,
long  tcount 
)

Definition at line 524 of file spi.c.

References SPI_execute().

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

525 {
526  return SPI_execute(src, false, tcount);
527 }
int SPI_execute(const char *src, bool read_only, long tcount)
Definition: spi.c:496

◆ SPI_execp()

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

Definition at line 558 of file spi.c.

References SPI_execute_plan().

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

559 {
560  return SPI_execute_plan(plan, Values, Nulls, false, tcount);
561 }
int SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls, bool read_only, long tcount)
Definition: spi.c:531
static bool Nulls[MAXATTR]
Definition: bootstrap.c:168

◆ SPI_execute()

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

Definition at line 496 of file spi.c.

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

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

497 {
498  _SPI_plan plan;
499  int res;
500 
501  if (src == NULL || tcount < 0)
502  return SPI_ERROR_ARGUMENT;
503 
504  res = _SPI_begin_call(true);
505  if (res < 0)
506  return res;
507 
508  memset(&plan, 0, sizeof(_SPI_plan));
509  plan.magic = _SPI_PLAN_MAGIC;
511 
512  _SPI_prepare_oneshot_plan(src, &plan);
513 
514  res = _SPI_execute_plan(&plan, NULL,
516  read_only, true, tcount);
517 
518  _SPI_end_call(true);
519  return res;
520 }
#define _SPI_PLAN_MAGIC
Definition: spi_priv.h:20
int magic
Definition: spi_priv.h:92
static void _SPI_prepare_oneshot_plan(const char *src, SPIPlanPtr plan)
Definition: spi.c:2043
static int _SPI_begin_call(bool use_exec)
Definition: spi.c:2649
static int _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI, Snapshot snapshot, Snapshot crosscheck_snapshot, bool read_only, bool fire_triggers, uint64 tcount)
Definition: spi.c:2101
#define SPI_ERROR_ARGUMENT
Definition: spi.h:44
static int _SPI_end_call(bool use_exec)
Definition: spi.c:2673
#define InvalidSnapshot
Definition: snapshot.h:123
#define CURSOR_OPT_PARALLEL_OK
Definition: parsenodes.h:2692
int cursor_options
Definition: spi_priv.h:98

◆ SPI_execute_plan()

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

Definition at line 531 of file spi.c.

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

Referenced by exec_stmt_set(), 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().

533 {
534  int res;
535 
536  if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC || tcount < 0)
537  return SPI_ERROR_ARGUMENT;
538 
539  if (plan->nargs > 0 && Values == NULL)
540  return SPI_ERROR_PARAM;
541 
542  res = _SPI_begin_call(true);
543  if (res < 0)
544  return res;
545 
546  res = _SPI_execute_plan(plan,
547  _SPI_convert_params(plan->nargs, plan->argtypes,
548  Values, Nulls),
550  read_only, true, tcount);
551 
552  _SPI_end_call(true);
553  return res;
554 }
Oid * argtypes
Definition: spi_priv.h:100
#define SPI_ERROR_PARAM
Definition: spi.h:45
#define _SPI_PLAN_MAGIC
Definition: spi_priv.h:20
int magic
Definition: spi_priv.h:92
static int _SPI_begin_call(bool use_exec)
Definition: spi.c:2649
static int _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI, Snapshot snapshot, Snapshot crosscheck_snapshot, bool read_only, bool fire_triggers, uint64 tcount)
Definition: spi.c:2101
#define SPI_ERROR_ARGUMENT
Definition: spi.h:44
static int _SPI_end_call(bool use_exec)
Definition: spi.c:2673
#define InvalidSnapshot
Definition: snapshot.h:123
int nargs
Definition: spi_priv.h:99
static ParamListInfo _SPI_convert_params(int nargs, Oid *argtypes, Datum *Values, const char *Nulls)
Definition: spi.c:2444
static bool Nulls[MAXATTR]
Definition: bootstrap.c:168

◆ SPI_execute_plan_with_paramlist()

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

Definition at line 565 of file spi.c.

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

Referenced by exec_run_select(), exec_stmt_call(), and exec_stmt_execsql().

567 {
568  int res;
569 
570  if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC || tcount < 0)
571  return SPI_ERROR_ARGUMENT;
572 
573  res = _SPI_begin_call(true);
574  if (res < 0)
575  return res;
576 
577  res = _SPI_execute_plan(plan, params,
579  read_only, true, tcount);
580 
581  _SPI_end_call(true);
582  return res;
583 }
#define _SPI_PLAN_MAGIC
Definition: spi_priv.h:20
int magic
Definition: spi_priv.h:92
static int _SPI_begin_call(bool use_exec)
Definition: spi.c:2649
static int _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI, Snapshot snapshot, Snapshot crosscheck_snapshot, bool read_only, bool fire_triggers, uint64 tcount)
Definition: spi.c:2101
#define SPI_ERROR_ARGUMENT
Definition: spi.h:44
static int _SPI_end_call(bool use_exec)
Definition: spi.c:2673
#define InvalidSnapshot
Definition: snapshot.h:123

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

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

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

603 {
604  int res;
605 
606  if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC || tcount < 0)
607  return SPI_ERROR_ARGUMENT;
608 
609  if (plan->nargs > 0 && Values == NULL)
610  return SPI_ERROR_PARAM;
611 
612  res = _SPI_begin_call(true);
613  if (res < 0)
614  return res;
615 
616  res = _SPI_execute_plan(plan,
617  _SPI_convert_params(plan->nargs, plan->argtypes,
618  Values, Nulls),
619  snapshot, crosscheck_snapshot,
620  read_only, fire_triggers, tcount);
621 
622  _SPI_end_call(true);
623  return res;
624 }
Oid * argtypes
Definition: spi_priv.h:100
#define SPI_ERROR_PARAM
Definition: spi.h:45
#define _SPI_PLAN_MAGIC
Definition: spi_priv.h:20
int magic
Definition: spi_priv.h:92
static int _SPI_begin_call(bool use_exec)
Definition: spi.c:2649
static int _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI, Snapshot snapshot, Snapshot crosscheck_snapshot, bool read_only, bool fire_triggers, uint64 tcount)
Definition: spi.c:2101
#define SPI_ERROR_ARGUMENT
Definition: spi.h:44
static int _SPI_end_call(bool use_exec)
Definition: spi.c:2673
int nargs
Definition: spi_priv.h:99
static ParamListInfo _SPI_convert_params(int nargs, Oid *argtypes, Datum *Values, const char *Nulls)
Definition: spi.c:2444
static bool Nulls[MAXATTR]
Definition: bootstrap.c:168

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

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

Referenced by exec_stmt_dynexecute().

637 {
638  int res;
639  _SPI_plan plan;
640  ParamListInfo paramLI;
641 
642  if (src == NULL || nargs < 0 || tcount < 0)
643  return SPI_ERROR_ARGUMENT;
644 
645  if (nargs > 0 && (argtypes == NULL || Values == NULL))
646  return SPI_ERROR_PARAM;
647 
648  res = _SPI_begin_call(true);
649  if (res < 0)
650  return res;
651 
652  memset(&plan, 0, sizeof(_SPI_plan));
653  plan.magic = _SPI_PLAN_MAGIC;
655  plan.nargs = nargs;
656  plan.argtypes = argtypes;
657  plan.parserSetup = NULL;
658  plan.parserSetupArg = NULL;
659 
660  paramLI = _SPI_convert_params(nargs, argtypes,
661  Values, Nulls);
662 
663  _SPI_prepare_oneshot_plan(src, &plan);
664 
665  res = _SPI_execute_plan(&plan, paramLI,
667  read_only, true, tcount);
668 
669  _SPI_end_call(true);
670  return res;
671 }
Oid * argtypes
Definition: spi_priv.h:100
#define SPI_ERROR_PARAM
Definition: spi.h:45
#define _SPI_PLAN_MAGIC
Definition: spi_priv.h:20
int magic
Definition: spi_priv.h:92
static void _SPI_prepare_oneshot_plan(const char *src, SPIPlanPtr plan)
Definition: spi.c:2043
static int _SPI_begin_call(bool use_exec)
Definition: spi.c:2649
static int _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI, Snapshot snapshot, Snapshot crosscheck_snapshot, bool read_only, bool fire_triggers, uint64 tcount)
Definition: spi.c:2101
#define SPI_ERROR_ARGUMENT
Definition: spi.h:44
static int _SPI_end_call(bool use_exec)
Definition: spi.c:2673
#define InvalidSnapshot
Definition: snapshot.h:123
int nargs
Definition: spi_priv.h:99
ParserSetupHook parserSetup
Definition: spi_priv.h:101
void * parserSetupArg
Definition: spi_priv.h:102
#define CURSOR_OPT_PARALLEL_OK
Definition: parsenodes.h:2692
int cursor_options
Definition: spi_priv.h:98
static ParamListInfo _SPI_convert_params(int nargs, Oid *argtypes, Datum *Values, const char *Nulls)
Definition: spi.c:2444
static bool Nulls[MAXATTR]
Definition: bootstrap.c:168

◆ SPI_finish()

int SPI_finish ( void  )

Definition at line 176 of file spi.c.

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

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(), pltcl_event_trigger_handler(), pltcl_func_handler(), pltcl_trigger_handler(), PLy_exec_function(), PLy_exec_trigger(), query_to_xml_and_xmlschema(), query_to_xml_internal(), query_to_xmlschema(), refresh_by_match_merge(), ri_Check_Pk_Match(), RI_FKey_cascade_del(), RI_FKey_cascade_upd(), RI_FKey_check(), RI_Initial_Check(), RI_PartitionRemove_Check(), ri_restrict(), ri_set(), schema_to_xml_internal(), schema_to_xmlschema_internal(), test_predtest(), ts_stat1(), ts_stat2(), tsquery_rewrite_query(), ttdummy(), and xpath_table().

177 {
178  int res;
179 
180  res = _SPI_begin_call(false); /* just check we're connected */
181  if (res < 0)
182  return res;
183 
184  /* Restore memory context as it was before procedure call */
186 
187  /* Release memory used in procedure call (including tuptables) */
189  _SPI_current->execCxt = NULL;
191  _SPI_current->procCxt = NULL;
192 
193  /*
194  * Restore outer API variables, especially SPI_tuptable which is probably
195  * pointing at a just-deleted tuptable
196  */
200 
201  /* Exit stack level */
202  _SPI_connected--;
203  if (_SPI_connected < 0)
204  _SPI_current = NULL;
205  else
207 
208  return SPI_OK_FINISH;
209 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
SPITupleTable * SPI_tuptable
Definition: spi.c:46
static int _SPI_connected
Definition: spi.c:52
static _SPI_connection * _SPI_current
Definition: spi.c:50
uint64 SPI_processed
Definition: spi.c:45
SPITupleTable * outer_tuptable
Definition: spi_priv.h:47
static int _SPI_begin_call(bool use_exec)
Definition: spi.c:2649
int SPI_result
Definition: spi.c:47
static _SPI_connection * _SPI_stack
Definition: spi.c:49
MemoryContext savedcxt
Definition: spi_priv.h:35
uint64 outer_processed
Definition: spi_priv.h:46
MemoryContext procCxt
Definition: spi_priv.h:33
MemoryContext execCxt
Definition: spi_priv.h:34
int outer_result
Definition: spi_priv.h:48
#define SPI_OK_FINISH
Definition: spi.h:54

◆ SPI_fname()

char* SPI_fname ( TupleDesc  tupdesc,
int  fnumber 
)

Definition at line 974 of file spi.c.

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().

975 {
976  const FormData_pg_attribute *att;
977 
978  SPI_result = 0;
979 
980  if (fnumber > tupdesc->natts || fnumber == 0 ||
982  {
984  return NULL;
985  }
986 
987  if (fnumber > 0)
988  att = TupleDescAttr(tupdesc, fnumber - 1);
989  else
990  att = SystemAttributeDefinition(fnumber);
991 
992  return pstrdup(NameStr(att->attname));
993 }
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
char * pstrdup(const char *in)
Definition: mcxt.c:1161
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
const FormData_pg_attribute * SystemAttributeDefinition(AttrNumber attno)
Definition: heap.c:250
int SPI_result
Definition: spi.c:47
#define SPI_ERROR_NOATTRIBUTE
Definition: spi.h:47
FormData_pg_attribute
Definition: pg_attribute.h:184
#define NameStr(name)
Definition: c.h:609

◆ SPI_fnumber()

int SPI_fnumber ( TupleDesc  tupdesc,
const char *  fname 
)

Definition at line 951 of file spi.c.

References FormData_pg_attribute, namestrcmp(), TupleDescData::natts, 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().

952 {
953  int res;
954  const FormData_pg_attribute *sysatt;
955 
956  for (res = 0; res < tupdesc->natts; res++)
957  {
958  Form_pg_attribute attr = TupleDescAttr(tupdesc, res);
959 
960  if (namestrcmp(&attr->attname, fname) == 0 &&
961  !attr->attisdropped)
962  return res + 1;
963  }
964 
965  sysatt = SystemAttributeByName(fname);
966  if (sysatt != NULL)
967  return sysatt->attnum;
968 
969  /* SPI_ERROR_NOATTRIBUTE is different from all sys column numbers */
970  return SPI_ERROR_NOATTRIBUTE;
971 }
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
int namestrcmp(Name name, const char *str)
Definition: name.c:287
const FormData_pg_attribute * SystemAttributeByName(const char *attname)
Definition: heap.c:262
#define SPI_ERROR_NOATTRIBUTE
Definition: spi.h:47
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
FormData_pg_attribute
Definition: pg_attribute.h:184

◆ SPI_freeplan()

int SPI_freeplan ( SPIPlanPtr  plan)

Definition at line 801 of file spi.c.

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

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

802 {
803  ListCell *lc;
804 
805  if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC)
806  return SPI_ERROR_ARGUMENT;
807 
808  /* Release the plancache entries */
809  foreach(lc, plan->plancache_list)
810  {
811  CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc);
812 
813  DropCachedPlan(plansource);
814  }
815 
816  /* Now get rid of the _SPI_plan and subsidiary data in its plancxt */
818 
819  return 0;
820 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
List * plancache_list
Definition: spi_priv.h:96
#define _SPI_PLAN_MAGIC
Definition: spi_priv.h:20
int magic
Definition: spi_priv.h:92
#define SPI_ERROR_ARGUMENT
Definition: spi.h:44
MemoryContext plancxt
Definition: spi_priv.h:97
#define lfirst(lc)
Definition: pg_list.h:190
void DropCachedPlan(CachedPlanSource *plansource)
Definition: plancache.c:496

◆ SPI_freetuple()

void SPI_freetuple ( HeapTuple  tuple)

Definition at line 1155 of file spi.c.

References heap_freetuple().

1156 {
1157  /* No longer need to worry which context tuple was in... */
1158  heap_freetuple(tuple);
1159 }
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338

◆ SPI_freetuptable()

void SPI_freetuptable ( SPITupleTable tuptable)

Definition at line 1162 of file spi.c.

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

Referenced by _SPI_execute_plan(), exec_assign_value(), exec_eval_cleanup(), exec_for_query(), exec_stmt_call(), exec_stmt_dynexecute(), exec_stmt_execsql(), exec_stmt_fetch(), exec_stmt_return_query(), 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().

1163 {
1164  bool found = false;
1165 
1166  /* ignore call if NULL pointer */
1167  if (tuptable == NULL)
1168  return;
1169 
1170  /*
1171  * Search only the topmost SPI context for a matching tuple table.
1172  */
1173  if (_SPI_current != NULL)
1174  {
1175  slist_mutable_iter siter;
1176 
1177  /* find tuptable in active list, then remove it */
1179  {
1180  SPITupleTable *tt;
1181 
1182  tt = slist_container(SPITupleTable, next, siter.cur);
1183  if (tt == tuptable)
1184  {
1185  slist_delete_current(&siter);
1186  found = true;
1187  break;
1188  }
1189  }
1190  }
1191 
1192  /*
1193  * Refuse the deletion if we didn't find it in the topmost SPI context.
1194  * This is primarily a guard against double deletion, but might prevent
1195  * other errors as well. Since the worst consequence of not deleting a
1196  * tuptable would be a transient memory leak, this is just a WARNING.
1197  */
1198  if (!found)
1199  {
1200  elog(WARNING, "attempt to delete invalid SPITupleTable %p", tuptable);
1201  return;
1202  }
1203 
1204  /* for safety, reset global variables that might point at tuptable */
1205  if (tuptable == _SPI_current->tuptable)
1206  _SPI_current->tuptable = NULL;
1207  if (tuptable == SPI_tuptable)
1208  SPI_tuptable = NULL;
1209 
1210  /* release all memory belonging to tuptable */
1211  MemoryContextDelete(tuptable->tuptabcxt);
1212 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
static int32 next
Definition: blutils.c:213
slist_node * cur
Definition: ilist.h:241
SPITupleTable * SPI_tuptable
Definition: spi.c:46
static _SPI_connection * _SPI_current
Definition: spi.c:50
#define slist_foreach_modify(iter, lhead)
Definition: ilist.h:716
SPITupleTable * tuptable
Definition: spi_priv.h:26
#define WARNING
Definition: elog.h:40
#define slist_container(type, membername, ptr)
Definition: ilist.h:674
#define elog(elevel,...)
Definition: elog.h:226
static void slist_delete_current(slist_mutable_iter *iter)
Definition: ilist.h:652
slist_head tuptables
Definition: spi_priv.h:32
MemoryContext tuptabcxt
Definition: spi.h:31

◆ SPI_getargcount()

int SPI_getargcount ( SPIPlanPtr  plan)

Definition at line 1623 of file spi.c.

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

1624 {
1625  if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC)
1626  {
1628  return -1;
1629  }
1630  return plan->nargs;
1631 }
#define _SPI_PLAN_MAGIC
Definition: spi_priv.h:20
int magic
Definition: spi_priv.h:92
int SPI_result
Definition: spi.c:47
#define SPI_ERROR_ARGUMENT
Definition: spi.h:44
int nargs
Definition: spi_priv.h:99

◆ SPI_getargtypeid()

Oid SPI_getargtypeid ( SPIPlanPtr  plan,
int  argIndex 
)

Definition at line 1608 of file spi.c.

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

1609 {
1610  if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC ||
1611  argIndex < 0 || argIndex >= plan->nargs)
1612  {
1614  return InvalidOid;
1615  }
1616  return plan->argtypes[argIndex];
1617 }
Oid * argtypes
Definition: spi_priv.h:100
#define _SPI_PLAN_MAGIC
Definition: spi_priv.h:20
int magic
Definition: spi_priv.h:92
int SPI_result
Definition: spi.c:47
#define SPI_ERROR_ARGUMENT
Definition: spi.h:44
int nargs
Definition: spi_priv.h:99
#define InvalidOid
Definition: postgres_ext.h:36

◆ SPI_getbinval()

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

Definition at line 1028 of file spi.c.

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

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

1029 {
1030  SPI_result = 0;
1031 
1032  if (fnumber > tupdesc->natts || fnumber == 0 ||
1034  {
1036  *isnull = true;
1037  return (Datum) NULL;
1038  }
1039 
1040  return heap_getattr(tuple, fnumber, tupdesc, isnull);
1041 }
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
int SPI_result
Definition: spi.c:47
#define SPI_ERROR_NOATTRIBUTE
Definition: spi.h:47
#define heap_getattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:762
uintptr_t Datum
Definition: postgres.h:367

◆ SPI_getnspname()

char* SPI_getnspname ( Relation  rel)

Definition at line 1108 of file spi.c.

References get_namespace_name(), and RelationGetNamespace.

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

1109 {
1111 }
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3094
#define RelationGetNamespace(relation)
Definition: rel.h:457

◆ SPI_getrelname()

char* SPI_getrelname ( Relation  rel)

Definition at line 1102 of file spi.c.

References pstrdup(), and RelationGetRelationName.

Referenced by autoinc(), check_foreign_key(), check_primary_key(), insert_username(), moddatetime(), plperl_trigger_build_args(), pltcl_trigger_handler(), PLy_trigger_build_args(), and ttdummy().

1103 {
1104  return pstrdup(RelationGetRelationName(rel));
1105 }
char * pstrdup(const char *in)
Definition: mcxt.c:1161
#define RelationGetRelationName(relation)
Definition: rel.h:450

◆ SPI_gettype()

char* SPI_gettype ( TupleDesc  tupdesc,
int  fnumber 
)

Definition at line 1044 of file spi.c.

References atttypid, 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().

1045 {
1046  Oid typoid;
1047  HeapTuple typeTuple;
1048  char *result;
1049 
1050  SPI_result = 0;
1051 
1052  if (fnumber > tupdesc->natts || fnumber == 0 ||
1054  {
1056  return NULL;
1057  }
1058 
1059  if (fnumber > 0)
1060  typoid = TupleDescAttr(tupdesc, fnumber - 1)->atttypid;
1061  else
1062  typoid = (SystemAttributeDefinition(fnumber))->atttypid;
1063 
1064  typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typoid));
1065 
1066  if (!HeapTupleIsValid(typeTuple))
1067  {
1069  return NULL;
1070  }
1071 
1072  result = pstrdup(NameStr(((Form_pg_type) GETSTRUCT(typeTuple))->typname));
1073  ReleaseSysCache(typeTuple);
1074  return result;
1075 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
char * pstrdup(const char *in)
Definition: mcxt.c:1161
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
unsigned int Oid
Definition: postgres_ext.h:31
const FormData_pg_attribute * SystemAttributeDefinition(AttrNumber attno)
Definition: heap.c:250
int SPI_result
Definition: spi.c:47
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define SPI_ERROR_NOATTRIBUTE
Definition: spi.h:47
Oid atttypid
Definition: pg_attribute.h:49
NameData typname
Definition: pg_type.h:42
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1124
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1172
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
FormData_pg_type * Form_pg_type
Definition: pg_type.h:251
#define SPI_ERROR_TYPUNKNOWN
Definition: spi.h:49
#define NameStr(name)
Definition: c.h:609

◆ SPI_gettypeid()

Oid SPI_gettypeid ( TupleDesc  tupdesc,
int  fnumber 
)

Definition at line 1084 of file spi.c.

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().

1085 {
1086  SPI_result = 0;
1087 
1088  if (fnumber > tupdesc->natts || fnumber == 0 ||
1090  {
1092  return InvalidOid;
1093  }
1094 
1095  if (fnumber > 0)
1096  return TupleDescAttr(tupdesc, fnumber - 1)->atttypid;
1097  else
1098  return (SystemAttributeDefinition(fnumber))->atttypid;
1099 }
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
const FormData_pg_attribute * SystemAttributeDefinition(AttrNumber attno)
Definition: heap.c:250
int SPI_result
Definition: spi.c:47
#define SPI_ERROR_NOATTRIBUTE
Definition: spi.h:47
#define InvalidOid
Definition: postgres_ext.h:36

◆ SPI_getvalue()

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

Definition at line 996 of file spi.c.

References atttypid, 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().

997 {
998  Datum val;
999  bool isnull;
1000  Oid typoid,
1001  foutoid;
1002  bool typisvarlena;
1003 
1004  SPI_result = 0;
1005 
1006  if (fnumber > tupdesc->natts || fnumber == 0 ||
1008  {
1010  return NULL;
1011  }
1012 
1013  val = heap_getattr(tuple, fnumber, tupdesc, &isnull);
1014  if (isnull)
1015  return NULL;
1016 
1017  if (fnumber > 0)
1018  typoid = TupleDescAttr(tupdesc, fnumber - 1)->atttypid;
1019  else
1020  typoid = (SystemAttributeDefinition(fnumber))->atttypid;
1021 
1022  getTypeOutputInfo(typoid, &foutoid, &typisvarlena);
1023 
1024  return OidOutputFunctionCall(foutoid, val);
1025 }
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:2674
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
unsigned int Oid
Definition: postgres_ext.h:31
const FormData_pg_attribute * SystemAttributeDefinition(AttrNumber attno)
Definition: heap.c:250
int SPI_result
Definition: spi.c:47
#define SPI_ERROR_NOATTRIBUTE
Definition: spi.h:47
Oid atttypid
Definition: pg_attribute.h:49
#define heap_getattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:762
uintptr_t Datum
Definition: postgres.h:367
char * OidOutputFunctionCall(Oid functionId, Datum val)
Definition: fmgr.c:1655
long val
Definition: informix.c:684

◆ SPI_inside_nonatomic_context()

bool SPI_inside_nonatomic_context ( void  )

Definition at line 484 of file spi.c.

References _SPI_connection::atomic.

Referenced by StartTransaction().

485 {
486  if (_SPI_current == NULL)
487  return false; /* not in any SPI context at all */
488  if (_SPI_current->atomic)
489  return false; /* it's atomic (ie function not procedure) */
490  return true;
491 }
static _SPI_connection * _SPI_current
Definition: spi.c:50

◆ SPI_is_cursor_plan()

bool SPI_is_cursor_plan ( SPIPlanPtr  plan)

Definition at line 1643 of file spi.c.

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

Referenced by SPI_cursor_open_internal().

1644 {
1645  CachedPlanSource *plansource;
1646 
1647  if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC)
1648  {
1650  return false;
1651  }
1652 
1653  if (list_length(plan->plancache_list) != 1)
1654  {
1655  SPI_result = 0;
1656  return false; /* not exactly 1 pre-rewrite command */
1657  }
1658  plansource = (CachedPlanSource *) linitial(plan->plancache_list);
1659 
1660  /*
1661  * We used to force revalidation of the cached plan here, but that seems
1662  * unnecessary: invalidation could mean a change in the rowtype of the
1663  * tuples returned by a plan, but not whether it returns tuples at all.
1664  */
1665  SPI_result = 0;
1666 
1667  /* Does it return tuples? */
1668  if (plansource->resultDesc)
1669  return true;
1670 
1671  return false;
1672 }
List * plancache_list
Definition: spi_priv.h:96
#define _SPI_PLAN_MAGIC
Definition: spi_priv.h:20
int magic
Definition: spi_priv.h:92
TupleDesc resultDesc
Definition: plancache.h:105
int SPI_result
Definition: spi.c:47
#define SPI_ERROR_ARGUMENT
Definition: spi.h:44
#define linitial(l)
Definition: pg_list.h:195
static int list_length(const List *l)
Definition: pg_list.h:169

◆ SPI_keepplan()

int SPI_keepplan ( SPIPlanPtr  plan)

Definition at line 752 of file spi.c.

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

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

753 {
754  ListCell *lc;
755 
756  if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC ||
757  plan->saved || plan->oneshot)
758  return SPI_ERROR_ARGUMENT;
759 
760  /*
761  * Mark it saved, reparent it under CacheMemoryContext, and mark all the
762  * component CachedPlanSources as saved. This sequence cannot fail
763  * partway through, so there's no risk of long-term memory leakage.
764  */
765  plan->saved = true;
767 
768  foreach(lc, plan->plancache_list)
769  {
770  CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc);
771 
772  SaveCachedPlan(plansource);
773  }
774 
775  return 0;
776 }
List * plancache_list
Definition: spi_priv.h:96
#define _SPI_PLAN_MAGIC
Definition: spi_priv.h:20
void MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
Definition: mcxt.c:354
int magic
Definition: spi_priv.h:92
#define SPI_ERROR_ARGUMENT
Definition: spi.h:44
MemoryContext plancxt
Definition: spi_priv.h:97
bool saved
Definition: spi_priv.h:93
void SaveCachedPlan(CachedPlanSource *plansource)
Definition: plancache.c:452
#define lfirst(lc)
Definition: pg_list.h:190
bool oneshot
Definition: spi_priv.h:94
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ SPI_modifytuple()

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

Definition at line 882 of file spi.c.

References heap_deform_tuple(), heap_form_tuple(), i, MemoryContextSwitchTo(), TupleDescData::natts, 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().

884 {
885  MemoryContext oldcxt;
886  HeapTuple mtuple;
887  int numberOfAttributes;
888  Datum *v;
889  bool *n;
890  int i;
891 
892  if (rel == NULL || tuple == NULL || natts < 0 || attnum == NULL || Values == NULL)
893  {
895  return NULL;
896  }
897 
898  if (_SPI_current == NULL)
899  {
901  return NULL;
902  }
903 
905 
906  SPI_result = 0;
907 
908  numberOfAttributes = rel->rd_att->natts;
909  v = (Datum *) palloc(numberOfAttributes * sizeof(Datum));
910  n = (bool *) palloc(numberOfAttributes * sizeof(bool));
911 
912  /* fetch old values and nulls */
913  heap_deform_tuple(tuple, rel->rd_att, v, n);
914 
915  /* replace values and nulls */
916  for (i = 0; i < natts; i++)
917  {
918  if (attnum[i] <= 0 || attnum[i] > numberOfAttributes)
919  break;
920  v[attnum[i] - 1] = Values[i];
921  n[attnum[i] - 1] = (Nulls && Nulls[i] == 'n') ? true : false;
922  }
923 
924  if (i == natts) /* no errors in *attnum */
925  {
926  mtuple = heap_form_tuple(rel->rd_att, v, n);
927 
928  /*
929  * copy the identification info of the old tuple: t_ctid, t_self, and
930  * OID (if any)
931  */
932  mtuple->t_data->t_ctid = tuple->t_data->t_ctid;
933  mtuple->t_self = tuple->t_self;
934  mtuple->t_tableOid = tuple->t_tableOid;
935  }
936  else
937  {
938  mtuple = NULL;
940  }
941 
942  pfree(v);
943  pfree(n);
944 
945  MemoryContextSwitchTo(oldcxt);
946 
947  return mtuple;
948 }
#define SPI_ERROR_UNCONNECTED
Definition: spi.h:42
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static _SPI_connection * _SPI_current
Definition: spi.c:50
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
HeapTupleHeader t_data
Definition: htup.h:68
int SPI_result
Definition: spi.c:47
#define SPI_ERROR_ARGUMENT
Definition: spi.h:44
void pfree(void *pointer)
Definition: mcxt.c:1031
ItemPointerData t_ctid
Definition: htup_details.h:160
ItemPointerData t_self
Definition: htup.h:65
#define SPI_ERROR_NOATTRIBUTE
Definition: spi.h:47
Oid t_tableOid
Definition: htup.h:66
MemoryContext savedcxt
Definition: spi_priv.h:35
uintptr_t Datum
Definition: postgres.h:367
TupleDesc rd_att
Definition: rel.h:84
int16 attnum
Definition: pg_attribute.h:79
void heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *values, bool *isnull)
Definition: heaptuple.c:1249
void * palloc(Size size)
Definition: mcxt.c:924
int i
static bool Nulls[MAXATTR]
Definition: bootstrap.c:168

◆ SPI_palloc()

void* SPI_palloc ( Size  size)

Definition at line 1114 of file spi.c.

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

Referenced by _SPI_strdup(), and coerce_function_result_tuple().

1115 {
1116  if (_SPI_current == NULL)
1117  elog(ERROR, "SPI_palloc called while not connected to SPI");
1118 
1119  return MemoryContextAlloc(_SPI_current->savedcxt, size);
1120 }
static _SPI_connection * _SPI_current
Definition: spi.c:50
#define ERROR
Definition: elog.h:43
MemoryContext savedcxt
Definition: spi_priv.h:35
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:771
#define elog(elevel,...)
Definition: elog.h:226

◆ SPI_pfree()

void SPI_pfree ( void *  pointer)

Definition at line 1130 of file spi.c.

References pfree().

1131 {
1132  /* No longer need to worry which context chunk was in... */
1133  pfree(pointer);
1134 }
void pfree(void *pointer)
Definition: mcxt.c:1031

◆ SPI_plan_get_cached_plan()

CachedPlan* SPI_plan_get_cached_plan ( SPIPlanPtr  plan)

Definition at line 1798 of file spi.c.

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

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

1799 {
1800  CachedPlanSource *plansource;
1801  CachedPlan *cplan;
1802  ErrorContextCallback spierrcontext;
1803 
1804  Assert(plan->magic == _SPI_PLAN_MAGIC);
1805 
1806  /* Can't support one-shot plans here */
1807  if (plan->oneshot)
1808  return NULL;
1809 
1810  /* Must have exactly one CachedPlanSource */
1811  if (list_length(plan->plancache_list) != 1)
1812  return NULL;
1813  plansource = (CachedPlanSource *) linitial(plan->plancache_list);
1814 
1815  /* Setup error traceback support for ereport() */
1816  spierrcontext.callback = _SPI_error_callback;
1817  spierrcontext.arg = unconstify(char *, plansource->query_string);
1818  spierrcontext.previous = error_context_stack;
1819  error_context_stack = &spierrcontext;
1820 
1821  /* Get the generic plan for the query */
1822  cplan = GetCachedPlan(plansource, NULL, plan->saved,
1824  Assert(cplan == plansource->gplan);
1825 
1826  /* Pop the error context stack */
1827  error_context_stack = spierrcontext.previous;
1828 
1829  return cplan;
1830 }
List * plancache_list
Definition: spi_priv.h:96
CachedPlan * GetCachedPlan(CachedPlanSource *plansource, ParamListInfo boundParams, bool useResOwner, QueryEnvironment *queryEnv)
Definition: plancache.c:1138
#define _SPI_PLAN_MAGIC
Definition: spi_priv.h:20
int magic
Definition: spi_priv.h:92
static _SPI_connection * _SPI_current
Definition: spi.c:50
void(* callback)(void *arg)
Definition: elog.h:254
struct ErrorContextCallback * previous
Definition: elog.h:253
struct CachedPlan * gplan
Definition: plancache.h:118
ErrorContextCallback * error_context_stack
Definition: elog.c:88
static void _SPI_error_callback(void *arg)
Definition: spi.c:2550
#define linitial(l)
Definition: pg_list.h:195
QueryEnvironment * queryEnv
Definition: spi_priv.h:37
#define unconstify(underlying_type, expr)
Definition: c.h:1163
bool saved
Definition: spi_priv.h:93
#define Assert(condition)
Definition: c.h:732
bool oneshot
Definition: spi_priv.h:94
const char * query_string
Definition: plancache.h:97
static int list_length(const List *l)
Definition: pg_list.h:169

◆ SPI_plan_get_plan_sources()

List* SPI_plan_get_plan_sources ( SPIPlanPtr  plan)

Definition at line 1782 of file spi.c.

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

Referenced by exec_simple_check_plan(), and exec_stmt_execsql().

1783 {
1784  Assert(plan->magic == _SPI_PLAN_MAGIC);
1785  return plan->plancache_list;
1786 }
List * plancache_list
Definition: spi_priv.h:96
#define _SPI_PLAN_MAGIC
Definition: spi_priv.h:20
int magic
Definition: spi_priv.h:92
#define Assert(condition)
Definition: c.h:732

◆ SPI_plan_is_valid()

bool SPI_plan_is_valid ( SPIPlanPtr  plan)

Definition at line 1681 of file spi.c.

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

Referenced by ri_FetchPreparedPlan().

1682 {
1683  ListCell *lc;
1684 
1685  Assert(plan->magic == _SPI_PLAN_MAGIC);
1686 
1687  foreach(lc, plan->plancache_list)
1688  {
1689  CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc);
1690 
1691  if (!CachedPlanIsValid(plansource))
1692  return false;
1693  }
1694  return true;
1695 }
List * plancache_list
Definition: spi_priv.h:96
#define _SPI_PLAN_MAGIC
Definition: spi_priv.h:20
int magic
Definition: spi_priv.h:92
#define Assert(condition)
Definition: c.h:732
#define lfirst(lc)
Definition: pg_list.h:190
bool CachedPlanIsValid(CachedPlanSource *plansource)
Definition: plancache.c:1415

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

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

Referenced by SPI_prepare().

682 {
683  _SPI_plan plan;
684  SPIPlanPtr result;
685 
686  if (src == NULL || nargs < 0 || (nargs > 0 && argtypes == NULL))
687  {
689  return NULL;
690  }
691 
692  SPI_result = _SPI_begin_call(true);
693  if (SPI_result < 0)
694  return NULL;
695 
696  memset(&plan, 0, sizeof(_SPI_plan));
697  plan.magic = _SPI_PLAN_MAGIC;
698  plan.cursor_options = cursorOptions;
699  plan.nargs = nargs;
700  plan.argtypes = argtypes;
701  plan.parserSetup = NULL;
702  plan.parserSetupArg = NULL;
703 
704  _SPI_prepare_plan(src, &plan);
705 
706  /* copy plan to procedure context */
707  result = _SPI_make_plan_non_temp(&plan);
708 
709  _SPI_end_call(true);
710 
711  return result;
712 }
static void _SPI_prepare_plan(const char *src, SPIPlanPtr plan)
Definition: spi.c:1938
Oid * argtypes
Definition: spi_priv.h:100
#define _SPI_PLAN_MAGIC
Definition: spi_priv.h:20
int magic
Definition: spi_priv.h:92
static int _SPI_begin_call(bool use_exec)
Definition: spi.c:2649
int SPI_result
Definition: spi.c:47
#define SPI_ERROR_ARGUMENT
Definition: spi.h:44
static SPIPlanPtr _SPI_make_plan_non_temp(SPIPlanPtr plan)
Definition: spi.c:2713
static int _SPI_end_call(bool use_exec)
Definition: spi.c:2673
int nargs
Definition: spi_priv.h:99
ParserSetupHook parserSetup
Definition: spi_priv.h:101
void * parserSetupArg
Definition: spi_priv.h:102
int cursor_options
Definition: spi_priv.h:98

◆ SPI_prepare_params()

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

Definition at line 715 of file spi.c.

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

Referenced by exec_prepare_plan().

719 {
720  _SPI_plan plan;
721  SPIPlanPtr result;
722 
723  if (src == NULL)
724  {
726  return NULL;
727  }
728 
729  SPI_result = _SPI_begin_call(true);
730  if (SPI_result < 0)
731  return NULL;
732 
733  memset(&plan, 0, sizeof(_SPI_plan));
734  plan.magic = _SPI_PLAN_MAGIC;
735  plan.cursor_options = cursorOptions;
736  plan.nargs = 0;
737  plan.argtypes = NULL;
738  plan.parserSetup = parserSetup;
739  plan.parserSetupArg = parserSetupArg;
740 
741  _SPI_prepare_plan(src, &plan);
742 
743  /* copy plan to procedure context */
744  result = _SPI_make_plan_non_temp(&plan);
745 
746  _SPI_end_call(true);
747 
748  return result;
749 }
static void _SPI_prepare_plan(const char *src, SPIPlanPtr plan)
Definition: spi.c:1938
Oid * argtypes
Definition: spi_priv.h:100
#define _SPI_PLAN_MAGIC
Definition: spi_priv.h:20
int magic
Definition: spi_priv.h:92
static int _SPI_begin_call(bool use_exec)
Definition: spi.c:2649
int SPI_result
Definition: spi.c:47
#define SPI_ERROR_ARGUMENT
Definition: spi.h:44
static SPIPlanPtr _SPI_make_plan_non_temp(SPIPlanPtr plan)
Definition: spi.c:2713
static int _SPI_end_call(bool use_exec)
Definition: spi.c:2673
int nargs
Definition: spi_priv.h:99
ParserSetupHook parserSetup
Definition: spi_priv.h:101
void * parserSetupArg
Definition: spi_priv.h:102
int cursor_options
Definition: spi_priv.h:98

◆ spi_printtup()

bool spi_printtup ( TupleTableSlot slot,
DestReceiver self 
)

Definition at line 1889 of file spi.c.

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

1890 {
1891  SPITupleTable *tuptable;
1892  MemoryContext oldcxt;
1893 
1894  if (_SPI_current == NULL)
1895  elog(ERROR, "spi_printtup called while not connected to SPI");
1896 
1897  tuptable = _SPI_current->tuptable;
1898  if (tuptable == NULL)
1899  elog(ERROR, "improper call to spi_printtup");
1900 
1901  oldcxt = MemoryContextSwitchTo(tuptable->tuptabcxt);
1902 
1903  if (tuptable->numvals >= tuptable->alloced)
1904  {
1905  /* Double the size of the pointer array */
1906  uint64 newalloced = tuptable->alloced * 2;
1907 
1908  tuptable->vals = (HeapTuple *) repalloc_huge(tuptable->vals,
1909  newalloced * sizeof(HeapTuple));
1910  tuptable->alloced = newalloced;
1911  }
1912 
1913  tuptable->vals[tuptable->numvals] = ExecCopySlotHeapTuple(slot);
1914  (tuptable->numvals)++;
1915 
1916  MemoryContextSwitchTo(oldcxt);
1917 
1918  return true;
1919 }
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static _SPI_connection * _SPI_current
Definition: spi.c:50
HeapTuple * vals
Definition: spi.h:26
uint64 numvals
Definition: spi.h:27
#define ERROR
Definition: elog.h:43
SPITupleTable * tuptable
Definition: spi_priv.h:26
static HeapTuple ExecCopySlotHeapTuple(TupleTableSlot *slot)
Definition: tuptable.h:453
void * repalloc_huge(void *pointer, Size size)
Definition: mcxt.c:1114
#define elog(elevel,...)
Definition: elog.h:226
uint64 alloced
Definition: spi.h:30
MemoryContext tuptabcxt
Definition: spi.h:31

◆ SPI_register_relation()

int SPI_register_relation ( EphemeralNamedRelation  enr)

Definition at line 2867 of file spi.c.

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

Referenced by SPI_register_trigger_data().

2868 {
2869  EphemeralNamedRelation match;
2870  int res;
2871 
2872  if (enr == NULL || enr->md.name == NULL)
2873  return SPI_ERROR_ARGUMENT;
2874 
2875  res = _SPI_begin_call(false); /* keep current memory context */
2876  if (res < 0)
2877  return res;
2878 
2879  match = _SPI_find_ENR_by_name(enr->md.name);
2880  if (match)
2882  else
2883  {
2884  if (_SPI_current->queryEnv == NULL)
2886 
2888  res = SPI_OK_REL_REGISTER;
2889  }
2890 
2891  _SPI_end_call(false);
2892 
2893  return res;
2894 }
EphemeralNamedRelationMetadataData md
#define SPI_ERROR_REL_DUPLICATE
Definition: spi.h:50
static EphemeralNamedRelation _SPI_find_ENR_by_name(const char *name)
Definition: spi.c:2850
static _SPI_connection * _SPI_current
Definition: spi.c:50
#define SPI_OK_REL_REGISTER
Definition: spi.h:67
static int _SPI_begin_call(bool use_exec)
Definition: spi.c:2649
#define SPI_ERROR_ARGUMENT
Definition: spi.h:44
QueryEnvironment * queryEnv
Definition: spi_priv.h:37
static int _SPI_end_call(bool use_exec)
Definition: spi.c:2673
void register_ENR(QueryEnvironment *queryEnv, EphemeralNamedRelation enr)
QueryEnvironment * create_queryEnv()

◆ SPI_register_trigger_data()

int SPI_register_trigger_data ( TriggerData tdata)

Definition at line 2934 of file spi.c.

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(), pltcl_trigger_handler(), and PLy_exec_trigger().

2935 {
2936  if (tdata == NULL)
2937  return SPI_ERROR_ARGUMENT;
2938 
2939  if (tdata->tg_newtable)
2940  {
2943  int rc;
2944 
2945  enr->md.name = tdata->tg_trigger->tgnewtable;
2946  enr->md.reliddesc = tdata->tg_relation->rd_id;
2947  enr->md.tupdesc = NULL;
2950  enr->reldata = tdata->tg_newtable;
2951  rc = SPI_register_relation(enr);
2952  if (rc != SPI_OK_REL_REGISTER)
2953  return rc;
2954  }
2955 
2956  if (tdata->tg_oldtable)
2957  {
2960  int rc;
2961 
2962  enr->md.name = tdata->tg_trigger->tgoldtable;
2963  enr->md.reliddesc = tdata->tg_relation->rd_id;
2964  enr->md.tupdesc = NULL;
2967  enr->reldata = tdata->tg_oldtable;
2968  rc = SPI_register_relation(enr);
2969  if (rc != SPI_OK_REL_REGISTER)
2970  return rc;
2971  }
2972 
2973  return SPI_OK_TD_REGISTER;
2974 }
EphemeralNamedRelationMetadataData md
#define SPI_OK_REL_REGISTER
Definition: spi.h:67
#define SPI_ERROR_ARGUMENT
Definition: spi.h:44
#define SPI_OK_TD_REGISTER
Definition: spi.h:69
Oid rd_id
Definition: rel.h:85
char * tgnewtable
Definition: reltrigger.h:43
Trigger * tg_trigger
Definition: trigger.h:37
int64 tuplestore_tuple_count(Tuplestorestate *state)
Definition: tuplestore.c:546
Tuplestorestate * tg_oldtable
Definition: trigger.h:40
int SPI_register_relation(EphemeralNamedRelation enr)
Definition: spi.c:2867
void * palloc(Size size)
Definition: mcxt.c:924
Tuplestorestate * tg_newtable
Definition: trigger.h:41
EphemeralNameRelationType enrtype
char * tgoldtable
Definition: reltrigger.h:42
Relation tg_relation
Definition: trigger.h:34

◆ SPI_repalloc()

void* SPI_repalloc ( void *  pointer,
Size  size 
)

Definition at line 1123 of file spi.c.

References repalloc().

1124 {
1125  /* No longer need to worry which context chunk was in... */
1126  return repalloc(pointer, size);
1127 }
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1044

◆ SPI_result_code_string()

const char* SPI_result_code_string ( int  code)

Definition at line 1705 of file spi.c.

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

Referenced by check_foreign_key(), check_primary_key(), exec_dynquery_with_params(), exec_prepare_plan(), exec_run_select(), exec_stmt_call(), exec_stmt_dynexecute(), exec_stmt_execsql(), exec_stmt_forc(), exec_stmt_open(), exec_stmt_set(), 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(), RI_Initial_Check(), RI_PartitionRemove_Check(), ri_PerformCheck(), ri_PlanCheck(), and ttdummy().

1706 {
1707  static char buf[64];
1708 
1709  switch (code)
1710  {
1711  case SPI_ERROR_CONNECT:
1712  return "SPI_ERROR_CONNECT";
1713  case SPI_ERROR_COPY:
1714  return "SPI_ERROR_COPY";
1715  case SPI_ERROR_OPUNKNOWN:
1716  return "SPI_ERROR_OPUNKNOWN";
1717  case SPI_ERROR_UNCONNECTED:
1718  return "SPI_ERROR_UNCONNECTED";
1719  case SPI_ERROR_ARGUMENT:
1720  return "SPI_ERROR_ARGUMENT";
1721  case SPI_ERROR_PARAM:
1722  return "SPI_ERROR_PARAM";
1723  case SPI_ERROR_TRANSACTION:
1724  return "SPI_ERROR_TRANSACTION";
1725  case SPI_ERROR_NOATTRIBUTE:
1726  return "SPI_ERROR_NOATTRIBUTE";
1727  case SPI_ERROR_NOOUTFUNC:
1728  return "SPI_ERROR_NOOUTFUNC";
1729  case SPI_ERROR_TYPUNKNOWN:
1730  return "SPI_ERROR_TYPUNKNOWN";
1732  return "SPI_ERROR_REL_DUPLICATE";
1734  return "SPI_ERROR_REL_NOT_FOUND";
1735  case SPI_OK_CONNECT:
1736  return "SPI_OK_CONNECT";
1737  case SPI_OK_FINISH:
1738  return "SPI_OK_FINISH";
1739  case SPI_OK_FETCH:
1740  return "SPI_OK_FETCH";
1741  case SPI_OK_UTILITY:
1742  return "SPI_OK_UTILITY";
1743  case SPI_OK_SELECT:
1744  return "SPI_OK_SELECT";
1745  case SPI_OK_SELINTO:
1746  return "SPI_OK_SELINTO";
1747  case SPI_OK_INSERT:
1748  return "SPI_OK_INSERT";
1749  case SPI_OK_DELETE:
1750  return "SPI_OK_DELETE";
1751  case SPI_OK_UPDATE:
1752  return "SPI_OK_UPDATE";
1753  case SPI_OK_CURSOR:
1754  return "SPI_OK_CURSOR";
1756  return "SPI_OK_INSERT_RETURNING";
1758  return "SPI_OK_DELETE_RETURNING";
1760  return "SPI_OK_UPDATE_RETURNING";
1761  case SPI_OK_REWRITTEN:
1762  return "SPI_OK_REWRITTEN";
1763  case SPI_OK_REL_REGISTER:
1764  return "SPI_OK_REL_REGISTER";
1765  case SPI_OK_REL_UNREGISTER:
1766  return "SPI_OK_REL_UNREGISTER";
1767  }
1768  /* Unrecognized code ... return something useful ... */
1769  sprintf(buf, "Unrecognized SPI code %d", code);
1770  return buf;
1771 }
#define SPI_OK_CONNECT
Definition: spi.h:53
#define SPI_ERROR_PARAM
Definition: spi.h:45
#define SPI_ERROR_REL_NOT_FOUND
Definition: spi.h:51
#define SPI_ERROR_REL_DUPLICATE
Definition: spi.h:50
#define SPI_ERROR_UNCONNECTED
Definition: spi.h:42
#define SPI_OK_DELETE_RETURNING
Definition: spi.h:64
#define SPI_OK_DELETE
Definition: spi.h:60
#define SPI_ERROR_COPY
Definition: spi.h:40
#define SPI_ERROR_OPUNKNOWN
Definition: spi.h:41
#define SPI_OK_REL_REGISTER
Definition: spi.h:67
#define SPI_ERROR_CONNECT
Definition: spi.h:39
#define SPI_OK_CURSOR
Definition: spi.h:62
#define sprintf
Definition: port.h:194
#define SPI_ERROR_NOOUTFUNC
Definition: spi.h:48
#define SPI_ERROR_ARGUMENT
Definition: spi.h:44
#define SPI_OK_INSERT_RETURNING
Definition: spi.h:63
static char * buf
Definition: pg_test_fsync.c:68
#define SPI_ERROR_NOATTRIBUTE
Definition: spi.h:47
#define SPI_OK_UTILITY
Definition: spi.h:56
#define SPI_OK_UPDATE_RETURNING
Definition: spi.h:65
#define SPI_OK_REWRITTEN
Definition: spi.h:66
#define SPI_ERROR_TRANSACTION
Definition: spi.h:46
#define SPI_OK_SELINTO
Definition: spi.h:58
#define SPI_OK_FETCH
Definition: spi.h:55
#define SPI_OK_SELECT
Definition: spi.h:57
#define SPI_OK_FINISH
Definition: spi.h:54
#define SPI_ERROR_TYPUNKNOWN
Definition: spi.h:49
#define SPI_OK_UPDATE
Definition: spi.h:61
#define SPI_OK_INSERT
Definition: spi.h:59
#define SPI_OK_REL_UNREGISTER
Definition: spi.h:68

◆ SPI_returntuple()

HeapTupleHeader SPI_returntuple ( HeapTuple  tuple,
TupleDesc  tupdesc 
)

Definition at line 850 of file spi.c.

References 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().

851 {
852  MemoryContext oldcxt;
853  HeapTupleHeader dtup;
854 
855  if (tuple == NULL || tupdesc == NULL)
856  {
858  return NULL;
859  }
860 
861  if (_SPI_current == NULL)
862  {
864  return NULL;
865  }
866 
867  /* For RECORD results, make sure a typmod has been assigned */
868  if (tupdesc->tdtypeid == RECORDOID &&
869  tupdesc->tdtypmod < 0)
870  assign_record_type_typmod(tupdesc);
871 
873 
874  dtup = DatumGetHeapTupleHeader(heap_copy_tuple_as_datum(tuple, tupdesc));
875 
876  MemoryContextSwitchTo(oldcxt);
877 
878  return dtup;
879 }
#define SPI_ERROR_UNCONNECTED
Definition: spi.h:42
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static _SPI_connection * _SPI_current
Definition: spi.c:50
#define DatumGetHeapTupleHeader(X)
Definition: fmgr.h:289
void assign_record_type_typmod(TupleDesc tupDesc)
Definition: typcache.c:1772
int SPI_result
Definition: spi.c:47
#define SPI_ERROR_ARGUMENT
Definition: spi.h:44
int32 tdtypmod
Definition: tupdesc.h:83
MemoryContext savedcxt
Definition: spi_priv.h:35
Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
Definition: heaptuple.c:984
Oid tdtypeid
Definition: tupdesc.h:82

◆ SPI_rollback()

void SPI_rollback ( void  )

Definition at line 333 of file spi.c.

References _SPI_rollback().

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

334 {
335  _SPI_rollback(false);
336 }
static void _SPI_rollback(bool chain)
Definition: spi.c:290

◆ SPI_rollback_and_chain()

void SPI_rollback_and_chain ( void  )

Definition at line 339 of file spi.c.

References _SPI_rollback().

Referenced by exec_stmt_rollback().

340 {
341  _SPI_rollback(true);
342 }
static void _SPI_rollback(bool chain)
Definition: spi.c:290

◆ SPI_saveplan()

SPIPlanPtr SPI_saveplan ( SPIPlanPtr  plan)

Definition at line 779 of file spi.c.

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

780 {
781  SPIPlanPtr newplan;
782 
783  if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC)
784  {
786  return NULL;
787  }
788 
789  SPI_result = _SPI_begin_call(false); /* don't change context */
790  if (SPI_result < 0)
791  return NULL;
792 
793  newplan = _SPI_save_plan(plan);
794 
795  SPI_result = _SPI_end_call(false);
796 
797  return newplan;
798 }
#define _SPI_PLAN_MAGIC
Definition: spi_priv.h:20
int magic
Definition: spi_priv.h:92
static int _SPI_begin_call(bool use_exec)
Definition: spi.c:2649
int SPI_result
Definition: spi.c:47
#define SPI_ERROR_ARGUMENT
Definition: spi.h:44
static SPIPlanPtr _SPI_save_plan(SPIPlanPtr plan)
Definition: spi.c:2780
static int _SPI_end_call(bool use_exec)
Definition: spi.c:2673

◆ SPI_scroll_cursor_fetch()

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

Definition at line 1568 of file spi.c.

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

Referenced by exec_stmt_fetch().

1569 {
1570  _SPI_cursor_operation(portal,
1571  direction, count,
1573  /* we know that the DestSPI receiver doesn't need a destroy call */
1574 }
Definition: dest.h:93
DestReceiver * CreateDestReceiver(CommandDest dest)
Definition: dest.c:113
static void _SPI_cursor_operation(Portal portal, FetchDirection direction, long count, DestReceiver *dest)
Definition: spi.c:2579

◆ SPI_scroll_cursor_move()

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

Definition at line 1583 of file spi.c.

References _SPI_cursor_operation(), and None_Receiver.

Referenced by exec_stmt_fetch().

1584 {
1585  _SPI_cursor_operation(portal, direction, count, None_Receiver);
1586 }
DestReceiver * None_Receiver
Definition: dest.c:96
static void _SPI_cursor_operation(Portal portal, FetchDirection direction, long count, DestReceiver *dest)
Definition: spi.c:2579

◆ SPI_start_transaction()

void SPI_start_transaction ( void  )

Definition at line 212 of file spi.c.

References CurrentMemoryContext, MemoryContextSwitchTo(), and StartTransactionCommand().

Referenced by exec_stmt_commit(), exec_stmt_rollback(), plperl_spi_commit(), plperl_spi_rollback(), pltcl_commit(), pltcl_rollback(), PLy_commit(), and PLy_rollback().

213 {
214  MemoryContext oldcontext = CurrentMemoryContext;
215 
217  MemoryContextSwitchTo(oldcontext);
218 }
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
void StartTransactionCommand(void)
Definition: xact.c:2794

◆ SPI_unregister_relation()

int SPI_unregister_relation ( const char *  name)

Definition at line 2901 of file spi.c.

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

2902 {
2903  EphemeralNamedRelation match;
2904  int res;
2905 
2906  if (name == NULL)
2907  return SPI_ERROR_ARGUMENT;
2908 
2909  res = _SPI_begin_call(false); /* keep current memory context */
2910  if (res < 0)
2911  return res;
2912 
2913  match = _SPI_find_ENR_by_name(name);
2914  if (match)
2915  {
2917  res = SPI_OK_REL_UNREGISTER;
2918  }
2919  else
2921 
2922  _SPI_end_call(false);
2923 
2924  return res;
2925 }
EphemeralNamedRelationMetadataData md
#define SPI_ERROR_REL_NOT_FOUND
Definition: spi.h:51
static EphemeralNamedRelation _SPI_find_ENR_by_name(const char *name)
Definition: spi.c:2850
static _SPI_connection * _SPI_current
Definition: spi.c:50
static int _SPI_begin_call(bool use_exec)
Definition: spi.c:2649
#define SPI_ERROR_ARGUMENT
Definition: spi.h:44
QueryEnvironment * queryEnv
Definition: spi_priv.h:37
void unregister_ENR(QueryEnvironment *queryEnv, const char *name)
static int _SPI_end_call(bool use_exec)
Definition: spi.c:2673
const char * name
Definition: encode.c:521
#define SPI_OK_REL_UNREGISTER
Definition: spi.h:68

◆ SPICleanup()

void SPICleanup ( void  )

Definition at line 349 of file spi.c.

References _SPI_connected, SPI_processed, and SPI_result.

Referenced by AtEOXact_SPI(), and PostgresMain().

350 {
351  _SPI_current = NULL;
352  _SPI_connected = -1;
353  /* Reset API global variables, too */
354  SPI_processed = 0;
355  SPI_tuptable = NULL;
356  SPI_result = 0;
357 }
SPITupleTable * SPI_tuptable
Definition: spi.c:46
static int _SPI_connected
Definition: spi.c:52
static _SPI_connection * _SPI_current
Definition: spi.c:50
uint64 SPI_processed
Definition: spi.c:45
int SPI_result
Definition: spi.c:47

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(), SPI_finish(), and SPICleanup().

◆ _SPI_current

_SPI_connection* _SPI_current = NULL
static

Definition at line 50 of file spi.c.

◆ _SPI_stack

_SPI_connection* _SPI_stack = NULL
static

Definition at line 49 of file spi.c.

◆ _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