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