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

Make use of plancache module for SPI plans. In particular, since plpgsql

uses SPI plans, this finally fixes the ancient gotcha that you can't
drop and recreate a temp table used by a plpgsql function.

Along the way, clean up SPI's API a little bit by declaring SPI plan
pointers as "SPIPlanPtr" instead of "void *".  This is cosmetic but
helps to forestall simple programming mistakes.  (I have changed some
but not all of the callers to match; there are still some "void *"'s
in contrib and the PL's.  This is intentional so that we can see if
anyone's compiler complains about it.)
This commit is contained in:
Tom Lane
2007-03-15 23:12:07 +00:00
parent d3ff180163
commit 95f6d2d209
16 changed files with 654 additions and 285 deletions

View File

@ -1,4 +1,4 @@
<!-- $PostgreSQL: pgsql/doc/src/sgml/spi.sgml,v 1.53 2007/02/18 01:47:40 momjian Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/spi.sgml,v 1.54 2007/03/15 23:12:06 tgl Exp $ -->
<chapter id="spi">
<title>Server Programming Interface</title>
@ -14,7 +14,7 @@
<acronym>SQL</acronym> commands inside their functions.
<acronym>SPI</acronym> is a set of
interface functions to simplify access to the parser, planner,
optimizer, and executor. <acronym>SPI</acronym> also does some
and executor. <acronym>SPI</acronym> also does some
memory management.
</para>
@ -322,7 +322,8 @@ SPI_execute("INSERT INTO foo SELECT * FROM bar", false, 5);
<para>
You can pass multiple commands in one string, but later commands cannot
depend on the creation of objects earlier in the string.
depend on the creation of objects earlier in the string, because the
whole string will be parsed and planned before execution begins.
<function>SPI_execute</function> returns the
result for the command executed last. The <parameter>count</parameter>
limit applies to each command separately, but it is not applied to
@ -699,7 +700,7 @@ int SPI_exec(const char * <parameter>command</parameter>, long <parameter>count<
<refsynopsisdiv>
<synopsis>
void * SPI_prepare(const char * <parameter>command</parameter>, int <parameter>nargs</parameter>, Oid * <parameter>argtypes</parameter>)
SPIPlanPtr SPI_prepare(const char * <parameter>command</parameter>, int <parameter>nargs</parameter>, Oid * <parameter>argtypes</parameter>)
</synopsis>
</refsynopsisdiv>
@ -790,6 +791,13 @@ void * SPI_prepare(const char * <parameter>command</parameter>, int <parameter>n
<refsect1>
<title>Notes</title>
<para>
<type>SPIPlanPtr</> is declared as a pointer to an opaque struct type in
<filename>spi.h</>. It is unwise to try to access its contents
directly, as that makes your code much more likely to break in
future revisions of <productname>PostgreSQL</productname>.
</para>
<para>
There is a disadvantage to using parameters: since the planner does
not know the values that will be supplied for the parameters, it
@ -816,7 +824,7 @@ void * SPI_prepare(const char * <parameter>command</parameter>, int <parameter>n
<refsynopsisdiv>
<synopsis>
int SPI_getargcount(void * <parameter>plan</parameter>)
int SPI_getargcount(SPIPlanPtr <parameter>plan</parameter>)
</synopsis>
</refsynopsisdiv>
@ -834,7 +842,7 @@ int SPI_getargcount(void * <parameter>plan</parameter>)
<variablelist>
<varlistentry>
<term><literal>void * <parameter>plan</parameter></literal></term>
<term><literal>SPIPlanPtr <parameter>plan</parameter></literal></term>
<listitem>
<para>
execution plan (returned by <function>SPI_prepare</function>)
@ -847,9 +855,10 @@ int SPI_getargcount(void * <parameter>plan</parameter>)
<refsect1>
<title>Return Value</title>
<para>
The expected argument count for the <parameter>plan</parameter>, or
<symbol>SPI_ERROR_ARGUMENT</symbol> if the <parameter>plan
</parameter> is <symbol>NULL</symbol>
The count of expected arguments for the <parameter>plan</parameter>.
If the <parameter>plan</parameter> is <symbol>NULL</symbol> or invalid,
<varname>SPI_result</varname> is set to <symbol>SPI_ERROR_ARGUMENT</symbol>
and <literal>-1</literal> is returned.
</para>
</refsect1>
</refentry>
@ -871,7 +880,7 @@ int SPI_getargcount(void * <parameter>plan</parameter>)
<refsynopsisdiv>
<synopsis>
Oid SPI_getargtypeid(void * <parameter>plan</parameter>, int <parameter>argIndex</parameter>)
Oid SPI_getargtypeid(SPIPlanPtr <parameter>plan</parameter>, int <parameter>argIndex</parameter>)
</synopsis>
</refsynopsisdiv>
@ -890,7 +899,7 @@ Oid SPI_getargtypeid(void * <parameter>plan</parameter>, int <parameter>argIndex
<variablelist>
<varlistentry>
<term><literal>void * <parameter>plan</parameter></literal></term>
<term><literal>SPIPlanPtr <parameter>plan</parameter></literal></term>
<listitem>
<para>
execution plan (returned by <function>SPI_prepare</function>)
@ -912,11 +921,13 @@ Oid SPI_getargtypeid(void * <parameter>plan</parameter>, int <parameter>argIndex
<refsect1>
<title>Return Value</title>
<para>
The type id of the argument at the given index, or
<symbol>SPI_ERROR_ARGUMENT</symbol> if the <parameter>plan</parameter> is
<symbol>NULL</symbol> or <parameter>argIndex</parameter> is less than 0 or
The type id of the argument at the given index.
If the <parameter>plan</parameter> is <symbol>NULL</symbol> or invalid,
or <parameter>argIndex</parameter> is less than 0 or
not less than the number of arguments declared for the
<parameter>plan</parameter>
<parameter>plan</parameter>,
<varname>SPI_result</varname> is set to <symbol>SPI_ERROR_ARGUMENT</symbol>
and <symbol>InvalidOid</symbol> is returned.
</para>
</refsect1>
</refentry>
@ -939,7 +950,7 @@ Oid SPI_getargtypeid(void * <parameter>plan</parameter>, int <parameter>argIndex
<refsynopsisdiv>
<synopsis>
bool SPI_is_cursor_plan(void * <parameter>plan</parameter>)
bool SPI_is_cursor_plan(SPIPlanPtr <parameter>plan</parameter>)
</synopsis>
</refsynopsisdiv>
@ -964,7 +975,7 @@ bool SPI_is_cursor_plan(void * <parameter>plan</parameter>)
<variablelist>
<varlistentry>
<term><literal>void * <parameter>plan</parameter></literal></term>
<term><literal>SPIPlanPtr <parameter>plan</parameter></literal></term>
<listitem>
<para>
execution plan (returned by <function>SPI_prepare</function>)
@ -978,9 +989,10 @@ bool SPI_is_cursor_plan(void * <parameter>plan</parameter>)
<title>Return Value</title>
<para>
<symbol>true</symbol> or <symbol>false</symbol> to indicate if the
<parameter>plan</parameter> can produce a cursor or not, or
<symbol>SPI_ERROR_ARGUMENT</symbol> if the <parameter>plan</parameter>
is <symbol>NULL</symbol>
<parameter>plan</parameter> can produce a cursor or not.
If the <parameter>plan</parameter> is <symbol>NULL</symbol> or invalid,
<varname>SPI_result</varname> is set to <symbol>SPI_ERROR_ARGUMENT</symbol>
and <symbol>false</symbol> is returned.
</para>
</refsect1>
</refentry>
@ -1001,7 +1013,7 @@ bool SPI_is_cursor_plan(void * <parameter>plan</parameter>)
<refsynopsisdiv>
<synopsis>
int SPI_execute_plan(void * <parameter>plan</parameter>, Datum * <parameter>values</parameter>, const char * <parameter>nulls</parameter>,
int SPI_execute_plan(SPIPlanPtr <parameter>plan</parameter>, Datum * <parameter>values</parameter>, const char * <parameter>nulls</parameter>,
bool <parameter>read_only</parameter>, long <parameter>count</parameter>)
</synopsis>
</refsynopsisdiv>
@ -1022,7 +1034,7 @@ int SPI_execute_plan(void * <parameter>plan</parameter>, Datum * <parameter>valu
<variablelist>
<varlistentry>
<term><literal>void * <parameter>plan</parameter></literal></term>
<term><literal>SPIPlanPtr <parameter>plan</parameter></literal></term>
<listitem>
<para>
execution plan (returned by <function>SPI_prepare</function>)
@ -1091,8 +1103,8 @@ int SPI_execute_plan(void * <parameter>plan</parameter>, Datum * <parameter>valu
<term><symbol>SPI_ERROR_ARGUMENT</symbol></term>
<listitem>
<para>
if <parameter>plan</parameter> is <symbol>NULL</symbol> or
<parameter>count</parameter> is less than 0
if <parameter>plan</parameter> is <symbol>NULL</symbol> or invalid,
or <parameter>count</parameter> is less than 0
</para>
</listitem>
</varlistentry>
@ -1143,7 +1155,7 @@ int SPI_execute_plan(void * <parameter>plan</parameter>, Datum * <parameter>valu
<refsynopsisdiv>
<synopsis>
int SPI_execp(void * <parameter>plan</parameter>, Datum * <parameter>values</parameter>, const char * <parameter>nulls</parameter>, long <parameter>count</parameter>)
int SPI_execp(SPIPlanPtr <parameter>plan</parameter>, Datum * <parameter>values</parameter>, const char * <parameter>nulls</parameter>, long <parameter>count</parameter>)
</synopsis>
</refsynopsisdiv>
@ -1163,7 +1175,7 @@ int SPI_execp(void * <parameter>plan</parameter>, Datum * <parameter>values</par
<variablelist>
<varlistentry>
<term><literal>void * <parameter>plan</parameter></literal></term>
<term><literal>SPIPlanPtr <parameter>plan</parameter></literal></term>
<listitem>
<para>
execution plan (returned by <function>SPI_prepare</function>)
@ -1242,7 +1254,7 @@ int SPI_execp(void * <parameter>plan</parameter>, Datum * <parameter>values</par
<refsynopsisdiv>
<synopsis>
Portal SPI_cursor_open(const char * <parameter>name</parameter>, void * <parameter>plan</parameter>,
Portal SPI_cursor_open(const char * <parameter>name</parameter>, SPIPlanPtr <parameter>plan</parameter>,
Datum * <parameter>values</parameter>, const char * <parameter>nulls</parameter>,
bool <parameter>read_only</parameter>)
</synopsis>
@ -1268,6 +1280,11 @@ Portal SPI_cursor_open(const char * <parameter>name</parameter>, void * <paramet
to the procedure's caller provides a way of returning a row set as
result.
</para>
<para>
The passed-in data will be copied into the cursor's portal, so it
can be freed while the cursor still exists.
</para>
</refsect1>
<refsect1>
@ -1285,7 +1302,7 @@ Portal SPI_cursor_open(const char * <parameter>name</parameter>, void * <paramet
</varlistentry>
<varlistentry>
<term><literal>void * <parameter>plan</parameter></literal></term>
<term><literal>SPIPlanPtr <parameter>plan</parameter></literal></term>
<listitem>
<para>
execution plan (returned by <function>SPI_prepare</function>)
@ -1602,7 +1619,7 @@ void SPI_cursor_close(Portal <parameter>portal</parameter>)
<refsynopsisdiv>
<synopsis>
void * SPI_saveplan(void * <parameter>plan</parameter>)
SPIPlanPtr SPI_saveplan(SPIPlanPtr <parameter>plan</parameter>)
</synopsis>
</refsynopsisdiv>
@ -1611,8 +1628,8 @@ void * SPI_saveplan(void * <parameter>plan</parameter>)
<para>
<function>SPI_saveplan</function> saves a passed plan (prepared by
<function>SPI_prepare</function>) in memory protected from freeing
by <function>SPI_finish</function> and by the transaction manager
<function>SPI_prepare</function>) in memory that will not be freed
by <function>SPI_finish</function> nor by the transaction manager,
and returns a pointer to the saved plan. This gives you the
ability to reuse prepared plans in the subsequent invocations of
your procedure in the current session.
@ -1624,7 +1641,7 @@ void * SPI_saveplan(void * <parameter>plan</parameter>)
<variablelist>
<varlistentry>
<term><literal>void * <parameter>plan</parameter></literal></term>
<term><literal>SPIPlanPtr <parameter>plan</parameter></literal></term>
<listitem>
<para>
the plan to be saved
@ -1646,7 +1663,7 @@ void * SPI_saveplan(void * <parameter>plan</parameter>)
<term><symbol>SPI_ERROR_ARGUMENT</symbol></term>
<listitem>
<para>
if <parameter>plan</parameter> is <symbol>NULL</symbol>
if <parameter>plan</parameter> is <symbol>NULL</symbol> or invalid
</para>
</listitem>
</varlistentry>
@ -1666,10 +1683,17 @@ void * SPI_saveplan(void * <parameter>plan</parameter>)
<refsect1>
<title>Notes</title>
<para>
The passed-in plan is not freed, so you might wish to do
<function>SPI_freeplan</function> on it to avoid leaking memory
until <function>SPI_finish</>.
</para>
<para>
If one of the objects (a table, function, etc.) referenced by the
prepared plan is dropped during the session then the results of
<function>SPI_execute_plan</function> for this plan will be unpredictable.
prepared plan is dropped or redefined, then future executions of
<function>SPI_execute_plan</function> may fail or return different
results than the plan initially indicates.
</para>
</refsect1>
</refentry>
@ -2879,7 +2903,7 @@ void SPI_freetuptable(SPITupleTable * <parameter>tuptable</parameter>)
<refsynopsisdiv>
<synopsis>
int SPI_freeplan(void *<parameter>plan</parameter>)
int SPI_freeplan(SPIPlanPtr <parameter>plan</parameter>)
</synopsis>
</refsynopsisdiv>
@ -2898,7 +2922,7 @@ int SPI_freeplan(void *<parameter>plan</parameter>)
<variablelist>
<varlistentry>
<term><literal>void * <parameter>plan</parameter></literal></term>
<term><literal>SPIPlanPtr <parameter>plan</parameter></literal></term>
<listitem>
<para>
pointer to plan to free
@ -2913,7 +2937,7 @@ int SPI_freeplan(void *<parameter>plan</parameter>)
<para>
<symbol>SPI_ERROR_ARGUMENT</symbol> if <parameter>plan</parameter>
is <symbol>NULL</symbol>.
is <symbol>NULL</symbol> or invalid
</para>
</refsect1>
</refentry>