Header And Logo

PostgreSQL
| The world's most advanced open source database.

Functions | Variables

spi.c File Reference

#include "postgres.h"
#include "access/htup_details.h"
#include "access/printtup.h"
#include "access/sysattr.h"
#include "access/xact.h"
#include "catalog/heap.h"
#include "catalog/pg_type.h"
#include "commands/trigger.h"
#include "executor/executor.h"
#include "executor/spi_priv.h"
#include "tcop/pquery.h"
#include "tcop/utility.h"
#include "utils/builtins.h"
#include "utils/datum.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/rel.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
#include "utils/typcache.h"
Include dependency graph for spi.c:

Go to the source code of this file.

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)
ListSPI_plan_get_plan_sources (SPIPlanPtr plan)
CachedPlanSPI_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
SPITupleTableSPI_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

Function Documentation

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 = &paramLI->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().

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;
}

static int _SPI_pquery ( QueryDesc queryDesc,
bool  fire_triggers,
long  tcount 
) [static]

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

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;
}

HeapTuple SPI_copytuple ( HeapTuple  tuple  ) 

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  ) 
void SPI_cursor_fetch ( Portal  portal,
bool  forward,
long  count 
)
Portal SPI_cursor_find ( const char *  name  ) 
void SPI_cursor_move ( Portal  portal,
bool  forward,
long  count 
)

Definition at line 1357 of file spi.c.

References _SPI_cursor_operation(), FETCH_BACKWARD, FETCH_FORWARD, and 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 
)
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  ) 
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];
}

Datum SPI_getbinval ( HeapTuple  tuple,
TupleDesc  tupdesc,
int  fnumber,
bool isnull 
)
char* SPI_getnspname ( Relation  rel  ) 
char* SPI_getrelname ( Relation  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;
}

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

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  ) 

Definition at line 1002 of file spi.c.

References pfree().

{
    /* No longer need to worry which context chunk was in... */
    pfree(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 
)
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   ) 
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);
}


Variable Documentation

int _SPI_connected = -1 [static]
int _SPI_curid = -1 [static]
_SPI_connection* _SPI_current = NULL [static]

Definition at line 44 of file spi.c.

_SPI_connection* _SPI_stack = NULL [static]

Definition at line 43 of file spi.c.

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