1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-28 23:42:10 +03:00

Simplify code by getting rid of SPI_push, SPI_pop, SPI_restore_connection.

The idea behind SPI_push was to allow transitioning back into an
"unconnected" state when a SPI-using procedure calls unrelated code that
might or might not invoke SPI.  That sounds good, but in practice the only
thing it does for us is to catch cases where a called SPI-using function
forgets to call SPI_connect --- which is a highly improbable failure mode,
since it would be exposed immediately by direct testing of said function.
As against that, we've had multiple bugs induced by forgetting to call
SPI_push/SPI_pop around code that might invoke SPI-using functions; these
are much harder to catch and indeed have gone undetected for years in some
cases.  And we've had to band-aid around some problems of this ilk by
introducing conditional push/pop pairs in some places, which really kind
of defeats the purpose altogether; if we can't draw bright lines between
connected and unconnected code, what's the point?

Hence, get rid of SPI_push[_conditional], SPI_pop[_conditional], and the
underlying state variable _SPI_curid.  It turns out SPI_restore_connection
can go away too, which is a nice side benefit since it was never more than
a kluge.  Provide no-op macros for the deleted functions so as to avoid an
API break for external modules.

A side effect of this removal is that SPI_palloc and allied functions no
longer permit being called when unconnected; they'll throw an error
instead.  The apparent usefulness of the previous behavior was a mirage
as well, because it was depended on by only a few places (which I fixed in
preceding commits), and it posed a risk of allocations being unexpectedly
long-lived if someone forgot a SPI_push call.

Discussion: <20808.1478481403@sss.pgh.pa.us>
This commit is contained in:
Tom Lane
2016-11-08 17:39:45 -05:00
parent 577f0bdd2b
commit 1833f1a1c3
12 changed files with 105 additions and 493 deletions

View File

@ -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.
</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>
@ -164,13 +149,6 @@ int SPI_finish(void)
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>
@ -200,86 +178,6 @@ int SPI_finish(void)
<!-- *********************************************** -->
<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>
@ -3361,17 +3259,8 @@ char * SPI_getnspname(Relation <parameter>rel</parameter>)
<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>
@ -3379,25 +3268,14 @@ char * SPI_getnspname(Relation <parameter>rel</parameter>)
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">
@ -3426,6 +3304,11 @@ void * SPI_palloc(Size <parameter>size</parameter>)
<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>
@ -3605,6 +3488,12 @@ HeapTuple SPI_copytuple(HeapTuple <parameter>row</parameter>)
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>
@ -3626,8 +3515,8 @@ HeapTuple SPI_copytuple(HeapTuple <parameter>row</parameter>)
<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>
@ -3663,6 +3552,12 @@ HeapTupleHeader SPI_returntuple(HeapTuple <parameter>row</parameter>, TupleDesc
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
@ -3699,10 +3594,9 @@ HeapTupleHeader SPI_returntuple(HeapTuple <parameter>row</parameter>, TupleDesc
<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>
@ -3736,6 +3630,13 @@ HeapTuple SPI_modifytuple(Relation <parameter>rel</parameter>, HeapTuple <parame
<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>
@ -3821,8 +3722,8 @@ HeapTuple SPI_modifytuple(Relation <parameter>rel</parameter>, HeapTuple <parame
<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>
@ -3845,11 +3746,20 @@ HeapTuple SPI_modifytuple(Relation <parameter>rel</parameter>, HeapTuple <parame
<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>