function if you want to execute commands through SPI. Some utility
SPI functions can be called from unconnected procedures.
</para>
-
- <para>
- If your procedure is already connected,
- <function>SPI_connect</function> will return the error code
- <returnvalue>SPI_ERROR_CONNECT</returnvalue>. This could happen if
- a procedure that has called <function>SPI_connect</function>
- directly calls another procedure that calls
- <function>SPI_connect</function>. While recursive calls to the
- <acronym>SPI</acronym> manager are permitted when an SQL command
- called through SPI invokes another function that uses
- <acronym>SPI</acronym>, directly nested calls to
- <function>SPI_connect</function> and
- <function>SPI_finish</function> are forbidden.
- (But see <function>SPI_push</function> and <function>SPI_pop</function>.)
- </para>
</refsect1>
<refsect1>
abort the transaction via <literal>elog(ERROR)</literal>. In that
case SPI will clean itself up automatically.
</para>
-
- <para>
- If <function>SPI_finish</function> is called without having a valid
- connection, it will return <symbol>SPI_ERROR_UNCONNECTED</symbol>.
- There is no fundamental problem with this; it means that the SPI
- manager has nothing to do.
- </para>
</refsect1>
<refsect1>
<!-- *********************************************** -->
-<refentry id="spi-spi-push">
- <indexterm><primary>SPI_push</primary></indexterm>
-
- <refmeta>
- <refentrytitle>SPI_push</refentrytitle>
- <manvolnum>3</manvolnum>
- </refmeta>
-
- <refnamediv>
- <refname>SPI_push</refname>
- <refpurpose>push SPI stack to allow recursive SPI usage</refpurpose>
- </refnamediv>
-
- <refsynopsisdiv>
-<synopsis>
-void SPI_push(void)
-</synopsis>
- </refsynopsisdiv>
-
- <refsect1>
- <title>Description</title>
-
- <para>
- <function>SPI_push</function> should be called before executing another
- procedure that might itself wish to use SPI.
- After <function>SPI_push</function>, SPI is no longer in a
- <quote>connected</> state, and SPI function calls will be rejected unless
- a fresh <function>SPI_connect</function> is done. This ensures a clean
- separation between your procedure's SPI state and that of another procedure
- you call. After the other procedure returns, call
- <function>SPI_pop</function> to restore access to your own SPI state.
- </para>
-
- <para>
- Note that <function>SPI_execute</function> and related functions
- automatically do the equivalent of <function>SPI_push</function> before
- passing control back to the SQL execution engine, so it is not necessary
- for you to worry about this when using those functions.
- Only when you are directly calling arbitrary code that might contain
- <function>SPI_connect</function> calls do you need to issue
- <function>SPI_push</function> and <function>SPI_pop</function>.
- </para>
- </refsect1>
-
-</refentry>
-
-<!-- *********************************************** -->
-
-<refentry id="spi-spi-pop">
- <indexterm><primary>SPI_pop</primary></indexterm>
-
- <refmeta>
- <refentrytitle>SPI_pop</refentrytitle>
- <manvolnum>3</manvolnum>
- </refmeta>
-
- <refnamediv>
- <refname>SPI_pop</refname>
- <refpurpose>pop SPI stack to return from recursive SPI usage</refpurpose>
- </refnamediv>
-
- <refsynopsisdiv>
-<synopsis>
-void SPI_pop(void)
-</synopsis>
- </refsynopsisdiv>
-
- <refsect1>
- <title>Description</title>
-
- <para>
- <function>SPI_pop</function> pops the previous environment from the
- SPI call stack. See <function>SPI_push</function>.
- </para>
- </refsect1>
-
-</refentry>
-
-<!-- *********************************************** -->
-
<refentry id="spi-spi-execute">
<indexterm><primary>SPI_execute</primary></indexterm>
<quote>upper executor context</quote>, that is, the memory context
that was current when <function>SPI_connect</function> was called,
which is precisely the right context for a value returned from your
- procedure.
- </para>
-
- <para>
- If <function>SPI_palloc</function> is called while the procedure is
- not connected to SPI, then it acts the same as a normal
- <function>palloc</function>. Before a procedure connects to the
- SPI manager, the current memory context is the upper executor
- context, so all allocations made by the procedure via
- <function>palloc</function> or by SPI utility functions are made in
- this context.
+ procedure. Several of the other utility procedures described in
+ this section also return objects created in the upper executor context.
</para>
<para>
context of the procedure, which is created by
<function>SPI_connect</function>, is made the current context. All
allocations made by <function>palloc</function>,
- <function>repalloc</function>, or SPI utility functions (except for
- <function>SPI_copytuple</function>,
- <function>SPI_returntuple</function>,
- <function>SPI_modifytuple</function>,
- <function>SPI_palloc</function>, and
- <function>SPI_datumTransfer</function>) are made in this context. When a
+ <function>repalloc</function>, or SPI utility functions (except as
+ described in this section) are made in this context. When a
procedure disconnects from the SPI manager (via
<function>SPI_finish</function>) the current context is restored to
the upper executor context, and all allocations made in the
procedure memory context are freed and cannot be used any more.
</para>
- <para>
- All functions described in this section can be used by both
- connected and unconnected procedures. In an unconnected procedure,
- they act the same as the underlying ordinary server functions
- (<function>palloc</>, etc.).
- </para>
-
<!-- *********************************************** -->
<refentry id="spi-spi-palloc">
<function>SPI_palloc</function> allocates memory in the upper
executor context.
</para>
+
+ <para>
+ This function can only be used while connected to SPI.
+ Otherwise, it throws an error.
+ </para>
</refsect1>
<refsect1>
row from a trigger. In a function declared to return a composite
type, use <function>SPI_returntuple</function> instead.
</para>
+
+ <para>
+ This function can only be used while connected to SPI.
+ Otherwise, it returns NULL and sets <varname>SPI_result</varname> to
+ <symbol>SPI_ERROR_UNCONNECTED</symbol>.
+ </para>
</refsect1>
<refsect1>
<title>Return Value</title>
<para>
- the copied row; <symbol>NULL</symbol> only if
- <parameter>tuple</parameter> is <symbol>NULL</symbol>
+ the copied row, or <symbol>NULL</symbol> on error
+ (see <varname>SPI_result</varname> for an error indication)
</para>
</refsect1>
</refentry>
before returning.
</para>
+ <para>
+ This function can only be used while connected to SPI.
+ Otherwise, it returns NULL and sets <varname>SPI_result</varname> to
+ <symbol>SPI_ERROR_UNCONNECTED</symbol>.
+ </para>
+
<para>
Note that this should be used for functions that are declared to return
composite types. It is not used for triggers; use
<title>Return Value</title>
<para>
- <type>HeapTupleHeader</type> pointing to copied row;
- <symbol>NULL</symbol> only if
- <parameter>row</parameter> or <parameter>rowdesc</parameter> is
- <symbol>NULL</symbol>
+ <type>HeapTupleHeader</type> pointing to copied row,
+ or <symbol>NULL</symbol> on error
+ (see <varname>SPI_result</varname> for an error indication)
</para>
</refsect1>
</refentry>
<function>SPI_modifytuple</function> creates a new row by
substituting new values for selected columns, copying the original
row's columns at other positions. The input row is not modified.
+ The new row is returned in the upper executor context.
+ </para>
+
+ <para>
+ This function can only be used while connected to SPI.
+ Otherwise, it returns NULL and sets <varname>SPI_result</varname> to
+ <symbol>SPI_ERROR_UNCONNECTED</symbol>.
</para>
</refsect1>
<para>
new row with modifications, allocated in the upper executor
- context; <symbol>NULL</symbol> only if <parameter>row</parameter>
- is <symbol>NULL</symbol>
+ context, or <symbol>NULL</symbol> on error
+ (see <varname>SPI_result</varname> for an error indication)
</para>
<para>
<listitem>
<para>
if <parameter>colnum</> contains an invalid column number (less
- than or equal to 0 or greater than the number of column in
+ than or equal to 0 or greater than the number of columns in
<parameter>row</>)
</para>
</listitem>
</varlistentry>
+
+ <varlistentry>
+ <term><symbol>SPI_ERROR_UNCONNECTED</symbol></term>
+ <listitem>
+ <para>
+ if SPI is not active
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</para>
</refsect1>
static _SPI_connection *_SPI_stack = NULL;
static _SPI_connection *_SPI_current = NULL;
static int _SPI_stack_depth = 0; /* allocated size of _SPI_stack */
-static int _SPI_connected = -1;
-static int _SPI_curid = -1;
+static int _SPI_connected = -1; /* current stack index */
static Portal SPI_cursor_open_internal(const char *name, SPIPlanPtr plan,
ParamListInfo paramLI, bool read_only);
{
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;
-
+ /* Enlarge stack if necessary */
if (_SPI_stack == NULL)
{
if (_SPI_connected != -1 || _SPI_stack_depth != 0)
}
}
- /*
- * We're entering procedure where _SPI_curid == _SPI_connected - 1
- */
+ /* Enter new stack level */
_SPI_connected++;
Assert(_SPI_connected >= 0 && _SPI_connected < _SPI_stack_depth);
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.
- */
+ /* Exit stack level */
_SPI_connected--;
- _SPI_curid--;
- if (_SPI_connected == -1)
+ if (_SPI_connected < 0)
_SPI_current = NULL;
else
_SPI_current = &(_SPI_stack[_SPI_connected]);
_SPI_current = _SPI_stack = NULL;
_SPI_stack_depth = 0;
- _SPI_connected = _SPI_curid = -1;
+ _SPI_connected = -1;
SPI_processed = 0;
SPI_lastoid = InvalidOid;
SPI_tuptable = NULL;
* be already gone.
*/
_SPI_connected--;
- _SPI_curid = _SPI_connected;
- if (_SPI_connected == -1)
+ if (_SPI_connected < 0)
_SPI_current = NULL;
else
_SPI_current = &(_SPI_stack[_SPI_connected]);
}
-/* Pushes SPI stack to allow recursive SPI calls */
-void
-SPI_push(void)
-{
- _SPI_curid++;
-}
-
-/* Pops SPI stack to allow recursive SPI calls */
-void
-SPI_pop(void)
-{
- _SPI_curid--;
-}
-
-/* Conditional push: push only if we're inside a SPI procedure */
-bool
-SPI_push_conditional(void)
-{
- 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;
-}
-
-/* Conditional pop: pop only if SPI_push_conditional pushed */
-void
-SPI_pop_conditional(bool pushed)
-{
- /* We should be in a state where SPI_connect would succeed */
- Assert(_SPI_curid == _SPI_connected);
- if (pushed)
- _SPI_curid--;
-}
-
-/* Restore state of SPI stack after aborting a subtransaction */
-void
-SPI_restore_connection(void)
-{
- Assert(_SPI_connected >= 0);
- _SPI_curid = _SPI_connected - 1;
-}
-
/* Parse, plan, and execute a query string */
int
SPI_execute(const char *src, bool read_only, long tcount)
HeapTuple
SPI_copytuple(HeapTuple tuple)
{
- MemoryContext oldcxt = NULL;
+ MemoryContext oldcxt;
HeapTuple ctuple;
if (tuple == NULL)
return NULL;
}
- if (_SPI_curid + 1 == _SPI_connected) /* connected */
+ if (_SPI_current == NULL)
{
- if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
- elog(ERROR, "SPI stack corrupted");
- oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
+ SPI_result = SPI_ERROR_UNCONNECTED;
+ return NULL;
}
+ oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
+
ctuple = heap_copytuple(tuple);
- if (oldcxt)
- MemoryContextSwitchTo(oldcxt);
+ MemoryContextSwitchTo(oldcxt);
return ctuple;
}
HeapTupleHeader
SPI_returntuple(HeapTuple tuple, TupleDesc tupdesc)
{
- MemoryContext oldcxt = NULL;
+ MemoryContext oldcxt;
HeapTupleHeader dtup;
if (tuple == NULL || tupdesc == NULL)
return NULL;
}
+ if (_SPI_current == NULL)
+ {
+ SPI_result = SPI_ERROR_UNCONNECTED;
+ 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);
- }
+ oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
dtup = DatumGetHeapTupleHeader(heap_copy_tuple_as_datum(tuple, tupdesc));
- if (oldcxt)
- MemoryContextSwitchTo(oldcxt);
+ MemoryContextSwitchTo(oldcxt);
return dtup;
}
SPI_modifytuple(Relation rel, HeapTuple tuple, int natts, int *attnum,
Datum *Values, const char *Nulls)
{
- MemoryContext oldcxt = NULL;
+ MemoryContext oldcxt;
HeapTuple mtuple;
int numberOfAttributes;
Datum *v;
return NULL;
}
- if (_SPI_curid + 1 == _SPI_connected) /* connected */
+ if (_SPI_current == NULL)
{
- if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
- elog(ERROR, "SPI stack corrupted");
- oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
+ SPI_result = SPI_ERROR_UNCONNECTED;
+ return NULL;
}
+
+ 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));
pfree(v);
pfree(n);
- if (oldcxt)
- MemoryContextSwitchTo(oldcxt);
+ MemoryContextSwitchTo(oldcxt);
return mtuple;
}
void *
SPI_palloc(Size size)
{
- 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);
+ if (_SPI_current == NULL)
+ elog(ERROR, "SPI_palloc called while not connected to SPI");
- return pointer;
+ return MemoryContextAlloc(_SPI_current->savedcxt, size);
}
void *
Datum
SPI_datumTransfer(Datum value, bool typByVal, int typLen)
{
- MemoryContext oldcxt = NULL;
+ MemoryContext oldcxt;
Datum result;
- 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);
- }
+ if (_SPI_current == NULL)
+ elog(ERROR, "SPI_datumTransfer called while not connected to SPI");
+
+ oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
result = datumTransfer(value, typByVal, typLen);
- if (oldcxt)
- MemoryContextSwitchTo(oldcxt);
+ MemoryContextSwitchTo(oldcxt);
return result;
}
return;
/*
- * Since this function might be called during error recovery, it seems
- * best not to insist that the caller be actively connected. We just
- * search the topmost SPI context, connected or not.
+ * Search only the topmost SPI context for a matching tuple table.
*/
- if (_SPI_connected >= 0)
+ if (_SPI_current != NULL)
{
slist_mutable_iter siter;
- if (_SPI_current != &(_SPI_stack[_SPI_connected]))
- elog(ERROR, "SPI stack corrupted");
-
/* find tuptable in active list, then remove it */
slist_foreach_modify(siter, &_SPI_current->tuptables)
{
/* 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;
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 == NULL)
+ elog(ERROR, "spi_dest_startup called while not connected to SPI");
if (_SPI_current->tuptable != NULL)
elog(ERROR, "improper call to spi_dest_startup");
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");
+ if (_SPI_current == NULL)
+ elog(ERROR, "spi_printtup called while not connected to SPI");
tuptable = _SPI_current->tuptable;
if (tuptable == NULL)
static int
_SPI_begin_call(bool execmem)
{
- if (_SPI_curid + 1 != _SPI_connected)
+ if (_SPI_current == NULL)
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();
static int
_SPI_end_call(bool procmem)
{
- /*
- * We're returning to procedure where _SPI_curid == _SPI_connected - 1
- */
- _SPI_curid--;
-
if (procmem) /* switch to the procedure memory context */
{
_SPI_procmem();
relid_list = schema_get_xml_visible_tables(nspid);
- SPI_push();
-
foreach(cell, relid_list)
{
Oid relid = lfirst_oid(cell);
appendStringInfoChar(result, '\n');
}
- SPI_pop();
SPI_finish();
xmldata_root_element_end(result, xmlsn);
nspid_list = database_get_xml_visible_schemas();
- SPI_push();
-
foreach(cell, nspid_list)
{
Oid nspid = lfirst_oid(cell);
appendStringInfoChar(result, '\n');
}
- SPI_pop();
SPI_finish();
xmldata_root_element_end(result, xmlcn);
#include "access/transam.h"
#include "catalog/namespace.h"
#include "executor/executor.h"
-#include "executor/spi.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/cost.h"
CachedPlan *plan;
List *plist;
bool snapshot_set;
- bool spi_pushed;
bool is_transient;
MemoryContext plan_context;
MemoryContext oldcxt = CurrentMemoryContext;
snapshot_set = true;
}
- /*
- * The planner may try to call SPI-using functions, which causes a problem
- * if we're already inside one. Rather than expect all SPI-using code to
- * do SPI_push whenever a replan could happen, it seems best to take care
- * of the case here.
- */
- spi_pushed = SPI_push_conditional();
-
/*
* Generate the plan.
*/
plist = pg_plan_queries(qlist, plansource->cursor_options, boundParams);
- /* Clean up SPI state */
- SPI_pop_conditional(spi_pushed);
-
/* Release snapshot if we got one */
if (snapshot_set)
PopActiveSnapshot();
#include "catalog/pg_language.h"
#include "catalog/pg_proc.h"
#include "executor/functions.h"
-#include "executor/spi.h"
#include "lib/stringinfo.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
* the caller should assume the result is NULL, but we'll call the input
* function anyway if it's not strict. So this is almost but not quite
* the same as FunctionCall3.
- *
- * One important difference from the bare function call is that we will
- * push any active SPI context, allowing SPI-using I/O functions to be
- * called from other SPI functions without extra notation. This is a hack,
- * but the alternative of expecting all SPI functions to do SPI_push/SPI_pop
- * around I/O calls seems worse.
*/
Datum
InputFunctionCall(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod)
{
FunctionCallInfoData fcinfo;
Datum result;
- bool pushed;
if (str == NULL && flinfo->fn_strict)
return (Datum) 0; /* just return null result */
- pushed = SPI_push_conditional();
-
InitFunctionCallInfoData(fcinfo, flinfo, 3, InvalidOid, NULL, NULL);
fcinfo.arg[0] = CStringGetDatum(str);
fcinfo.flinfo->fn_oid);
}
- SPI_pop_conditional(pushed);
-
return result;
}
*
* Do not call this on NULL datums.
*
- * This is almost just window dressing for FunctionCall1, but it includes
- * SPI context pushing for the same reasons as InputFunctionCall.
+ * This is currently little more than window dressing for FunctionCall1.
*/
char *
OutputFunctionCall(FmgrInfo *flinfo, Datum val)
{
- char *result;
- bool pushed;
-
- pushed = SPI_push_conditional();
-
- result = DatumGetCString(FunctionCall1(flinfo, val));
-
- SPI_pop_conditional(pushed);
-
- return result;
+ return DatumGetCString(FunctionCall1(flinfo, val));
}
/*
* "buf" may be NULL to indicate we are reading a NULL. In this case
* the caller should assume the result is NULL, but we'll call the receive
* function anyway if it's not strict. So this is almost but not quite
- * the same as FunctionCall3. Also, this includes SPI context pushing for
- * the same reasons as InputFunctionCall.
+ * the same as FunctionCall3.
*/
Datum
ReceiveFunctionCall(FmgrInfo *flinfo, StringInfo buf,
{
FunctionCallInfoData fcinfo;
Datum result;
- bool pushed;
if (buf == NULL && flinfo->fn_strict)
return (Datum) 0; /* just return null result */
- pushed = SPI_push_conditional();
-
InitFunctionCallInfoData(fcinfo, flinfo, 3, InvalidOid, NULL, NULL);
fcinfo.arg[0] = PointerGetDatum(buf);
fcinfo.flinfo->fn_oid);
}
- SPI_pop_conditional(pushed);
-
return result;
}
*
* This is little more than window dressing for FunctionCall1, but it does
* guarantee a non-toasted result, which strictly speaking the underlying
- * function doesn't. Also, this includes SPI context pushing for the same
- * reasons as InputFunctionCall.
+ * function doesn't.
*/
bytea *
SendFunctionCall(FmgrInfo *flinfo, Datum val)
{
- bytea *result;
- bool pushed;
-
- pushed = SPI_push_conditional();
-
- result = DatumGetByteaP(FunctionCall1(flinfo, val));
-
- SPI_pop_conditional(pushed);
-
- return result;
+ return DatumGetByteaP(FunctionCall1(flinfo, val));
}
/*
#define SPI_OK_UPDATE_RETURNING 13
#define SPI_OK_REWRITTEN 14
+/* These used to be functions, now just no-ops for backwards compatibility */
+#define SPI_push() ((void) 0)
+#define SPI_pop() ((void) 0)
+#define SPI_push_conditional() false
+#define SPI_pop_conditional(pushed) ((void) 0)
+#define SPI_restore_connection() ((void) 0)
+
extern PGDLLIMPORT uint64 SPI_processed;
extern PGDLLIMPORT Oid SPI_lastoid;
extern PGDLLIMPORT SPITupleTable *SPI_tuptable;
extern int SPI_connect(void);
extern int SPI_finish(void);
-extern void SPI_push(void);
-extern void SPI_pop(void);
-extern bool SPI_push_conditional(void);
-extern void SPI_pop_conditional(bool pushed);
-extern void SPI_restore_connection(void);
extern int SPI_execute(const char *src, bool read_only, long tcount);
extern int SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls,
bool read_only, long tcount);
ReleaseCurrentSubTransaction();
MemoryContextSwitchTo(oldcontext);
CurrentResourceOwner = oldowner;
-
- /*
- * AtEOSubXact_SPI() should not have popped any SPI context, but just
- * in case it did, make sure we remain connected.
- */
- SPI_restore_connection();
}
PG_CATCH();
{
MemoryContextSwitchTo(oldcontext);
CurrentResourceOwner = oldowner;
- /*
- * If AtEOSubXact_SPI() popped any SPI context of the subxact, it will
- * have left us in a disconnected state. We need this hack to return
- * to connected state.
- */
- SPI_restore_connection();
-
/* Punt the error to Perl */
croak_cstr(edata->message);
ReleaseCurrentSubTransaction();
MemoryContextSwitchTo(oldcontext);
CurrentResourceOwner = oldowner;
-
- /*
- * AtEOSubXact_SPI() should not have popped any SPI context, but just
- * in case it did, make sure we remain connected.
- */
- SPI_restore_connection();
}
PG_CATCH();
{
MemoryContextSwitchTo(oldcontext);
CurrentResourceOwner = oldowner;
- /*
- * If AtEOSubXact_SPI() popped any SPI context of the subxact, it will
- * have left us in a disconnected state. We need this hack to return
- * to connected state.
- */
- SPI_restore_connection();
-
/* Punt the error to Perl */
croak_cstr(edata->message);
ReleaseCurrentSubTransaction();
MemoryContextSwitchTo(oldcontext);
CurrentResourceOwner = oldowner;
-
- /*
- * AtEOSubXact_SPI() should not have popped any SPI context, but just
- * in case it did, make sure we remain connected.
- */
- SPI_restore_connection();
}
PG_CATCH();
{
MemoryContextSwitchTo(oldcontext);
CurrentResourceOwner = oldowner;
- /*
- * If AtEOSubXact_SPI() popped any SPI context of the subxact, it will
- * have left us in a disconnected state. We need this hack to return
- * to connected state.
- */
- SPI_restore_connection();
-
/* Punt the error to Perl */
croak_cstr(edata->message);
ReleaseCurrentSubTransaction();
MemoryContextSwitchTo(oldcontext);
CurrentResourceOwner = oldowner;
-
- /*
- * AtEOSubXact_SPI() should not have popped any SPI context, but just
- * in case it did, make sure we remain connected.
- */
- SPI_restore_connection();
}
PG_CATCH();
{
MemoryContextSwitchTo(oldcontext);
CurrentResourceOwner = oldowner;
- /*
- * If AtEOSubXact_SPI() popped any SPI context of the subxact, it will
- * have left us in a disconnected state. We need this hack to return
- * to connected state.
- */
- SPI_restore_connection();
-
/* Punt the error to Perl */
croak_cstr(edata->message);
ReleaseCurrentSubTransaction();
MemoryContextSwitchTo(oldcontext);
CurrentResourceOwner = oldowner;
-
- /*
- * AtEOSubXact_SPI() should not have popped any SPI context, but just
- * in case it did, make sure we remain connected.
- */
- SPI_restore_connection();
}
PG_CATCH();
{
MemoryContextSwitchTo(oldcontext);
CurrentResourceOwner = oldowner;
- /*
- * If AtEOSubXact_SPI() popped any SPI context of the subxact, it will
- * have left us in a disconnected state. We need this hack to return
- * to connected state.
- */
- SPI_restore_connection();
-
/* Punt the error to Perl */
croak_cstr(edata->message);
ReleaseCurrentSubTransaction();
MemoryContextSwitchTo(oldcontext);
CurrentResourceOwner = oldowner;
-
- /*
- * AtEOSubXact_SPI() should not have popped any SPI context, but just
- * in case it did, make sure we remain connected.
- */
- SPI_restore_connection();
}
PG_CATCH();
{
MemoryContextSwitchTo(oldcontext);
CurrentResourceOwner = oldowner;
- /*
- * If AtEOSubXact_SPI() popped any SPI context of the subxact, it will
- * have left us in a disconnected state. We need this hack to return
- * to connected state.
- */
- SPI_restore_connection();
-
/* Punt the error to Perl */
croak_cstr(edata->message);
* automatically cleaned up during subxact exit.)
*/
estate->eval_econtext = old_eval_econtext;
-
- /*
- * AtEOSubXact_SPI() should not have popped any SPI context, but
- * just in case it did, make sure we remain connected.
- */
- SPI_restore_connection();
}
PG_CATCH();
{
/* Revert to outer eval_econtext */
estate->eval_econtext = old_eval_econtext;
- /*
- * If AtEOSubXact_SPI() popped any SPI context of the subxact, it
- * will have left us in a disconnected state. We need this hack
- * to return to connected state.
- */
- SPI_restore_connection();
-
/*
* Must clean up the econtext too. However, any tuple table made
* in the subxact will have been thrown away by SPI during subxact
* Without this, stable functions within the expression would fail to see
* updates made so far by our own function.
*/
- SPI_push();
-
oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
if (!estate->readonly_func)
{
MemoryContextSwitchTo(oldcontext);
- SPI_pop();
-
/*
* Now we can release our refcount on the cached plan.
*/
ExprContext *econtext = estate->eval_econtext;
MemoryContext oldcontext;
- SPI_push();
-
oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
econtext->caseValue_datum = value;
cast_entry->cast_in_use = false;
MemoryContextSwitchTo(oldcontext);
-
- SPI_pop();
}
}
RollbackAndReleaseCurrentSubTransaction();
- SPI_restore_connection();
-
subtransactiondata = (PLySubtransactionData *) linitial(explicit_subtransactions);
explicit_subtransactions = list_delete_first(explicit_subtransactions);
ReleaseCurrentSubTransaction();
MemoryContextSwitchTo(oldcontext);
CurrentResourceOwner = oldowner;
-
- /*
- * AtEOSubXact_SPI() should not have popped any SPI context, but just in
- * case it did, make sure we remain connected.
- */
- SPI_restore_connection();
}
void
MemoryContextSwitchTo(oldcontext);
CurrentResourceOwner = oldowner;
- /*
- * If AtEOSubXact_SPI() popped any SPI context of the subxact, it will
- * have left us in a disconnected state. We need this hack to return to
- * connected state.
- */
- SPI_restore_connection();
-
/* Look up the correct exception */
entry = hash_search(PLy_spi_exceptions, &(edata->sqlerrcode),
HASH_FIND, NULL);
#include "postgres.h"
#include "access/xact.h"
-#include "executor/spi.h"
#include "utils/memutils.h"
#include "plpython.h"
CurrentResourceOwner = subxactdata->oldowner;
pfree(subxactdata);
- /*
- * AtEOSubXact_SPI() should not have popped any SPI context, but just in
- * case it did, make sure we remain connected.
- */
- SPI_restore_connection();
-
Py_INCREF(Py_None);
return Py_None;
}
{
HeapTuple tuple;
- SPI_push();
tuple = pltcl_build_tuple_result(interp, rowObjv, rowObjc,
call_state);
tuplestore_puttuple(call_state->tuple_store, tuple);
- SPI_pop();
}
}
else
ReleaseCurrentSubTransaction();
MemoryContextSwitchTo(oldcontext);
CurrentResourceOwner = oldowner;
-
- /*
- * AtEOSubXact_SPI() should not have popped any SPI context, but just in
- * case it did, make sure we remain connected.
- */
- SPI_restore_connection();
}
static void
MemoryContextSwitchTo(oldcontext);
CurrentResourceOwner = oldowner;
- /*
- * If AtEOSubXact_SPI() popped any SPI context of the subxact, it will
- * have left us in a disconnected state. We need this hack to return to
- * connected state.
- */
- SPI_restore_connection();
-
/* Pass the error data to Tcl */
pltcl_construct_errorCode(interp, edata);
UTF_BEGIN;
* mess, there's no way to prevent the datatype input functions it calls
* from leaking. Run it in a short-lived context, unless we're about to
* exit the procedure anyway.
- *
- * Also, caller is responsible for doing SPI_push/SPI_pop if calling from
- * inside SPI environment.
**********************************************************************/
static HeapTuple
pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,