#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"
Go to the source code of this file.
Functions | |
static Portal | SPI_cursor_open_internal (const char *name, SPIPlanPtr plan, ParamListInfo paramLI, bool read_only) |
static void | _SPI_prepare_plan (const char *src, SPIPlanPtr plan) |
static void | _SPI_prepare_oneshot_plan (const char *src, SPIPlanPtr plan) |
static int | _SPI_execute_plan (SPIPlanPtr plan, ParamListInfo paramLI, Snapshot snapshot, Snapshot crosscheck_snapshot, bool read_only, bool fire_triggers, long tcount) |
static ParamListInfo | _SPI_convert_params (int nargs, Oid *argtypes, Datum *Values, const char *Nulls) |
static int | _SPI_pquery (QueryDesc *queryDesc, bool fire_triggers, long tcount) |
static void | _SPI_error_callback (void *arg) |
static void | _SPI_cursor_operation (Portal portal, FetchDirection direction, long count, DestReceiver *dest) |
static SPIPlanPtr | _SPI_make_plan_non_temp (SPIPlanPtr plan) |
static SPIPlanPtr | _SPI_save_plan (SPIPlanPtr plan) |
static int | _SPI_begin_call (bool execmem) |
static int | _SPI_end_call (bool procmem) |
static MemoryContext | _SPI_execmem (void) |
static MemoryContext | _SPI_procmem (void) |
static bool | _SPI_checktuples (void) |
int | SPI_connect (void) |
int | SPI_finish (void) |
void | AtEOXact_SPI (bool isCommit) |
void | AtEOSubXact_SPI (bool isCommit, SubTransactionId mySubid) |
void | SPI_push (void) |
void | SPI_pop (void) |
bool | SPI_push_conditional (void) |
void | SPI_pop_conditional (bool pushed) |
void | SPI_restore_connection (void) |
int | SPI_execute (const char *src, bool read_only, long tcount) |
int | SPI_exec (const char *src, long tcount) |
int | SPI_execute_plan (SPIPlanPtr plan, Datum *Values, const char *Nulls, bool read_only, long tcount) |
int | SPI_execp (SPIPlanPtr plan, Datum *Values, const char *Nulls, long tcount) |
int | SPI_execute_plan_with_paramlist (SPIPlanPtr plan, ParamListInfo params, bool read_only, long tcount) |
int | SPI_execute_snapshot (SPIPlanPtr plan, Datum *Values, const char *Nulls, Snapshot snapshot, Snapshot crosscheck_snapshot, bool read_only, bool fire_triggers, long tcount) |
int | SPI_execute_with_args (const char *src, int nargs, Oid *argtypes, Datum *Values, const char *Nulls, bool read_only, long tcount) |
SPIPlanPtr | SPI_prepare (const char *src, int nargs, Oid *argtypes) |
SPIPlanPtr | SPI_prepare_cursor (const char *src, int nargs, Oid *argtypes, int cursorOptions) |
SPIPlanPtr | SPI_prepare_params (const char *src, ParserSetupHook parserSetup, void *parserSetupArg, int cursorOptions) |
int | SPI_keepplan (SPIPlanPtr plan) |
SPIPlanPtr | SPI_saveplan (SPIPlanPtr plan) |
int | SPI_freeplan (SPIPlanPtr plan) |
HeapTuple | SPI_copytuple (HeapTuple tuple) |
HeapTupleHeader | SPI_returntuple (HeapTuple tuple, TupleDesc tupdesc) |
HeapTuple | SPI_modifytuple (Relation rel, HeapTuple tuple, int natts, int *attnum, Datum *Values, const char *Nulls) |
int | SPI_fnumber (TupleDesc tupdesc, const char *fname) |
char * | SPI_fname (TupleDesc tupdesc, int fnumber) |
char * | SPI_getvalue (HeapTuple tuple, TupleDesc tupdesc, int fnumber) |
Datum | SPI_getbinval (HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool *isnull) |
char * | SPI_gettype (TupleDesc tupdesc, int fnumber) |
Oid | SPI_gettypeid (TupleDesc tupdesc, int fnumber) |
char * | SPI_getrelname (Relation rel) |
char * | SPI_getnspname (Relation rel) |
void * | SPI_palloc (Size size) |
void * | SPI_repalloc (void *pointer, Size size) |
void | SPI_pfree (void *pointer) |
void | SPI_freetuple (HeapTuple tuple) |
void | SPI_freetuptable (SPITupleTable *tuptable) |
Portal | SPI_cursor_open (const char *name, SPIPlanPtr plan, Datum *Values, const char *Nulls, bool read_only) |
Portal | SPI_cursor_open_with_args (const char *name, const char *src, int nargs, Oid *argtypes, Datum *Values, const char *Nulls, bool read_only, int cursorOptions) |
Portal | SPI_cursor_open_with_paramlist (const char *name, SPIPlanPtr plan, ParamListInfo params, bool read_only) |
Portal | SPI_cursor_find (const char *name) |
void | SPI_cursor_fetch (Portal portal, bool forward, long count) |
void | SPI_cursor_move (Portal portal, bool forward, long count) |
void | SPI_scroll_cursor_fetch (Portal portal, FetchDirection direction, long count) |
void | SPI_scroll_cursor_move (Portal portal, FetchDirection direction, long count) |
void | SPI_cursor_close (Portal portal) |
Oid | SPI_getargtypeid (SPIPlanPtr plan, int argIndex) |
int | SPI_getargcount (SPIPlanPtr plan) |
bool | SPI_is_cursor_plan (SPIPlanPtr plan) |
bool | SPI_plan_is_valid (SPIPlanPtr plan) |
const char * | SPI_result_code_string (int code) |
List * | SPI_plan_get_plan_sources (SPIPlanPtr plan) |
CachedPlan * | SPI_plan_get_cached_plan (SPIPlanPtr plan) |
void | spi_dest_startup (DestReceiver *self, int operation, TupleDesc typeinfo) |
void | spi_printtup (TupleTableSlot *slot, DestReceiver *self) |
Variables | |
uint32 | SPI_processed = 0 |
Oid | SPI_lastoid = InvalidOid |
SPITupleTable * | SPI_tuptable = NULL |
int | SPI_result |
static _SPI_connection * | _SPI_stack = NULL |
static _SPI_connection * | _SPI_current = NULL |
static int | _SPI_stack_depth = 0 |
static int | _SPI_connected = -1 |
static int | _SPI_curid = -1 |
static int _SPI_begin_call | ( | bool | execmem | ) | [static] |
Definition at line 2420 of file spi.c.
References _SPI_connected, _SPI_curid, _SPI_execmem(), elog, and ERROR.
Referenced by _SPI_cursor_operation(), SPI_cursor_open_internal(), SPI_cursor_open_with_args(), SPI_execute(), SPI_execute_plan(), SPI_execute_plan_with_paramlist(), SPI_execute_snapshot(), SPI_execute_with_args(), SPI_finish(), SPI_prepare_cursor(), SPI_prepare_params(), and SPI_saveplan().
{ if (_SPI_curid + 1 != _SPI_connected) return SPI_ERROR_UNCONNECTED; _SPI_curid++; if (_SPI_current != &(_SPI_stack[_SPI_curid])) elog(ERROR, "SPI stack corrupted"); if (execmem) /* switch to the Executor memory context */ _SPI_execmem(); return 0; }
static bool _SPI_checktuples | ( | void | ) | [static] |
Definition at line 2458 of file spi.c.
References SPITupleTable::alloced, SPITupleTable::free, NULL, _SPI_connection::processed, and _SPI_connection::tuptable.
Referenced by _SPI_cursor_operation(), and _SPI_pquery().
{ uint32 processed = _SPI_current->processed; SPITupleTable *tuptable = _SPI_current->tuptable; bool failed = false; if (tuptable == NULL) /* spi_dest_startup was not called */ failed = true; else if (processed != (tuptable->alloced - tuptable->free)) failed = true; return failed; }
static ParamListInfo _SPI_convert_params | ( | int | nargs, | |
Oid * | argtypes, | |||
Datum * | Values, | |||
const char * | Nulls | |||
) | [static] |
Definition at line 2210 of file spi.c.
References i, ParamExternData::isnull, ParamListInfoData::numParams, palloc(), ParamListInfoData::paramFetch, ParamListInfoData::paramFetchArg, ParamListInfoData::params, ParamListInfoData::parserSetup, ParamListInfoData::parserSetupArg, 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().
{ ParamListInfo paramLI; if (nargs > 0) { int i; /* sizeof(ParamListInfoData) includes the first array element */ paramLI = (ParamListInfo) palloc(sizeof(ParamListInfoData) + (nargs - 1) * sizeof(ParamExternData)); /* we have static list of params, so no hooks needed */ paramLI->paramFetch = NULL; paramLI->paramFetchArg = NULL; paramLI->parserSetup = NULL; paramLI->parserSetupArg = NULL; paramLI->numParams = nargs; for (i = 0; i < nargs; i++) { ParamExternData *prm = ¶mLI->params[i]; prm->value = Values[i]; prm->isnull = (Nulls && Nulls[i] == 'n'); prm->pflags = PARAM_FLAG_CONST; prm->ptype = argtypes[i]; } } else paramLI = NULL; return paramLI; }
static void _SPI_cursor_operation | ( | Portal | portal, | |
FetchDirection | direction, | |||
long | count, | |||
DestReceiver * | dest | |||
) | [static] |
Definition at line 2354 of file spi.c.
References _SPI_begin_call(), _SPI_checktuples(), _SPI_end_call(), DestSPI, elog, ERROR, _DestReceiver::mydest, PortalIsValid, PortalRunFetch(), _SPI_connection::processed, SPI_processed, and _SPI_connection::tuptable.
Referenced by SPI_cursor_fetch(), SPI_cursor_move(), SPI_scroll_cursor_fetch(), and SPI_scroll_cursor_move().
{ long nfetched; /* Check that the portal is valid */ if (!PortalIsValid(portal)) elog(ERROR, "invalid portal in SPI cursor operation"); /* Push the SPI stack */ if (_SPI_begin_call(true) < 0) elog(ERROR, "SPI cursor operation called while not connected"); /* Reset the SPI result (note we deliberately don't touch lastoid) */ SPI_processed = 0; SPI_tuptable = NULL; _SPI_current->processed = 0; _SPI_current->tuptable = NULL; /* Run the cursor */ nfetched = PortalRunFetch(portal, direction, count, dest); /* * Think not to combine this store with the preceding function call. If * the portal contains calls to functions that use SPI, then SPI_stack is * likely to move around while the portal runs. When control returns, * _SPI_current will point to the correct stack entry... but the pointer * may be different than it was beforehand. So we must be sure to re-fetch * the pointer after the function call completes. */ _SPI_current->processed = nfetched; if (dest->mydest == DestSPI && _SPI_checktuples()) elog(ERROR, "consistency check on SPI tuple count failed"); /* Put the result into place for access by caller */ SPI_processed = _SPI_current->processed; SPI_tuptable = _SPI_current->tuptable; /* tuptable now is caller's responsibility, not SPI's */ _SPI_current->tuptable = NULL; /* Pop the SPI stack */ _SPI_end_call(true); }
static int _SPI_end_call | ( | bool | procmem | ) | [static] |
Definition at line 2440 of file spi.c.
References _SPI_curid, _SPI_procmem(), _SPI_connection::execCxt, and MemoryContextResetAndDeleteChildren().
Referenced by _SPI_cursor_operation(), SPI_cursor_open_internal(), SPI_cursor_open_with_args(), SPI_execute(), SPI_execute_plan(), SPI_execute_plan_with_paramlist(), SPI_execute_snapshot(), SPI_execute_with_args(), SPI_prepare_cursor(), SPI_prepare_params(), and SPI_saveplan().
{ /* * We're returning to procedure where _SPI_curid == _SPI_connected - 1 */ _SPI_curid--; if (procmem) /* switch to the procedure memory context */ { _SPI_procmem(); /* and free Executor memory */ MemoryContextResetAndDeleteChildren(_SPI_current->execCxt); } return 0; }
static void _SPI_error_callback | ( | void * | arg | ) | [static] |
Definition at line 2328 of file spi.c.
References errcontext, errposition(), geterrposition(), internalerrposition(), and internalerrquery().
{ const char *query = (const char *) arg; int syntaxerrposition; /* * If there is a syntax error position, convert to internal syntax error; * otherwise treat the query as an item of context stack */ syntaxerrposition = geterrposition(); if (syntaxerrposition > 0) { errposition(0); internalerrposition(syntaxerrposition); internalerrquery(query); } else errcontext("SQL statement \"%s\"", query); }
static MemoryContext _SPI_execmem | ( | void | ) | [static] |
Definition at line 2405 of file spi.c.
References _SPI_connection::execCxt, and MemoryContextSwitchTo().
Referenced by _SPI_begin_call().
{ return MemoryContextSwitchTo(_SPI_current->execCxt); }
static int _SPI_execute_plan | ( | SPIPlanPtr | plan, | |
ParamListInfo | paramLI, | |||
Snapshot | snapshot, | |||
Snapshot | crosscheck_snapshot, | |||
bool | read_only, | |||
bool | fire_triggers, | |||
long | tcount | |||
) | [static] |
Definition at line 1891 of file spi.c.
References _SPI_pquery(), ActiveSnapshotSet(), SPITupleTable::alloced, ErrorContextCallback::arg, _SPI_plan::argtypes, Assert, ErrorContextCallback::callback, CommandCounterIncrement(), CommandIsReadOnly(), CompleteCachedPlan(), CreateCommandTag(), CreateDestReceiver(), CreateQueryDesc(), _SPI_plan::cursor_options, DestNone, DestSPI, ereport, errcode(), errmsg(), ERROR, error_context_stack, CopyStmt::filename, SPITupleTable::free, FreeQueryDesc(), GetActiveSnapshot(), GetCachedPlan(), GetTransactionSnapshot(), InvalidSnapshot, IsA, _SPI_connection::lastoid, lfirst, list_length(), _SPI_plan::nargs, NULL, _SPI_plan::oneshot, _SPI_plan::parserSetup, _SPI_plan::parserSetupArg, pg_analyze_and_rewrite(), pg_analyze_and_rewrite_params(), _SPI_plan::plancache_list, PopActiveSnapshot(), ErrorContextCallback::previous, PROCESS_UTILITY_QUERY, _SPI_connection::processed, ProcessUtility(), PushActiveSnapshot(), PushCopiedSnapshot(), CachedPlanSource::query_string, CachedPlanSource::raw_parse_tree, ReleaseCachedPlan(), _SPI_plan::saved, SPI_freetuptable(), SPI_lastoid, SPI_processed, CachedPlan::stmt_list, _SPI_connection::tuptable, and UpdateActiveSnapshotCommandId().
Referenced by SPI_execute(), SPI_execute_plan(), SPI_execute_plan_with_paramlist(), SPI_execute_snapshot(), and SPI_execute_with_args().
{ int my_res = 0; uint32 my_processed = 0; Oid my_lastoid = InvalidOid; SPITupleTable *my_tuptable = NULL; int res = 0; bool pushed_active_snap = false; ErrorContextCallback spierrcontext; CachedPlan *cplan = NULL; ListCell *lc1; /* * Setup error traceback support for ereport() */ spierrcontext.callback = _SPI_error_callback; spierrcontext.arg = NULL; /* we'll fill this below */ spierrcontext.previous = error_context_stack; error_context_stack = &spierrcontext; /* * We support four distinct snapshot management behaviors: * * snapshot != InvalidSnapshot, read_only = true: use exactly the given * snapshot. * * snapshot != InvalidSnapshot, read_only = false: use the given snapshot, * modified by advancing its command ID before each querytree. * * snapshot == InvalidSnapshot, read_only = true: use the entry-time * ActiveSnapshot, if any (if there isn't one, we run with no snapshot). * * snapshot == InvalidSnapshot, read_only = false: take a full new * snapshot for each user command, and advance its command ID before each * querytree within the command. * * In the first two cases, we can just push the snap onto the stack once * for the whole plan list. */ if (snapshot != InvalidSnapshot) { if (read_only) { PushActiveSnapshot(snapshot); pushed_active_snap = true; } else { /* Make sure we have a private copy of the snapshot to modify */ PushCopiedSnapshot(snapshot); pushed_active_snap = true; } } foreach(lc1, plan->plancache_list) { CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc1); List *stmt_list; ListCell *lc2; spierrcontext.arg = (void *) plansource->query_string; /* * If this is a one-shot plan, we still need to do parse analysis. */ if (plan->oneshot) { Node *parsetree = plansource->raw_parse_tree; const char *src = plansource->query_string; List *stmt_list; /* * Parameter datatypes are driven by parserSetup hook if provided, * otherwise we use the fixed parameter list. */ if (plan->parserSetup != NULL) { Assert(plan->nargs == 0); stmt_list = pg_analyze_and_rewrite_params(parsetree, src, plan->parserSetup, plan->parserSetupArg); } else { stmt_list = pg_analyze_and_rewrite(parsetree, src, plan->argtypes, plan->nargs); } /* Finish filling in the CachedPlanSource */ CompleteCachedPlan(plansource, stmt_list, NULL, plan->argtypes, plan->nargs, plan->parserSetup, plan->parserSetupArg, plan->cursor_options, false); /* not fixed result */ } /* * Replan if needed, and increment plan refcount. If it's a saved * plan, the refcount must be backed by the CurrentResourceOwner. */ cplan = GetCachedPlan(plansource, paramLI, plan->saved); stmt_list = cplan->stmt_list; /* * In the default non-read-only case, get a new snapshot, replacing * any that we pushed in a previous cycle. */ if (snapshot == InvalidSnapshot && !read_only) { if (pushed_active_snap) PopActiveSnapshot(); PushActiveSnapshot(GetTransactionSnapshot()); pushed_active_snap = true; } foreach(lc2, stmt_list) { Node *stmt = (Node *) lfirst(lc2); bool canSetTag; DestReceiver *dest; _SPI_current->processed = 0; _SPI_current->lastoid = InvalidOid; _SPI_current->tuptable = NULL; if (IsA(stmt, PlannedStmt)) { canSetTag = ((PlannedStmt *) stmt)->canSetTag; } else { /* utilities are canSetTag if only thing in list */ canSetTag = (list_length(stmt_list) == 1); if (IsA(stmt, CopyStmt)) { CopyStmt *cstmt = (CopyStmt *) stmt; if (cstmt->filename == NULL) { my_res = SPI_ERROR_COPY; goto fail; } } else if (IsA(stmt, TransactionStmt)) { my_res = SPI_ERROR_TRANSACTION; goto fail; } } if (read_only && !CommandIsReadOnly(stmt)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), /* translator: %s is a SQL statement name */ errmsg("%s is not allowed in a non-volatile function", CreateCommandTag(stmt)))); /* * If not read-only mode, advance the command counter before each * command and update the snapshot. */ if (!read_only) { CommandCounterIncrement(); UpdateActiveSnapshotCommandId(); } dest = CreateDestReceiver(canSetTag ? DestSPI : DestNone); if (IsA(stmt, PlannedStmt) && ((PlannedStmt *) stmt)->utilityStmt == NULL) { QueryDesc *qdesc; Snapshot snap; if (ActiveSnapshotSet()) snap = GetActiveSnapshot(); else snap = InvalidSnapshot; qdesc = CreateQueryDesc((PlannedStmt *) stmt, plansource->query_string, snap, crosscheck_snapshot, dest, paramLI, 0); res = _SPI_pquery(qdesc, fire_triggers, canSetTag ? tcount : 0); FreeQueryDesc(qdesc); } else { char completionTag[COMPLETION_TAG_BUFSIZE]; ProcessUtility(stmt, plansource->query_string, PROCESS_UTILITY_QUERY, paramLI, dest, completionTag); /* Update "processed" if stmt returned tuples */ if (_SPI_current->tuptable) _SPI_current->processed = _SPI_current->tuptable->alloced - _SPI_current->tuptable->free; res = SPI_OK_UTILITY; /* * Some utility statements return a row count, even though the * tuples are not returned to the caller. */ if (IsA(stmt, CreateTableAsStmt)) { Assert(strncmp(completionTag, "SELECT ", 7) == 0); _SPI_current->processed = strtoul(completionTag + 7, NULL, 10); /* * For historical reasons, if CREATE TABLE AS was spelled * as SELECT INTO, return a special return code. */ if (((CreateTableAsStmt *) stmt)->is_select_into) res = SPI_OK_SELINTO; } else if (IsA(stmt, CopyStmt)) { Assert(strncmp(completionTag, "COPY ", 5) == 0); _SPI_current->processed = strtoul(completionTag + 5, NULL, 10); } } /* * The last canSetTag query sets the status values returned to the * caller. Be careful to free any tuptables not returned, to * avoid intratransaction memory leak. */ if (canSetTag) { my_processed = _SPI_current->processed; my_lastoid = _SPI_current->lastoid; SPI_freetuptable(my_tuptable); my_tuptable = _SPI_current->tuptable; my_res = res; } else { SPI_freetuptable(_SPI_current->tuptable); _SPI_current->tuptable = NULL; } /* we know that the receiver doesn't need a destroy call */ if (res < 0) { my_res = res; goto fail; } } /* Done with this plan, so release refcount */ ReleaseCachedPlan(cplan, plan->saved); cplan = NULL; /* * If not read-only mode, advance the command counter after the last * command. This ensures that its effects are visible, in case it was * DDL that would affect the next CachedPlanSource. */ if (!read_only) CommandCounterIncrement(); } fail: /* Pop the snapshot off the stack if we pushed one */ if (pushed_active_snap) PopActiveSnapshot(); /* We no longer need the cached plan refcount, if any */ if (cplan) ReleaseCachedPlan(cplan, plan->saved); /* * Pop the error context stack */ error_context_stack = spierrcontext.previous; /* Save results for caller */ SPI_processed = my_processed; SPI_lastoid = my_lastoid; SPI_tuptable = my_tuptable; /* tuptable now is caller's responsibility, not SPI's */ _SPI_current->tuptable = NULL; /* * If none of the queries had canSetTag, return SPI_OK_REWRITTEN. Prior to * 8.4, we used return the last query's result code, but not its auxiliary * results, but that's confusing. */ if (my_res == 0) my_res = SPI_OK_REWRITTEN; return my_res; }
static SPIPlanPtr _SPI_make_plan_non_temp | ( | SPIPlanPtr | plan | ) | [static] |
Definition at line 2482 of file spi.c.
References _SPI_PLAN_MAGIC, ALLOCSET_SMALL_INITSIZE, ALLOCSET_SMALL_MAXSIZE, ALLOCSET_SMALL_MINSIZE, AllocSetContextCreate(), _SPI_plan::argtypes, Assert, CachedPlanSetParentContext(), _SPI_plan::cursor_options, lappend(), lfirst, _SPI_plan::magic, MemoryContextSwitchTo(), _SPI_plan::nargs, NULL, _SPI_plan::oneshot, palloc(), _SPI_plan::parserSetup, _SPI_plan::parserSetupArg, _SPI_plan::plancache_list, _SPI_plan::plancxt, _SPI_connection::procCxt, and _SPI_plan::saved.
Referenced by SPI_prepare_cursor(), and SPI_prepare_params().
{ SPIPlanPtr newplan; MemoryContext parentcxt = _SPI_current->procCxt; MemoryContext plancxt; MemoryContext oldcxt; ListCell *lc; /* Assert the input is a temporary SPIPlan */ Assert(plan->magic == _SPI_PLAN_MAGIC); Assert(plan->plancxt == NULL); /* One-shot plans can't be saved */ Assert(!plan->oneshot); /* * Create a memory context for the plan, underneath the procedure context. * We don't expect the plan to be very large, so use smaller-than-default * alloc parameters. */ plancxt = AllocSetContextCreate(parentcxt, "SPI Plan", ALLOCSET_SMALL_MINSIZE, ALLOCSET_SMALL_INITSIZE, ALLOCSET_SMALL_MAXSIZE); oldcxt = MemoryContextSwitchTo(plancxt); /* Copy the SPI_plan struct and subsidiary data into the new context */ newplan = (SPIPlanPtr) palloc(sizeof(_SPI_plan)); newplan->magic = _SPI_PLAN_MAGIC; newplan->saved = false; newplan->oneshot = false; newplan->plancache_list = NIL; newplan->plancxt = plancxt; newplan->cursor_options = plan->cursor_options; newplan->nargs = plan->nargs; if (plan->nargs > 0) { newplan->argtypes = (Oid *) palloc(plan->nargs * sizeof(Oid)); memcpy(newplan->argtypes, plan->argtypes, plan->nargs * sizeof(Oid)); } else newplan->argtypes = NULL; newplan->parserSetup = plan->parserSetup; newplan->parserSetupArg = plan->parserSetupArg; /* * Reparent all the CachedPlanSources into the procedure context. In * theory this could fail partway through due to the pallocs, but we don't * care too much since both the procedure context and the executor context * would go away on error. */ foreach(lc, plan->plancache_list) { CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc); CachedPlanSetParentContext(plansource, parentcxt); /* Build new list, with list cells in plancxt */ newplan->plancache_list = lappend(newplan->plancache_list, plansource); } MemoryContextSwitchTo(oldcxt); /* For safety, unlink the CachedPlanSources from the temporary plan */ plan->plancache_list = NIL; return newplan; }
Definition at line 2245 of file spi.c.
References _SPI_checktuples(), Assert, CMD_DELETE, CMD_INSERT, CMD_SELECT, CMD_UPDATE, QueryDesc::dest, DestSPI, elog, ERROR, EState::es_lastoid, EState::es_processed, QueryDesc::estate, ExecutorEnd(), ExecutorFinish(), ExecutorRun(), ExecutorStart(), ForwardScanDirection, PlannedStmt::hasReturning, _SPI_connection::lastoid, _DestReceiver::mydest, NULL, QueryDesc::operation, QueryDesc::plannedstmt, _SPI_connection::processed, ResetUsage(), ShowUsage(), SPI_OK_SELECT, and PlannedStmt::utilityStmt.
Referenced by _SPI_execute_plan().
{ int operation = queryDesc->operation; int eflags; int res; switch (operation) { case CMD_SELECT: Assert(queryDesc->plannedstmt->utilityStmt == NULL); if (queryDesc->dest->mydest != DestSPI) { /* Don't return SPI_OK_SELECT if we're discarding result */ res = SPI_OK_UTILITY; } else res = SPI_OK_SELECT; break; case CMD_INSERT: if (queryDesc->plannedstmt->hasReturning) res = SPI_OK_INSERT_RETURNING; else res = SPI_OK_INSERT; break; case CMD_DELETE: if (queryDesc->plannedstmt->hasReturning) res = SPI_OK_DELETE_RETURNING; else res = SPI_OK_DELETE; break; case CMD_UPDATE: if (queryDesc->plannedstmt->hasReturning) res = SPI_OK_UPDATE_RETURNING; else res = SPI_OK_UPDATE; break; default: return SPI_ERROR_OPUNKNOWN; } #ifdef SPI_EXECUTOR_STATS if (ShowExecutorStats) ResetUsage(); #endif /* Select execution options */ if (fire_triggers) eflags = 0; /* default run-to-completion flags */ else eflags = EXEC_FLAG_SKIP_TRIGGERS; ExecutorStart(queryDesc, eflags); ExecutorRun(queryDesc, ForwardScanDirection, tcount); _SPI_current->processed = queryDesc->estate->es_processed; _SPI_current->lastoid = queryDesc->estate->es_lastoid; if ((res == SPI_OK_SELECT || queryDesc->plannedstmt->hasReturning) && queryDesc->dest->mydest == DestSPI) { if (_SPI_checktuples()) elog(ERROR, "consistency check on SPI tuple count failed"); } ExecutorFinish(queryDesc); ExecutorEnd(queryDesc); /* FreeQueryDesc is done by the caller */ #ifdef SPI_EXECUTOR_STATS if (ShowExecutorStats) ShowUsage("SPI EXECUTOR STATS"); #endif return res; }
static void _SPI_prepare_oneshot_plan | ( | const char * | src, | |
SPIPlanPtr | plan | |||
) | [static] |
Definition at line 1833 of file spi.c.
References ErrorContextCallback::arg, ErrorContextCallback::callback, CreateCommandTag(), CreateOneShotCachedPlan(), error_context_stack, lappend(), lfirst, _SPI_plan::oneshot, pg_parse_query(), _SPI_plan::plancache_list, and ErrorContextCallback::previous.
Referenced by SPI_execute(), and SPI_execute_with_args().
{ List *raw_parsetree_list; List *plancache_list; ListCell *list_item; ErrorContextCallback spierrcontext; /* * Setup error traceback support for ereport() */ spierrcontext.callback = _SPI_error_callback; spierrcontext.arg = (void *) src; spierrcontext.previous = error_context_stack; error_context_stack = &spierrcontext; /* * Parse the request string into a list of raw parse trees. */ raw_parsetree_list = pg_parse_query(src); /* * Construct plancache entries, but don't do parse analysis yet. */ plancache_list = NIL; foreach(list_item, raw_parsetree_list) { Node *parsetree = (Node *) lfirst(list_item); CachedPlanSource *plansource; plansource = CreateOneShotCachedPlan(parsetree, src, CreateCommandTag(parsetree)); plancache_list = lappend(plancache_list, plansource); } plan->plancache_list = plancache_list; plan->oneshot = true; /* * Pop the error context stack */ error_context_stack = spierrcontext.previous; }
static void _SPI_prepare_plan | ( | const char * | src, | |
SPIPlanPtr | plan | |||
) | [static] |
Definition at line 1730 of file spi.c.
References ErrorContextCallback::arg, _SPI_plan::argtypes, Assert, ErrorContextCallback::callback, CompleteCachedPlan(), CreateCachedPlan(), CreateCommandTag(), _SPI_plan::cursor_options, error_context_stack, lappend(), lfirst, _SPI_plan::nargs, NULL, _SPI_plan::oneshot, _SPI_plan::parserSetup, _SPI_plan::parserSetupArg, pg_analyze_and_rewrite(), pg_analyze_and_rewrite_params(), pg_parse_query(), _SPI_plan::plancache_list, and ErrorContextCallback::previous.
Referenced by SPI_cursor_open_with_args(), SPI_prepare_cursor(), and SPI_prepare_params().
{ List *raw_parsetree_list; List *plancache_list; ListCell *list_item; ErrorContextCallback spierrcontext; /* * Setup error traceback support for ereport() */ spierrcontext.callback = _SPI_error_callback; spierrcontext.arg = (void *) src; spierrcontext.previous = error_context_stack; error_context_stack = &spierrcontext; /* * Parse the request string into a list of raw parse trees. */ raw_parsetree_list = pg_parse_query(src); /* * Do parse analysis and rule rewrite for each raw parsetree, storing the * results into unsaved plancache entries. */ plancache_list = NIL; foreach(list_item, raw_parsetree_list) { Node *parsetree = (Node *) lfirst(list_item); List *stmt_list; CachedPlanSource *plansource; /* * Create the CachedPlanSource before we do parse analysis, since it * needs to see the unmodified raw parse tree. */ plansource = CreateCachedPlan(parsetree, src, CreateCommandTag(parsetree)); /* * Parameter datatypes are driven by parserSetup hook if provided, * otherwise we use the fixed parameter list. */ if (plan->parserSetup != NULL) { Assert(plan->nargs == 0); stmt_list = pg_analyze_and_rewrite_params(parsetree, src, plan->parserSetup, plan->parserSetupArg); } else { stmt_list = pg_analyze_and_rewrite(parsetree, src, plan->argtypes, plan->nargs); } /* Finish filling in the CachedPlanSource */ CompleteCachedPlan(plansource, stmt_list, NULL, plan->argtypes, plan->nargs, plan->parserSetup, plan->parserSetupArg, plan->cursor_options, false); /* not fixed result */ plancache_list = lappend(plancache_list, plansource); } plan->plancache_list = plancache_list; plan->oneshot = false; /* * Pop the error context stack */ error_context_stack = spierrcontext.previous; }
static MemoryContext _SPI_procmem | ( | void | ) | [static] |
Definition at line 2411 of file spi.c.
References MemoryContextSwitchTo(), and _SPI_connection::procCxt.
Referenced by _SPI_end_call(), and spi_dest_startup().
{ return MemoryContextSwitchTo(_SPI_current->procCxt); }
static SPIPlanPtr _SPI_save_plan | ( | SPIPlanPtr | plan | ) | [static] |
Definition at line 2555 of file spi.c.
References ALLOCSET_SMALL_INITSIZE, ALLOCSET_SMALL_MAXSIZE, ALLOCSET_SMALL_MINSIZE, AllocSetContextCreate(), _SPI_plan::argtypes, Assert, CacheMemoryContext, CopyCachedPlan(), CurrentMemoryContext, _SPI_plan::cursor_options, lappend(), lfirst, _SPI_plan::magic, MemoryContextSetParent(), MemoryContextSwitchTo(), _SPI_plan::nargs, _SPI_plan::oneshot, palloc(), _SPI_plan::parserSetup, _SPI_plan::parserSetupArg, _SPI_plan::plancache_list, _SPI_plan::plancxt, SaveCachedPlan(), and _SPI_plan::saved.
Referenced by SPI_saveplan().
{ SPIPlanPtr newplan; MemoryContext plancxt; MemoryContext oldcxt; ListCell *lc; /* One-shot plans can't be saved */ Assert(!plan->oneshot); /* * Create a memory context for the plan. We don't expect the plan to be * very large, so use smaller-than-default alloc parameters. It's a * transient context until we finish copying everything. */ plancxt = AllocSetContextCreate(CurrentMemoryContext, "SPI Plan", ALLOCSET_SMALL_MINSIZE, ALLOCSET_SMALL_INITSIZE, ALLOCSET_SMALL_MAXSIZE); oldcxt = MemoryContextSwitchTo(plancxt); /* Copy the SPI plan into its own context */ newplan = (SPIPlanPtr) palloc(sizeof(_SPI_plan)); newplan->magic = _SPI_PLAN_MAGIC; newplan->saved = false; newplan->oneshot = false; newplan->plancache_list = NIL; newplan->plancxt = plancxt; newplan->cursor_options = plan->cursor_options; newplan->nargs = plan->nargs; if (plan->nargs > 0) { newplan->argtypes = (Oid *) palloc(plan->nargs * sizeof(Oid)); memcpy(newplan->argtypes, plan->argtypes, plan->nargs * sizeof(Oid)); } else newplan->argtypes = NULL; newplan->parserSetup = plan->parserSetup; newplan->parserSetupArg = plan->parserSetupArg; /* Copy all the plancache entries */ foreach(lc, plan->plancache_list) { CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc); CachedPlanSource *newsource; newsource = CopyCachedPlan(plansource); newplan->plancache_list = lappend(newplan->plancache_list, newsource); } MemoryContextSwitchTo(oldcxt); /* * Mark it saved, reparent it under CacheMemoryContext, and mark all the * component CachedPlanSources as saved. This sequence cannot fail * partway through, so there's no risk of long-term memory leakage. */ newplan->saved = true; MemoryContextSetParent(newplan->plancxt, CacheMemoryContext); foreach(lc, newplan->plancache_list) { CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc); SaveCachedPlan(plansource); } return newplan; }
void AtEOSubXact_SPI | ( | bool | isCommit, | |
SubTransactionId | mySubid | |||
) |
Definition at line 230 of file spi.c.
References _SPI_connected, _SPI_curid, _SPI_connection::connectSubid, ereport, errcode(), errhint(), errmsg(), _SPI_connection::execCxt, MemoryContextDelete(), MemoryContextResetAndDeleteChildren(), _SPI_connection::procCxt, SPI_freetuptable(), SPI_lastoid, SPI_processed, _SPI_connection::tuptable, and WARNING.
Referenced by AbortSubTransaction(), and CommitSubTransaction().
{ bool found = false; while (_SPI_connected >= 0) { _SPI_connection *connection = &(_SPI_stack[_SPI_connected]); if (connection->connectSubid != mySubid) break; /* couldn't be any underneath it either */ found = true; /* * Release procedure memory explicitly (see note in SPI_connect) */ if (connection->execCxt) { MemoryContextDelete(connection->execCxt); connection->execCxt = NULL; } if (connection->procCxt) { MemoryContextDelete(connection->procCxt); connection->procCxt = NULL; } /* * Pop the stack entry and reset global variables. Unlike * SPI_finish(), we don't risk switching to memory contexts that might * be already gone. */ _SPI_connected--; _SPI_curid = _SPI_connected; if (_SPI_connected == -1) _SPI_current = NULL; else _SPI_current = &(_SPI_stack[_SPI_connected]); SPI_processed = 0; SPI_lastoid = InvalidOid; SPI_tuptable = NULL; } if (found && isCommit) ereport(WARNING, (errcode(ERRCODE_WARNING), errmsg("subtransaction left non-empty SPI stack"), errhint("Check for missing \"SPI_finish\" calls."))); /* * If we are aborting a subtransaction and there is an open SPI context * surrounding the subxact, clean up to prevent memory leakage. */ if (_SPI_current && !isCommit) { /* free Executor memory the same as _SPI_end_call would do */ MemoryContextResetAndDeleteChildren(_SPI_current->execCxt); /* throw away any partially created tuple-table */ SPI_freetuptable(_SPI_current->tuptable); _SPI_current->tuptable = NULL; } }
void AtEOXact_SPI | ( | bool | isCommit | ) |
Definition at line 202 of file spi.c.
References _SPI_connected, _SPI_curid, _SPI_stack_depth, ereport, errcode(), errhint(), errmsg(), SPI_lastoid, SPI_processed, and WARNING.
Referenced by AbortTransaction(), CommitTransaction(), and PrepareTransaction().
{ /* * Note that memory contexts belonging to SPI stack entries will be freed * automatically, so we can ignore them here. We just need to restore our * static variables to initial state. */ if (isCommit && _SPI_connected != -1) ereport(WARNING, (errcode(ERRCODE_WARNING), errmsg("transaction left non-empty SPI stack"), errhint("Check for missing \"SPI_finish\" calls."))); _SPI_current = _SPI_stack = NULL; _SPI_stack_depth = 0; _SPI_connected = _SPI_curid = -1; SPI_processed = 0; SPI_lastoid = InvalidOid; SPI_tuptable = NULL; }
int SPI_connect | ( | void | ) |
Definition at line 84 of file spi.c.
References _SPI_connected, _SPI_curid, _SPI_stack_depth, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE, ALLOCSET_DEFAULT_MINSIZE, AllocSetContextCreate(), Assert, _SPI_connection::connectSubid, elog, ERROR, _SPI_connection::execCxt, GetCurrentSubTransactionId(), _SPI_connection::lastoid, MemoryContextAlloc(), MemoryContextSwitchTo(), NULL, _SPI_connection::procCxt, _SPI_connection::processed, repalloc(), _SPI_connection::savedcxt, TopTransactionContext, and _SPI_connection::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(), funny_dup17(), get_crosstab_tuplestore(), get_tuple_of_interest(), initialize_worker_spi(), load_categories_hash(), pg_get_ruledef_worker(), pg_get_viewdef_worker(), plperl_func_handler(), plperl_inline_handler(), plperl_trigger_handler(), plpgsql_call_handler(), plpgsql_inline_handler(), plpgsql_validator(), plpython_call_handler(), plpython_inline_handler(), pltcl_func_handler(), pltcl_trigger_handler(), query_to_xml_and_xmlschema(), query_to_xml_internal(), query_to_xmlschema(), ri_Check_Pk_Match(), RI_FKey_cascade_del(), RI_FKey_cascade_upd(), RI_FKey_check(), RI_FKey_setdefault_del(), RI_FKey_setdefault_upd(), RI_FKey_setnull_del(), RI_FKey_setnull_upd(), RI_Initial_Check(), ri_restrict_del(), ri_restrict_upd(), schema_to_xml_internal(), schema_to_xmlschema_internal(), timetravel(), ts_stat1(), ts_stat2(), tsquery_rewrite_query(), ttdummy(), worker_spi_main(), and xpath_table().
{ int newdepth; /* * When procedure called by Executor _SPI_curid expected to be equal to * _SPI_connected */ if (_SPI_curid != _SPI_connected) return SPI_ERROR_CONNECT; if (_SPI_stack == NULL) { if (_SPI_connected != -1 || _SPI_stack_depth != 0) elog(ERROR, "SPI stack corrupted"); newdepth = 16; _SPI_stack = (_SPI_connection *) MemoryContextAlloc(TopTransactionContext, newdepth * sizeof(_SPI_connection)); _SPI_stack_depth = newdepth; } else { if (_SPI_stack_depth <= 0 || _SPI_stack_depth <= _SPI_connected) elog(ERROR, "SPI stack corrupted"); if (_SPI_stack_depth == _SPI_connected + 1) { newdepth = _SPI_stack_depth * 2; _SPI_stack = (_SPI_connection *) repalloc(_SPI_stack, newdepth * sizeof(_SPI_connection)); _SPI_stack_depth = newdepth; } } /* * We're entering procedure where _SPI_curid == _SPI_connected - 1 */ _SPI_connected++; Assert(_SPI_connected >= 0 && _SPI_connected < _SPI_stack_depth); _SPI_current = &(_SPI_stack[_SPI_connected]); _SPI_current->processed = 0; _SPI_current->lastoid = InvalidOid; _SPI_current->tuptable = NULL; _SPI_current->procCxt = NULL; /* in case we fail to create 'em */ _SPI_current->execCxt = NULL; _SPI_current->connectSubid = GetCurrentSubTransactionId(); /* * Create memory contexts for this procedure * * XXX it would be better to use PortalContext as the parent context, but * we may not be inside a portal (consider deferred-trigger execution). * Perhaps CurTransactionContext would do? For now it doesn't matter * because we clean up explicitly in AtEOSubXact_SPI(). */ _SPI_current->procCxt = AllocSetContextCreate(TopTransactionContext, "SPI Proc", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); _SPI_current->execCxt = AllocSetContextCreate(TopTransactionContext, "SPI Exec", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); /* ... and switch to procedure's context */ _SPI_current->savedcxt = MemoryContextSwitchTo(_SPI_current->procCxt); return SPI_OK_CONNECT; }
Definition at line 670 of file spi.c.
References _SPI_connected, _SPI_curid, elog, ERROR, heap_copytuple(), MemoryContextSwitchTo(), NULL, _SPI_connection::savedcxt, and SPI_result.
Referenced by get_tuple_of_interest(), plpgsql_exec_trigger(), and ttdummy().
{ MemoryContext oldcxt = NULL; HeapTuple ctuple; if (tuple == NULL) { SPI_result = SPI_ERROR_ARGUMENT; return NULL; } if (_SPI_curid + 1 == _SPI_connected) /* connected */ { if (_SPI_current != &(_SPI_stack[_SPI_curid + 1])) elog(ERROR, "SPI stack corrupted"); oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt); } ctuple = heap_copytuple(tuple); if (oldcxt) MemoryContextSwitchTo(oldcxt); return ctuple; }
void SPI_cursor_close | ( | Portal | portal | ) |
Definition at line 1398 of file spi.c.
References elog, ERROR, PortalDrop(), and PortalIsValid.
Referenced by exec_stmt_close(), exec_stmt_dynfors(), exec_stmt_forc(), exec_stmt_fors(), exec_stmt_return_query(), plperl_spi_cursor_close(), plperl_spi_fetchrow(), PLy_cursor_close(), PLy_cursor_dealloc(), query_to_xml_and_xmlschema(), query_to_xmlschema(), ts_stat_sql(), and tsquery_rewrite_query().
{ if (!PortalIsValid(portal)) elog(ERROR, "invalid portal in SPI cursor operation"); PortalDrop(portal, false); }
Definition at line 1342 of file spi.c.
References _SPI_cursor_operation(), CreateDestReceiver(), DestSPI, FETCH_BACKWARD, and FETCH_FORWARD.
Referenced by cursor_to_xml(), exec_for_query(), exec_stmt_return_query(), plperl_spi_fetchrow(), PLy_cursor_fetch(), PLy_cursor_iternext(), ts_stat_sql(), and tsquery_rewrite_query().
{ _SPI_cursor_operation(portal, forward ? FETCH_FORWARD : FETCH_BACKWARD, count, CreateDestReceiver(DestSPI)); /* we know that the DestSPI receiver doesn't need a destroy call */ }
Portal SPI_cursor_find | ( | const char * | name | ) |
Definition at line 1330 of file spi.c.
References GetPortalByName().
Referenced by cursor_to_xml(), cursor_to_xmlschema(), exec_stmt_close(), exec_stmt_fetch(), exec_stmt_forc(), exec_stmt_open(), plperl_spi_cursor_close(), and plperl_spi_fetchrow().
{ return GetPortalByName(name); }
Definition at line 1357 of file spi.c.
References _SPI_cursor_operation(), FETCH_BACKWARD, FETCH_FORWARD, and None_Receiver.
{ _SPI_cursor_operation(portal, forward ? FETCH_FORWARD : FETCH_BACKWARD, count, None_Receiver); }
Portal SPI_cursor_open | ( | const char * | name, | |
SPIPlanPtr | plan, | |||
Datum * | Values, | |||
const char * | Nulls, | |||
bool | read_only | |||
) |
Definition at line 1029 of file spi.c.
References _SPI_convert_params(), _SPI_plan::argtypes, _SPI_plan::nargs, pfree(), and SPI_cursor_open_internal().
Referenced by plperl_spi_query(), plperl_spi_query_prepared(), PLy_cursor_plan(), PLy_cursor_query(), query_to_xml_and_xmlschema(), query_to_xmlschema(), ts_stat_sql(), and tsquery_rewrite_query().
{ Portal portal; ParamListInfo paramLI; /* build transient ParamListInfo in caller's context */ paramLI = _SPI_convert_params(plan->nargs, plan->argtypes, Values, Nulls); portal = SPI_cursor_open_internal(name, plan, paramLI, read_only); /* done with the transient ParamListInfo */ if (paramLI) pfree(paramLI); return portal; }
static Portal SPI_cursor_open_internal | ( | const char * | name, | |
SPIPlanPtr | plan, | |||
ParamListInfo | paramLI, | |||
bool | read_only | |||
) | [static] |
Definition at line 1125 of file spi.c.
References _SPI_begin_call(), _SPI_end_call(), ErrorContextCallback::arg, Assert, ErrorContextCallback::callback, CommandCounterIncrement(), CommandIsReadOnly(), CachedPlanSource::commandTag, copyObject(), copyParamList(), CreateCommandTag(), CreateNewPortal(), CreatePortal(), CURSOR_OPT_NO_SCROLL, CURSOR_OPT_SCROLL, _SPI_plan::cursor_options, PortalData::cursorOptions, elog, ereport, errcode(), errdetail(), errmsg(), ERROR, error_context_stack, ExecSupportsBackwardScan(), GetActiveSnapshot(), GetCachedPlan(), GetTransactionSnapshot(), IsA, lfirst, linitial, list_length(), MemoryContextStrdup(), MemoryContextSwitchTo(), NIL, NULL, _SPI_plan::plancache_list, PORTAL_MULTI_QUERY, PortalDefineQuery(), PortalGetHeapMemory, PortalStart(), ErrorContextCallback::previous, _SPI_connection::processed, CachedPlanSource::query_string, ReleaseCachedPlan(), _SPI_plan::saved, SPI_is_cursor_plan(), SPI_processed, CachedPlan::stmt_list, PortalData::strategy, and _SPI_connection::tuptable.
Referenced by SPI_cursor_open(), SPI_cursor_open_with_args(), and SPI_cursor_open_with_paramlist().
{ CachedPlanSource *plansource; CachedPlan *cplan; List *stmt_list; char *query_string; Snapshot snapshot; MemoryContext oldcontext; Portal portal; ErrorContextCallback spierrcontext; /* * Check that the plan is something the Portal code will special-case as * returning one tupleset. */ if (!SPI_is_cursor_plan(plan)) { /* try to give a good error message */ if (list_length(plan->plancache_list) != 1) ereport(ERROR, (errcode(ERRCODE_INVALID_CURSOR_DEFINITION), errmsg("cannot open multi-query plan as cursor"))); plansource = (CachedPlanSource *) linitial(plan->plancache_list); ereport(ERROR, (errcode(ERRCODE_INVALID_CURSOR_DEFINITION), /* translator: %s is name of a SQL command, eg INSERT */ errmsg("cannot open %s query as cursor", plansource->commandTag))); } Assert(list_length(plan->plancache_list) == 1); plansource = (CachedPlanSource *) linitial(plan->plancache_list); /* Push the SPI stack */ if (_SPI_begin_call(true) < 0) elog(ERROR, "SPI_cursor_open called while not connected"); /* Reset SPI result (note we deliberately don't touch lastoid) */ SPI_processed = 0; SPI_tuptable = NULL; _SPI_current->processed = 0; _SPI_current->tuptable = NULL; /* Create the portal */ if (name == NULL || name[0] == '\0') { /* Use a random nonconflicting name */ portal = CreateNewPortal(); } else { /* In this path, error if portal of same name already exists */ portal = CreatePortal(name, false, false); } /* Copy the plan's query string into the portal */ query_string = MemoryContextStrdup(PortalGetHeapMemory(portal), plansource->query_string); /* * Setup error traceback support for ereport(), in case GetCachedPlan * throws an error. */ spierrcontext.callback = _SPI_error_callback; spierrcontext.arg = (void *) plansource->query_string; spierrcontext.previous = error_context_stack; error_context_stack = &spierrcontext; /* * Note: for a saved plan, we mustn't have any failure occur between * GetCachedPlan and PortalDefineQuery; that would result in leaking our * plancache refcount. */ /* Replan if needed, and increment plan refcount for portal */ cplan = GetCachedPlan(plansource, paramLI, false); stmt_list = cplan->stmt_list; /* Pop the error context stack */ error_context_stack = spierrcontext.previous; if (!plan->saved) { /* * We don't want the portal to depend on an unsaved CachedPlanSource, * so must copy the plan into the portal's context. An error here * will result in leaking our refcount on the plan, but it doesn't * matter because the plan is unsaved and hence transient anyway. */ oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal)); stmt_list = copyObject(stmt_list); MemoryContextSwitchTo(oldcontext); ReleaseCachedPlan(cplan, false); cplan = NULL; /* portal shouldn't depend on cplan */ } /* * Set up the portal. */ PortalDefineQuery(portal, NULL, /* no statement name */ query_string, plansource->commandTag, stmt_list, cplan); /* * Set up options for portal. Default SCROLL type is chosen the same way * as PerformCursorOpen does it. */ portal->cursorOptions = plan->cursor_options; if (!(portal->cursorOptions & (CURSOR_OPT_SCROLL | CURSOR_OPT_NO_SCROLL))) { if (list_length(stmt_list) == 1 && IsA((Node *) linitial(stmt_list), PlannedStmt) && ((PlannedStmt *) linitial(stmt_list))->rowMarks == NIL && ExecSupportsBackwardScan(((PlannedStmt *) linitial(stmt_list))->planTree)) portal->cursorOptions |= CURSOR_OPT_SCROLL; else portal->cursorOptions |= CURSOR_OPT_NO_SCROLL; } /* * Disallow SCROLL with SELECT FOR UPDATE. This is not redundant with the * check in transformDeclareCursorStmt because the cursor options might * not have come through there. */ if (portal->cursorOptions & CURSOR_OPT_SCROLL) { if (list_length(stmt_list) == 1 && IsA((Node *) linitial(stmt_list), PlannedStmt) && ((PlannedStmt *) linitial(stmt_list))->rowMarks != NIL) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("DECLARE SCROLL CURSOR ... FOR UPDATE/SHARE is not supported"), errdetail("Scrollable cursors must be READ ONLY."))); } /* * If told to be read-only, we'd better check for read-only queries. This * can't be done earlier because we need to look at the finished, planned * queries. (In particular, we don't want to do it between GetCachedPlan * and PortalDefineQuery, because throwing an error between those steps * would result in leaking our plancache refcount.) */ if (read_only) { ListCell *lc; foreach(lc, stmt_list) { Node *pstmt = (Node *) lfirst(lc); if (!CommandIsReadOnly(pstmt)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), /* translator: %s is a SQL statement name */ errmsg("%s is not allowed in a non-volatile function", CreateCommandTag(pstmt)))); } } /* Set up the snapshot to use. */ if (read_only) snapshot = GetActiveSnapshot(); else { CommandCounterIncrement(); snapshot = GetTransactionSnapshot(); } /* * If the plan has parameters, copy them into the portal. Note that this * must be done after revalidating the plan, because in dynamic parameter * cases the set of parameters could have changed during re-parsing. */ if (paramLI) { oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal)); paramLI = copyParamList(paramLI); MemoryContextSwitchTo(oldcontext); } /* * Start portal execution. */ PortalStart(portal, paramLI, 0, snapshot); Assert(portal->strategy != PORTAL_MULTI_QUERY); /* Pop the SPI stack */ _SPI_end_call(true); /* Return the created portal */ return portal; }
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 1056 of file spi.c.
References _SPI_begin_call(), _SPI_convert_params(), _SPI_curid, _SPI_end_call(), _SPI_prepare_plan(), _SPI_plan::argtypes, _SPI_plan::cursor_options, elog, ERROR, _SPI_plan::magic, _SPI_plan::nargs, NULL, _SPI_plan::parserSetup, _SPI_plan::parserSetupArg, SPI_cursor_open_internal(), and SPI_result.
Referenced by exec_dynquery_with_params().
{ Portal result; _SPI_plan plan; ParamListInfo paramLI; if (src == NULL || nargs < 0) elog(ERROR, "SPI_cursor_open_with_args called with invalid arguments"); if (nargs > 0 && (argtypes == NULL || Values == NULL)) elog(ERROR, "SPI_cursor_open_with_args called with missing parameters"); SPI_result = _SPI_begin_call(true); if (SPI_result < 0) elog(ERROR, "SPI_cursor_open_with_args called while not connected"); memset(&plan, 0, sizeof(_SPI_plan)); plan.magic = _SPI_PLAN_MAGIC; plan.cursor_options = cursorOptions; plan.nargs = nargs; plan.argtypes = argtypes; plan.parserSetup = NULL; plan.parserSetupArg = NULL; /* build transient ParamListInfo in executor context */ paramLI = _SPI_convert_params(nargs, argtypes, Values, Nulls); _SPI_prepare_plan(src, &plan); /* We needn't copy the plan; SPI_cursor_open_internal will do so */ /* Adjust stack so that SPI_cursor_open_internal doesn't complain */ _SPI_curid--; result = SPI_cursor_open_internal(name, &plan, paramLI, read_only); /* And clean up */ _SPI_curid++; _SPI_end_call(true); return result; }
Portal SPI_cursor_open_with_paramlist | ( | const char * | name, | |
SPIPlanPtr | plan, | |||
ParamListInfo | params, | |||
bool | read_only | |||
) |
Definition at line 1112 of file spi.c.
References SPI_cursor_open_internal().
Referenced by exec_run_select(), exec_stmt_forc(), and exec_stmt_open().
{ return SPI_cursor_open_internal(name, plan, params, read_only); }
void spi_dest_startup | ( | DestReceiver * | self, | |
int | operation, | |||
TupleDesc | typeinfo | |||
) |
Definition at line 1635 of file spi.c.
References _SPI_connected, _SPI_curid, _SPI_procmem(), SPITupleTable::alloced, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE, ALLOCSET_DEFAULT_MINSIZE, AllocSetContextCreate(), CreateTupleDescCopy(), CurrentMemoryContext, elog, ERROR, SPITupleTable::free, MemoryContextSwitchTo(), NULL, palloc(), SPITupleTable::tupdesc, SPITupleTable::tuptabcxt, _SPI_connection::tuptable, and SPITupleTable::vals.
{ SPITupleTable *tuptable; MemoryContext oldcxt; MemoryContext tuptabcxt; /* * When called by Executor _SPI_curid expected to be equal to * _SPI_connected */ if (_SPI_curid != _SPI_connected || _SPI_connected < 0) elog(ERROR, "improper call to spi_dest_startup"); if (_SPI_current != &(_SPI_stack[_SPI_curid])) elog(ERROR, "SPI stack corrupted"); if (_SPI_current->tuptable != NULL) elog(ERROR, "improper call to spi_dest_startup"); oldcxt = _SPI_procmem(); /* switch to procedure memory context */ tuptabcxt = AllocSetContextCreate(CurrentMemoryContext, "SPI TupTable", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); MemoryContextSwitchTo(tuptabcxt); _SPI_current->tuptable = tuptable = (SPITupleTable *) palloc(sizeof(SPITupleTable)); tuptable->tuptabcxt = tuptabcxt; tuptable->alloced = tuptable->free = 128; tuptable->vals = (HeapTuple *) palloc(tuptable->alloced * sizeof(HeapTuple)); tuptable->tupdesc = CreateTupleDescCopy(typeinfo); MemoryContextSwitchTo(oldcxt); }
int SPI_exec | ( | const char * | src, | |
long | tcount | |||
) |
Definition at line 371 of file spi.c.
References SPI_execute().
Referenced by funny_dup17(), get_tuple_of_interest(), and xpath_table().
{ return SPI_execute(src, false, tcount); }
int SPI_execp | ( | SPIPlanPtr | plan, | |
Datum * | Values, | |||
const char * | Nulls, | |||
long | tcount | |||
) |
Definition at line 405 of file spi.c.
References SPI_execute_plan().
Referenced by check_foreign_key(), check_primary_key(), timetravel(), and ttdummy().
{ return SPI_execute_plan(plan, Values, Nulls, false, tcount); }
int SPI_execute | ( | const char * | src, | |
bool | read_only, | |||
long | tcount | |||
) |
Definition at line 343 of file spi.c.
References _SPI_begin_call(), _SPI_end_call(), _SPI_execute_plan(), _SPI_prepare_oneshot_plan(), _SPI_plan::cursor_options, InvalidSnapshot, _SPI_plan::magic, and NULL.
Referenced by build_tuplestore_recursively(), crosstab(), exec_stmt_dynexecute(), get_crosstab_tuplestore(), initialize_worker_spi(), load_categories_hash(), plperl_spi_exec(), pltcl_init_load_unknown(), pltcl_SPI_execute(), PLy_spi_execute_query(), query_to_oid_list(), query_to_xml_internal(), SPI_exec(), and worker_spi_main().
{ _SPI_plan plan; int res; if (src == NULL || tcount < 0) return SPI_ERROR_ARGUMENT; res = _SPI_begin_call(true); if (res < 0) return res; memset(&plan, 0, sizeof(_SPI_plan)); plan.magic = _SPI_PLAN_MAGIC; plan.cursor_options = 0; _SPI_prepare_oneshot_plan(src, &plan); res = _SPI_execute_plan(&plan, NULL, InvalidSnapshot, InvalidSnapshot, read_only, true, tcount); _SPI_end_call(true); return res; }
int SPI_execute_plan | ( | SPIPlanPtr | plan, | |
Datum * | Values, | |||
const char * | Nulls, | |||
bool | read_only, | |||
long | tcount | |||
) |
Definition at line 378 of file spi.c.
References _SPI_begin_call(), _SPI_convert_params(), _SPI_end_call(), _SPI_execute_plan(), _SPI_PLAN_MAGIC, _SPI_plan::argtypes, InvalidSnapshot, _SPI_plan::magic, _SPI_plan::nargs, and NULL.
Referenced by pg_get_ruledef_worker(), pg_get_viewdef_worker(), plperl_spi_exec_prepared(), pltcl_SPI_execute_plan(), PLy_spi_execute_plan(), and SPI_execp().
{ int res; if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC || tcount < 0) return SPI_ERROR_ARGUMENT; if (plan->nargs > 0 && Values == NULL) return SPI_ERROR_PARAM; res = _SPI_begin_call(true); if (res < 0) return res; res = _SPI_execute_plan(plan, _SPI_convert_params(plan->nargs, plan->argtypes, Values, Nulls), InvalidSnapshot, InvalidSnapshot, read_only, true, tcount); _SPI_end_call(true); return res; }
int SPI_execute_plan_with_paramlist | ( | SPIPlanPtr | plan, | |
ParamListInfo | params, | |||
bool | read_only, | |||
long | tcount | |||
) |
Definition at line 412 of file spi.c.
References _SPI_begin_call(), _SPI_end_call(), _SPI_execute_plan(), _SPI_PLAN_MAGIC, InvalidSnapshot, _SPI_plan::magic, and NULL.
Referenced by exec_run_select(), and exec_stmt_execsql().
{ int res; if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC || tcount < 0) return SPI_ERROR_ARGUMENT; res = _SPI_begin_call(true); if (res < 0) return res; res = _SPI_execute_plan(plan, params, InvalidSnapshot, InvalidSnapshot, read_only, true, tcount); _SPI_end_call(true); return res; }
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 446 of file spi.c.
References _SPI_begin_call(), _SPI_convert_params(), _SPI_end_call(), _SPI_execute_plan(), _SPI_PLAN_MAGIC, _SPI_plan::argtypes, _SPI_plan::magic, _SPI_plan::nargs, and NULL.
Referenced by RI_Initial_Check(), and ri_PerformCheck().
{ int res; if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC || tcount < 0) return SPI_ERROR_ARGUMENT; if (plan->nargs > 0 && Values == NULL) return SPI_ERROR_PARAM; res = _SPI_begin_call(true); if (res < 0) return res; res = _SPI_execute_plan(plan, _SPI_convert_params(plan->nargs, plan->argtypes, Values, Nulls), snapshot, crosscheck_snapshot, read_only, fire_triggers, tcount); _SPI_end_call(true); return res; }
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 480 of file spi.c.
References _SPI_begin_call(), _SPI_convert_params(), _SPI_end_call(), _SPI_execute_plan(), _SPI_prepare_oneshot_plan(), _SPI_plan::argtypes, _SPI_plan::cursor_options, InvalidSnapshot, _SPI_plan::magic, _SPI_plan::nargs, NULL, _SPI_plan::parserSetup, and _SPI_plan::parserSetupArg.
Referenced by exec_stmt_dynexecute().
{ int res; _SPI_plan plan; ParamListInfo paramLI; if (src == NULL || nargs < 0 || tcount < 0) return SPI_ERROR_ARGUMENT; if (nargs > 0 && (argtypes == NULL || Values == NULL)) return SPI_ERROR_PARAM; res = _SPI_begin_call(true); if (res < 0) return res; memset(&plan, 0, sizeof(_SPI_plan)); plan.magic = _SPI_PLAN_MAGIC; plan.cursor_options = 0; plan.nargs = nargs; plan.argtypes = argtypes; plan.parserSetup = NULL; plan.parserSetupArg = NULL; paramLI = _SPI_convert_params(nargs, argtypes, Values, Nulls); _SPI_prepare_oneshot_plan(src, &plan); res = _SPI_execute_plan(&plan, paramLI, InvalidSnapshot, InvalidSnapshot, read_only, true, tcount); _SPI_end_call(true); return res; }
int SPI_finish | ( | void | ) |
Definition at line 158 of file spi.c.
References _SPI_begin_call(), _SPI_connected, _SPI_curid, _SPI_connection::execCxt, MemoryContextDelete(), MemoryContextSwitchTo(), _SPI_connection::procCxt, _SPI_connection::savedcxt, SPI_lastoid, and SPI_processed.
Referenced by check_foreign_key(), check_primary_key(), connectby(), crosstab(), cursor_to_xml(), cursor_to_xmlschema(), database_to_xml_internal(), database_to_xmlschema_internal(), funny_dup17(), get_crosstab_tuplestore(), get_tuple_of_interest(), initialize_worker_spi(), load_categories_hash(), pg_get_ruledef_worker(), pg_get_viewdef_worker(), plperl_func_handler(), plperl_inline_handler(), plperl_trigger_handler(), plpgsql_call_handler(), plpgsql_inline_handler(), plpgsql_validator(), pltcl_func_handler(), pltcl_trigger_handler(), PLy_exec_function(), PLy_exec_trigger(), query_to_xml_and_xmlschema(), query_to_xml_internal(), query_to_xmlschema(), ri_Check_Pk_Match(), RI_FKey_cascade_del(), RI_FKey_cascade_upd(), RI_FKey_check(), RI_FKey_setdefault_del(), RI_FKey_setdefault_upd(), RI_FKey_setnull_del(), RI_FKey_setnull_upd(), RI_Initial_Check(), ri_restrict_del(), ri_restrict_upd(), schema_to_xml_internal(), schema_to_xmlschema_internal(), timetravel(), ts_stat1(), ts_stat2(), tsquery_rewrite_query(), ttdummy(), worker_spi_main(), and xpath_table().
{ int res; res = _SPI_begin_call(false); /* live in procedure memory */ if (res < 0) return res; /* Restore memory context as it was before procedure call */ MemoryContextSwitchTo(_SPI_current->savedcxt); /* Release memory used in procedure call */ MemoryContextDelete(_SPI_current->execCxt); _SPI_current->execCxt = NULL; MemoryContextDelete(_SPI_current->procCxt); _SPI_current->procCxt = NULL; /* * Reset result variables, especially SPI_tuptable which is probably * pointing at a just-deleted tuptable */ SPI_processed = 0; SPI_lastoid = InvalidOid; SPI_tuptable = NULL; /* * After _SPI_begin_call _SPI_connected == _SPI_curid. Now we are closing * connection to SPI and returning to upper Executor and so _SPI_connected * must be equal to _SPI_curid. */ _SPI_connected--; _SPI_curid--; if (_SPI_connected == -1) _SPI_current = NULL; else _SPI_current = &(_SPI_stack[_SPI_connected]); return SPI_OK_FINISH; }
char* SPI_fname | ( | TupleDesc | tupdesc, | |
int | fnumber | |||
) |
Definition at line 823 of file spi.c.
References tupleDesc::attrs, FirstLowInvalidHeapAttributeNumber, NameStr, tupleDesc::natts, pstrdup(), SPI_result, and SystemAttributeDefinition().
Referenced by funny_dup17(), get_pkey_attnames(), ri_ReportViolation(), and SPI_sql_row_to_xmlelement().
{ Form_pg_attribute att; SPI_result = 0; if (fnumber > tupdesc->natts || fnumber == 0 || fnumber <= FirstLowInvalidHeapAttributeNumber) { SPI_result = SPI_ERROR_NOATTRIBUTE; return NULL; } if (fnumber > 0) att = tupdesc->attrs[fnumber - 1]; else att = SystemAttributeDefinition(fnumber, true); return pstrdup(NameStr(att->attname)); }
int SPI_fnumber | ( | TupleDesc | tupdesc, | |
const char * | fname | |||
) |
Definition at line 803 of file spi.c.
References tupleDesc::attrs, namestrcmp(), tupleDesc::natts, NULL, and SystemAttributeByName().
Referenced by autoinc(), check_foreign_key(), check_primary_key(), exec_assign_value(), exec_eval_datum(), exec_get_datum_type(), exec_get_datum_type_info(), insert_username(), lo_manage(), make_ruledef(), make_viewdef(), moddatetime(), plperl_build_tuple_result(), plperl_modify_tuple(), pltcl_init_load_unknown(), pltcl_trigger_handler(), PLy_modify_tuple(), timetravel(), tsvector_update_trigger(), and ttdummy().
{ int res; Form_pg_attribute sysatt; for (res = 0; res < tupdesc->natts; res++) { if (namestrcmp(&tupdesc->attrs[res]->attname, fname) == 0) return res + 1; } sysatt = SystemAttributeByName(fname, true /* "oid" will be accepted */ ); if (sysatt != NULL) return sysatt->attnum; /* SPI_ERROR_NOATTRIBUTE is different from all sys column numbers */ return SPI_ERROR_NOATTRIBUTE; }
int SPI_freeplan | ( | SPIPlanPtr | plan | ) |
Definition at line 648 of file spi.c.
References _SPI_PLAN_MAGIC, DropCachedPlan(), lfirst, _SPI_plan::magic, MemoryContextDelete(), NULL, _SPI_plan::plancache_list, and _SPI_plan::plancxt.
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().
{ ListCell *lc; if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC) return SPI_ERROR_ARGUMENT; /* Release the plancache entries */ foreach(lc, plan->plancache_list) { CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc); DropCachedPlan(plansource); } /* Now get rid of the _SPI_plan and subsidiary data in its plancxt */ MemoryContextDelete(plan->plancxt); return 0; }
void SPI_freetuple | ( | HeapTuple | tuple | ) |
Definition at line 1009 of file spi.c.
References heap_freetuple().
Referenced by ttdummy().
{ /* No longer need to worry which context tuple was in... */ heap_freetuple(tuple); }
void SPI_freetuptable | ( | SPITupleTable * | tuptable | ) |
Definition at line 1016 of file spi.c.
References MemoryContextDelete(), NULL, and SPITupleTable::tuptabcxt.
Referenced by _SPI_execute_plan(), AtEOSubXact_SPI(), exec_assign_value(), exec_eval_cleanup(), exec_for_query(), exec_stmt_dynexecute(), exec_stmt_execsql(), exec_stmt_fetch(), exec_stmt_return_query(), plperl_spi_execute_fetch_result(), plperl_spi_fetchrow(), pltcl_init_load_unknown(), pltcl_process_SPI_result(), PLy_cursor_fetch(), PLy_cursor_iternext(), PLy_spi_execute_fetch_result(), ts_stat_sql(), and tsquery_rewrite_query().
{ if (tuptable != NULL) MemoryContextDelete(tuptable->tuptabcxt); }
int SPI_getargcount | ( | SPIPlanPtr | plan | ) |
Definition at line 1426 of file spi.c.
References _SPI_PLAN_MAGIC, _SPI_plan::magic, _SPI_plan::nargs, NULL, and SPI_result.
{ if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC) { SPI_result = SPI_ERROR_ARGUMENT; return -1; } return plan->nargs; }
Oid SPI_getargtypeid | ( | SPIPlanPtr | plan, | |
int | argIndex | |||
) |
Definition at line 1411 of file spi.c.
References _SPI_PLAN_MAGIC, _SPI_plan::argtypes, _SPI_plan::magic, _SPI_plan::nargs, NULL, and SPI_result.
{ if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC || argIndex < 0 || argIndex >= plan->nargs) { SPI_result = SPI_ERROR_ARGUMENT; return InvalidOid; } return plan->argtypes[argIndex]; }
Definition at line 894 of file spi.c.
References FirstLowInvalidHeapAttributeNumber, heap_getattr, tupleDesc::natts, and SPI_result.
Referenced by autoinc(), check_foreign_key(), check_primary_key(), exec_eval_datum(), exec_eval_expr(), exec_move_row(), initialize_worker_spi(), make_ruledef(), make_viewdef(), query_to_oid_list(), SPI_sql_row_to_xmlelement(), timetravel(), ts_stat_sql(), tsquery_rewrite_query(), tsvector_update_trigger(), ttdummy(), and worker_spi_main().
{ SPI_result = 0; if (fnumber > tupdesc->natts || fnumber == 0 || fnumber <= FirstLowInvalidHeapAttributeNumber) { SPI_result = SPI_ERROR_NOATTRIBUTE; *isnull = true; return (Datum) NULL; } return heap_getattr(tuple, fnumber, tupdesc, isnull); }
char* SPI_getnspname | ( | Relation | rel | ) |
Definition at line 968 of file spi.c.
References get_namespace_name(), and RelationGetNamespace.
Referenced by plperl_trigger_build_args(), pltcl_trigger_handler(), and PLy_trigger_build_args().
{ return get_namespace_name(RelationGetNamespace(rel)); }
char* SPI_getrelname | ( | Relation | rel | ) |
Definition at line 962 of file spi.c.
References pstrdup(), and RelationGetRelationName.
Referenced by autoinc(), check_foreign_key(), check_primary_key(), funny_dup17(), insert_username(), moddatetime(), plperl_trigger_build_args(), pltcl_trigger_handler(), PLy_trigger_build_args(), timetravel(), and ttdummy().
{ return pstrdup(RelationGetRelationName(rel)); }
char* SPI_gettype | ( | TupleDesc | tupdesc, | |
int | fnumber | |||
) |
Definition at line 910 of file spi.c.
References tupleDesc::attrs, FirstLowInvalidHeapAttributeNumber, GETSTRUCT, HeapTupleIsValid, NameStr, tupleDesc::natts, ObjectIdGetDatum, pstrdup(), ReleaseSysCache(), SearchSysCache1, SPI_result, SystemAttributeDefinition(), and TYPEOID.
Referenced by check_foreign_key(), and funny_dup17().
{ Oid typoid; HeapTuple typeTuple; char *result; SPI_result = 0; if (fnumber > tupdesc->natts || fnumber == 0 || fnumber <= FirstLowInvalidHeapAttributeNumber) { SPI_result = SPI_ERROR_NOATTRIBUTE; return NULL; } if (fnumber > 0) typoid = tupdesc->attrs[fnumber - 1]->atttypid; else typoid = (SystemAttributeDefinition(fnumber, true))->atttypid; typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typoid)); if (!HeapTupleIsValid(typeTuple)) { SPI_result = SPI_ERROR_TYPUNKNOWN; return NULL; } result = pstrdup(NameStr(((Form_pg_type) GETSTRUCT(typeTuple))->typname)); ReleaseSysCache(typeTuple); return result; }
Definition at line 944 of file spi.c.
References tupleDesc::attrs, FirstLowInvalidHeapAttributeNumber, tupleDesc::natts, SPI_result, and SystemAttributeDefinition().
Referenced by autoinc(), check_foreign_key(), check_primary_key(), exec_assign_value(), exec_eval_datum(), exec_eval_expr(), exec_get_datum_type(), exec_get_datum_type_info(), exec_move_row(), insert_username(), moddatetime(), SPI_sql_row_to_xmlelement(), timetravel(), ts_stat_sql(), tsquery_rewrite_query(), tsvector_update_trigger(), and ttdummy().
{ SPI_result = 0; if (fnumber > tupdesc->natts || fnumber == 0 || fnumber <= FirstLowInvalidHeapAttributeNumber) { SPI_result = SPI_ERROR_NOATTRIBUTE; return InvalidOid; } if (fnumber > 0) return tupdesc->attrs[fnumber - 1]->atttypid; else return (SystemAttributeDefinition(fnumber, true))->atttypid; }
Definition at line 845 of file spi.c.
References tupleDesc::attrs, DatumGetPointer, FirstLowInvalidHeapAttributeNumber, getTypeOutputInfo(), heap_getattr, tupleDesc::natts, OidOutputFunctionCall(), pfree(), PG_DETOAST_DATUM, PointerGetDatum, SPI_result, SystemAttributeDefinition(), and val.
Referenced by build_tuplestore_recursively(), check_foreign_key(), crosstab(), funny_dup17(), get_crosstab_tuplestore(), get_sql_insert(), get_sql_update(), lo_manage(), load_categories_hash(), make_ruledef(), make_viewdef(), pltcl_init_load_unknown(), ri_ReportViolation(), triggered_change_notification(), and xpath_table().
{ char *result; Datum origval, val; bool isnull; Oid typoid, foutoid; bool typisvarlena; SPI_result = 0; if (fnumber > tupdesc->natts || fnumber == 0 || fnumber <= FirstLowInvalidHeapAttributeNumber) { SPI_result = SPI_ERROR_NOATTRIBUTE; return NULL; } origval = heap_getattr(tuple, fnumber, tupdesc, &isnull); if (isnull) return NULL; if (fnumber > 0) typoid = tupdesc->attrs[fnumber - 1]->atttypid; else typoid = (SystemAttributeDefinition(fnumber, true))->atttypid; getTypeOutputInfo(typoid, &foutoid, &typisvarlena); /* * If we have a toasted datum, forcibly detoast it here to avoid memory * leakage inside the type's output routine. */ if (typisvarlena) val = PointerGetDatum(PG_DETOAST_DATUM(origval)); else val = origval; result = OidOutputFunctionCall(foutoid, val); /* Clean up detoasted copy, if any */ if (val != origval) pfree(DatumGetPointer(val)); return result; }
bool SPI_is_cursor_plan | ( | SPIPlanPtr | plan | ) |
Definition at line 1446 of file spi.c.
References _SPI_PLAN_MAGIC, linitial, list_length(), _SPI_plan::magic, NULL, _SPI_plan::plancache_list, CachedPlanSource::resultDesc, and SPI_result.
Referenced by SPI_cursor_open_internal().
{ CachedPlanSource *plansource; if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC) { SPI_result = SPI_ERROR_ARGUMENT; return false; } if (list_length(plan->plancache_list) != 1) { SPI_result = 0; return false; /* not exactly 1 pre-rewrite command */ } plansource = (CachedPlanSource *) linitial(plan->plancache_list); /* * We used to force revalidation of the cached plan here, but that seems * unnecessary: invalidation could mean a change in the rowtype of the * tuples returned by a plan, but not whether it returns tuples at all. */ SPI_result = 0; /* Does it return tuples? */ if (plansource->resultDesc) return true; return false; }
int SPI_keepplan | ( | SPIPlanPtr | plan | ) |
Definition at line 599 of file spi.c.
References _SPI_PLAN_MAGIC, CacheMemoryContext, lfirst, _SPI_plan::magic, MemoryContextSetParent(), NULL, _SPI_plan::oneshot, _SPI_plan::plancache_list, _SPI_plan::plancxt, SaveCachedPlan(), and _SPI_plan::saved.
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(), timetravel(), and ttdummy().
{ ListCell *lc; if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC || plan->saved || plan->oneshot) return SPI_ERROR_ARGUMENT; /* * Mark it saved, reparent it under CacheMemoryContext, and mark all the * component CachedPlanSources as saved. This sequence cannot fail * partway through, so there's no risk of long-term memory leakage. */ plan->saved = true; MemoryContextSetParent(plan->plancxt, CacheMemoryContext); foreach(lc, plan->plancache_list) { CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc); SaveCachedPlan(plansource); } return 0; }
HeapTuple SPI_modifytuple | ( | Relation | rel, | |
HeapTuple | tuple, | |||
int | natts, | |||
int * | attnum, | |||
Datum * | Values, | |||
const char * | Nulls | |||
) |
Definition at line 734 of file spi.c.
References _SPI_connected, _SPI_curid, elog, ERROR, heap_deform_tuple(), heap_form_tuple(), HeapTupleGetOid, HeapTupleSetOid, i, MemoryContextSwitchTo(), tupleDesc::natts, NULL, palloc(), pfree(), RelationData::rd_att, _SPI_connection::savedcxt, SPI_result, HeapTupleHeaderData::t_ctid, HeapTupleData::t_data, HeapTupleData::t_self, HeapTupleData::t_tableOid, and tupleDesc::tdhasoid.
Referenced by autoinc(), insert_username(), moddatetime(), plperl_modify_tuple(), pltcl_trigger_handler(), PLy_modify_tuple(), timetravel(), tsvector_update_trigger(), and ttdummy().
{ MemoryContext oldcxt = NULL; HeapTuple mtuple; int numberOfAttributes; Datum *v; bool *n; int i; if (rel == NULL || tuple == NULL || natts < 0 || attnum == NULL || Values == NULL) { SPI_result = SPI_ERROR_ARGUMENT; return NULL; } if (_SPI_curid + 1 == _SPI_connected) /* connected */ { if (_SPI_current != &(_SPI_stack[_SPI_curid + 1])) elog(ERROR, "SPI stack corrupted"); oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt); } SPI_result = 0; numberOfAttributes = rel->rd_att->natts; v = (Datum *) palloc(numberOfAttributes * sizeof(Datum)); n = (bool *) palloc(numberOfAttributes * sizeof(bool)); /* fetch old values and nulls */ heap_deform_tuple(tuple, rel->rd_att, v, n); /* replace values and nulls */ for (i = 0; i < natts; i++) { if (attnum[i] <= 0 || attnum[i] > numberOfAttributes) break; v[attnum[i] - 1] = Values[i]; n[attnum[i] - 1] = (Nulls && Nulls[i] == 'n') ? true : false; } if (i == natts) /* no errors in *attnum */ { mtuple = heap_form_tuple(rel->rd_att, v, n); /* * copy the identification info of the old tuple: t_ctid, t_self, and * OID (if any) */ mtuple->t_data->t_ctid = tuple->t_data->t_ctid; mtuple->t_self = tuple->t_self; mtuple->t_tableOid = tuple->t_tableOid; if (rel->rd_att->tdhasoid) HeapTupleSetOid(mtuple, HeapTupleGetOid(tuple)); } else { mtuple = NULL; SPI_result = SPI_ERROR_NOATTRIBUTE; } pfree(v); pfree(n); if (oldcxt) MemoryContextSwitchTo(oldcxt); return mtuple; }
void* SPI_palloc | ( | Size | size | ) |
Definition at line 974 of file spi.c.
References _SPI_connected, _SPI_curid, elog, ERROR, MemoryContextSwitchTo(), palloc(), and _SPI_connection::savedcxt.
Referenced by _SPI_strdup(), and plpgsql_exec_function().
{ MemoryContext oldcxt = NULL; void *pointer; if (_SPI_curid + 1 == _SPI_connected) /* connected */ { if (_SPI_current != &(_SPI_stack[_SPI_curid + 1])) elog(ERROR, "SPI stack corrupted"); oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt); } pointer = palloc(size); if (oldcxt) MemoryContextSwitchTo(oldcxt); return pointer; }
void SPI_pfree | ( | void * | pointer | ) |
CachedPlan* SPI_plan_get_cached_plan | ( | SPIPlanPtr | plan | ) |
Definition at line 1593 of file spi.c.
References _SPI_PLAN_MAGIC, ErrorContextCallback::arg, Assert, ErrorContextCallback::callback, error_context_stack, GetCachedPlan(), CachedPlanSource::gplan, linitial, list_length(), _SPI_plan::magic, NULL, _SPI_plan::oneshot, _SPI_plan::plancache_list, ErrorContextCallback::previous, CachedPlanSource::query_string, and _SPI_plan::saved.
Referenced by exec_eval_simple_expr(), and exec_simple_check_plan().
{ CachedPlanSource *plansource; CachedPlan *cplan; ErrorContextCallback spierrcontext; Assert(plan->magic == _SPI_PLAN_MAGIC); /* Can't support one-shot plans here */ if (plan->oneshot) return NULL; /* Must have exactly one CachedPlanSource */ if (list_length(plan->plancache_list) != 1) return NULL; plansource = (CachedPlanSource *) linitial(plan->plancache_list); /* Setup error traceback support for ereport() */ spierrcontext.callback = _SPI_error_callback; spierrcontext.arg = (void *) plansource->query_string; spierrcontext.previous = error_context_stack; error_context_stack = &spierrcontext; /* Get the generic plan for the query */ cplan = GetCachedPlan(plansource, NULL, plan->saved); Assert(cplan == plansource->gplan); /* Pop the error context stack */ error_context_stack = spierrcontext.previous; return cplan; }
List* SPI_plan_get_plan_sources | ( | SPIPlanPtr | plan | ) |
Definition at line 1577 of file spi.c.
References _SPI_PLAN_MAGIC, Assert, _SPI_plan::magic, and _SPI_plan::plancache_list.
Referenced by exec_simple_check_plan(), and exec_stmt_execsql().
{ Assert(plan->magic == _SPI_PLAN_MAGIC); return plan->plancache_list; }
bool SPI_plan_is_valid | ( | SPIPlanPtr | plan | ) |
Definition at line 1484 of file spi.c.
References _SPI_PLAN_MAGIC, Assert, CachedPlanIsValid(), lfirst, _SPI_plan::magic, and _SPI_plan::plancache_list.
Referenced by ri_FetchPreparedPlan().
{ ListCell *lc; Assert(plan->magic == _SPI_PLAN_MAGIC); foreach(lc, plan->plancache_list) { CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc); if (!CachedPlanIsValid(plansource)) return false; } return true; }
void SPI_pop | ( | void | ) |
Definition at line 303 of file spi.c.
References _SPI_curid.
Referenced by database_to_xml_internal(), exec_eval_simple_expr(), and schema_to_xml_internal().
{ _SPI_curid--; }
void SPI_pop_conditional | ( | bool | pushed | ) |
Definition at line 325 of file spi.c.
References _SPI_connected, _SPI_curid, and Assert.
Referenced by BuildCachedPlan(), InputFunctionCall(), OutputFunctionCall(), ReceiveFunctionCall(), and SendFunctionCall().
{ /* We should be in a state where SPI_connect would succeed */ Assert(_SPI_curid == _SPI_connected); if (pushed) _SPI_curid--; }
SPIPlanPtr SPI_prepare | ( | const char * | src, | |
int | nargs, | |||
Oid * | argtypes | |||
) |
Definition at line 521 of file spi.c.
References SPI_prepare_cursor().
Referenced by check_foreign_key(), check_primary_key(), pg_get_ruledef_worker(), pg_get_viewdef_worker(), plperl_spi_prepare(), plperl_spi_query(), pltcl_SPI_prepare(), PLy_cursor_query(), PLy_spi_prepare(), query_to_xml_and_xmlschema(), query_to_xmlschema(), RI_Initial_Check(), ri_PlanCheck(), timetravel(), ts_stat_sql(), tsquery_rewrite_query(), and ttdummy().
{ return SPI_prepare_cursor(src, nargs, argtypes, 0); }
SPIPlanPtr SPI_prepare_cursor | ( | const char * | src, | |
int | nargs, | |||
Oid * | argtypes, | |||
int | cursorOptions | |||
) |
Definition at line 527 of file spi.c.
References _SPI_begin_call(), _SPI_end_call(), _SPI_make_plan_non_temp(), _SPI_prepare_plan(), _SPI_plan::argtypes, _SPI_plan::cursor_options, _SPI_plan::magic, _SPI_plan::nargs, NULL, _SPI_plan::parserSetup, _SPI_plan::parserSetupArg, and SPI_result.
Referenced by SPI_prepare().
{ _SPI_plan plan; SPIPlanPtr result; if (src == NULL || nargs < 0 || (nargs > 0 && argtypes == NULL)) { SPI_result = SPI_ERROR_ARGUMENT; return NULL; } SPI_result = _SPI_begin_call(true); if (SPI_result < 0) return NULL; memset(&plan, 0, sizeof(_SPI_plan)); plan.magic = _SPI_PLAN_MAGIC; plan.cursor_options = cursorOptions; plan.nargs = nargs; plan.argtypes = argtypes; plan.parserSetup = NULL; plan.parserSetupArg = NULL; _SPI_prepare_plan(src, &plan); /* copy plan to procedure context */ result = _SPI_make_plan_non_temp(&plan); _SPI_end_call(true); return result; }
SPIPlanPtr SPI_prepare_params | ( | const char * | src, | |
ParserSetupHook | parserSetup, | |||
void * | parserSetupArg, | |||
int | cursorOptions | |||
) |
Definition at line 562 of file spi.c.
References _SPI_begin_call(), _SPI_end_call(), _SPI_make_plan_non_temp(), _SPI_prepare_plan(), _SPI_plan::argtypes, _SPI_plan::cursor_options, _SPI_plan::magic, _SPI_plan::nargs, NULL, _SPI_plan::parserSetup, _SPI_plan::parserSetupArg, and SPI_result.
Referenced by exec_prepare_plan().
{ _SPI_plan plan; SPIPlanPtr result; if (src == NULL) { SPI_result = SPI_ERROR_ARGUMENT; return NULL; } SPI_result = _SPI_begin_call(true); if (SPI_result < 0) return NULL; memset(&plan, 0, sizeof(_SPI_plan)); plan.magic = _SPI_PLAN_MAGIC; plan.cursor_options = cursorOptions; plan.nargs = 0; plan.argtypes = NULL; plan.parserSetup = parserSetup; plan.parserSetupArg = parserSetupArg; _SPI_prepare_plan(src, &plan); /* copy plan to procedure context */ result = _SPI_make_plan_non_temp(&plan); _SPI_end_call(true); return result; }
void spi_printtup | ( | TupleTableSlot * | slot, | |
DestReceiver * | self | |||
) |
Definition at line 1678 of file spi.c.
References _SPI_connected, _SPI_curid, SPITupleTable::alloced, elog, ERROR, ExecCopySlotTuple(), SPITupleTable::free, MemoryContextSwitchTo(), NULL, repalloc(), SPITupleTable::tuptabcxt, _SPI_connection::tuptable, and SPITupleTable::vals.
{ SPITupleTable *tuptable; MemoryContext oldcxt; /* * When called by Executor _SPI_curid expected to be equal to * _SPI_connected */ if (_SPI_curid != _SPI_connected || _SPI_connected < 0) elog(ERROR, "improper call to spi_printtup"); if (_SPI_current != &(_SPI_stack[_SPI_curid])) elog(ERROR, "SPI stack corrupted"); tuptable = _SPI_current->tuptable; if (tuptable == NULL) elog(ERROR, "improper call to spi_printtup"); oldcxt = MemoryContextSwitchTo(tuptable->tuptabcxt); if (tuptable->free == 0) { tuptable->free = 256; tuptable->alloced += tuptable->free; tuptable->vals = (HeapTuple *) repalloc(tuptable->vals, tuptable->alloced * sizeof(HeapTuple)); } tuptable->vals[tuptable->alloced - tuptable->free] = ExecCopySlotTuple(slot); (tuptable->free)--; MemoryContextSwitchTo(oldcxt); }
void SPI_push | ( | void | ) |
Definition at line 296 of file spi.c.
References _SPI_curid.
Referenced by database_to_xml_internal(), exec_eval_simple_expr(), and schema_to_xml_internal().
{ _SPI_curid++; }
bool SPI_push_conditional | ( | void | ) |
Definition at line 310 of file spi.c.
References _SPI_connected, _SPI_curid, and Assert.
Referenced by BuildCachedPlan(), InputFunctionCall(), OutputFunctionCall(), ReceiveFunctionCall(), and SendFunctionCall().
{ bool pushed = (_SPI_curid != _SPI_connected); if (pushed) { _SPI_curid++; /* We should now be in a state where SPI_connect would succeed */ Assert(_SPI_curid == _SPI_connected); } return pushed; }
void* SPI_repalloc | ( | void * | pointer, | |
Size | size | |||
) |
Definition at line 995 of file spi.c.
References repalloc().
{ /* No longer need to worry which context chunk was in... */ return repalloc(pointer, size); }
void SPI_restore_connection | ( | void | ) |
Definition at line 335 of file spi.c.
References _SPI_connected, _SPI_curid, and Assert.
Referenced by exec_stmt_block(), plperl_spi_exec(), plperl_spi_exec_prepared(), plperl_spi_fetchrow(), plperl_spi_prepare(), plperl_spi_query(), plperl_spi_query_prepared(), pltcl_subtrans_abort(), pltcl_subtrans_commit(), PLy_abort_open_subtransactions(), PLy_spi_subtransaction_abort(), PLy_spi_subtransaction_commit(), and PLy_subtransaction_exit().
{ Assert(_SPI_connected >= 0); _SPI_curid = _SPI_connected - 1; }
const char* SPI_result_code_string | ( | int | code | ) |
Definition at line 1508 of file spi.c.
References buf, SPI_ERROR_ARGUMENT, SPI_ERROR_CONNECT, SPI_ERROR_COPY, SPI_ERROR_NOATTRIBUTE, SPI_ERROR_NOOUTFUNC, SPI_ERROR_OPUNKNOWN, SPI_ERROR_PARAM, SPI_ERROR_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_REWRITTEN, SPI_OK_SELECT, SPI_OK_SELINTO, SPI_OK_UPDATE, SPI_OK_UPDATE_RETURNING, and SPI_OK_UTILITY.
Referenced by exec_dynquery_with_params(), exec_prepare_plan(), exec_run_select(), exec_stmt_dynexecute(), exec_stmt_execsql(), exec_stmt_forc(), exec_stmt_open(), plperl_modify_tuple(), 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(), and PLy_spi_prepare().
{ static char buf[64]; switch (code) { case SPI_ERROR_CONNECT: return "SPI_ERROR_CONNECT"; case SPI_ERROR_COPY: return "SPI_ERROR_COPY"; case SPI_ERROR_OPUNKNOWN: return "SPI_ERROR_OPUNKNOWN"; case SPI_ERROR_UNCONNECTED: return "SPI_ERROR_UNCONNECTED"; case SPI_ERROR_ARGUMENT: return "SPI_ERROR_ARGUMENT"; case SPI_ERROR_PARAM: return "SPI_ERROR_PARAM"; case SPI_ERROR_TRANSACTION: return "SPI_ERROR_TRANSACTION"; case SPI_ERROR_NOATTRIBUTE: return "SPI_ERROR_NOATTRIBUTE"; case SPI_ERROR_NOOUTFUNC: return "SPI_ERROR_NOOUTFUNC"; case SPI_ERROR_TYPUNKNOWN: return "SPI_ERROR_TYPUNKNOWN"; case SPI_OK_CONNECT: return "SPI_OK_CONNECT"; case SPI_OK_FINISH: return "SPI_OK_FINISH"; case SPI_OK_FETCH: return "SPI_OK_FETCH"; case SPI_OK_UTILITY: return "SPI_OK_UTILITY"; case SPI_OK_SELECT: return "SPI_OK_SELECT"; case SPI_OK_SELINTO: return "SPI_OK_SELINTO"; case SPI_OK_INSERT: return "SPI_OK_INSERT"; case SPI_OK_DELETE: return "SPI_OK_DELETE"; case SPI_OK_UPDATE: return "SPI_OK_UPDATE"; case SPI_OK_CURSOR: return "SPI_OK_CURSOR"; case SPI_OK_INSERT_RETURNING: return "SPI_OK_INSERT_RETURNING"; case SPI_OK_DELETE_RETURNING: return "SPI_OK_DELETE_RETURNING"; case SPI_OK_UPDATE_RETURNING: return "SPI_OK_UPDATE_RETURNING"; case SPI_OK_REWRITTEN: return "SPI_OK_REWRITTEN"; } /* Unrecognized code ... return something useful ... */ sprintf(buf, "Unrecognized SPI code %d", code); return buf; }
HeapTupleHeader SPI_returntuple | ( | HeapTuple | tuple, | |
TupleDesc | tupdesc | |||
) |
Definition at line 697 of file spi.c.
References _SPI_connected, _SPI_curid, assign_record_type_typmod(), elog, ERROR, HeapTupleHeaderSetDatumLength, HeapTupleHeaderSetTypeId, HeapTupleHeaderSetTypMod, MemoryContextSwitchTo(), NULL, palloc(), RECORDOID, _SPI_connection::savedcxt, SPI_result, HeapTupleData::t_data, HeapTupleData::t_len, tupleDesc::tdtypeid, and tupleDesc::tdtypmod.
Referenced by plpgsql_exec_function().
{ MemoryContext oldcxt = NULL; HeapTupleHeader dtup; if (tuple == NULL || tupdesc == NULL) { SPI_result = SPI_ERROR_ARGUMENT; return NULL; } /* For RECORD results, make sure a typmod has been assigned */ if (tupdesc->tdtypeid == RECORDOID && tupdesc->tdtypmod < 0) assign_record_type_typmod(tupdesc); if (_SPI_curid + 1 == _SPI_connected) /* connected */ { if (_SPI_current != &(_SPI_stack[_SPI_curid + 1])) elog(ERROR, "SPI stack corrupted"); oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt); } dtup = (HeapTupleHeader) palloc(tuple->t_len); memcpy((char *) dtup, (char *) tuple->t_data, tuple->t_len); HeapTupleHeaderSetDatumLength(dtup, tuple->t_len); HeapTupleHeaderSetTypeId(dtup, tupdesc->tdtypeid); HeapTupleHeaderSetTypMod(dtup, tupdesc->tdtypmod); if (oldcxt) MemoryContextSwitchTo(oldcxt); return dtup; }
SPIPlanPtr SPI_saveplan | ( | SPIPlanPtr | plan | ) |
Definition at line 626 of file spi.c.
References _SPI_begin_call(), _SPI_end_call(), _SPI_PLAN_MAGIC, _SPI_save_plan(), _SPI_plan::magic, NULL, and SPI_result.
{ SPIPlanPtr newplan; if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC) { SPI_result = SPI_ERROR_ARGUMENT; return NULL; } SPI_result = _SPI_begin_call(false); /* don't change context */ if (SPI_result < 0) return NULL; newplan = _SPI_save_plan(plan); SPI_result = _SPI_end_call(false); return newplan; }
void SPI_scroll_cursor_fetch | ( | Portal | portal, | |
FetchDirection | direction, | |||
long | count | |||
) |
Definition at line 1371 of file spi.c.
References _SPI_cursor_operation(), CreateDestReceiver(), and DestSPI.
Referenced by exec_stmt_fetch().
{ _SPI_cursor_operation(portal, direction, count, CreateDestReceiver(DestSPI)); /* we know that the DestSPI receiver doesn't need a destroy call */ }
void SPI_scroll_cursor_move | ( | Portal | portal, | |
FetchDirection | direction, | |||
long | count | |||
) |
Definition at line 1386 of file spi.c.
References _SPI_cursor_operation(), and None_Receiver.
Referenced by exec_stmt_fetch().
{ _SPI_cursor_operation(portal, direction, count, None_Receiver); }
int _SPI_connected = -1 [static] |
Definition at line 46 of file spi.c.
Referenced by _SPI_begin_call(), AtEOSubXact_SPI(), AtEOXact_SPI(), SPI_connect(), SPI_copytuple(), spi_dest_startup(), SPI_finish(), SPI_modifytuple(), SPI_palloc(), SPI_pop_conditional(), spi_printtup(), SPI_push_conditional(), SPI_restore_connection(), and SPI_returntuple().
int _SPI_curid = -1 [static] |
Definition at line 47 of file spi.c.
Referenced by _SPI_begin_call(), _SPI_end_call(), AtEOSubXact_SPI(), AtEOXact_SPI(), SPI_connect(), SPI_copytuple(), SPI_cursor_open_with_args(), spi_dest_startup(), SPI_finish(), SPI_modifytuple(), SPI_palloc(), SPI_pop(), SPI_pop_conditional(), spi_printtup(), SPI_push(), SPI_push_conditional(), SPI_restore_connection(), and SPI_returntuple().
_SPI_connection* _SPI_current = NULL [static] |
_SPI_connection* _SPI_stack = NULL [static] |
int _SPI_stack_depth = 0 [static] |
Definition at line 45 of file spi.c.
Referenced by AtEOXact_SPI(), and SPI_connect().
Oid SPI_lastoid = InvalidOid |
Definition at line 39 of file spi.c.
Referenced by _SPI_execute_plan(), AtEOSubXact_SPI(), AtEOXact_SPI(), exec_run_select(), exec_stmt_dynexecute(), exec_stmt_execsql(), pltcl_SPI_lastoid(), and SPI_finish().
uint32 SPI_processed = 0 |
Definition at line 38 of file spi.c.
Referenced by _SPI_cursor_operation(), _SPI_execute_plan(), AtEOSubXact_SPI(), AtEOXact_SPI(), build_tuplestore_recursively(), check_foreign_key(), check_primary_key(), crosstab(), cursor_to_xml(), exec_for_query(), exec_run_select(), exec_stmt_dynexecute(), exec_stmt_execsql(), exec_stmt_fetch(), exec_stmt_return_query(), funny_dup17(), get_crosstab_tuplestore(), get_tuple_of_interest(), initialize_worker_spi(), load_categories_hash(), pg_get_ruledef_worker(), pg_get_viewdef_worker(), plperl_spi_exec(), plperl_spi_exec_prepared(), plperl_spi_fetchrow(), pltcl_init_load_unknown(), pltcl_SPI_execute(), pltcl_SPI_execute_plan(), PLy_cursor_fetch(), PLy_cursor_iternext(), PLy_spi_execute_plan(), PLy_spi_execute_query(), query_to_oid_list(), query_to_xml_internal(), RI_Initial_Check(), ri_PerformCheck(), SPI_cursor_open_internal(), SPI_finish(), ts_stat_sql(), tsquery_rewrite_query(), worker_spi_main(), and xpath_table().
int SPI_result |
Definition at line 41 of file spi.c.
Referenced by autoinc(), check_foreign_key(), check_primary_key(), exec_dynquery_with_params(), exec_prepare_plan(), exec_run_select(), exec_stmt_forc(), exec_stmt_open(), insert_username(), moddatetime(), plperl_modify_tuple(), plperl_spi_prepare(), plperl_spi_query(), plperl_spi_query_prepared(), pltcl_trigger_handler(), PLy_cursor_plan(), PLy_cursor_query(), PLy_modify_tuple(), PLy_spi_prepare(), RI_Initial_Check(), ri_PlanCheck(), SPI_copytuple(), SPI_cursor_open_with_args(), SPI_fname(), SPI_getargcount(), SPI_getargtypeid(), SPI_getbinval(), SPI_gettype(), SPI_gettypeid(), SPI_getvalue(), SPI_is_cursor_plan(), SPI_modifytuple(), SPI_prepare_cursor(), SPI_prepare_params(), SPI_returntuple(), SPI_saveplan(), timetravel(), tsvector_update_trigger(), and ttdummy().
SPITupleTable* SPI_tuptable = NULL |
Definition at line 40 of file spi.c.
Referenced by build_tuplestore_recursively(), crosstab(), exec_for_query(), exec_run_select(), exec_stmt_dynexecute(), exec_stmt_execsql(), exec_stmt_fetch(), exec_stmt_return_query(), funny_dup17(), get_crosstab_tuplestore(), get_tuple_of_interest(), initialize_worker_spi(), load_categories_hash(), pg_get_ruledef_worker(), pg_get_viewdef_worker(), plperl_spi_exec(), plperl_spi_exec_prepared(), plperl_spi_fetchrow(), pltcl_init_load_unknown(), pltcl_SPI_execute(), pltcl_SPI_execute_plan(), PLy_cursor_fetch(), PLy_cursor_iternext(), PLy_spi_execute_plan(), PLy_spi_execute_query(), query_to_oid_list(), RI_Initial_Check(), SPI_sql_row_to_xmlelement(), ts_stat_sql(), tsquery_rewrite_query(), worker_spi_main(), and xpath_table().