Commit b3bbeed1 authored by Tom Lane's avatar Tom Lane

Overhaul SPI documentation: bring it into some semblance of agreement

with reality, and add doco for Jan's recent round of enhancements.
parent a370cad9
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/spi.sgml,v 1.19 2001/11/14 22:26:02 tgl Exp $
-->
<Chapter id="spi">
<DocInfo>
<AuthorGroup>
......@@ -16,10 +20,15 @@ The <FirstTerm>Server Programming Interface</FirstTerm>
(<Acronym>SPI</Acronym>) gives users the
ability to run <Acronym>SQL</Acronym> queries inside user-defined
<Acronym>C</Acronym> functions.
The available Procedural Languages (<Acronym>PL</Acronym>) give an alternate
means to access these capabilities.
</Para>
<note>
<para>
The available Procedural Languages (<Acronym>PL</Acronym>) give an alternate
means to build functions that can execute queries.
</para>
</note>
<Para>
In fact, <Acronym>SPI</Acronym> is just a set of native interface functions
to simplify access to the Parser, Planner, Optimizer and Executor.
......@@ -42,15 +51,15 @@ recursively, it may itself call procedures which may make
</Para>
<Para>
Note, that if during execution of a query from a procedure the transaction
is aborted then control will not be returned to your procedure. Rather, all work
Note that if during execution of a query from a procedure the transaction is
aborted, then control will not be returned to your procedure. Rather, all work
will be rolled back and the server will wait for the next command from the
client. This will be changed in future versions.
client. This will probably be changed in future versions.
</Para>
<Para>
Other restrictions are the inability to execute BEGIN, END and ABORT
(transaction control statements) and cursor operations. This will also be
A related restriction is the inability to execute BEGIN, END and ABORT
(transaction control statements). This will also be
changed in the future.
</Para>
......@@ -142,8 +151,9 @@ Return status
<TITLE>Description
</TITLE>
<PARA>
<FUNCTION>SPI_connect</FUNCTION> opens a connection to the <ProductName>Postgres</ProductName> backend.
You should call this function if you will need to execute queries. Some
<FUNCTION>SPI_connect</FUNCTION> opens a connection from a procedure
invocation to the SPI manager.
You must call this function if you will need to execute queries. Some
utility SPI functions may be called from un-connected procedures.
</PARA>
<PARA>
......@@ -259,8 +269,10 @@ SPI_finish(void)
<TITLE>Description
</TITLE>
<PARA>
<FUNCTION>SPI_finish</FUNCTION> closes an existing connection to the <ProductName>Postgres</ProductName> backend.
You should call this function after completing operations through the SPI manager.
<FUNCTION>SPI_finish</FUNCTION> closes an existing connection to the
SPI manager.
You must call this function after completing the SPI operations needed
during your procedure's current invocation.
</para>
<PARA>
You may get the error return <ReturnValue>SPI_ERROR_UNCONNECTED</ReturnValue> if <Function>SPI_finish</Function> is
......@@ -273,10 +285,11 @@ SPI_finish(void)
<TITLE>Usage
</TITLE>
<PARA>
<Function>SPI_finish</Function> <Emphasis>must</Emphasis> be called as a final step by a connected procedure
<Function>SPI_finish</Function> <Emphasis>must</Emphasis> be called as a final step by a connected procedure,
or you may get
unpredictable results! Note that you can safely skip the call to <Function>SPI_finish</Function>
if you abort the transaction (via elog(ERROR)).
unpredictable results! However, you do not need to worry about making
this happen if the transaction is aborted via elog(ERROR). In that case
SPI will clean itself up.
</PARA>
</REFSECT1>
......@@ -369,9 +382,6 @@ Maximum number of tuples to return
<LISTITEM>
<PARA>
<SimpleList>
<Member>
<ReturnValue>SPI_OK_EXEC</ReturnValue> if properly disconnected
</Member>
<Member>
<ReturnValue>SPI_ERROR_UNCONNECTED</ReturnValue> if called from an un-connected procedure
</Member>
......@@ -444,7 +454,7 @@ Maximum number of tuples to return
This should only be called from a connected procedure.
If <REPLACEABLE CLASS="PARAMETER">tcount</REPLACEABLE> is zero then it executes the query for all tuples returned by the
query scan. Using <REPLACEABLE CLASS="PARAMETER">tcount</REPLACEABLE> > 0 you may restrict the number of tuples for
which the query will be executed. For example,
which the query will be executed (much like a LIMIT clause). For example,
<ProgramListing>
SPI_exec ("INSERT INTO tab SELECT * FROM tab", 5);
......@@ -456,7 +466,7 @@ will allow at most 5 tuples to be inserted into table.
<Note>
<Para>
You may pass many queries in one string or query string may be
You may pass multiple queries in one string or query string may be
re-written by RULEs. <Function>SPI_exec</Function> returns the result for the last query
executed.
</Para>
......@@ -466,11 +476,8 @@ You may pass many queries in one string or query string may be
The actual number of tuples for which the (last) query was executed is
returned in the global variable SPI_processed (if not <ReturnValue>SPI_OK_UTILITY</ReturnValue>).
If <ReturnValue>SPI_OK_SELECT</ReturnValue> returned and SPI_processed &gt; 0 then you may use global
pointer SPITupleTable *SPI_tuptable to access the selected tuples:
Also NOTE, that <Function>SPI_finish</Function> frees and makes all SPITupleTables
unusable! (See Memory management).
If <ReturnValue>SPI_OK_SELECT</ReturnValue> is returned and SPI_processed &gt; 0 then you may use global
pointer SPITupleTable *SPI_tuptable to access the result tuples.
</Para>
<Para>
......@@ -498,51 +505,61 @@ You may pass many queries in one string or query string may be
</PARA>
</REFSECT1>
<!--
<REFSECT1 ID="R1-SPI-SPIEXEC-3">
<TITLE>Algorithm
</TITLE>
<PARA><FUNCTION>SPI_exec</FUNCTION> performs the following:
Disconnects your procedure from the SPI manager and frees all memory
allocations made by your procedure via <Function>palloc</Function> since the <Function>SPI_connect</Function>.
These allocations can't be used any more! See Memory management.
<PARA>
</PARA>
</REFSECT1>
<!--
-->
<REFSECT1 ID="R1-SPI-SPIEXEC-4">
<TITLE>Structures
</TITLE>
<PARA>
If <ReturnValue>SPI_OK_SELECT</ReturnValue> returned and SPI_processed > 0 then you may use the global
<Para>
If <ReturnValue>SPI_OK_SELECT</ReturnValue> is returned and SPI_processed &gt; 0 then you may use the global
pointer SPITupleTable *SPI_tuptable to access the selected tuples.
</Para>
<Para>
Structure SPITupleTable is defined in spi.h:
<ProgramListing>
typedef struct
{
MemoryContext tuptabcxt; /* memory context of result table */
uint32 alloced; /* # of alloced vals */
uint32 free; /* # of free vals */
TupleDesc tupdesc; /* tuple descriptor */
HeapTuple *vals; /* tuples */
} SPITupleTable;
</ProgramListing>
</Para>
<Para>
HeapTuple *vals is an array of pointers to tuples. TupleDesc tupdesc is
vals is an array of pointers to tuples (the number of useful entries
is given by SPI_processed). TupleDesc tupdesc is
a tuple descriptor which you may pass to SPI functions dealing with
tuples.
tuples. tuptabcxt, alloced, and free are internal fields not intended
for use by SPI callers.
</Para>
<note>
<Para>
NOTE! Functions <Function>SPI_exec</Function>, <Function>SPI_execp</Function> and <Function>SPI_prepare</Function> change both
SPI_processed and SPI_tuptable (just the pointer, not the contents of the
structure)! So, save them in local procedure variables if you need them.
Functions <Function>SPI_exec</Function>, <Function>SPI_execp</Function> and
<Function>SPI_prepare</Function> change both SPI_processed and SPI_tuptable
(just the pointer, not the contents of the structure).
Save these two global variables into local procedure variables if you need
to access the result of one <Function>SPI_exec</Function> or
<Function>SPI_execp</Function> across later calls.
</Para>
</note>
<Para>
Also NOTE, that <Function>SPI_finish</Function> frees and makes all SPITupleTables
unusable! (See Memory management).
</PARA>
<Function>SPI_finish</Function> frees all SPITupleTables allocated during
the current procedure. You can free a particular result table earlier,
if you are done with it, by calling <Function>SPI_freetuptable</Function>.
</Para>
</REFSECT1>
-->
</REFENTRY>
<!-- *********************************************** -->
......@@ -558,7 +575,7 @@ You may pass many queries in one string or query string may be
<REFNAME>SPI_prepare
</REFNAME>
<REFPURPOSE>
Connects your procedure to the SPI manager.
Prepares a plan for a query, without executing it yet
</REFPURPOSE>
<INDEXTERM ID="IX-SPI-SPIPREPARE-1"><PRIMARY>SPI</PRIMARY><SECONDARY>connecting</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-SPI-SPIPREPARE-2"><PRIMARY>SPI_prepare</PRIMARY></INDEXTERM>
......@@ -604,7 +621,7 @@ Number of input parameters ($1 ... $nargs - as in SQL-functions)
</TERM>
<LISTITEM>
<PARA>
Pointer list of type <Acronym>OID</Acronym>s to input arguments
Pointer to array of type <Acronym>OID</Acronym>s for input parameter types
</PARA>
</LISTITEM>
</VARLISTENTRY>
......@@ -647,18 +664,35 @@ Pointer to an execution plan (parser+planner+optimizer)
<REFSECT1 ID="R1-SPI-SPIPREPARE-2">
<TITLE>Usage
</TITLE>
<Para>
When the same or similar query is to be executed repeatedly, it may
be advantageous to perform query planning only once.
<FUNCTION>SPI_prepare</FUNCTION> converts a query string into an execution
plan that can be passed repeatedly to <FUNCTION>SPI_execp</FUNCTION>.
</para>
<PARA>
nargs is number of parameters ($1 ... $nargs - as in SQL-functions),
and nargs may be 0 only if there is not any $1 in query.
A prepared query can be generalized by writing parameters ($1, $2, etc)
in place of what would be constants in a normal query. The values of
the parameters are then specified when <FUNCTION>SPI_execp</FUNCTION>
is called. This allows the prepared query to be used over a wider
range of situations than would be possible without parameters.
</para>
<Para>
Execution of prepared execution plans is sometimes much faster so this
feature may be useful if the same query will be executed many times.
<note>
<PARA>
However, there is a disadvantage: since the planner does not know the
values that will be supplied for the parameters, it may make worse
query planning choices than it would make for a simple query with
all constants visible.
</para>
</note>
<PARA>
If the query uses parameters, their number and datatypes must be
specified in the call to <FUNCTION>SPI_prepare</FUNCTION>.
</para>
<Para>
The plan returned by <Function>SPI_prepare</Function> may be used only in current
invocation of the procedure since <Function>SPI_finish</Function> frees memory allocated for a plan.
See <Function>SPI_saveplan</Function>.
But see <Function>SPI_saveplan</Function> to save a plan for longer.
</para>
<Para>
If successful, a non-null pointer will be returned. Otherwise, you'll get
......@@ -692,149 +726,6 @@ TBD
<!-- *********************************************** -->
<!-- *********************************************** -->
<REFENTRY ID="SPI-SPISAVEPLAN">
<REFMETA>
<REFENTRYTITLE>SPI_saveplan</REFENTRYTITLE>
<REFMISCINFO>SPI - Plan Storage</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>SPI_saveplan
</REFNAME>
<REFPURPOSE>
Saves a passed plan
</REFPURPOSE>
<INDEXTERM ID="IX-SPI-SPISAVEPLAN-1"><PRIMARY>SPI</PRIMARY><SECONDARY>connecting</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-SPI-SPISAVEPLAN-2"><PRIMARY>SPI_saveplan</PRIMARY></INDEXTERM>
</REFNAMEDIV>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
<DATE>1997-12-24</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
SPI_saveplan(<REPLACEABLE CLASS="PARAMETER">plan</REPLACEABLE>)
</SYNOPSIS>
<REFSECT2 ID="R2-SPI-SPISAVEPLAN-1">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Inputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
void *<REPLACEABLE CLASS="PARAMETER">query</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Passed plan
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
<REFSECT2 ID="R2-SPI-SPISAVEPLAN-2">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Outputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>void *
</TERM>
<LISTITEM>
<PARA>
Execution plan location. NULL if unsuccessful.
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>SPI_result
</TERM>
<LISTITEM>
<PARA>
<SimpleList>
<Member>
<ReturnValue>SPI_ERROR_ARGUMENT</ReturnValue> if plan is NULL
</Member>
<Member>
<ReturnValue>SPI_ERROR_UNCONNECTED</ReturnValue> if procedure is un-connected
</Member>
</SimpleList>
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
</REFSYNOPSISDIV>
<REFSECT1 ID="R1-SPI-SPISAVEPLAN-1">
<REFSECT1INFO>
<DATE>1997-12-24</DATE>
</REFSECT1INFO>
<TITLE>Description
</TITLE>
<PARA>
<FUNCTION>SPI_saveplan</FUNCTION>
stores a plan prepared by <Function>SPI_prepare</Function> in safe memory
protected from freeing by <Function>SPI_finish</Function> or the transaction manager.
</para>
<Para>
In the current version of <ProductName>Postgres</ProductName> there is no ability to
store prepared plans in the system
catalog and fetch them from there for execution. This will be implemented
in future versions.
As an alternative, there is the ability to reuse prepared plans in the
consequent invocations of your procedure in the current session.
Use <Function>SPI_execp</Function> to execute this saved plan.
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-SPI-SPISAVEPLAN-2">
<TITLE>Usage
</TITLE>
<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 and
returns a pointer to the saved plan. You may save the pointer returned in
a local variable. Always check if this pointer is NULL or not either when
preparing a plan or using an already prepared plan in SPI_execp (see below).
<Note>
<Para>
If one of the objects (a relation, function, etc.) referenced by the prepared
plan is dropped during your session (by your backend or another process) then the
results of <Function>SPI_execp</Function> for this plan will be unpredictable.
</Para>
</Note>
</PARA>
</REFSECT1>
<!--
<REFSECT1 ID="R1-SPI-SPISAVEPLAN-3">
<TITLE>Algorithm
</TITLE>
<PARA><FUNCTION>SPI_saveplan</FUNCTION> performs the following:
TBD
</PARA>
</REFSECT1>
-->
<!--
<REFSECT1 ID="R1-SPI-SPISAVEPLAN-4">
<TITLE>Structures
</TITLE>
<PARA>None
</PARA>
</REFSECT1>
-->
</REFENTRY>
<!-- *********************************************** -->
<!-- *********************************************** -->
<!-- *********************************************** -->
<REFENTRY ID="SPI-SPIEXECP">
<REFMETA>
<REFENTRYTITLE>SPI_execp</REFENTRYTITLE>
......@@ -844,7 +735,7 @@ TBD
<REFNAME>SPI_execp
</REFNAME>
<REFPURPOSE>
Executes a plan from <Function>SPI_saveplan</Function>
Executes a plan from <Function>SPI_prepare</Function>
</REFPURPOSE>
<INDEXTERM ID="IX-SPI-SPIEXECP-1"><PRIMARY>SPI</PRIMARY><SECONDARY>connecting</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-SPI-SPIEXECP-2"><PRIMARY>SPI_execp</PRIMARY></INDEXTERM>
......@@ -893,10 +784,10 @@ char *<REPLACEABLE CLASS="PARAMETER">nulls</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Array describing what parameters get NULLs
Array describing which parameters are NULLs
<SimpleList>
<Member><literal>n</literal> indicates NULL allowed</Member>
<Member>A space indicates NULL not allowed</Member>
<Member><literal>n</literal> indicates NULL (values[] entry ignored)</Member>
<Member>space indicates not NULL (values[] entry is valid)</Member>
</SimpleList>
</PARA>
</LISTITEM>
......@@ -976,19 +867,10 @@ initialized as in
</TITLE>
<PARA>
<FUNCTION>SPI_execp</FUNCTION>
stores a plan prepared by <Function>SPI_prepare</Function> in safe memory
protected from freeing by <Function>SPI_finish</Function> or the transaction manager.
executes a plan prepared by <Function>SPI_prepare</Function>.
<REPLACEABLE CLASS="PARAMETER">tcount</REPLACEABLE> has the same
interpretation as in <Function>SPI_exec</Function>.
</para>
<Para>
In the current version of <ProductName>Postgres</ProductName> there is no ability to
store prepared plans in the system
catalog and fetch them from there for execution. This will be implemented
in future versions.
As a work arround, there is the ability to reuse prepared plans in the
consequent invocations of your procedure in the current session.
Use <Function>SPI_execp</Function> to execute this saved plan.
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-SPI-SPIEXECP-2">
<TITLE>Usage
......@@ -997,7 +879,7 @@ initialized as in
If <REPLACEABLE CLASS="PARAMETER">nulls</REPLACEABLE>
is NULL then
<Function>SPI_execp</Function>
assumes that all values (if any) are NOT NULL.
assumes that all parameters (if any) are NOT NULL.
<Note>
<Para>
......@@ -1028,88 +910,102 @@ TBD
-->
</REFENTRY>
</Sect1>
<Sect1 id="spi-interface-support">
<Title>Interface Support Functions</Title>
<Para>
All functions described below may be used by connected and unconnected
procedures.
</Para>
<!-- *********************************************** -->
<!-- *********************************************** -->
<!-- *********************************************** -->
<REFENTRY ID="SPI-SPICOPYTUPLE">
<REFENTRY ID="SPI-SPICURSOR-OPEN">
<REFMETA>
<REFENTRYTITLE>SPI_copytuple</REFENTRYTITLE>
<REFMISCINFO>SPI - Tuple Copy</REFMISCINFO>
<REFENTRYTITLE>SPI_cursor_open</REFENTRYTITLE>
<REFMISCINFO>SPI - Cursor Support</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>SPI_copytuple
<REFNAME>SPI_cursor_open
</REFNAME>
<REFPURPOSE>
Makes copy of tuple in upper Executor context
Sets up a cursor using a plan created with <Function>SPI_prepare</Function>
</REFPURPOSE>
<INDEXTERM ID="IX-SPI-SPICOPYTUPLE-1"><PRIMARY>SPI</PRIMARY><SECONDARY>copying tuples</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-SPI-SPICOPYTUPLE-2"><PRIMARY>SPI_copytuple</PRIMARY></INDEXTERM>
<INDEXTERM ID="IX-SPI-SPICURSOR-OPEN-1"><PRIMARY>SPI</PRIMARY><SECONDARY>cursors</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-SPI-SPICURSOR-OPEN-2"><PRIMARY>SPI_cursor_open</PRIMARY></INDEXTERM>
</REFNAMEDIV>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
<DATE>1997-12-24</DATE>
<DATE>2001-11-14</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
SPI_copytuple(<REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE>)
SPI_cursor_open(<REPLACEABLE CLASS="PARAMETER">name</REPLACEABLE>,
<REPLACEABLE CLASS="PARAMETER">plan</REPLACEABLE>,
<REPLACEABLE CLASS="PARAMETER">values</REPLACEABLE>,
<REPLACEABLE CLASS="PARAMETER">nulls</REPLACEABLE>)
</SYNOPSIS>
<REFSECT2 ID="R2-SPI-SPICOPYTUPLE-1">
<REFSECT2 ID="R2-SPI-SPICURSOR-OPEN-1">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
<DATE>2001-11-14</DATE>
</REFSECT2INFO>
<TITLE>Inputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
HeapTuple <REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE>
char *<REPLACEABLE CLASS="PARAMETER">name</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Input tuple to be copied
Name for portal, or NULL to let the system select a name
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
void *<REPLACEABLE CLASS="PARAMETER">plan</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Execution plan
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
Datum *<REPLACEABLE CLASS="PARAMETER">values</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Actual parameter values
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
char *<REPLACEABLE CLASS="PARAMETER">nulls</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Array describing which parameters are NULLs
<SimpleList>
<Member><literal>n</literal> indicates NULL (values[] entry ignored)</Member>
<Member>space indicates not NULL (values[] entry is valid)</Member>
</SimpleList>
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
<REFSECT2 ID="R2-SPI-SPICOPYTUPLE-2">
<REFSECT2 ID="R2-SPI-SPICURSOR-OPEN-2">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
<DATE>2001-11-14</DATE>
</REFSECT2INFO>
<TITLE>Outputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
HeapTuple
<TERM>Portal
</TERM>
<LISTITEM>
<PARA>
Copied tuple
<SimpleList>
<Member>
<ReturnValue>non-NULL</ReturnValue>
if <REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE>
is not NULL and the copy was successful
</Member>
<Member>
<ReturnValue>NULL</ReturnValue>
only if <REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE>
is NULL
</Member>
</SimpleList>
Pointer to Portal containing cursor, or NULL on error
</para>
</LISTITEM>
</VARLISTENTRY>
......@@ -1117,37 +1013,42 @@ Copied tuple
</REFSECT2>
</REFSYNOPSISDIV>
<REFSECT1 ID="R1-SPI-SPICOPYTUPLE-1">
<REFSECT1 ID="R1-SPI-SPICURSOR-OPEN-1">
<REFSECT1INFO>
<DATE>1997-12-24</DATE>
<DATE>2001-11-14</DATE>
</REFSECT1INFO>
<TITLE>Description
</TITLE>
<PARA>
<FUNCTION>SPI_copytuple</FUNCTION>
makes a copy of tuple in upper Executor context. See the section on Memory Management.
</PARA>
<FUNCTION>SPI_cursor_open</FUNCTION>
sets up a cursor (internally, a Portal) that will execute a plan
prepared by <Function>SPI_prepare</Function>.
</para>
<para>
Using a cursor instead of executing the plan directly has two
benefits. First, the result rows can be retrieved a few at a time,
avoiding memory overrun for queries that return many rows. Second,
a Portal can outlive the current procedure (it can, in fact, live to
the end of the current transaction). Returning the portal name to
the procedure's caller provides a way of returning a rowset result.
</para>
</REFSECT1>
<REFSECT1 ID="R1-SPI-SPICOPYTUPLE-2">
<REFSECT1 ID="R1-SPI-SPICURSOR-OPEN-2">
<TITLE>Usage
</TITLE>
<Para>
TBD
If <REPLACEABLE CLASS="PARAMETER">nulls</REPLACEABLE>
is NULL then
<Function>SPI_cursor_open</Function>
assumes that all parameters (if any) are NOT NULL.
</PARA>
</REFSECT1>
<!--
<REFSECT1 ID="R1-SPI-SPICOPYTUPLE-3">
<REFSECT1 ID="R1-SPI-SPICURSOR-OPEN-3">
<TITLE>Algorithm
</TITLE>
<PARA>
</PARA>
</REFSECT1>
-->
<!--
<REFSECT1 ID="R1-SPI-SPICOPYTUPLE-4">
<TITLE>Structures
</TITLE>
<PARA>None
<PARA><FUNCTION>SPI_cursor_open</FUNCTION> performs the following:
TBD
</PARA>
</REFSECT1>
-->
......@@ -1157,74 +1058,61 @@ TBD
<!-- *********************************************** -->
<!-- *********************************************** -->
<REFENTRY ID="SPI-SPICOPYTUPLEDESC">
<REFENTRY ID="SPI-SPICURSOR-FIND">
<REFMETA>
<REFENTRYTITLE>SPI_copytupledesc</REFENTRYTITLE>
<REFMISCINFO>SPI - Tuple Descriptor Copy</REFMISCINFO>
<REFENTRYTITLE>SPI_cursor_find</REFENTRYTITLE>
<REFMISCINFO>SPI - Cursor Support</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>SPI_copytupledesc
<REFNAME>SPI_cursor_find
</REFNAME>
<REFPURPOSE>
Makes copy of tuple descriptor in upper Executor context
Finds an existing cursor (Portal) by name
</REFPURPOSE>
<INDEXTERM ID="IX-SPI-SPICOPYTUPLEDESC-1"><PRIMARY>SPI</PRIMARY><SECONDARY>copying tuple descriptors</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-SPI-SPICOPYTUPLEDESC-2"><PRIMARY>SPI_copytupledesc</PRIMARY></INDEXTERM>
<INDEXTERM ID="IX-SPI-SPICURSOR-FIND-1"><PRIMARY>SPI</PRIMARY><SECONDARY>cursors</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-SPI-SPICURSOR-FIND-2"><PRIMARY>SPI_cursor_find</PRIMARY></INDEXTERM>
</REFNAMEDIV>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
<DATE>2001-08-02</DATE>
<DATE>2001-11-14</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
SPI_copytupledesc(<REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>)
SPI_cursor_find(<REPLACEABLE CLASS="PARAMETER">name</REPLACEABLE>)
</SYNOPSIS>
<REFSECT2 ID="R2-SPI-SPICOPYTUPLEDESC-1">
<REFSECT2 ID="R2-SPI-SPICURSOR-FIND-1">
<REFSECT2INFO>
<DATE>2001-08-02</DATE>
<DATE>2001-11-14</DATE>
</REFSECT2INFO>
<TITLE>Inputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
TupleDesc <REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>
char *<REPLACEABLE CLASS="PARAMETER">name</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Input tuple descriptor to be copied
Name of portal
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
<REFSECT2 ID="R2-SPI-SPICOPYTUPLEDESC-2">
<REFSECT2 ID="R2-SPI-SPICURSOR-FIND-2">
<REFSECT2INFO>
<DATE>2001-08-02</DATE>
<DATE>2001-11-14</DATE>
</REFSECT2INFO>
<TITLE>Outputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
TupleDesc
<TERM>Portal
</TERM>
<LISTITEM>
<PARA>
Copied tuple descriptor
<SimpleList>
<Member>
<ReturnValue>non-NULL</ReturnValue>
if <REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>
is not NULL and the copy was successful
</Member>
<Member>
<ReturnValue>NULL</ReturnValue>
only if <REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>
is NULL
</Member>
</SimpleList>
Pointer to Portal with given name, or NULL if not found
</para>
</LISTITEM>
</VARLISTENTRY>
......@@ -1232,37 +1120,32 @@ Copied tuple descriptor
</REFSECT2>
</REFSYNOPSISDIV>
<REFSECT1 ID="R1-SPI-SPICOPYTUPLEDESC-1">
<REFSECT1 ID="R1-SPI-SPICURSOR-FIND-1">
<REFSECT1INFO>
<DATE>2001-08-02</DATE>
<DATE>2001-11-14</DATE>
</REFSECT1INFO>
<TITLE>Description
</TITLE>
<PARA>
<FUNCTION>SPI_copytupledesc</FUNCTION>
makes a copy of tupdesc in upper Executor context. See the section on Memory Management.
</PARA>
<FUNCTION>SPI_cursor_find</FUNCTION>
finds a pre-existing Portal by name. This is primarily useful
to resolve a cursor name returned as text by some other function.
</para>
</REFSECT1>
<REFSECT1 ID="R1-SPI-SPICOPYTUPLEDESC-2">
<!--
<REFSECT1 ID="R1-SPI-SPICURSOR-FIND-2">
<TITLE>Usage
</TITLE>
<Para>
TBD
</PARA>
</REFSECT1>
<!--
<REFSECT1 ID="R1-SPI-SPICOPYTUPLEDESC-3">
<TITLE>Algorithm
</TITLE>
<PARA>
</PARA>
</REFSECT1>
-->
<!--
<REFSECT1 ID="R1-SPI-SPICOPYTUPLEDESC-4">
<TITLE>Structures
<REFSECT1 ID="R1-SPI-SPICURSOR-FIND-3">
<TITLE>Algorithm
</TITLE>
<PARA>None
<PARA><FUNCTION>SPI_cursor_find</FUNCTION> performs the following:
TBD
</PARA>
</REFSECT1>
-->
......@@ -1272,126 +1155,127 @@ TBD
<!-- *********************************************** -->
<!-- *********************************************** -->
<REFENTRY ID="SPI-SPICOPYTUPLEINTOSLOT">
<REFENTRY ID="SPI-SPICURSOR-FETCH">
<REFMETA>
<REFENTRYTITLE>SPI_copytupleintoslot</REFENTRYTITLE>
<REFMISCINFO>SPI - Tuple and Descriptor Copy</REFMISCINFO>
<REFENTRYTITLE>SPI_cursor_fetch</REFENTRYTITLE>
<REFMISCINFO>SPI - Cursor Support</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>SPI_copytupleintoslot
<REFNAME>SPI_cursor_fetch
</REFNAME>
<REFPURPOSE>
Makes copy of tuple and descriptor in upper Executor context
Fetches some rows from a cursor
</REFPURPOSE>
<INDEXTERM ID="IX-SPI-SPICOPYTUPLEINTOSLOT-1"><PRIMARY>SPI</PRIMARY><SECONDARY>copying tuples</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-SPI-SPICOPYTUPLEINTOSLOT-2"><PRIMARY>SPI_copytupleintoslot</PRIMARY></INDEXTERM>
<INDEXTERM ID="IX-SPI-SPICURSOR-FETCH-1"><PRIMARY>SPI</PRIMARY><SECONDARY>cursors</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-SPI-SPICURSOR-FETCH-2"><PRIMARY>SPI_cursor_fetch</PRIMARY></INDEXTERM>
</REFNAMEDIV>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
<DATE>1997-12-24</DATE>
<DATE>2001-11-14</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
SPI_copytupleintoslot(<REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE>, <REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>)
SPI_cursor_fetch(<REPLACEABLE CLASS="PARAMETER">portal</REPLACEABLE>,
<REPLACEABLE CLASS="PARAMETER">forward</REPLACEABLE>,
<REPLACEABLE CLASS="PARAMETER">count</REPLACEABLE>)
</SYNOPSIS>
<REFSECT2 ID="R2-SPI-SPICOPYTUPLEINTOSLOT-1">
<REFSECT2 ID="R2-SPI-SPICURSOR-FETCH-1">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
<DATE>2001-11-14</DATE>
</REFSECT2INFO>
<TITLE>Inputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
HeapTuple <REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE>
Portal <REPLACEABLE CLASS="PARAMETER">portal</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Input tuple to be copied
Portal containing cursor
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
TupleDesc <REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>
bool <REPLACEABLE CLASS="PARAMETER">forward</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Input tuple descriptor to be copied
True for fetch forward, false for fetch backward
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
int <REPLACEABLE CLASS="PARAMETER">count</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Maximum number of rows to fetch
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
<REFSECT2 ID="R2-SPI-SPICOPYTUPLEINTOSLOT-2">
<REFSECT2 ID="R2-SPI-SPICURSOR-FETCH-2">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
<DATE>2001-11-14</DATE>
</REFSECT2INFO>
<TITLE>Outputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
TupleTableSlot *
<TERM>SPI_tuptable
</TERM>
<LISTITEM>
<PARA>
Tuple slot containing copied tuple and descriptor
<SimpleList>
<Member>
<ReturnValue>non-NULL</ReturnValue>
if <REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE>
and <REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>
are not NULL and the copy was successful
</Member>
<Member>
<ReturnValue>NULL</ReturnValue>
only if <REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE>
or <REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>
is NULL
</Member>
</SimpleList>
</para>
initialized as in
<Function>SPI_exec</Function> if successful
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>SPI_processed
</TERM>
<LISTITEM>
<PARA>
initialized as in
<Function>SPI_exec</Function> if successful
</para>
</listitem>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
</REFSYNOPSISDIV>
<REFSECT1 ID="R1-SPI-SPICOPYTUPLEINTOSLOT-1">
<REFSECT1 ID="R1-SPI-SPICURSOR-FETCH-1">
<REFSECT1INFO>
<DATE>1997-12-24</DATE>
<DATE>2001-11-14</DATE>
</REFSECT1INFO>
<TITLE>Description
</TITLE>
<PARA>
<FUNCTION>SPI_copytupleintoslot</FUNCTION>
makes a copy of tuple in upper Executor context, returning it in the
form of a filled-in TupleTableSlot.
See the section on Memory Management.
</PARA>
<FUNCTION>SPI_cursor_fetch</FUNCTION>
fetches some (more) rows from a cursor. This is equivalent to the
SQL command <command>FETCH</>.
</para>
</REFSECT1>
<REFSECT1 ID="R1-SPI-SPICOPYTUPLEINTOSLOT-2">
<!--
<REFSECT1 ID="R1-SPI-SPICURSOR-FETCH-2">
<TITLE>Usage
</TITLE>
<Para>
TBD
</PARA>
</REFSECT1>
<!--
<REFSECT1 ID="R1-SPI-SPICOPYTUPLEINTOSLOT-3">
<TITLE>Algorithm
</TITLE>
<PARA>
</PARA>
</REFSECT1>
-->
<!--
<REFSECT1 ID="R1-SPI-SPICOPYTUPLEINTOSLOT-4">
<TITLE>Structures
<REFSECT1 ID="R1-SPI-SPICURSOR-FETCH-3">
<TITLE>Algorithm
</TITLE>
<PARA>None
<PARA><FUNCTION>SPI_cursor_fetch</FUNCTION> performs the following:
TBD
</PARA>
</REFSECT1>
-->
......@@ -1401,184 +1285,115 @@ TBD
<!-- *********************************************** -->
<!-- *********************************************** -->
<REFENTRY ID="SPI-SPIMODIFYTUPLE">
<REFENTRY ID="SPI-SPICURSOR-MOVE">
<REFMETA>
<REFENTRYTITLE>SPI_modifytuple</REFENTRYTITLE>
<REFMISCINFO>SPI - Tuple Modify</REFMISCINFO>
<REFENTRYTITLE>SPI_cursor_move</REFENTRYTITLE>
<REFMISCINFO>SPI - Cursor Support</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>SPI_modifytuple
<REFNAME>SPI_cursor_move
</REFNAME>
<REFPURPOSE>
Modifies tuple of relation
Moves a cursor
</REFPURPOSE>
<INDEXTERM ID="IX-SPI-SPIMODIFYTUPLE-1"><PRIMARY>SPI</PRIMARY><SECONDARY>modifying tuples</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-SPI-SPIMODIFYTUPLE-2"><PRIMARY>SPI_modifytuple</PRIMARY></INDEXTERM>
<INDEXTERM ID="IX-SPI-SPICURSOR-MOVE-1"><PRIMARY>SPI</PRIMARY><SECONDARY>cursors</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-SPI-SPICURSOR-MOVE-2"><PRIMARY>SPI_cursor_move</PRIMARY></INDEXTERM>
</REFNAMEDIV>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
<DATE>1997-12-24</DATE>
<DATE>2001-11-14</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
SPI_modifytuple(<REPLACEABLE CLASS="PARAMETER">rel</REPLACEABLE>, <REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE> , <REPLACEABLE CLASS="PARAMETER">nattrs</REPLACEABLE>
, <REPLACEABLE CLASS="PARAMETER">attnum</REPLACEABLE> , <REPLACEABLE CLASS="PARAMETER">Values</REPLACEABLE> , <REPLACEABLE CLASS="PARAMETER">Nulls</REPLACEABLE>)
SPI_cursor_move(<REPLACEABLE CLASS="PARAMETER">portal</REPLACEABLE>,
<REPLACEABLE CLASS="PARAMETER">forward</REPLACEABLE>,
<REPLACEABLE CLASS="PARAMETER">count</REPLACEABLE>)
</SYNOPSIS>
<REFSECT2 ID="R2-SPI-SPIMODIFYTUPLE-1">
<REFSECT2 ID="R2-SPI-SPICURSOR-MOVE-1">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
<DATE>2001-11-14</DATE>
</REFSECT2INFO>
<TITLE>Inputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
Relation <REPLACEABLE CLASS="PARAMETER">rel</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
HeapTuple <REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Input tuple to be modified
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
int <REPLACEABLE CLASS="PARAMETER">nattrs</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Number of attribute numbers in attnum
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
int * <REPLACEABLE CLASS="PARAMETER">attnum</REPLACEABLE>
Portal <REPLACEABLE CLASS="PARAMETER">portal</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Array of numbers of the attributes that are to be changed
Portal containing cursor
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
Datum * <REPLACEABLE CLASS="PARAMETER">Values</REPLACEABLE>
bool <REPLACEABLE CLASS="PARAMETER">forward</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
New values for the attributes specified
True for move forward, false for move backward
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
char * <REPLACEABLE CLASS="PARAMETER">Nulls</REPLACEABLE>
int <REPLACEABLE CLASS="PARAMETER">count</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Which attributes are NULL, if any
Maximum number of rows to move
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
<REFSECT2 ID="R2-SPI-SPIMODIFYTUPLE-2">
<REFSECT2 ID="R2-SPI-SPICURSOR-MOVE-2">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
<DATE>2001-11-14</DATE>
</REFSECT2INFO>
<TITLE>Outputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
HeapTuple
</TERM>
<LISTITEM>
<PARA>
New tuple with modifications
<SimpleList>
<Member>
<ReturnValue>non-NULL</ReturnValue>
if <REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE>
is not NULL and the modify was successful
</Member>
<Member>
<ReturnValue>NULL</ReturnValue>
only if <REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE>
is NULL
</Member>
</SimpleList>
</para>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
SPI_result
<TERM>None
</TERM>
<LISTITEM>
<PARA>
<SimpleList>
<Member>
<ReturnValue>SPI_ERROR_ARGUMENT</ReturnValue> if rel is NULL or tuple is NULL or natts &le; 0 or
attnum is NULL or Values is NULL.
</Member>
<Member>
<ReturnValue>SPI_ERROR_NOATTRIBUTE</ReturnValue> if there is an invalid
attribute number in attnum (attnum &le; 0 or &gt; number of
attributes in tuple)
</Member>
</SimpleList>
</para>
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
</REFSYNOPSISDIV>
<REFSECT1 ID="R1-SPI-SPIMODIFYTUPLE-1">
<REFSECT1 ID="R1-SPI-SPICURSOR-MOVE-1">
<REFSECT1INFO>
<DATE>1997-12-24</DATE>
<DATE>2001-11-14</DATE>
</REFSECT1INFO>
<TITLE>Description
</TITLE>
<PARA>
<FUNCTION>SPI_modifytuple</FUNCTION>
Modifies a tuple in upper Executor context. See the section on Memory Management.
</PARA>
<FUNCTION>SPI_cursor_move</FUNCTION>
skips over some number of rows in a cursor. This is equivalent to the
SQL command <command>MOVE</>.
</para>
</REFSECT1>
<REFSECT1 ID="R1-SPI-SPIMODIFYTUPLE-2">
<!--
<REFSECT1 ID="R1-SPI-SPICURSOR-MOVE-2">
<TITLE>Usage
</TITLE>
<Para>
If successful, a pointer to the new tuple is returned. The new tuple is
allocated in upper Executor context (see Memory management). Passed tuple
is not changed.
</PARA>
</REFSECT1>
<!--
<REFSECT1 ID="R1-SPI-SPIMODIFYTUPLE-3">
<TITLE>Algorithm
</TITLE>
<PARA>
</PARA>
</REFSECT1>
-->
<!--
<REFSECT1 ID="R1-SPI-SPIMODIFYTUPLE-4">
<TITLE>Structures
<REFSECT1 ID="R1-SPI-SPICURSOR-MOVE-3">
<TITLE>Algorithm
</TITLE>
<PARA>None
<PARA><FUNCTION>SPI_cursor_move</FUNCTION> performs the following:
TBD
</PARA>
</REFSECT1>
-->
......@@ -1588,29 +1403,284 @@ is not changed.
<!-- *********************************************** -->
<!-- *********************************************** -->
<REFENTRY ID="SPI-SPIFNUMBER">
<REFENTRY ID="SPI-SPICURSOR-CLOSE">
<REFMETA>
<REFENTRYTITLE>SPI_fnumber</REFENTRYTITLE>
<REFMISCINFO>SPI - Tuple Information</REFMISCINFO>
<REFENTRYTITLE>SPI_cursor_close</REFENTRYTITLE>
<REFMISCINFO>SPI - Cursor Support</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>SPI_fnumber
<REFNAME>SPI_cursor_close
</REFNAME>
<REFPURPOSE>
Finds the attribute number for specified attribute
Closes a cursor
</REFPURPOSE>
<INDEXTERM ID="IX-SPI-SPIFNUMBER-1"><PRIMARY>SPI</PRIMARY><SECONDARY>decoding tuples</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-SPI-SPIFNUMBER-2"><PRIMARY>SPI_fnumber</PRIMARY></INDEXTERM>
<INDEXTERM ID="IX-SPI-SPICURSOR-CLOSE-1"><PRIMARY>SPI</PRIMARY><SECONDARY>cursors</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-SPI-SPICURSOR-CLOSE-2"><PRIMARY>SPI_cursor_close</PRIMARY></INDEXTERM>
</REFNAMEDIV>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
<DATE>1997-12-24</DATE>
<DATE>2001-11-14</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
SPI_fnumber(<REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>, <REPLACEABLE CLASS="PARAMETER">fname</REPLACEABLE>)
SPI_cursor_close(<REPLACEABLE CLASS="PARAMETER">portal</REPLACEABLE>)
</SYNOPSIS>
<REFSECT2 ID="R2-SPI-SPIFNUMBER-1">
<REFSECT2 ID="R2-SPI-SPICURSOR-CLOSE-1">
<REFSECT2INFO>
<DATE>2001-11-14</DATE>
</REFSECT2INFO>
<TITLE>Inputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
Portal <REPLACEABLE CLASS="PARAMETER">portal</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Portal containing cursor
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
<REFSECT2 ID="R2-SPI-SPICURSOR-CLOSE-2">
<REFSECT2INFO>
<DATE>2001-11-14</DATE>
</REFSECT2INFO>
<TITLE>Outputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>None
</TERM>
<LISTITEM>
<PARA>
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
</REFSYNOPSISDIV>
<REFSECT1 ID="R1-SPI-SPICURSOR-CLOSE-1">
<REFSECT1INFO>
<DATE>2001-11-14</DATE>
</REFSECT1INFO>
<TITLE>Description
</TITLE>
<PARA>
<FUNCTION>SPI_cursor_close</FUNCTION>
closes a previously created cursor and releases its Portal storage.
</para>
</REFSECT1>
<REFSECT1 ID="R1-SPI-SPICURSOR-CLOSE-2">
<TITLE>Usage
</TITLE>
<Para>
All open cursors are closed implicitly at transaction end.
<FUNCTION>SPI_cursor_close</FUNCTION> need only be invoked if
it is desirable to release resources sooner.
</PARA>
</REFSECT1>
<!--
<REFSECT1 ID="R1-SPI-SPICURSOR-CLOSE-3">
<TITLE>Algorithm
</TITLE>
<PARA><FUNCTION>SPI_cursor_close</FUNCTION> performs the following:
TBD
</PARA>
</REFSECT1>
-->
</REFENTRY>
<!-- *********************************************** -->
<!-- *********************************************** -->
<!-- *********************************************** -->
<REFENTRY ID="SPI-SPISAVEPLAN">
<REFMETA>
<REFENTRYTITLE>SPI_saveplan</REFENTRYTITLE>
<REFMISCINFO>SPI - Plan Storage</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>SPI_saveplan
</REFNAME>
<REFPURPOSE>
Saves a passed plan
</REFPURPOSE>
<INDEXTERM ID="IX-SPI-SPISAVEPLAN-1"><PRIMARY>SPI</PRIMARY><SECONDARY>connecting</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-SPI-SPISAVEPLAN-2"><PRIMARY>SPI_saveplan</PRIMARY></INDEXTERM>
</REFNAMEDIV>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
<DATE>1997-12-24</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
SPI_saveplan(<REPLACEABLE CLASS="PARAMETER">plan</REPLACEABLE>)
</SYNOPSIS>
<REFSECT2 ID="R2-SPI-SPISAVEPLAN-1">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Inputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
void *<REPLACEABLE CLASS="PARAMETER">query</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Passed plan
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
<REFSECT2 ID="R2-SPI-SPISAVEPLAN-2">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Outputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>void *
</TERM>
<LISTITEM>
<PARA>
Execution plan location. NULL if unsuccessful.
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>SPI_result
</TERM>
<LISTITEM>
<PARA>
<SimpleList>
<Member>
<ReturnValue>SPI_ERROR_ARGUMENT</ReturnValue> if plan is NULL
</Member>
<Member>
<ReturnValue>SPI_ERROR_UNCONNECTED</ReturnValue> if procedure is un-connected
</Member>
</SimpleList>
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
</REFSYNOPSISDIV>
<REFSECT1 ID="R1-SPI-SPISAVEPLAN-1">
<REFSECT1INFO>
<DATE>1997-12-24</DATE>
</REFSECT1INFO>
<TITLE>Description
</TITLE>
<PARA>
<FUNCTION>SPI_saveplan</FUNCTION>
stores a plan prepared by <Function>SPI_prepare</Function> in safe memory
protected from freeing by <Function>SPI_finish</Function> or the transaction manager.
</para>
<Para>
In the current version of <ProductName>Postgres</ProductName> there is no ability to
store prepared plans in the system
catalog and fetch them from there for execution. This will be implemented
in future versions.
As an alternative, there is the ability to reuse prepared plans in the
subsequent invocations of your procedure in the current session.
Use <Function>SPI_execp</Function> to execute this saved plan.
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-SPI-SPISAVEPLAN-2">
<TITLE>Usage
</TITLE>
<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 and
returns a pointer to the saved plan. You may save the pointer returned in
a local variable. Always check if this pointer is NULL or not either when
preparing a plan or using an already prepared plan in SPI_execp (see below).
<Note>
<Para>
If one of the objects (a relation, function, etc.) referenced by the prepared
plan is dropped during your session (by your backend or another process) then the
results of <Function>SPI_execp</Function> for this plan will be unpredictable.
</Para>
</Note>
</PARA>
</REFSECT1>
<!--
<REFSECT1 ID="R1-SPI-SPISAVEPLAN-3">
<TITLE>Algorithm
</TITLE>
<PARA><FUNCTION>SPI_saveplan</FUNCTION> performs the following:
TBD
</PARA>
</REFSECT1>
-->
<!--
<REFSECT1 ID="R1-SPI-SPISAVEPLAN-4">
<TITLE>Structures
</TITLE>
<PARA>None
</PARA>
</REFSECT1>
-->
</REFENTRY>
</Sect1>
<Sect1 id="spi-interface-support">
<Title>Interface Support Functions</Title>
<Para>
The functions described here provide convenient interfaces for extracting
information from tuple sets returned by <function>SPI_exec</> and other
SPI interface functions.
</Para>
<Para>
All functions described in this section may be used by both connected and
unconnected procedures.
</Para>
<!-- *********************************************** -->
<!-- *********************************************** -->
<!-- *********************************************** -->
<REFENTRY ID="SPI-SPIFNUMBER">
<REFMETA>
<REFENTRYTITLE>SPI_fnumber</REFENTRYTITLE>
<REFMISCINFO>SPI - Tuple Information</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>SPI_fnumber
</REFNAME>
<REFPURPOSE>
Finds the attribute number for specified attribute name
</REFPURPOSE>
<INDEXTERM ID="IX-SPI-SPIFNUMBER-1"><PRIMARY>SPI</PRIMARY><SECONDARY>decoding tuples</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-SPI-SPIFNUMBER-2"><PRIMARY>SPI_fnumber</PRIMARY></INDEXTERM>
</REFNAMEDIV>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
<DATE>1997-12-24</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
SPI_fnumber(<REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>, <REPLACEABLE CLASS="PARAMETER">fname</REPLACEABLE>)
</SYNOPSIS>
<REFSECT2 ID="R2-SPI-SPIFNUMBER-1">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
......@@ -1685,7 +1755,15 @@ Valid one-based index number of attribute
</TITLE>
<Para>
Attribute numbers are 1 based.
</PARA>
</Para>
<Para>
If the given fname refers to a system attribute (eg, <literal>oid</>)
then the appropriate negative attribute number will be returned.
The caller should be careful to test for exact equality to
<ReturnValue>SPI_ERROR_NOATTRIBUTE</ReturnValue> to detect error;
testing for result &lt;= 0 is not correct unless system attributes
should be rejected.
</Para>
</REFSECT1>
<!--
<REFSECT1 ID="R1-SPI-SPIFNUMBER-3">
......@@ -1718,7 +1796,7 @@ Attribute numbers are 1 based.
<REFNAME>SPI_fname
</REFNAME>
<REFPURPOSE>
Finds the attribute name for the specified attribute
Finds the attribute name for the specified attribute number
</REFPURPOSE>
<INDEXTERM ID="IX-SPI-SPIFNAME-1"><PRIMARY>SPI</PRIMARY><SECONDARY>decoding tuples</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-SPI-SPIFNAME-2"><PRIMARY>SPI_fname</PRIMARY></INDEXTERM>
......@@ -1728,7 +1806,7 @@ Finds the attribute name for the specified attribute
<DATE>1997-12-24</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
SPI_fname(<REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>, <REPLACEABLE CLASS="PARAMETER">fname</REPLACEABLE>)
SPI_fname(<REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>, <REPLACEABLE CLASS="PARAMETER">fnumber</REPLACEABLE>)
</SYNOPSIS>
<REFSECT2 ID="R2-SPI-SPIFNAME-1">
......@@ -1814,6 +1892,7 @@ Attribute numbers are 1 based.
</TITLE>
<PARA>
Returns a newly-allocated copy of the attribute name.
(Use pfree() to release the copy when done with it.)
</PARA>
</REFSECT1>
<!--
......@@ -1950,7 +2029,8 @@ Attribute numbers are 1 based.
<TITLE>Algorithm
</TITLE>
<PARA>
Allocates memory as required by the value.
The result is returned as a palloc'd string.
(Use pfree() to release the string when done with it.)
</PARA>
</REFSECT1>
<!--
......@@ -2082,7 +2162,7 @@ SPI_result
</TITLE>
<PARA>
<FUNCTION>SPI_getbinval</FUNCTION>
returns the binary value of the specified attribute.
returns the specified attribute's value in internal form (as a Datum).
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-SPI-SPIGETBINVAL-2">
......@@ -2096,7 +2176,8 @@ Attribute numbers are 1 based.
<TITLE>Algorithm
</TITLE>
<PARA>
Does not allocate new space for the binary value.
Does not allocate new space for the datum. In the case of a pass-by-
reference datatype, the Datum will be a pointer into the given tuple.
</PARA>
</REFSECT1>
<!--
......@@ -2208,7 +2289,8 @@ SPI_result
</TITLE>
<PARA>
<FUNCTION>SPI_gettype</FUNCTION>
returns a copy of the type name for the specified attribute.
returns a copy of the type name for the specified attribute,
or NULL on error.
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-SPI-SPIGETTYPE-2">
......@@ -2222,7 +2304,8 @@ Attribute numbers are 1 based.
<TITLE>Algorithm
</TITLE>
<PARA>
Does not allocate new space for the binary value.
Returns a newly-allocated copy of the type name.
(Use pfree() to release the copy when done with it.)
</PARA>
</REFSECT1>
<!--
......@@ -2344,6 +2427,7 @@ SPI_result
Attribute numbers are 1 based.
</PARA>
</REFSECT1>
<!--
<REFSECT1 ID="R1-SPI-SPIGETTYPEID-3">
<TITLE>Algorithm
</TITLE>
......@@ -2351,6 +2435,7 @@ Attribute numbers are 1 based.
TBD
</PARA>
</REFSECT1>
-->
<!--
<REFSECT1 ID="R1-SPI-SPIGETTYPEID-4">
<TITLE>Structures
......@@ -2428,33 +2513,656 @@ The name of the specified relation
</REFSECT2>
</REFSYNOPSISDIV>
<REFSECT1 ID="R1-SPI-SPIGETRELNAME-1">
<REFSECT1 ID="R1-SPI-SPIGETRELNAME-1">
<REFSECT1INFO>
<DATE>1997-12-24</DATE>
</REFSECT1INFO>
<TITLE>Description
</TITLE>
<PARA>
<FUNCTION>SPI_getrelname</FUNCTION>
returns the name of the specified relation.
</PARA>
</REFSECT1>
<!--
<REFSECT1 ID="R1-SPI-SPIGETRELNAME-2">
<TITLE>Usage
</TITLE>
<Para>
TBD
</PARA>
</REFSECT1>
-->
<REFSECT1 ID="R1-SPI-SPIGETRELNAME-3">
<TITLE>Algorithm
</TITLE>
<PARA>
Returns a newly-allocated copy of the rel name.
(Use pfree() to release the copy when done with it.)
</PARA>
</REFSECT1>
<!--
<REFSECT1 ID="R1-SPI-SPIGETRELNAME-4">
<TITLE>Structures
</TITLE>
<PARA>None
</PARA>
</REFSECT1>
-->
</REFENTRY>
</Sect1>
<Sect1 id="spi-memory">
<Title>Memory Management</Title>
<Para>
<ProductName>Postgres</ProductName> allocates memory within memory
<firstterm>contexts</firstterm>, which provide a convenient method of
managing allocations made in many different places that need to live
for differing amounts of time. Destroying a context releases all the
memory that was allocated in it. Thus, it is not necessary to keep track
of individual objects to avoid memory leaks --- only a relatively small number
of contexts have to be managed. <Function>palloc</Function> and related
functions allocate memory from the <quote>current</> context.
</Para>
<Para>
<Function>SPI_connect</Function> creates a new memory context and makes
it current. <Function>SPI_finish</Function> restores the previous
current memory context and destroys the context created by
<Function>SPI_connect</Function>. These actions ensure that transient
memory allocations made inside your procedure are reclaimed at procedure
exit, avoiding memory leakage.
</Para>
<Para>
However, if your procedure needs to return an allocated memory object
(such as a value of a pass-by-reference datatype), you can't allocate
the return object using <Function>palloc</Function>, at least not while
you are connected to SPI. If you try, the object will be deallocated
during <Function>SPI_finish</Function>, and your procedure will not
work reliably!
</Para>
<Para>
To solve this problem, use <Function>SPI_palloc</Function> to allocate
your return object. <Function>SPI_palloc</Function> allocates space
from <quote>upper Executor</> memory --- that is, the memory context
that was current when <Function>SPI_connect</Function> was called,
which is precisely the right context for return values of your procedure.
</Para>
<Para>
If called while not connected to SPI, <Function>SPI_palloc</Function>
acts the same as plain <Function>palloc</Function>.
</Para>
<Para>
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.
</Para>
<Para>
After <Function>SPI_connect</Function> is called, the current context is
the procedure's private context made by <Function>SPI_connect</Function>.
All allocations made via
<Function>palloc</Function>/<Function>repalloc</Function> or by SPI utility
functions (except for <Function>SPI_copytuple</Function>,
<Function>SPI_copytupledesc</Function>,
<Function>SPI_copytupleintoslot</Function>,
<Function>SPI_modifytuple</Function>,
and <Function>SPI_palloc</Function>) are
made in this context.
</Para>
<Para>
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 can't be used any more!
</Para>
<Para>
All functions described in this section may be used by both connected and
unconnected procedures. In an unconnected procedure, they act the same
as the underlying ordinary backend functions (<function>palloc</> etc).
</Para>
<!-- *********************************************** -->
<!-- *********************************************** -->
<!-- *********************************************** -->
<REFENTRY ID="SPI-SPICOPYTUPLE">
<REFMETA>
<REFENTRYTITLE>SPI_copytuple</REFENTRYTITLE>
<REFMISCINFO>SPI - Tuple Copy</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>SPI_copytuple
</REFNAME>
<REFPURPOSE>
Makes copy of tuple in upper Executor context
</REFPURPOSE>
<INDEXTERM ID="IX-SPI-SPICOPYTUPLE-1"><PRIMARY>SPI</PRIMARY><SECONDARY>copying tuples</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-SPI-SPICOPYTUPLE-2"><PRIMARY>SPI_copytuple</PRIMARY></INDEXTERM>
</REFNAMEDIV>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
<DATE>1997-12-24</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
SPI_copytuple(<REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE>)
</SYNOPSIS>
<REFSECT2 ID="R2-SPI-SPICOPYTUPLE-1">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Inputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
HeapTuple <REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Input tuple to be copied
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
<REFSECT2 ID="R2-SPI-SPICOPYTUPLE-2">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Outputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
HeapTuple
</TERM>
<LISTITEM>
<PARA>
Copied tuple
<SimpleList>
<Member>
<ReturnValue>non-NULL</ReturnValue>
if <REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE>
is not NULL and the copy was successful
</Member>
<Member>
<ReturnValue>NULL</ReturnValue>
only if <REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE>
is NULL
</Member>
</SimpleList>
</para>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
</REFSYNOPSISDIV>
<REFSECT1 ID="R1-SPI-SPICOPYTUPLE-1">
<REFSECT1INFO>
<DATE>1997-12-24</DATE>
</REFSECT1INFO>
<TITLE>Description
</TITLE>
<PARA>
<FUNCTION>SPI_copytuple</FUNCTION>
makes a copy of tuple in upper Executor context.
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-SPI-SPICOPYTUPLE-2">
<TITLE>Usage
</TITLE>
<Para>
TBD
</PARA>
</REFSECT1>
<!--
<REFSECT1 ID="R1-SPI-SPICOPYTUPLE-3">
<TITLE>Algorithm
</TITLE>
<PARA>
</PARA>
</REFSECT1>
-->
<!--
<REFSECT1 ID="R1-SPI-SPICOPYTUPLE-4">
<TITLE>Structures
</TITLE>
<PARA>None
</PARA>
</REFSECT1>
-->
</REFENTRY>
<!-- *********************************************** -->
<!-- *********************************************** -->
<!-- *********************************************** -->
<REFENTRY ID="SPI-SPICOPYTUPLEDESC">
<REFMETA>
<REFENTRYTITLE>SPI_copytupledesc</REFENTRYTITLE>
<REFMISCINFO>SPI - Tuple Descriptor Copy</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>SPI_copytupledesc
</REFNAME>
<REFPURPOSE>
Makes copy of tuple descriptor in upper Executor context
</REFPURPOSE>
<INDEXTERM ID="IX-SPI-SPICOPYTUPLEDESC-1"><PRIMARY>SPI</PRIMARY><SECONDARY>copying tuple descriptors</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-SPI-SPICOPYTUPLEDESC-2"><PRIMARY>SPI_copytupledesc</PRIMARY></INDEXTERM>
</REFNAMEDIV>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
<DATE>2001-08-02</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
SPI_copytupledesc(<REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>)
</SYNOPSIS>
<REFSECT2 ID="R2-SPI-SPICOPYTUPLEDESC-1">
<REFSECT2INFO>
<DATE>2001-08-02</DATE>
</REFSECT2INFO>
<TITLE>Inputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
TupleDesc <REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Input tuple descriptor to be copied
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
<REFSECT2 ID="R2-SPI-SPICOPYTUPLEDESC-2">
<REFSECT2INFO>
<DATE>2001-08-02</DATE>
</REFSECT2INFO>
<TITLE>Outputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
TupleDesc
</TERM>
<LISTITEM>
<PARA>
Copied tuple descriptor
<SimpleList>
<Member>
<ReturnValue>non-NULL</ReturnValue>
if <REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>
is not NULL and the copy was successful
</Member>
<Member>
<ReturnValue>NULL</ReturnValue>
only if <REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>
is NULL
</Member>
</SimpleList>
</para>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
</REFSYNOPSISDIV>
<REFSECT1 ID="R1-SPI-SPICOPYTUPLEDESC-1">
<REFSECT1INFO>
<DATE>2001-08-02</DATE>
</REFSECT1INFO>
<TITLE>Description
</TITLE>
<PARA>
<FUNCTION>SPI_copytupledesc</FUNCTION>
makes a copy of tupdesc in upper Executor context.
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-SPI-SPICOPYTUPLEDESC-2">
<TITLE>Usage
</TITLE>
<Para>
TBD
</PARA>
</REFSECT1>
<!--
<REFSECT1 ID="R1-SPI-SPICOPYTUPLEDESC-3">
<TITLE>Algorithm
</TITLE>
<PARA>
</PARA>
</REFSECT1>
-->
<!--
<REFSECT1 ID="R1-SPI-SPICOPYTUPLEDESC-4">
<TITLE>Structures
</TITLE>
<PARA>None
</PARA>
</REFSECT1>
-->
</REFENTRY>
<!-- *********************************************** -->
<!-- *********************************************** -->
<!-- *********************************************** -->
<REFENTRY ID="SPI-SPICOPYTUPLEINTOSLOT">
<REFMETA>
<REFENTRYTITLE>SPI_copytupleintoslot</REFENTRYTITLE>
<REFMISCINFO>SPI - Tuple and Descriptor Copy</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>SPI_copytupleintoslot
</REFNAME>
<REFPURPOSE>
Makes copy of tuple and descriptor in upper Executor context
</REFPURPOSE>
<INDEXTERM ID="IX-SPI-SPICOPYTUPLEINTOSLOT-1"><PRIMARY>SPI</PRIMARY><SECONDARY>copying tuples</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-SPI-SPICOPYTUPLEINTOSLOT-2"><PRIMARY>SPI_copytupleintoslot</PRIMARY></INDEXTERM>
</REFNAMEDIV>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
<DATE>1997-12-24</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
SPI_copytupleintoslot(<REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE>, <REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>)
</SYNOPSIS>
<REFSECT2 ID="R2-SPI-SPICOPYTUPLEINTOSLOT-1">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Inputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
HeapTuple <REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Input tuple to be copied
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
TupleDesc <REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Input tuple descriptor to be copied
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
<REFSECT2 ID="R2-SPI-SPICOPYTUPLEINTOSLOT-2">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Outputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
TupleTableSlot *
</TERM>
<LISTITEM>
<PARA>
Tuple slot containing copied tuple and descriptor
<SimpleList>
<Member>
<ReturnValue>non-NULL</ReturnValue>
if <REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE>
and <REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>
are not NULL and the copy was successful
</Member>
<Member>
<ReturnValue>NULL</ReturnValue>
only if <REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE>
or <REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>
is NULL
</Member>
</SimpleList>
</para>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
</REFSYNOPSISDIV>
<REFSECT1 ID="R1-SPI-SPICOPYTUPLEINTOSLOT-1">
<REFSECT1INFO>
<DATE>1997-12-24</DATE>
</REFSECT1INFO>
<TITLE>Description
</TITLE>
<PARA>
<FUNCTION>SPI_copytupleintoslot</FUNCTION>
makes a copy of tuple in upper Executor context, returning it in the
form of a filled-in TupleTableSlot.
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-SPI-SPICOPYTUPLEINTOSLOT-2">
<TITLE>Usage
</TITLE>
<Para>
TBD
</PARA>
</REFSECT1>
<!--
<REFSECT1 ID="R1-SPI-SPICOPYTUPLEINTOSLOT-3">
<TITLE>Algorithm
</TITLE>
<PARA>
</PARA>
</REFSECT1>
-->
<!--
<REFSECT1 ID="R1-SPI-SPICOPYTUPLEINTOSLOT-4">
<TITLE>Structures
</TITLE>
<PARA>None
</PARA>
</REFSECT1>
-->
</REFENTRY>
<!-- *********************************************** -->
<!-- *********************************************** -->
<!-- *********************************************** -->
<REFENTRY ID="SPI-SPIMODIFYTUPLE">
<REFMETA>
<REFENTRYTITLE>SPI_modifytuple</REFENTRYTITLE>
<REFMISCINFO>SPI - Tuple Modify</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>SPI_modifytuple
</REFNAME>
<REFPURPOSE>
Creates a tuple by replacing selected fields of a given tuple
</REFPURPOSE>
<INDEXTERM ID="IX-SPI-SPIMODIFYTUPLE-1"><PRIMARY>SPI</PRIMARY><SECONDARY>modifying tuples</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-SPI-SPIMODIFYTUPLE-2"><PRIMARY>SPI_modifytuple</PRIMARY></INDEXTERM>
</REFNAMEDIV>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
<DATE>1997-12-24</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
SPI_modifytuple(<REPLACEABLE CLASS="PARAMETER">rel</REPLACEABLE>, <REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE>, <REPLACEABLE CLASS="PARAMETER">nattrs</REPLACEABLE>, <REPLACEABLE CLASS="PARAMETER">attnum</REPLACEABLE>, <REPLACEABLE CLASS="PARAMETER">Values</REPLACEABLE>, <REPLACEABLE CLASS="PARAMETER">Nulls</REPLACEABLE>)
</SYNOPSIS>
<REFSECT2 ID="R2-SPI-SPIMODIFYTUPLE-1">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Inputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
Relation <REPLACEABLE CLASS="PARAMETER">rel</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Used only as source of tuple descriptor for tuple. (Passing a relation
rather than a tuple descriptor is a misfeature.)
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
HeapTuple <REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Input tuple to be modified
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
int <REPLACEABLE CLASS="PARAMETER">nattrs</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Number of attribute numbers in attnum array
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
int * <REPLACEABLE CLASS="PARAMETER">attnum</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Array of numbers of the attributes that are to be changed
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
Datum * <REPLACEABLE CLASS="PARAMETER">Values</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
New values for the attributes specified
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
char * <REPLACEABLE CLASS="PARAMETER">Nulls</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Which new values are NULL, if any
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
<REFSECT2 ID="R2-SPI-SPIMODIFYTUPLE-2">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Outputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
HeapTuple
</TERM>
<LISTITEM>
<PARA>
New tuple with modifications
<SimpleList>
<Member>
<ReturnValue>non-NULL</ReturnValue>
if <REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE>
is not NULL and the modify was successful
</Member>
<Member>
<ReturnValue>NULL</ReturnValue>
only if <REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE>
is NULL
</Member>
</SimpleList>
</para>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
SPI_result
</TERM>
<LISTITEM>
<PARA>
<SimpleList>
<Member>
<ReturnValue>SPI_ERROR_ARGUMENT</ReturnValue> if rel is NULL or tuple is NULL or natts &lt;= 0 or
attnum is NULL or Values is NULL.
</Member>
<Member>
<ReturnValue>SPI_ERROR_NOATTRIBUTE</ReturnValue> if there is an invalid
attribute number in attnum (attnum &lt;= 0 or &gt; number of
attributes in tuple)
</Member>
</SimpleList>
</para>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
</REFSYNOPSISDIV>
<REFSECT1 ID="R1-SPI-SPIMODIFYTUPLE-1">
<REFSECT1INFO>
<DATE>1997-12-24</DATE>
</REFSECT1INFO>
<TITLE>Description
</TITLE>
<PARA>
<FUNCTION>SPI_getrelname</FUNCTION>
returns the name of the specified relation.
<FUNCTION>SPI_modifytuple</FUNCTION>
creates a new tuple by substituting new values for selected attributes,
copying the original tuple's attributes at other positions. The input
tuple is not modified.
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-SPI-SPIGETRELNAME-2">
<REFSECT1 ID="R1-SPI-SPIMODIFYTUPLE-2">
<TITLE>Usage
</TITLE>
<Para>
TBD
If successful, a pointer to the new tuple is returned. The new tuple is
allocated in upper Executor context.
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-SPI-SPIGETRELNAME-3">
<!--
<REFSECT1 ID="R1-SPI-SPIMODIFYTUPLE-3">
<TITLE>Algorithm
</TITLE>
<PARA>
Copies the relation name into new storage.
</PARA>
</REFSECT1>
-->
<!--
<REFSECT1 ID="R1-SPI-SPIGETRELNAME-4">
<REFSECT1 ID="R1-SPI-SPIMODIFYTUPLE-4">
<TITLE>Structures
</TITLE>
<PARA>None
......@@ -2538,7 +3246,7 @@ New storage space of specified size
</TITLE>
<PARA>
<FUNCTION>SPI_palloc</FUNCTION>
allocates memory in upper Executor context. See section on memory management.
allocates memory in upper Executor context.
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-SPI-SPIPALLOC-2">
......@@ -2652,14 +3360,15 @@ New storage space of specified size with contents copied from existing area
</TITLE>
<PARA>
<FUNCTION>SPI_repalloc</FUNCTION>
re-allocates memory in upper Executor context. See section on memory management.
re-allocates memory in upper Executor context.
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-SPI-SPIREPALLOC-2">
<TITLE>Usage
</TITLE>
<Para>
TBD
This function is no longer different from plain <FUNCTION>repalloc</FUNCTION>.
It's kept just for backward compatibility of existing code.
</PARA>
</REFSECT1>
<!--
......@@ -2694,7 +3403,7 @@ TBD
<REFNAME>SPI_pfree
</REFNAME>
<REFPURPOSE>
Frees memory from upper Executor context
Frees memory in upper Executor context
</REFPURPOSE>
<INDEXTERM ID="IX-SPI-SPIPFREE-1"><PRIMARY>SPI</PRIMARY><SECONDARY>allocating space</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-SPI-SPIPFREE-2"><PRIMARY>SPI_pfree</PRIMARY></INDEXTERM>
......@@ -2755,105 +3464,280 @@ None
</TITLE>
<PARA>
<FUNCTION>SPI_pfree</FUNCTION>
frees memory in upper Executor context. See section on memory management.
frees memory in upper Executor context.
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-SPI-SPIPFREE-2">
<TITLE>Usage
</TITLE>
<Para>
TBD
This function is no longer different from plain <FUNCTION>pfree</FUNCTION>.
It's kept just for backward compatibility of existing code.
</PARA>
</REFSECT1>
<!--
<REFSECT1 ID="R1-SPI-SPIPFREE-3">
<TITLE>Algorithm
</REFENTRY>
<!-- *********************************************** -->
<!-- *********************************************** -->
<!-- *********************************************** -->
<REFENTRY ID="SPI-SPIFREETUPLE">
<REFMETA>
<REFENTRYTITLE>SPI_freetuple</REFENTRYTITLE>
<REFMISCINFO>SPI - Memory Management</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>SPI_freetuple
</REFNAME>
<REFPURPOSE>
Frees a tuple allocated in upper Executor context
</REFPURPOSE>
<INDEXTERM ID="IX-SPI-SPIFREETUPLE-1"><PRIMARY>SPI</PRIMARY><SECONDARY>allocating space</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-SPI-SPIFREETUPLE-2"><PRIMARY>SPI_freetuple</PRIMARY></INDEXTERM>
</REFNAMEDIV>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
<DATE>1997-12-24</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
SPI_freetuple(<REPLACEABLE CLASS="PARAMETER">pointer</REPLACEABLE>)
</SYNOPSIS>
<REFSECT2 ID="R2-SPI-SPIFREETUPLE-1">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Inputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
HeapTuple <REPLACEABLE CLASS="PARAMETER">pointer</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
TBD
Pointer to allocated tuple
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
<REFSECT2 ID="R2-SPI-SPIFREETUPLE-2">
<REFSECT2INFO>
<DATE>1997-12-24</DATE>
</REFSECT2INFO>
<TITLE>Outputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
None
</TERM>
<LISTITEM>
<PARA>
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
</REFSYNOPSISDIV>
<REFSECT1 ID="R1-SPI-SPIFREETUPLE-1">
<REFSECT1INFO>
<DATE>1997-12-24</DATE>
</REFSECT1INFO>
<TITLE>Description
</TITLE>
<PARA>
<FUNCTION>SPI_freetuple</FUNCTION>
frees a tuple previously allocated in upper Executor context.
</PARA>
</REFSECT1>
-->
<!--
<REFSECT1 ID="R1-SPI-SPIPFREE-4">
<TITLE>Structures
<REFSECT1 ID="R1-SPI-SPIFREETUPLE-2">
<TITLE>Usage
</TITLE>
<PARA>None
<Para>
This function is no longer different from plain <FUNCTION>heap_freetuple</FUNCTION>.
It's kept just for backward compatibility of existing code.
</PARA>
</REFSECT1>
-->
</REFENTRY>
</Sect1>
<Sect1 id="spi-memory">
<Title>Memory Management</Title>
<Para>
Server allocates memory in memory contexts in such way that allocations
made in one context may be freed by context destruction without affecting
allocations made in other contexts. All allocations (via <Function>palloc</Function>, etc) are
made in the context that is chosen as the current one. You'll get
unpredictable results if you'll try to free (or reallocate) memory allocated
not in current context.
</Para>
<Para>
Creation and switching between memory contexts are subject of SPI manager
memory management.
</Para>
<Para>
SPI procedures deal with two memory contexts: upper Executor memory
context and procedure memory context (if connected).
</Para>
<Para>
Before a procedure is connected to the SPI manager, current memory context
is upper Executor context so all allocation made by the procedure itself via
<Function>palloc</Function>/<Function>repalloc</Function> or by SPI utility functions before connecting to SPI are
made in this context.
</Para>
<Para>
<!-- *********************************************** -->
<!-- *********************************************** -->
<!-- *********************************************** -->
After <Function>SPI_connect</Function> is called current context is the
procedure's one. All allocations made via
<Function>palloc</Function>/<Function>repalloc</Function> or by SPI utility
functions (except for <Function>SPI_copytuple</Function>,
<Function>SPI_copytupledesc</Function>,
<Function>SPI_copytupleintoslot</Function>,
<Function>SPI_modifytuple</Function>,
<Function>SPI_palloc</Function> and <Function>SPI_repalloc</Function>) are
made in this context.
</Para>
<REFENTRY ID="SPI-SPIFREETUPTABLE">
<REFMETA>
<REFENTRYTITLE>SPI_freetuptable</REFENTRYTITLE>
<REFMISCINFO>SPI - Memory Management</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>SPI_freetuptable
</REFNAME>
<REFPURPOSE>
Frees a tuple set created by <function>SPI_exec</> or similar function
</REFPURPOSE>
<INDEXTERM ID="IX-SPI-SPIFREETUPTABLE-1"><PRIMARY>SPI</PRIMARY><SECONDARY>allocating space</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-SPI-SPIFREETUPTABLE-2"><PRIMARY>SPI_freetuptable</PRIMARY></INDEXTERM>
</REFNAMEDIV>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
<DATE>2001-11-14</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
SPI_freetuptable(<REPLACEABLE CLASS="PARAMETER">tuptable</REPLACEABLE>)
</SYNOPSIS>
<Para>
<REFSECT2 ID="R2-SPI-SPIFREETUPTABLE-1">
<REFSECT2INFO>
<DATE>2001-11-14</DATE>
</REFSECT2INFO>
<TITLE>Inputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
SPITupleTable * <REPLACEABLE CLASS="PARAMETER">tuptable</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Pointer to tuple table
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
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 can't be used any more!
</Para>
<REFSECT2 ID="R2-SPI-SPIFREETUPTABLE-2">
<REFSECT2INFO>
<DATE>2001-11-14</DATE>
</REFSECT2INFO>
<TITLE>Outputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
None
</TERM>
<LISTITEM>
<PARA>
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
</REFSYNOPSISDIV>
<REFSECT1 ID="R1-SPI-SPIFREETUPTABLE-1">
<REFSECT1INFO>
<DATE>2001-11-14</DATE>
</REFSECT1INFO>
<TITLE>Description
</TITLE>
<PARA>
<FUNCTION>SPI_freetuptable</FUNCTION>
frees a tuple set created by a prior SPI query function, such as
<function>SPI_exec</>.
</PARA>
</REFSECT1>
<REFSECT1 ID="R1-SPI-SPIFREETUPTABLE-2">
<TITLE>Usage
</TITLE>
<Para>
This function is useful if a SPI procedure needs to execute multiple
queries and does not want to keep the results of earlier queries around
until it ends. Note that any unfreed tuple sets will be freed anyway
at <function>SPI_finish</>.
</PARA>
</REFSECT1>
</REFENTRY>
If you want to return something to the upper Executor then you have to
allocate memory for this in the upper context!
</Para>
<!-- *********************************************** -->
<!-- *********************************************** -->
<!-- *********************************************** -->
<Para>
<REFENTRY ID="SPI-SPIFREEPLAN">
<REFMETA>
<REFENTRYTITLE>SPI_freeplan</REFENTRYTITLE>
<REFMISCINFO>SPI - Memory Management</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>SPI_freeplan
</REFNAME>
<REFPURPOSE>
Releases a previously saved plan
</REFPURPOSE>
<INDEXTERM ID="IX-SPI-SPIFREEPLAN-1"><PRIMARY>SPI</PRIMARY><SECONDARY>allocating space</SECONDARY></INDEXTERM>
<INDEXTERM ID="IX-SPI-SPIFREEPLAN-2"><PRIMARY>SPI_freeplan</PRIMARY></INDEXTERM>
</REFNAMEDIV>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
<DATE>2001-11-14</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
SPI_freeplan(<REPLACEABLE CLASS="PARAMETER">plan</REPLACEABLE>)
</SYNOPSIS>
SPI has no ability to automatically free allocations in the upper Executor
context!
</Para>
<REFSECT2 ID="R2-SPI-SPIFREEPLAN-1">
<REFSECT2INFO>
<DATE>2001-11-14</DATE>
</REFSECT2INFO>
<TITLE>Inputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
void *<REPLACEABLE CLASS="PARAMETER">plan</REPLACEABLE>
</TERM>
<LISTITEM>
<PARA>
Passed plan
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
<Para>
<REFSECT2 ID="R2-SPI-SPIFREEPLAN-2">
<REFSECT2INFO>
<DATE>2001-11-14</DATE>
</REFSECT2INFO>
<TITLE>Outputs
</TITLE>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>int
</TERM>
<LISTITEM>
<PARA>
<SimpleList>
<Member>
<ReturnValue>SPI_ERROR_ARGUMENT</ReturnValue> if plan is NULL
</Member>
</SimpleList>
</PARA>
</LISTITEM>
</VARLISTENTRY>
</VARIABLELIST>
</REFSECT2>
</REFSYNOPSISDIV>
SPI automatically frees memory allocated during execution of a query when
this query is done!
</Para>
<REFSECT1 ID="R1-SPI-SPIFREEPLAN-1">
<REFSECT1INFO>
<DATE>2001-11-14</DATE>
</REFSECT1INFO>
<TITLE>Description
</TITLE>
<PARA>
<FUNCTION>SPI_freeplan</FUNCTION>
releases a query plan previously returned by
<Function>SPI_prepare</Function> or saved by
<Function>SPI_saveplan</Function>.
</para>
</REFSECT1>
</REFENTRY>
</Sect1>
......@@ -2864,9 +3748,9 @@ this query is done!
<ProductName>Postgres</ProductName> data changes visibility rule: during a query execution, data
changes made by the query itself (via SQL-function, SPI-function, triggers)
are invisible to the query scan. For example, in query
<programlisting>
INSERT INTO a SELECT * FROM a
</programlisting>
tuples inserted are invisible for SELECT's scan. In effect, this
duplicates the database table within itself (subject to unique index
rules, of course) without recursing.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment