diff --git a/doc/src/sgml/spi.sgml b/doc/src/sgml/spi.sgml index 39133c9038..836ce0822f 100644 --- a/doc/src/sgml/spi.sgml +++ b/doc/src/sgml/spi.sgml @@ -90,21 +90,6 @@ int SPI_connect(void) function if you want to execute commands through SPI. Some utility SPI functions can be called from unconnected procedures. - - - If your procedure is already connected, - SPI_connect will return the error code - SPI_ERROR_CONNECT. This could happen if - a procedure that has called SPI_connect - directly calls another procedure that calls - SPI_connect. While recursive calls to the - SPI manager are permitted when an SQL command - called through SPI invokes another function that uses - SPI, directly nested calls to - SPI_connect and - SPI_finish are forbidden. - (But see SPI_push and SPI_pop.) - @@ -164,13 +149,6 @@ int SPI_finish(void) abort the transaction via elog(ERROR). In that case SPI will clean itself up automatically. - - - If SPI_finish is called without having a valid - connection, it will return SPI_ERROR_UNCONNECTED. - There is no fundamental problem with this; it means that the SPI - manager has nothing to do. - @@ -200,86 +178,6 @@ int SPI_finish(void) - - SPI_push - - - SPI_push - 3 - - - - SPI_push - push SPI stack to allow recursive SPI usage - - - - -void SPI_push(void) - - - - - Description - - - SPI_push should be called before executing another - procedure that might itself wish to use SPI. - After SPI_push, SPI is no longer in a - connected state, and SPI function calls will be rejected unless - a fresh SPI_connect 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 - SPI_pop to restore access to your own SPI state. - - - - Note that SPI_execute and related functions - automatically do the equivalent of SPI_push 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 - SPI_connect calls do you need to issue - SPI_push and SPI_pop. - - - - - - - - - SPI_pop - - - SPI_pop - 3 - - - - SPI_pop - pop SPI stack to return from recursive SPI usage - - - - -void SPI_pop(void) - - - - - Description - - - SPI_pop pops the previous environment from the - SPI call stack. See SPI_push. - - - - - - - SPI_execute @@ -3361,17 +3259,8 @@ char * SPI_getnspname(Relation rel) upper executor context, that is, the memory context that was current when SPI_connect was called, which is precisely the right context for a value returned from your - procedure. - - - - If SPI_palloc is called while the procedure is - not connected to SPI, then it acts the same as a normal - palloc. 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 - palloc 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. @@ -3379,25 +3268,14 @@ char * SPI_getnspname(Relation rel) context of the procedure, which is created by SPI_connect, is made the current context. All allocations made by palloc, - repalloc, or SPI utility functions (except for - SPI_copytuple, - SPI_returntuple, - SPI_modifytuple, - SPI_palloc, and - SPI_datumTransfer) are made in this context. When a + repalloc, or SPI utility functions (except as + described in this section) are made in this context. When a procedure disconnects from the SPI manager (via SPI_finish) 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. - - 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 - (palloc, etc.). - - @@ -3426,6 +3304,11 @@ void * SPI_palloc(Size size) SPI_palloc allocates memory in the upper executor context. + + + This function can only be used while connected to SPI. + Otherwise, it throws an error. + @@ -3605,6 +3488,12 @@ HeapTuple SPI_copytuple(HeapTuple row) row from a trigger. In a function declared to return a composite type, use SPI_returntuple instead. + + + This function can only be used while connected to SPI. + Otherwise, it returns NULL and sets SPI_result to + SPI_ERROR_UNCONNECTED. + @@ -3626,8 +3515,8 @@ HeapTuple SPI_copytuple(HeapTuple row) Return Value - the copied row; NULL only if - tuple is NULL + the copied row, or NULL on error + (see SPI_result for an error indication) @@ -3663,6 +3552,12 @@ HeapTupleHeader SPI_returntuple(HeapTuple row, TupleDesc before returning. + + This function can only be used while connected to SPI. + Otherwise, it returns NULL and sets SPI_result to + SPI_ERROR_UNCONNECTED. + + Note that this should be used for functions that are declared to return composite types. It is not used for triggers; use @@ -3699,10 +3594,9 @@ HeapTupleHeader SPI_returntuple(HeapTuple row, TupleDesc Return Value - HeapTupleHeader pointing to copied row; - NULL only if - row or rowdesc is - NULL + HeapTupleHeader pointing to copied row, + or NULL on error + (see SPI_result for an error indication) @@ -3736,6 +3630,13 @@ HeapTuple SPI_modifytuple(Relation rel, HeapTuple SPI_modifytuple 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. + + + + This function can only be used while connected to SPI. + Otherwise, it returns NULL and sets SPI_result to + SPI_ERROR_UNCONNECTED. @@ -3821,8 +3722,8 @@ HeapTuple SPI_modifytuple(Relation rel, HeapTuple new row with modifications, allocated in the upper executor - context; NULL only if row - is NULL + context, or NULL on error + (see SPI_result for an error indication) @@ -3845,11 +3746,20 @@ HeapTuple SPI_modifytuple(Relation rel, HeapTuple if 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 row) + + + SPI_ERROR_UNCONNECTED + + + if SPI is not active + + + diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c index 8e650bc412..80fc4c4725 100644 --- a/src/backend/executor/spi.c +++ b/src/backend/executor/spi.c @@ -44,8 +44,7 @@ int SPI_result; 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); @@ -86,13 +85,7 @@ SPI_connect(void) { 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) @@ -117,9 +110,7 @@ SPI_connect(void) } } - /* - * 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); @@ -178,14 +169,9 @@ SPI_finish(void) 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]); @@ -212,7 +198,7 @@ AtEOXact_SPI(bool isCommit) _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; @@ -258,8 +244,7 @@ AtEOSubXact_SPI(bool isCommit, SubTransactionId mySubid) * 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]); @@ -313,53 +298,6 @@ AtEOSubXact_SPI(bool isCommit, SubTransactionId mySubid) } -/* 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) @@ -691,7 +629,7 @@ SPI_freeplan(SPIPlanPtr plan) HeapTuple SPI_copytuple(HeapTuple tuple) { - MemoryContext oldcxt = NULL; + MemoryContext oldcxt; HeapTuple ctuple; if (tuple == NULL) @@ -700,17 +638,17 @@ SPI_copytuple(HeapTuple tuple) 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; } @@ -718,7 +656,7 @@ SPI_copytuple(HeapTuple tuple) HeapTupleHeader SPI_returntuple(HeapTuple tuple, TupleDesc tupdesc) { - MemoryContext oldcxt = NULL; + MemoryContext oldcxt; HeapTupleHeader dtup; if (tuple == NULL || tupdesc == NULL) @@ -727,22 +665,22 @@ SPI_returntuple(HeapTuple tuple, TupleDesc tupdesc) 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; } @@ -751,7 +689,7 @@ HeapTuple 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; @@ -764,13 +702,16 @@ SPI_modifytuple(Relation rel, HeapTuple tuple, int natts, int *attnum, 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)); @@ -810,8 +751,7 @@ SPI_modifytuple(Relation rel, HeapTuple tuple, int natts, int *attnum, pfree(v); pfree(n); - if (oldcxt) - MemoryContextSwitchTo(oldcxt); + MemoryContextSwitchTo(oldcxt); return mtuple; } @@ -980,22 +920,10 @@ SPI_getnspname(Relation rel) void * SPI_palloc(Size size) { - MemoryContext oldcxt = NULL; - void *pointer; + if (_SPI_current == NULL) + elog(ERROR, "SPI_palloc called while not connected to SPI"); - 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; + return MemoryContextAlloc(_SPI_current->savedcxt, size); } void * @@ -1015,20 +943,17 @@ SPI_pfree(void *pointer) 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; } @@ -1050,17 +975,12 @@ SPI_freetuptable(SPITupleTable *tuptable) 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) { @@ -1168,13 +1088,9 @@ SPI_cursor_open_with_args(const char *name, /* 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; @@ -1723,14 +1639,8 @@ spi_dest_startup(DestReceiver *self, int operation, TupleDesc typeinfo) 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"); @@ -1775,14 +1685,8 @@ spi_printtup(TupleTableSlot *slot, DestReceiver *self) 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) @@ -2534,11 +2438,8 @@ _SPI_procmem(void) 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(); @@ -2554,11 +2455,6 @@ _SPI_begin_call(bool 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(); diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c index b144920ec6..057c3bfd7c 100644 --- a/src/backend/utils/adt/xml.c +++ b/src/backend/utils/adt/xml.c @@ -2644,8 +2644,6 @@ schema_to_xml_internal(Oid nspid, const char *xmlschema, bool nulls, relid_list = schema_get_xml_visible_tables(nspid); - SPI_push(); - foreach(cell, relid_list) { Oid relid = lfirst_oid(cell); @@ -2658,7 +2656,6 @@ schema_to_xml_internal(Oid nspid, const char *xmlschema, bool nulls, appendStringInfoChar(result, '\n'); } - SPI_pop(); SPI_finish(); xmldata_root_element_end(result, xmlsn); @@ -2822,8 +2819,6 @@ database_to_xml_internal(const char *xmlschema, bool nulls, nspid_list = database_get_xml_visible_schemas(); - SPI_push(); - foreach(cell, nspid_list) { Oid nspid = lfirst_oid(cell); @@ -2836,7 +2831,6 @@ database_to_xml_internal(const char *xmlschema, bool nulls, appendStringInfoChar(result, '\n'); } - SPI_pop(); SPI_finish(); xmldata_root_element_end(result, xmlcn); diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c index c96a86500a..884cdab702 100644 --- a/src/backend/utils/cache/plancache.c +++ b/src/backend/utils/cache/plancache.c @@ -53,7 +53,6 @@ #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" @@ -878,7 +877,6 @@ BuildCachedPlan(CachedPlanSource *plansource, List *qlist, CachedPlan *plan; List *plist; bool snapshot_set; - bool spi_pushed; bool is_transient; MemoryContext plan_context; MemoryContext oldcxt = CurrentMemoryContext; @@ -926,22 +924,11 @@ BuildCachedPlan(CachedPlanSource *plansource, List *qlist, 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(); diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c index 46a55ba7b9..3340b17d90 100644 --- a/src/backend/utils/fmgr/fmgr.c +++ b/src/backend/utils/fmgr/fmgr.c @@ -19,7 +19,6 @@ #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" @@ -1878,25 +1877,16 @@ OidFunctionCall9Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2, * 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); @@ -1922,8 +1912,6 @@ InputFunctionCall(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod) fcinfo.flinfo->fn_oid); } - SPI_pop_conditional(pushed); - return result; } @@ -1932,22 +1920,12 @@ InputFunctionCall(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod) * * 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)); } /* @@ -1956,8 +1934,7 @@ OutputFunctionCall(FmgrInfo *flinfo, Datum 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, @@ -1965,13 +1942,10 @@ 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); @@ -1997,8 +1971,6 @@ ReceiveFunctionCall(FmgrInfo *flinfo, StringInfo buf, fcinfo.flinfo->fn_oid); } - SPI_pop_conditional(pushed); - return result; } @@ -2009,22 +1981,12 @@ ReceiveFunctionCall(FmgrInfo *flinfo, StringInfo buf, * * 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)); } /* diff --git a/src/include/executor/spi.h b/src/include/executor/spi.h index 1792fb1217..76ba394a2b 100644 --- a/src/include/executor/spi.h +++ b/src/include/executor/spi.h @@ -59,6 +59,13 @@ typedef struct _SPI_plan *SPIPlanPtr; #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; @@ -66,11 +73,6 @@ extern PGDLLIMPORT int SPI_result; 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); diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c index 461986cda3..9a2d0527f8 100644 --- a/src/pl/plperl/plperl.c +++ b/src/pl/plperl/plperl.c @@ -3057,12 +3057,6 @@ plperl_spi_exec(char *query, int limit) 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(); { @@ -3078,13 +3072,6 @@ plperl_spi_exec(char *query, int limit) 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); @@ -3296,12 +3283,6 @@ plperl_spi_query(char *query) 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(); { @@ -3317,13 +3298,6 @@ plperl_spi_query(char *query) 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); @@ -3382,12 +3356,6 @@ plperl_spi_fetchrow(char *cursor) 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(); { @@ -3403,13 +3371,6 @@ plperl_spi_fetchrow(char *cursor) 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); @@ -3543,12 +3504,6 @@ plperl_spi_prepare(char *query, int argc, SV **argv) 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(); { @@ -3574,13 +3529,6 @@ plperl_spi_prepare(char *query, int argc, SV **argv) 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); @@ -3694,12 +3642,6 @@ plperl_spi_exec_prepared(char *query, HV *attr, int argc, SV **argv) 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(); { @@ -3715,13 +3657,6 @@ plperl_spi_exec_prepared(char *query, HV *attr, int argc, SV **argv) 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); @@ -3823,12 +3758,6 @@ plperl_spi_query_prepared(char *query, int argc, SV **argv) 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(); { @@ -3844,13 +3773,6 @@ plperl_spi_query_prepared(char *query, int argc, SV **argv) 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); diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index 91e1f8dd3f..77e7440002 100644 --- a/src/pl/plpgsql/src/pl_exec.c +++ b/src/pl/plpgsql/src/pl_exec.c @@ -1337,12 +1337,6 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block) * 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(); { @@ -1384,13 +1378,6 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block) /* 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 @@ -5587,8 +5574,6 @@ exec_eval_simple_expr(PLpgSQL_execstate *estate, * 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) { @@ -5636,8 +5621,6 @@ exec_eval_simple_expr(PLpgSQL_execstate *estate, MemoryContextSwitchTo(oldcontext); - SPI_pop(); - /* * Now we can release our refcount on the cached plan. */ @@ -6281,8 +6264,6 @@ exec_cast_value(PLpgSQL_execstate *estate, ExprContext *econtext = estate->eval_econtext; MemoryContext oldcontext; - SPI_push(); - oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate)); econtext->caseValue_datum = value; @@ -6296,8 +6277,6 @@ exec_cast_value(PLpgSQL_execstate *estate, cast_entry->cast_in_use = false; MemoryContextSwitchTo(oldcontext); - - SPI_pop(); } } diff --git a/src/pl/plpython/plpy_exec.c b/src/pl/plpython/plpy_exec.c index fa5b25a5fa..697a0e1cc0 100644 --- a/src/pl/plpython/plpy_exec.c +++ b/src/pl/plpython/plpy_exec.c @@ -1103,8 +1103,6 @@ PLy_abort_open_subtransactions(int save_subxact_level) RollbackAndReleaseCurrentSubTransaction(); - SPI_restore_connection(); - subtransactiondata = (PLySubtransactionData *) linitial(explicit_subtransactions); explicit_subtransactions = list_delete_first(explicit_subtransactions); diff --git a/src/pl/plpython/plpy_spi.c b/src/pl/plpython/plpy_spi.c index b082d017ea..07ab6a087e 100644 --- a/src/pl/plpython/plpy_spi.c +++ b/src/pl/plpython/plpy_spi.c @@ -516,12 +516,6 @@ PLy_spi_subtransaction_commit(MemoryContext oldcontext, ResourceOwner oldowner) 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 @@ -541,13 +535,6 @@ PLy_spi_subtransaction_abort(MemoryContext oldcontext, ResourceOwner oldowner) 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); diff --git a/src/pl/plpython/plpy_subxactobject.c b/src/pl/plpython/plpy_subxactobject.c index 81fb3a3a4a..9f1caa87d9 100644 --- a/src/pl/plpython/plpy_subxactobject.c +++ b/src/pl/plpython/plpy_subxactobject.c @@ -7,7 +7,6 @@ #include "postgres.h" #include "access/xact.h" -#include "executor/spi.h" #include "utils/memutils.h" #include "plpython.h" @@ -213,12 +212,6 @@ PLy_subtransaction_exit(PyObject *self, PyObject *args) 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; } diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c index 20809102ef..b0d9e419bb 100644 --- a/src/pl/tcl/pltcl.c +++ b/src/pl/tcl/pltcl.c @@ -2182,11 +2182,9 @@ pltcl_returnnext(ClientData cdata, Tcl_Interp *interp, { HeapTuple tuple; - SPI_push(); tuple = pltcl_build_tuple_result(interp, rowObjv, rowObjc, call_state); tuplestore_puttuple(call_state->tuple_store, tuple); - SPI_pop(); } } else @@ -2249,12 +2247,6 @@ pltcl_subtrans_commit(MemoryContext oldcontext, ResourceOwner oldowner) 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 @@ -2273,13 +2265,6 @@ pltcl_subtrans_abort(Tcl_Interp *interp, 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; @@ -3029,9 +3014,6 @@ pltcl_build_tuple_argument(HeapTuple tuple, TupleDesc tupdesc) * 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,