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 "tcop/pquery.h"
#include "tcop/utility.h"
#include "utils/builtins.h"
#include "utils/datum.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/rel.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
#include "utils/typcache.h"
Include dependency graph for spi.c:

Go to the source code of this file.

Data Structures

struct  SPICallbackArg
 

Typedefs

typedef struct SPICallbackArg SPICallbackArg
 

Functions

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

Variables

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

Typedef Documentation

◆ SPICallbackArg

Function Documentation

◆ _SPI_begin_call()

static int _SPI_begin_call ( bool  use_exec)
static

Definition at line 3094 of file spi.c.

3095{
3096 if (_SPI_current == NULL)
3097 return SPI_ERROR_UNCONNECTED;
3098
3099 if (use_exec)
3100 {
3101 /* remember when the Executor operation started */
3103 /* switch to the Executor memory context */
3104 _SPI_execmem();
3105 }
3106
3107 return 0;
3108}
static _SPI_connection * _SPI_current
Definition: spi.c:49
static MemoryContext _SPI_execmem(void)
Definition: spi.c:3075
#define SPI_ERROR_UNCONNECTED
Definition: spi.h:71
SubTransactionId execSubid
Definition: spi_priv.h:29
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:791

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

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

◆ _SPI_checktuples()

static bool _SPI_checktuples ( void  )
static

Definition at line 3134 of file spi.c.

3135{
3136 uint64 processed = _SPI_current->processed;
3137 SPITupleTable *tuptable = _SPI_current->tuptable;
3138 bool failed = false;
3139
3140 if (tuptable == NULL) /* spi_dest_startup was not called */
3141 failed = true;
3142 else if (processed != tuptable->numvals)
3143 failed = true;
3144
3145 return failed;
3146}
uint64_t uint64
Definition: c.h:503
uint64 numvals
Definition: spi.h:27
uint64 processed
Definition: spi_priv.h:25
SPITupleTable * tuptable
Definition: spi_priv.h:26

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

Referenced by _SPI_cursor_operation(), and _SPI_pquery().

◆ _SPI_commit()

static void _SPI_commit ( bool  chain)
static

Definition at line 228 of file spi.c.

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

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

Referenced by SPI_commit(), and SPI_commit_and_chain().

◆ _SPI_convert_params()

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

Definition at line 2856 of file spi.c.

2858{
2859 ParamListInfo paramLI;
2860
2861 if (nargs > 0)
2862 {
2863 paramLI = makeParamList(nargs);
2864
2865 for (int i = 0; i < nargs; i++)
2866 {
2867 ParamExternData *prm = &paramLI->params[i];
2868
2869 prm->value = Values[i];
2870 prm->isnull = (Nulls && Nulls[i] == 'n');
2871 prm->pflags = PARAM_FLAG_CONST;
2872 prm->ptype = argtypes[i];
2873 }
2874 }
2875 else
2876 paramLI = NULL;
2877 return paramLI;
2878}
static bool Nulls[MAXATTR]
Definition: bootstrap.c:152
int i
Definition: isn.c:74
ParamListInfo makeParamList(int numParams)
Definition: params.c:44
#define PARAM_FLAG_CONST
Definition: params.h:88
bool isnull
Definition: params.h:93
uint16 pflags
Definition: params.h:94
Datum value
Definition: params.h:92
ParamExternData params[FLEXIBLE_ARRAY_MEMBER]
Definition: params.h:125

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

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

◆ _SPI_cursor_operation()

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

Definition at line 3024 of file spi.c.

3026{
3027 uint64 nfetched;
3028
3029 /* Check that the portal is valid */
3030 if (!PortalIsValid(portal))
3031 elog(ERROR, "invalid portal in SPI cursor operation");
3032
3033 /* Push the SPI stack */
3034 if (_SPI_begin_call(true) < 0)
3035 elog(ERROR, "SPI cursor operation called while not connected");
3036
3037 /* Reset the SPI result (note we deliberately don't touch lastoid) */
3038 SPI_processed = 0;
3039 SPI_tuptable = NULL;
3041 _SPI_current->tuptable = NULL;
3042
3043 /* Run the cursor */
3044 nfetched = PortalRunFetch(portal,
3045 direction,
3046 count,
3047 dest);
3048
3049 /*
3050 * Think not to combine this store with the preceding function call. If
3051 * the portal contains calls to functions that use SPI, then _SPI_stack is
3052 * likely to move around while the portal runs. When control returns,
3053 * _SPI_current will point to the correct stack entry... but the pointer
3054 * may be different than it was beforehand. So we must be sure to re-fetch
3055 * the pointer after the function call completes.
3056 */
3057 _SPI_current->processed = nfetched;
3058
3059 if (dest->mydest == DestSPI && _SPI_checktuples())
3060 elog(ERROR, "consistency check on SPI tuple count failed");
3061
3062 /* Put the result into place for access by caller */
3065
3066 /* tuptable now is caller's responsibility, not SPI's */
3067 _SPI_current->tuptable = NULL;
3068
3069 /* Pop the SPI stack */
3070 _SPI_end_call(true);
3071}
@ DestSPI
Definition: dest.h:92
#define elog(elevel,...)
Definition: elog.h:225
#define PortalIsValid(p)
Definition: portal.h:212
uint64 PortalRunFetch(Portal portal, FetchDirection fdirection, long count, DestReceiver *dest)
Definition: pquery.c:1427
static int _SPI_end_call(bool use_exec)
Definition: spi.c:3118
uint64 SPI_processed
Definition: spi.c:44
SPITupleTable * SPI_tuptable
Definition: spi.c:45
static int _SPI_begin_call(bool use_exec)
Definition: spi.c:3094
static bool _SPI_checktuples(void)
Definition: spi.c:3134

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

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

◆ _SPI_end_call()

static int _SPI_end_call ( bool  use_exec)
static

Definition at line 3118 of file spi.c.

3119{
3120 if (use_exec)
3121 {
3122 /* switch to the procedure memory context */
3123 _SPI_procmem();
3124 /* mark Executor context no longer in use */
3126 /* and free Executor memory */
3128 }
3129
3130 return 0;
3131}
#define InvalidSubTransactionId
Definition: c.h:629
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:383
static MemoryContext _SPI_procmem(void)
Definition: spi.c:3081
MemoryContext execCxt
Definition: spi_priv.h:34

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

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

◆ _SPI_error_callback()

static void _SPI_error_callback ( void *  arg)
static

Definition at line 2978 of file spi.c.

2979{
2980 SPICallbackArg *carg = (SPICallbackArg *) arg;
2981 const char *query = carg->query;
2982 int syntaxerrposition;
2983
2984 if (query == NULL) /* in case arg wasn't set yet */
2985 return;
2986
2987 /*
2988 * If there is a syntax error position, convert to internal syntax error;
2989 * otherwise treat the query as an item of context stack
2990 */
2991 syntaxerrposition = geterrposition();
2992 if (syntaxerrposition > 0)
2993 {
2994 errposition(0);
2995 internalerrposition(syntaxerrposition);
2996 internalerrquery(query);
2997 }
2998 else
2999 {
3000 /* Use the parse mode to decide how to describe the query */
3001 switch (carg->mode)
3002 {
3004 errcontext("PL/pgSQL expression \"%s\"", query);
3005 break;
3009 errcontext("PL/pgSQL assignment \"%s\"", query);
3010 break;
3011 default:
3012 errcontext("SQL statement \"%s\"", query);
3013 break;
3014 }
3015 }
3016}
int internalerrquery(const char *query)
Definition: elog.c:1482
int internalerrposition(int cursorpos)
Definition: elog.c:1462
int geterrposition(void)
Definition: elog.c:1595
int errposition(int cursorpos)
Definition: elog.c:1446
#define errcontext
Definition: elog.h:196
@ RAW_PARSE_PLPGSQL_EXPR
Definition: parser.h:41
@ RAW_PARSE_PLPGSQL_ASSIGN2
Definition: parser.h:43
@ RAW_PARSE_PLPGSQL_ASSIGN1
Definition: parser.h:42
@ RAW_PARSE_PLPGSQL_ASSIGN3
Definition: parser.h:44
void * arg
const char * query
Definition: spi.c:55
RawParseMode mode
Definition: spi.c:56

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

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

◆ _SPI_execmem()

static MemoryContext _SPI_execmem ( void  )
static

Definition at line 3075 of file spi.c.

3076{
3078}

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

Referenced by _SPI_begin_call().

◆ _SPI_execute_plan()

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

Definition at line 2401 of file spi.c.

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

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

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

◆ _SPI_find_ENR_by_name()

static EphemeralNamedRelation _SPI_find_ENR_by_name ( const char *  name)
static

Definition at line 3297 of file spi.c.

3298{
3299 /* internal static function; any error is bug in SPI itself */
3300 Assert(name != NULL);
3301
3302 /* fast exit if no tuplestores have been added */
3303 if (_SPI_current->queryEnv == NULL)
3304 return NULL;
3305
3307}
EphemeralNamedRelation get_ENR(QueryEnvironment *queryEnv, const char *name)
const char * name

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

Referenced by SPI_register_relation(), and SPI_unregister_relation().

◆ _SPI_make_plan_non_temp()

static SPIPlanPtr _SPI_make_plan_non_temp ( SPIPlanPtr  plan)
static

Definition at line 3158 of file spi.c.

3159{
3160 SPIPlanPtr newplan;
3161 MemoryContext parentcxt = _SPI_current->procCxt;
3162 MemoryContext plancxt;
3163 MemoryContext oldcxt;
3164 ListCell *lc;
3165
3166 /* Assert the input is a temporary SPIPlan */
3167 Assert(plan->magic == _SPI_PLAN_MAGIC);
3168 Assert(plan->plancxt == NULL);
3169 /* One-shot plans can't be saved */
3170 Assert(!plan->oneshot);
3171
3172 /*
3173 * Create a memory context for the plan, underneath the procedure context.
3174 * We don't expect the plan to be very large.
3175 */
3176 plancxt = AllocSetContextCreate(parentcxt,
3177 "SPI Plan",
3179 oldcxt = MemoryContextSwitchTo(plancxt);
3180
3181 /* Copy the _SPI_plan struct and subsidiary data into the new context */
3182 newplan = (SPIPlanPtr) palloc0(sizeof(_SPI_plan));
3183 newplan->magic = _SPI_PLAN_MAGIC;
3184 newplan->plancxt = plancxt;
3185 newplan->parse_mode = plan->parse_mode;
3186 newplan->cursor_options = plan->cursor_options;
3187 newplan->nargs = plan->nargs;
3188 if (plan->nargs > 0)
3189 {
3190 newplan->argtypes = (Oid *) palloc(plan->nargs * sizeof(Oid));
3191 memcpy(newplan->argtypes, plan->argtypes, plan->nargs * sizeof(Oid));
3192 }
3193 else
3194 newplan->argtypes = NULL;
3195 newplan->parserSetup = plan->parserSetup;
3196 newplan->parserSetupArg = plan->parserSetupArg;
3197
3198 /*
3199 * Reparent all the CachedPlanSources into the procedure context. In
3200 * theory this could fail partway through due to the pallocs, but we don't
3201 * care too much since both the procedure context and the executor context
3202 * would go away on error.
3203 */
3204 foreach(lc, plan->plancache_list)
3205 {
3206 CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc);
3207
3208 CachedPlanSetParentContext(plansource, parentcxt);
3209
3210 /* Build new list, with list cells in plancxt */
3211 newplan->plancache_list = lappend(newplan->plancache_list, plansource);
3212 }
3213
3214 MemoryContextSwitchTo(oldcxt);
3215
3216 /* For safety, unlink the CachedPlanSources from the temporary plan */
3217 plan->plancache_list = NIL;
3218
3219 return newplan;
3220}
List * lappend(List *list, void *datum)
Definition: list.c:339
void * palloc0(Size size)
Definition: mcxt.c:1347
void * palloc(Size size)
Definition: mcxt.c:1317
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:170
void CachedPlanSetParentContext(CachedPlanSource *plansource, MemoryContext newcontext)
Definition: plancache.c:1642
unsigned int Oid
Definition: postgres_ext.h:32
struct _SPI_plan * SPIPlanPtr
Definition: spi.h:66
#define _SPI_PLAN_MAGIC
Definition: spi_priv.h:20
MemoryContext procCxt
Definition: spi_priv.h:33
ParserSetupHook parserSetup
Definition: spi_priv.h:101
List * plancache_list
Definition: spi_priv.h:95
int magic
Definition: spi_priv.h:92
int cursor_options
Definition: spi_priv.h:98
Oid * argtypes
Definition: spi_priv.h:100
int nargs
Definition: spi_priv.h:99
MemoryContext plancxt
Definition: spi_priv.h:96
RawParseMode parse_mode
Definition: spi_priv.h:97
void * parserSetupArg
Definition: spi_priv.h:102

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

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

◆ _SPI_pquery()

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

Definition at line 2881 of file spi.c.

2883{
2884 int operation = queryDesc->operation;
2885 int eflags;
2886 int res;
2887
2888 switch (operation)
2889 {
2890 case CMD_SELECT:
2891 if (queryDesc->dest->mydest == DestNone)
2892 {
2893 /* Don't return SPI_OK_SELECT if we're discarding result */
2894 res = SPI_OK_UTILITY;
2895 }
2896 else
2897 res = SPI_OK_SELECT;
2898 break;
2899 case CMD_INSERT:
2900 if (queryDesc->plannedstmt->hasReturning)
2902 else
2903 res = SPI_OK_INSERT;
2904 break;
2905 case CMD_DELETE:
2906 if (queryDesc->plannedstmt->hasReturning)
2908 else
2909 res = SPI_OK_DELETE;
2910 break;
2911 case CMD_UPDATE:
2912 if (queryDesc->plannedstmt->hasReturning)
2914 else
2915 res = SPI_OK_UPDATE;
2916 break;
2917 case CMD_MERGE:
2918 if (queryDesc->plannedstmt->hasReturning)
2920 else
2921 res = SPI_OK_MERGE;
2922 break;
2923 default:
2924 return SPI_ERROR_OPUNKNOWN;
2925 }
2926
2927#ifdef SPI_EXECUTOR_STATS
2928 if (ShowExecutorStats)
2929 ResetUsage();
2930#endif
2931
2932 /* Select execution options */
2933 if (fire_triggers)
2934 eflags = 0; /* default run-to-completion flags */
2935 else
2936 eflags = EXEC_FLAG_SKIP_TRIGGERS;
2937
2938 if (queryDesc->cplan)
2939 {
2940 ExecutorStartCachedPlan(queryDesc, eflags, plansource, query_index);
2941 Assert(queryDesc->planstate);
2942 }
2943 else
2944 {
2945 if (!ExecutorStart(queryDesc, eflags))
2946 elog(ERROR, "ExecutorStart() failed unexpectedly");
2947 }
2948
2949 ExecutorRun(queryDesc, ForwardScanDirection, tcount);
2950
2952
2953 if ((res == SPI_OK_SELECT || queryDesc->plannedstmt->hasReturning) &&
2954 queryDesc->dest->mydest == DestSPI)
2955 {
2956 if (_SPI_checktuples())
2957 elog(ERROR, "consistency check on SPI tuple count failed");
2958 }
2959
2960 ExecutorFinish(queryDesc);
2961 ExecutorEnd(queryDesc);
2962 /* FreeQueryDesc is done by the caller */
2963
2964#ifdef SPI_EXECUTOR_STATS
2965 if (ShowExecutorStats)
2966 ShowUsage("SPI EXECUTOR STATS");
2967#endif
2968
2969 return res;
2970}
bool ExecutorStart(QueryDesc *queryDesc, int eflags)
Definition: execMain.c:125
void ExecutorStartCachedPlan(QueryDesc *queryDesc, int eflags, CachedPlanSource *plansource, int query_index)
Definition: execMain.c:292
void ExecutorEnd(QueryDesc *queryDesc)
Definition: execMain.c:535
void ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:472
void ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count)
Definition: execMain.c:362
#define EXEC_FLAG_SKIP_TRIGGERS
Definition: executor.h:71
@ CMD_MERGE
Definition: nodes.h:271
@ CMD_INSERT
Definition: nodes.h:269
@ CMD_DELETE
Definition: nodes.h:270
@ CMD_UPDATE
Definition: nodes.h:268
@ CMD_SELECT
Definition: nodes.h:267
void ShowUsage(const char *title)
Definition: postgres.c:5050
void ResetUsage(void)
Definition: postgres.c:5043
@ ForwardScanDirection
Definition: sdir.h:28
#define SPI_OK_INSERT
Definition: spi.h:88
#define SPI_OK_UPDATE
Definition: spi.h:90
#define SPI_OK_MERGE
Definition: spi.h:99
#define SPI_ERROR_OPUNKNOWN
Definition: spi.h:70
#define SPI_OK_UPDATE_RETURNING
Definition: spi.h:94
#define SPI_OK_DELETE
Definition: spi.h:89
#define SPI_OK_INSERT_RETURNING
Definition: spi.h:92
#define SPI_OK_DELETE_RETURNING
Definition: spi.h:93
#define SPI_OK_MERGE_RETURNING
Definition: spi.h:100
#define SPI_OK_SELECT
Definition: spi.h:86
uint64 es_processed
Definition: execnodes.h:706
bool hasReturning
Definition: plannodes.h:62
DestReceiver * dest
Definition: execdesc.h:42
EState * estate
Definition: execdesc.h:49
CachedPlan * cplan
Definition: execdesc.h:38
CmdType operation
Definition: execdesc.h:36
PlannedStmt * plannedstmt
Definition: execdesc.h:37
PlanState * planstate
Definition: execdesc.h:50
CommandDest mydest
Definition: dest.h:128

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

Referenced by _SPI_execute_plan().

◆ _SPI_prepare_oneshot_plan()

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

Definition at line 2331 of file spi.c.

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

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

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

◆ _SPI_prepare_plan()

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

Definition at line 2223 of file spi.c.

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

References _SPI_current, _SPI_error_callback(), ErrorContextCallback::arg, Assert(), ErrorContextCallback::callback, CompleteCachedPlan(), CreateCachedPlan(), CreateCommandTag(), error_context_stack, lappend(), lfirst_node, SPICallbackArg::mode, NIL, pg_analyze_and_rewrite_fixedparams(), pg_analyze_and_rewrite_withcb(), plan, ErrorContextCallback::previous, SPICallbackArg::query, _SPI_connection::queryEnv, raw_parser(), and RawStmt::stmt.

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

◆ _SPI_procmem()

static MemoryContext _SPI_procmem ( void  )
static

Definition at line 3081 of file spi.c.

3082{
3084}

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

Referenced by _SPI_end_call(), and spi_dest_startup().

◆ _SPI_rollback()

static void _SPI_rollback ( bool  chain)
static

Definition at line 333 of file spi.c.

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

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

Referenced by SPI_rollback(), and SPI_rollback_and_chain().

◆ _SPI_save_plan()

static SPIPlanPtr _SPI_save_plan ( SPIPlanPtr  plan)
static

Definition at line 3226 of file spi.c.

3227{
3228 SPIPlanPtr newplan;
3229 MemoryContext plancxt;
3230 MemoryContext oldcxt;
3231 ListCell *lc;
3232
3233 /* One-shot plans can't be saved */
3234 Assert(!plan->oneshot);
3235
3236 /*
3237 * Create a memory context for the plan. We don't expect the plan to be
3238 * very large, so use smaller-than-default alloc parameters. It's a
3239 * transient context until we finish copying everything.
3240 */
3242 "SPI Plan",
3244 oldcxt = MemoryContextSwitchTo(plancxt);
3245
3246 /* Copy the SPI plan into its own context */
3247 newplan = (SPIPlanPtr) palloc0(sizeof(_SPI_plan));
3248 newplan->magic = _SPI_PLAN_MAGIC;
3249 newplan->plancxt = plancxt;
3250 newplan->parse_mode = plan->parse_mode;
3251 newplan->cursor_options = plan->cursor_options;
3252 newplan->nargs = plan->nargs;
3253 if (plan->nargs > 0)
3254 {
3255 newplan->argtypes = (Oid *) palloc(plan->nargs * sizeof(Oid));
3256 memcpy(newplan->argtypes, plan->argtypes, plan->nargs * sizeof(Oid));
3257 }
3258 else
3259 newplan->argtypes = NULL;
3260 newplan->parserSetup = plan->parserSetup;
3261 newplan->parserSetupArg = plan->parserSetupArg;
3262
3263 /* Copy all the plancache entries */
3264 foreach(lc, plan->plancache_list)
3265 {
3266 CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc);
3267 CachedPlanSource *newsource;
3268
3269 newsource = CopyCachedPlan(plansource);
3270 newplan->plancache_list = lappend(newplan->plancache_list, newsource);
3271 }
3272
3273 MemoryContextSwitchTo(oldcxt);
3274
3275 /*
3276 * Mark it saved, reparent it under CacheMemoryContext, and mark all the
3277 * component CachedPlanSources as saved. This sequence cannot fail
3278 * partway through, so there's no risk of long-term memory leakage.
3279 */
3280 newplan->saved = true;
3282
3283 foreach(lc, newplan->plancache_list)
3284 {
3285 CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc);
3286
3287 SaveCachedPlan(plansource);
3288 }
3289
3290 return newplan;
3291}
void MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
Definition: mcxt.c:637
MemoryContext CacheMemoryContext
Definition: mcxt.c:152
void SaveCachedPlan(CachedPlanSource *plansource)
Definition: plancache.c:483
CachedPlanSource * CopyCachedPlan(CachedPlanSource *plansource)
Definition: plancache.c:1680
bool saved
Definition: spi_priv.h:93

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

Referenced by SPI_saveplan().

◆ AtEOSubXact_SPI()

void AtEOSubXact_SPI ( bool  isCommit,
SubTransactionId  mySubid 
)

Definition at line 483 of file spi.c.

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

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

Referenced by AbortSubTransaction(), and CommitSubTransaction().

◆ AtEOXact_SPI()

void AtEOXact_SPI ( bool  isCommit)

Definition at line 429 of file spi.c.

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

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

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

◆ SPI_commit()

void SPI_commit ( void  )

Definition at line 321 of file spi.c.

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

References _SPI_commit().

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

◆ SPI_commit_and_chain()

void SPI_commit_and_chain ( void  )

Definition at line 327 of file spi.c.

328{
329 _SPI_commit(true);
330}

References _SPI_commit().

Referenced by exec_stmt_commit().

◆ SPI_connect()

◆ SPI_connect_ext()

int SPI_connect_ext ( int  options)

Definition at line 101 of file spi.c.

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

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

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

◆ SPI_copytuple()

HeapTuple SPI_copytuple ( HeapTuple  tuple)

Definition at line 1048 of file spi.c.

1049{
1050 MemoryContext oldcxt;
1051 HeapTuple ctuple;
1052
1053 if (tuple == NULL)
1054 {
1056 return NULL;
1057 }
1058
1059 if (_SPI_current == NULL)
1060 {
1062 return NULL;
1063 }
1064
1066
1067 ctuple = heap_copytuple(tuple);
1068
1069 MemoryContextSwitchTo(oldcxt);
1070
1071 return ctuple;
1072}
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:778
#define SPI_ERROR_ARGUMENT
Definition: spi.h:73

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

Referenced by get_tuple_of_interest(), and plpgsql_exec_trigger().

◆ SPI_cursor_close()

void SPI_cursor_close ( Portal  portal)

Definition at line 1864 of file spi.c.

1865{
1866 if (!PortalIsValid(portal))
1867 elog(ERROR, "invalid portal in SPI cursor operation");
1868
1869 PortalDrop(portal, false);
1870}
void PortalDrop(Portal portal, bool isTopCommit)
Definition: portalmem.c:470

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

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

◆ SPI_cursor_fetch()

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

Definition at line 1808 of file spi.c.

1809{
1810 _SPI_cursor_operation(portal,
1811 forward ? FETCH_FORWARD : FETCH_BACKWARD, count,
1813 /* we know that the DestSPI receiver doesn't need a destroy call */
1814}
@ FETCH_FORWARD
Definition: parsenodes.h:3406
@ FETCH_BACKWARD
Definition: parsenodes.h:3407
static void _SPI_cursor_operation(Portal portal, FetchDirection direction, long count, DestReceiver *dest)
Definition: spi.c:3024

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

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

◆ SPI_cursor_find()

Portal SPI_cursor_find ( const char *  name)

Definition at line 1796 of file spi.c.

1797{
1798 return GetPortalByName(name);
1799}
Portal GetPortalByName(const char *name)
Definition: portalmem.c:130

References GetPortalByName(), and name.

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

◆ SPI_cursor_move()

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

Definition at line 1823 of file spi.c.

1824{
1825 _SPI_cursor_operation(portal,
1826 forward ? FETCH_FORWARD : FETCH_BACKWARD, count,
1828}
DestReceiver * None_Receiver
Definition: dest.c:96

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

◆ SPI_cursor_open()

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

Definition at line 1446 of file spi.c.

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

References _SPI_convert_params(), name, Nulls, pfree(), plan, and SPI_cursor_open_internal().

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

◆ SPI_cursor_open_internal()

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

Definition at line 1578 of file spi.c.

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

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

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

◆ SPI_cursor_open_with_args()

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

Definition at line 1473 of file spi.c.

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

References _SPI_begin_call(), _SPI_convert_params(), _SPI_end_call(), _SPI_PLAN_MAGIC, _SPI_prepare_plan(), elog, ERROR, name, Nulls, plan, RAW_PARSE_DEFAULT, SPI_cursor_open_internal(), and SPI_result.

◆ SPI_cursor_open_with_paramlist()

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

Definition at line 1526 of file spi.c.

1528{
1529 return SPI_cursor_open_internal(name, plan, params, read_only);
1530}

References name, plan, and SPI_cursor_open_internal().

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

◆ SPI_cursor_parse_open()

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

Definition at line 1534 of file spi.c.

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

References _SPI_begin_call(), _SPI_end_call(), _SPI_PLAN_MAGIC, _SPI_prepare_plan(), elog, ERROR, name, plan, RAW_PARSE_DEFAULT, SPI_cursor_open_internal(), and SPI_result.

Referenced by exec_dynquery_with_params().

◆ SPI_datumTransfer()

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

Definition at line 1362 of file spi.c.

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

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

Referenced by coerce_function_result_tuple(), and plpgsql_exec_function().

◆ spi_dest_startup()

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

Definition at line 2125 of file spi.c.

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

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

◆ SPI_exec()

int SPI_exec ( const char *  src,
long  tcount 
)

Definition at line 631 of file spi.c.

632{
633 return SPI_execute(src, false, tcount);
634}
int SPI_execute(const char *src, bool read_only, long tcount)
Definition: spi.c:597

References SPI_execute().

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

◆ SPI_execp()

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

Definition at line 705 of file spi.c.

706{
707 return SPI_execute_plan(plan, Values, Nulls, false, tcount);
708}
int SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls, bool read_only, long tcount)
Definition: spi.c:673

References Nulls, plan, and SPI_execute_plan().

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

◆ SPI_execute()

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

Definition at line 597 of file spi.c.

598{
601 int res;
602
603 if (src == NULL || tcount < 0)
604 return SPI_ERROR_ARGUMENT;
605
606 res = _SPI_begin_call(true);
607 if (res < 0)
608 return res;
609
610 memset(&plan, 0, sizeof(_SPI_plan));
611 plan.magic = _SPI_PLAN_MAGIC;
612 plan.parse_mode = RAW_PARSE_DEFAULT;
613 plan.cursor_options = CURSOR_OPT_PARALLEL_OK;
614
616
617 memset(&options, 0, sizeof(options));
618 options.read_only = read_only;
619 options.tcount = tcount;
620
623 true);
624
625 _SPI_end_call(true);
626 return res;
627}
#define CURSOR_OPT_PARALLEL_OK
Definition: parsenodes.h:3378
static char ** options
static int _SPI_execute_plan(SPIPlanPtr plan, const SPIExecuteOptions *options, Snapshot snapshot, Snapshot crosscheck_snapshot, bool fire_triggers)
Definition: spi.c:2401
static void _SPI_prepare_oneshot_plan(const char *src, SPIPlanPtr plan)
Definition: spi.c:2331

References _SPI_begin_call(), _SPI_end_call(), _SPI_execute_plan(), _SPI_PLAN_MAGIC, _SPI_prepare_oneshot_plan(), CURSOR_OPT_PARALLEL_OK, InvalidSnapshot, options, plan, RAW_PARSE_DEFAULT, and SPI_ERROR_ARGUMENT.

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

◆ SPI_execute_extended()

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

Definition at line 638 of file spi.c.

640{
641 int res;
643
644 if (src == NULL || options == NULL)
645 return SPI_ERROR_ARGUMENT;
646
647 res = _SPI_begin_call(true);
648 if (res < 0)
649 return res;
650
651 memset(&plan, 0, sizeof(_SPI_plan));
652 plan.magic = _SPI_PLAN_MAGIC;
653 plan.parse_mode = RAW_PARSE_DEFAULT;
654 plan.cursor_options = CURSOR_OPT_PARALLEL_OK;
655 if (options->params)
656 {
657 plan.parserSetup = options->params->parserSetup;
658 plan.parserSetupArg = options->params->parserSetupArg;
659 }
660
662
665 true);
666
667 _SPI_end_call(true);
668 return res;
669}

References _SPI_begin_call(), _SPI_end_call(), _SPI_execute_plan(), _SPI_PLAN_MAGIC, _SPI_prepare_oneshot_plan(), CURSOR_OPT_PARALLEL_OK, InvalidSnapshot, plan, RAW_PARSE_DEFAULT, and SPI_ERROR_ARGUMENT.

Referenced by exec_stmt_dynexecute(), and exec_stmt_return_query().

◆ SPI_execute_plan()

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

Definition at line 673 of file spi.c.

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

References _SPI_begin_call(), _SPI_convert_params(), _SPI_end_call(), _SPI_execute_plan(), _SPI_PLAN_MAGIC, InvalidSnapshot, Nulls, options, plan, SPI_ERROR_ARGUMENT, and SPI_ERROR_PARAM.

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

◆ SPI_execute_plan_extended()

int SPI_execute_plan_extended ( SPIPlanPtr  plan,
const SPIExecuteOptions options 
)

Definition at line 712 of file spi.c.

714{
715 int res;
716
717 if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC || options == NULL)
718 return SPI_ERROR_ARGUMENT;
719
720 res = _SPI_begin_call(true);
721 if (res < 0)
722 return res;
723
726 true);
727
728 _SPI_end_call(true);
729 return res;
730}

References _SPI_begin_call(), _SPI_end_call(), _SPI_execute_plan(), _SPI_PLAN_MAGIC, InvalidSnapshot, plan, and SPI_ERROR_ARGUMENT.

Referenced by exec_stmt_call(), and exec_stmt_return_query().

◆ SPI_execute_plan_with_paramlist()

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

Definition at line 734 of file spi.c.

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

References _SPI_begin_call(), _SPI_end_call(), _SPI_execute_plan(), _SPI_PLAN_MAGIC, InvalidSnapshot, options, plan, and SPI_ERROR_ARGUMENT.

Referenced by exec_run_select(), and exec_stmt_execsql().

◆ SPI_execute_snapshot()

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

Definition at line 774 of file spi.c.

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

References _SPI_begin_call(), _SPI_convert_params(), _SPI_end_call(), _SPI_execute_plan(), _SPI_PLAN_MAGIC, Nulls, options, plan, SPI_ERROR_ARGUMENT, and SPI_ERROR_PARAM.

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

◆ SPI_execute_with_args()

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

Definition at line 813 of file spi.c.

817{
818 int res;
820 ParamListInfo paramLI;
822
823 if (src == NULL || nargs < 0 || tcount < 0)
824 return SPI_ERROR_ARGUMENT;
825
826 if (nargs > 0 && (argtypes == NULL || Values == NULL))
827 return SPI_ERROR_PARAM;
828
829 res = _SPI_begin_call(true);
830 if (res < 0)
831 return res;
832
833 memset(&plan, 0, sizeof(_SPI_plan));
834 plan.magic = _SPI_PLAN_MAGIC;
835 plan.parse_mode = RAW_PARSE_DEFAULT;
836 plan.cursor_options = CURSOR_OPT_PARALLEL_OK;
837 plan.nargs = nargs;
838 plan.argtypes = argtypes;
839 plan.parserSetup = NULL;
840 plan.parserSetupArg = NULL;
841
842 paramLI = _SPI_convert_params(nargs, argtypes,
843 Values, Nulls);
844
846
847 memset(&options, 0, sizeof(options));
848 options.params = paramLI;
849 options.read_only = read_only;
850 options.tcount = tcount;
851
854 true);
855
856 _SPI_end_call(true);
857 return res;
858}

References _SPI_begin_call(), _SPI_convert_params(), _SPI_end_call(), _SPI_execute_plan(), _SPI_PLAN_MAGIC, _SPI_prepare_oneshot_plan(), CURSOR_OPT_PARALLEL_OK, InvalidSnapshot, Nulls, options, plan, RAW_PARSE_DEFAULT, SPI_ERROR_ARGUMENT, and SPI_ERROR_PARAM.

◆ SPI_finish()

int SPI_finish ( void  )

Definition at line 183 of file spi.c.

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

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

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

◆ SPI_fname()

char * SPI_fname ( TupleDesc  tupdesc,
int  fnumber 
)

Definition at line 1199 of file spi.c.

1200{
1201 const FormData_pg_attribute *att;
1202
1203 SPI_result = 0;
1204
1205 if (fnumber > tupdesc->natts || fnumber == 0 ||
1207 {
1209 return NULL;
1210 }
1211
1212 if (fnumber > 0)
1213 att = TupleDescAttr(tupdesc, fnumber - 1);
1214 else
1215 att = SystemAttributeDefinition(fnumber);
1216
1217 return pstrdup(NameStr(att->attname));
1218}
#define NameStr(name)
Definition: c.h:717
const FormData_pg_attribute * SystemAttributeDefinition(AttrNumber attno)
Definition: heap.c:236
char * pstrdup(const char *in)
Definition: mcxt.c:1699
FormData_pg_attribute
Definition: pg_attribute.h:184
#define SPI_ERROR_NOATTRIBUTE
Definition: spi.h:76
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:154

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

Referenced by get_pkey_attnames(), and SPI_sql_row_to_xmlelement().

◆ SPI_fnumber()

int SPI_fnumber ( TupleDesc  tupdesc,
const char *  fname 
)

Definition at line 1176 of file spi.c.

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

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

◆ SPI_freeplan()

int SPI_freeplan ( SPIPlanPtr  plan)

Definition at line 1026 of file spi.c.

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

References _SPI_PLAN_MAGIC, DropCachedPlan(), lfirst, MemoryContextDelete(), plan, and SPI_ERROR_ARGUMENT.

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

◆ SPI_freetuple()

void SPI_freetuple ( HeapTuple  tuple)

Definition at line 1380 of file spi.c.

1381{
1382 /* No longer need to worry which context tuple was in... */
1383 heap_freetuple(tuple);
1384}
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1435

References heap_freetuple().

◆ SPI_freetuptable()

void SPI_freetuptable ( SPITupleTable tuptable)

Definition at line 1387 of file spi.c.

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

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

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

◆ SPI_getargcount()

int SPI_getargcount ( SPIPlanPtr  plan)

Definition at line 1892 of file spi.c.

1893{
1894 if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC)
1895 {
1897 return -1;
1898 }
1899 return plan->nargs;
1900}

References _SPI_PLAN_MAGIC, plan, SPI_ERROR_ARGUMENT, and SPI_result.

◆ SPI_getargtypeid()

Oid SPI_getargtypeid ( SPIPlanPtr  plan,
int  argIndex 
)

Definition at line 1877 of file spi.c.

1878{
1879 if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC ||
1880 argIndex < 0 || argIndex >= plan->nargs)
1881 {
1883 return InvalidOid;
1884 }
1885 return plan->argtypes[argIndex];
1886}
#define InvalidOid
Definition: postgres_ext.h:37

References _SPI_PLAN_MAGIC, InvalidOid, plan, SPI_ERROR_ARGUMENT, and SPI_result.

◆ SPI_getbinval()

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

Definition at line 1253 of file spi.c.

1254{
1255 SPI_result = 0;
1256
1257 if (fnumber > tupdesc->natts || fnumber == 0 ||
1259 {
1261 *isnull = true;
1262 return (Datum) NULL;
1263 }
1264
1265 return heap_getattr(tuple, fnumber, tupdesc, isnull);
1266}
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:903

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

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

◆ SPI_getnspname()

char * SPI_getnspname ( Relation  rel)

Definition at line 1333 of file spi.c.

1334{
1336}
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3449
#define RelationGetNamespace(relation)
Definition: rel.h:554

References get_namespace_name(), and RelationGetNamespace.

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

◆ SPI_getrelname()

char * SPI_getrelname ( Relation  rel)

◆ SPI_gettype()

char * SPI_gettype ( TupleDesc  tupdesc,
int  fnumber 
)

Definition at line 1269 of file spi.c.

1270{
1271 Oid typoid;
1272 HeapTuple typeTuple;
1273 char *result;
1274
1275 SPI_result = 0;
1276
1277 if (fnumber > tupdesc->natts || fnumber == 0 ||
1279 {
1281 return NULL;
1282 }
1283
1284 if (fnumber > 0)
1285 typoid = TupleDescAttr(tupdesc, fnumber - 1)->atttypid;
1286 else
1287 typoid = (SystemAttributeDefinition(fnumber))->atttypid;
1288
1289 typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typoid));
1290
1291 if (!HeapTupleIsValid(typeTuple))
1292 {
1294 return NULL;
1295 }
1296
1297 result = pstrdup(NameStr(((Form_pg_type) GETSTRUCT(typeTuple))->typname));
1298 ReleaseSysCache(typeTuple);
1299 return result;
1300}
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
Definition: htup_details.h:728
FormData_pg_type * Form_pg_type
Definition: pg_type.h:261
NameData typname
Definition: pg_type.h:41
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
#define SPI_ERROR_TYPUNKNOWN
Definition: spi.h:78
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221

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

Referenced by check_foreign_key().

◆ SPI_gettypeid()

Oid SPI_gettypeid ( TupleDesc  tupdesc,
int  fnumber 
)

Definition at line 1309 of file spi.c.

1310{
1311 SPI_result = 0;
1312
1313 if (fnumber > tupdesc->natts || fnumber == 0 ||
1315 {
1317 return InvalidOid;
1318 }
1319
1320 if (fnumber > 0)
1321 return TupleDescAttr(tupdesc, fnumber - 1)->atttypid;
1322 else
1323 return (SystemAttributeDefinition(fnumber))->atttypid;
1324}

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

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

◆ SPI_getvalue()

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

Definition at line 1221 of file spi.c.

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

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

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

◆ SPI_inside_nonatomic_context()

bool SPI_inside_nonatomic_context ( void  )

Definition at line 582 of file spi.c.

583{
584 if (_SPI_current == NULL)
585 return false; /* not in any SPI context at all */
586 /* these tests must match _SPI_commit's opinion of what's atomic: */
587 if (_SPI_current->atomic)
588 return false; /* it's atomic (ie function not procedure) */
589 if (IsSubTransaction())
590 return false; /* if within subtransaction, it's atomic */
591 return true;
592}

References _SPI_current, _SPI_connection::atomic, and IsSubTransaction().

Referenced by StartTransaction().

◆ SPI_is_cursor_plan()

bool SPI_is_cursor_plan ( SPIPlanPtr  plan)

Definition at line 1912 of file spi.c.

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

References _SPI_PLAN_MAGIC, linitial, list_length(), plan, CachedPlanSource::resultDesc, SPI_ERROR_ARGUMENT, and SPI_result.

Referenced by SPI_cursor_open_internal().

◆ SPI_keepplan()

int SPI_keepplan ( SPIPlanPtr  plan)

Definition at line 977 of file spi.c.

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

References _SPI_PLAN_MAGIC, CacheMemoryContext, lfirst, MemoryContextSetParent(), plan, SaveCachedPlan(), and SPI_ERROR_ARGUMENT.

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

◆ SPI_modifytuple()

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

Definition at line 1107 of file spi.c.

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

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

Referenced by ttdummy().

◆ SPI_palloc()

void * SPI_palloc ( Size  size)

Definition at line 1339 of file spi.c.

1340{
1341 if (_SPI_current == NULL)
1342 elog(ERROR, "SPI_palloc called while not connected to SPI");
1343
1345}

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

Referenced by _SPI_strdup(), and coerce_function_result_tuple().

◆ SPI_pfree()

void SPI_pfree ( void *  pointer)

Definition at line 1355 of file spi.c.

1356{
1357 /* No longer need to worry which context chunk was in... */
1358 pfree(pointer);
1359}

References pfree().

◆ SPI_plan_get_cached_plan()

CachedPlan * SPI_plan_get_cached_plan ( SPIPlanPtr  plan)

Definition at line 2078 of file spi.c.

2079{
2080 CachedPlanSource *plansource;
2081 CachedPlan *cplan;
2082 SPICallbackArg spicallbackarg;
2083 ErrorContextCallback spierrcontext;
2084
2085 Assert(plan->magic == _SPI_PLAN_MAGIC);
2086
2087 /* Can't support one-shot plans here */
2088 if (plan->oneshot)
2089 return NULL;
2090
2091 /* Must have exactly one CachedPlanSource */
2092 if (list_length(plan->plancache_list) != 1)
2093 return NULL;
2094 plansource = (CachedPlanSource *) linitial(plan->plancache_list);
2095
2096 /* Setup error traceback support for ereport() */
2097 spicallbackarg.query = plansource->query_string;
2098 spicallbackarg.mode = plan->parse_mode;
2099 spierrcontext.callback = _SPI_error_callback;
2100 spierrcontext.arg = &spicallbackarg;
2101 spierrcontext.previous = error_context_stack;
2102 error_context_stack = &spierrcontext;
2103
2104 /* Get the generic plan for the query */
2105 cplan = GetCachedPlan(plansource, NULL,
2106 plan->saved ? CurrentResourceOwner : NULL,
2108 Assert(cplan == plansource->gplan);
2109
2110 /* Pop the error context stack */
2111 error_context_stack = spierrcontext.previous;
2112
2113 return cplan;
2114}
struct CachedPlan * gplan
Definition: plancache.h:118

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

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

◆ SPI_plan_get_plan_sources()

List * SPI_plan_get_plan_sources ( SPIPlanPtr  plan)

Definition at line 2059 of file spi.c.

2060{
2061 Assert(plan->magic == _SPI_PLAN_MAGIC);
2062 return plan->plancache_list;
2063}

References _SPI_PLAN_MAGIC, Assert(), and plan.

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

◆ SPI_plan_is_valid()

bool SPI_plan_is_valid ( SPIPlanPtr  plan)

Definition at line 1950 of file spi.c.

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

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

Referenced by ri_FetchPreparedPlan().

◆ SPI_prepare()

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

◆ SPI_prepare_cursor()

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

Definition at line 867 of file spi.c.

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

References _SPI_begin_call(), _SPI_end_call(), _SPI_make_plan_non_temp(), _SPI_PLAN_MAGIC, _SPI_prepare_plan(), plan, RAW_PARSE_DEFAULT, SPI_ERROR_ARGUMENT, and SPI_result.

Referenced by SPI_prepare().

◆ SPI_prepare_extended()

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

Definition at line 903 of file spi.c.

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

References _SPI_begin_call(), _SPI_end_call(), _SPI_make_plan_non_temp(), _SPI_PLAN_MAGIC, _SPI_prepare_plan(), plan, SPI_ERROR_ARGUMENT, and SPI_result.

Referenced by exec_prepare_plan().

◆ SPI_prepare_params()

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

Definition at line 939 of file spi.c.

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

References _SPI_begin_call(), _SPI_end_call(), _SPI_make_plan_non_temp(), _SPI_PLAN_MAGIC, _SPI_prepare_plan(), plan, RAW_PARSE_DEFAULT, SPI_ERROR_ARGUMENT, and SPI_result.

◆ spi_printtup()

bool spi_printtup ( TupleTableSlot slot,
DestReceiver self 
)

Definition at line 2173 of file spi.c.

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

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

◆ SPI_register_relation()

int SPI_register_relation ( EphemeralNamedRelation  enr)

Definition at line 3314 of file spi.c.

3315{
3317 int res;
3318
3319 if (enr == NULL || enr->md.name == NULL)
3320 return SPI_ERROR_ARGUMENT;
3321
3322 res = _SPI_begin_call(false); /* keep current memory context */
3323 if (res < 0)
3324 return res;
3325
3326 match = _SPI_find_ENR_by_name(enr->md.name);
3327 if (match)
3329 else
3330 {
3331 if (_SPI_current->queryEnv == NULL)
3333
3335 res = SPI_OK_REL_REGISTER;
3336 }
3337
3338 _SPI_end_call(false);
3339
3340 return res;
3341}
QueryEnvironment * create_queryEnv(void)
void register_ENR(QueryEnvironment *queryEnv, EphemeralNamedRelation enr)
static EphemeralNamedRelation _SPI_find_ENR_by_name(const char *name)
Definition: spi.c:3297
#define SPI_ERROR_REL_DUPLICATE
Definition: spi.h:79
#define SPI_OK_REL_REGISTER
Definition: spi.h:96
EphemeralNamedRelationMetadataData md

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

Referenced by SPI_register_trigger_data().

◆ SPI_register_trigger_data()

int SPI_register_trigger_data ( TriggerData tdata)

Definition at line 3381 of file spi.c.

3382{
3383 if (tdata == NULL)
3384 return SPI_ERROR_ARGUMENT;
3385
3386 if (tdata->tg_newtable)
3387 {
3390 int rc;
3391
3392 enr->md.name = tdata->tg_trigger->tgnewtable;
3393 enr->md.reliddesc = tdata->tg_relation->rd_id;
3394 enr->md.tupdesc = NULL;
3397 enr->reldata = tdata->tg_newtable;
3398 rc = SPI_register_relation(enr);
3399 if (rc != SPI_OK_REL_REGISTER)
3400 return rc;
3401 }
3402
3403 if (tdata->tg_oldtable)
3404 {
3407 int rc;
3408
3409 enr->md.name = tdata->tg_trigger->tgoldtable;
3410 enr->md.reliddesc = tdata->tg_relation->rd_id;
3411 enr->md.tupdesc = NULL;
3414 enr->reldata = tdata->tg_oldtable;
3415 rc = SPI_register_relation(enr);
3416 if (rc != SPI_OK_REL_REGISTER)
3417 return rc;
3418 }
3419
3420 return SPI_OK_TD_REGISTER;
3421}
@ ENR_NAMED_TUPLESTORE
int SPI_register_relation(EphemeralNamedRelation enr)
Definition: spi.c:3314
#define SPI_OK_TD_REGISTER
Definition: spi.h:98
EphemeralNameRelationType enrtype
Oid rd_id
Definition: rel.h:113
Tuplestorestate * tg_oldtable
Definition: trigger.h:41
Relation tg_relation
Definition: trigger.h:35
Tuplestorestate * tg_newtable
Definition: trigger.h:42
Trigger * tg_trigger
Definition: trigger.h:38
char * tgoldtable
Definition: reltrigger.h:43
char * tgnewtable
Definition: reltrigger.h:44
int64 tuplestore_tuple_count(Tuplestorestate *state)
Definition: tuplestore.c:580

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

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

◆ SPI_repalloc()

void * SPI_repalloc ( void *  pointer,
Size  size 
)

Definition at line 1348 of file spi.c.

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

References repalloc().

◆ SPI_result_code_string()

const char * SPI_result_code_string ( int  code)

Definition at line 1974 of file spi.c.

1975{
1976 static char buf[64];
1977
1978 switch (code)
1979 {
1980 case SPI_ERROR_CONNECT:
1981 return "SPI_ERROR_CONNECT";
1982 case SPI_ERROR_COPY:
1983 return "SPI_ERROR_COPY";
1985 return "SPI_ERROR_OPUNKNOWN";
1987 return "SPI_ERROR_UNCONNECTED";
1988 case SPI_ERROR_ARGUMENT:
1989 return "SPI_ERROR_ARGUMENT";
1990 case SPI_ERROR_PARAM:
1991 return "SPI_ERROR_PARAM";
1993 return "SPI_ERROR_TRANSACTION";
1995 return "SPI_ERROR_NOATTRIBUTE";
1997 return "SPI_ERROR_NOOUTFUNC";
1999 return "SPI_ERROR_TYPUNKNOWN";
2001 return "SPI_ERROR_REL_DUPLICATE";
2003 return "SPI_ERROR_REL_NOT_FOUND";
2004 case SPI_OK_CONNECT:
2005 return "SPI_OK_CONNECT";
2006 case SPI_OK_FINISH:
2007 return "SPI_OK_FINISH";
2008 case SPI_OK_FETCH:
2009 return "SPI_OK_FETCH";
2010 case SPI_OK_UTILITY:
2011 return "SPI_OK_UTILITY";
2012 case SPI_OK_SELECT:
2013 return "SPI_OK_SELECT";
2014 case SPI_OK_SELINTO:
2015 return "SPI_OK_SELINTO";
2016 case SPI_OK_INSERT:
2017 return "SPI_OK_INSERT";
2018 case SPI_OK_DELETE:
2019 return "SPI_OK_DELETE";
2020 case SPI_OK_UPDATE:
2021 return "SPI_OK_UPDATE";
2022 case SPI_OK_CURSOR:
2023 return "SPI_OK_CURSOR";
2025 return "SPI_OK_INSERT_RETURNING";
2027 return "SPI_OK_DELETE_RETURNING";
2029 return "SPI_OK_UPDATE_RETURNING";
2030 case SPI_OK_REWRITTEN:
2031 return "SPI_OK_REWRITTEN";
2033 return "SPI_OK_REL_REGISTER";
2035 return "SPI_OK_REL_UNREGISTER";
2036 case SPI_OK_TD_REGISTER:
2037 return "SPI_OK_TD_REGISTER";
2038 case SPI_OK_MERGE:
2039 return "SPI_OK_MERGE";
2041 return "SPI_OK_MERGE_RETURNING";
2042 }
2043 /* Unrecognized code ... return something useful ... */
2044 sprintf(buf, "Unrecognized SPI code %d", code);
2045 return buf;
2046}
static char * buf
Definition: pg_test_fsync.c:72
#define sprintf
Definition: port.h:241
#define SPI_ERROR_REL_NOT_FOUND
Definition: spi.h:80
#define SPI_OK_CURSOR
Definition: spi.h:91
#define SPI_OK_FETCH
Definition: spi.h:84
#define SPI_OK_REL_UNREGISTER
Definition: spi.h:97
#define SPI_ERROR_NOOUTFUNC
Definition: spi.h:77
#define SPI_ERROR_CONNECT
Definition: spi.h:68

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

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

◆ SPI_returntuple()

HeapTupleHeader SPI_returntuple ( HeapTuple  tuple,
TupleDesc  tupdesc 
)

Definition at line 1075 of file spi.c.

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

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

Referenced by coerce_function_result_tuple().

◆ SPI_rollback()

void SPI_rollback ( void  )

Definition at line 414 of file spi.c.

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

References _SPI_rollback().

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

◆ SPI_rollback_and_chain()

void SPI_rollback_and_chain ( void  )

Definition at line 420 of file spi.c.

421{
422 _SPI_rollback(true);
423}

References _SPI_rollback().

Referenced by exec_stmt_rollback().

◆ SPI_saveplan()

SPIPlanPtr SPI_saveplan ( SPIPlanPtr  plan)

Definition at line 1004 of file spi.c.

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

References _SPI_begin_call(), _SPI_end_call(), _SPI_PLAN_MAGIC, _SPI_save_plan(), plan, SPI_ERROR_ARGUMENT, and SPI_result.

◆ SPI_scroll_cursor_fetch()

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

Definition at line 1837 of file spi.c.

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

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

Referenced by exec_stmt_fetch().

◆ SPI_scroll_cursor_move()

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

Definition at line 1852 of file spi.c.

1853{
1854 _SPI_cursor_operation(portal, direction, count, None_Receiver);
1855}

References _SPI_cursor_operation(), and None_Receiver.

Referenced by exec_stmt_fetch().

◆ SPI_start_transaction()

void SPI_start_transaction ( void  )

Definition at line 223 of file spi.c.

224{
225}

◆ SPI_unregister_relation()

int SPI_unregister_relation ( const char *  name)

Definition at line 3348 of file spi.c.

3349{
3351 int res;
3352
3353 if (name == NULL)
3354 return SPI_ERROR_ARGUMENT;
3355
3356 res = _SPI_begin_call(false); /* keep current memory context */
3357 if (res < 0)
3358 return res;
3359
3360 match = _SPI_find_ENR_by_name(name);
3361 if (match)
3362 {
3365 }
3366 else
3368
3369 _SPI_end_call(false);
3370
3371 return res;
3372}
void unregister_ENR(QueryEnvironment *queryEnv, const char *name)

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

Variable Documentation

◆ _SPI_connected

int _SPI_connected = -1
static

Definition at line 51 of file spi.c.

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

◆ _SPI_current

◆ _SPI_stack

_SPI_connection* _SPI_stack = NULL
static

Definition at line 48 of file spi.c.

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

◆ _SPI_stack_depth

int _SPI_stack_depth = 0
static

Definition at line 50 of file spi.c.

Referenced by SPI_connect_ext().

◆ SPI_processed

◆ SPI_result

◆ SPI_tuptable