<!-- $Header: /cvsroot/pgsql/doc/src/sgml/spi.sgml,v 1.22 2002/03/22 19:20:30 petere Exp $ --> <Chapter id="spi"> <DocInfo> <AuthorGroup> <Author> <FirstName>Vadim</FirstName> <Surname>Mikheev</Surname> </Author> </AuthorGroup> <Date>Transcribed 1998-01-16</Date> </DocInfo> <Title>Server Programming Interface</Title> <Para> 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. </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. <Acronym>SPI</Acronym> also does some memory management. </Para> <Para> To avoid misunderstanding we'll use <FirstTerm>function</FirstTerm> to mean <Acronym>SPI</Acronym> interface functions and <FirstTerm>procedure</FirstTerm> for user-defined C-functions using <Acronym>SPI</Acronym>. </Para> <Para> Procedures which use <Acronym>SPI</Acronym> are called by the Executor. The <Acronym>SPI</Acronym> calls recursively invoke the Executor in turn to run queries. When the Executor is invoked recursively, it may itself call procedures which may make <Acronym>SPI</Acronym> calls. </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 will be rolled back and the server will wait for the next command from the client. This will probably be changed in future versions. </Para> <Para> A related restriction is the inability to execute BEGIN, END and ABORT (transaction control statements). This will also be changed in the future. </Para> <Para> If successful, <Acronym>SPI</Acronym> functions return a non-negative result (either via a returned integer value or in SPI_result global variable, as described below). On error, a negative or NULL result will be returned. </Para> <Sect1 id="spi-interface"> <Title>Interface Functions</Title> <REFENTRY ID="SPI-SPICONNECT"> <REFMETA> <REFENTRYTITLE>SPI_connect</REFENTRYTITLE> <REFMISCINFO>SPI - Connection Management</REFMISCINFO> </REFMETA> <REFNAMEDIV> <REFNAME>SPI_connect </REFNAME> <REFPURPOSE> Connects your procedure to the SPI manager. </REFPURPOSE> <INDEXTERM ID="IX-SPI-SPICONNECT-1"><PRIMARY>SPI</PRIMARY><SECONDARY>connecting</SECONDARY></INDEXTERM> <INDEXTERM ID="IX-SPI-SPICONNECT-2"><PRIMARY>SPI_connect</PRIMARY></INDEXTERM> </REFNAMEDIV> <REFSYNOPSISDIV> <REFSYNOPSISDIVINFO> <DATE>1997-12-24</DATE> </REFSYNOPSISDIVINFO> <SYNOPSIS> int SPI_connect(void) </SYNOPSIS> <REFSECT2 ID="R2-SPI-SPICONNECT-1"> <REFSECT2INFO> <DATE>1997-12-24</DATE> </REFSECT2INFO> <TITLE>Inputs </TITLE> <PARA>None </PARA> </REFSECT2> <REFSECT2 ID="R2-SPI-SPICONNECT-2"> <REFSECT2INFO> <DATE>1997-12-24</DATE> </REFSECT2INFO> <TITLE>Outputs </TITLE> <VARIABLELIST> <VARLISTENTRY> <TERM>int </TERM> <LISTITEM> <PARA> Return status <VARIABLELIST> <VARLISTENTRY> <TERM><ReturnValue>SPI_OK_CONNECT</ReturnValue> </TERM> <LISTITEM> <PARA> if connected </PARA> </LISTITEM> </VARLISTENTRY> <VARLISTENTRY> <TERM><ReturnValue>SPI_ERROR_CONNECT</ReturnValue> </TERM> <LISTITEM> <PARA> if not connected </PARA> </LISTITEM> </VARLISTENTRY> </VARIABLELIST> </para> </LISTITEM> </VARLISTENTRY> </VARIABLELIST> </REFSECT2> </REFSYNOPSISDIV> <REFSECT1 ID="R1-SPI-SPICONNECT-1"> <REFSECT1INFO> <DATE>1997-12-24</DATE> </REFSECT1INFO> <TITLE>Description </TITLE> <PARA> <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> If your procedure is already connected, <Function>SPI_connect</Function> will return an <ReturnValue>SPI_ERROR_CONNECT</ReturnValue> error. Note that this may happen if a procedure which has called <Function>SPI_connect</Function> directly calls another procedure which itself calls <Function>SPI_connect</Function>. While recursive calls to the <Acronym>SPI</Acronym> manager are permitted when an <Acronym>SPI</Acronym> query invokes another function which uses <Acronym>SPI</Acronym>, directly nested calls to <Function>SPI_connect</Function> and <Function>SPI_finish</Function> are forbidden. </PARA> </REFSECT1> <REFSECT1 ID="R1-SPI-SPICONNECT-2"> <TITLE>Usage </TITLE> <PARA> <!-- XXX thomas 1997-12-24 --> </PARA> </REFSECT1> <REFSECT1 ID="R1-SPI-SPICONNECT-3"> <TITLE>Algorithm </TITLE> <PARA><FUNCTION>SPI_connect</FUNCTION> performs the following: Initializes the SPI internal structures for query execution and memory management. </PARA> </REFSECT1> <!-- <REFSECT1 ID="R1-SPI-SPICONNECT-4"> <TITLE>Structures </TITLE> <PARA>None </PARA> </REFSECT1> --> </REFENTRY> <!-- *********************************************** --> <!-- *********************************************** --> <!-- *********************************************** --> <REFENTRY ID="SPI-SPIFINISH"> <REFMETA> <REFENTRYTITLE>SPI_finish</REFENTRYTITLE> <REFMISCINFO>SPI - Connection Management</REFMISCINFO> </REFMETA> <REFNAMEDIV> <REFNAME>SPI_finish </REFNAME> <REFPURPOSE> Disconnects your procedure from the SPI manager. </REFPURPOSE> <INDEXTERM ID="IX-SPI-SPIFINISH-1"><PRIMARY>SPI</PRIMARY><SECONDARY>disconnecting</SECONDARY></INDEXTERM> <INDEXTERM ID="IX-SPI-SPIFINISH-2"><PRIMARY>SPI_finish</PRIMARY></INDEXTERM> </REFNAMEDIV> <REFSYNOPSISDIV> <REFSYNOPSISDIVINFO> <DATE>1997-12-24</DATE> </REFSYNOPSISDIVINFO> <SYNOPSIS> SPI_finish(void) </SYNOPSIS> <REFSECT2 ID="R2-SPI-SPIFINISH-1"> <REFSECT2INFO> <DATE>1997-12-24</DATE> </REFSECT2INFO> <TITLE>Inputs </TITLE> <PARA>None </PARA> </REFSECT2> <REFSECT2 ID="R2-SPI-SPIFINISH-2"> <REFSECT2INFO> <DATE>1997-12-24</DATE> </REFSECT2INFO> <TITLE>Outputs </TITLE> <VARIABLELIST> <VARLISTENTRY> <TERM>int </TERM> <LISTITEM> <PARA> <SimpleList> <Member> <ReturnValue>SPI_OK_FINISH</ReturnValue> if properly disconnected </Member> <Member> <ReturnValue>SPI_ERROR_UNCONNECTED</ReturnValue> if called from an un-connected procedure </Member> </SimpleList> </PARA> </LISTITEM> </VARLISTENTRY> </VARIABLELIST> </REFSECT2> </REFSYNOPSISDIV> <REFSECT1 ID="R1-SPI-SPIFINISH-1"> <REFSECT1INFO> <DATE>1997-12-24</DATE> </REFSECT1INFO> <TITLE>Description </TITLE> <PARA> <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 called without having a current valid connection. There is no fundamental problem with this; it means that nothing was done by the SPI manager. </PARA> </REFSECT1> <REFSECT1 ID="R1-SPI-SPIFINISH-2"> <TITLE>Usage </TITLE> <PARA> <Function>SPI_finish</Function> <Emphasis>must</Emphasis> be called as a final step by a connected procedure, or you may get 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> <REFSECT1 ID="R1-SPI-SPIFINISH-3"> <TITLE>Algorithm </TITLE> <PARA><FUNCTION>SPI_finish</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> </REFSECT1> <!-- <REFSECT1 ID="R1-SPI-SPIFINISH-4"> <TITLE>Structures </TITLE> <PARA>None </PARA> </REFSECT1> --> </REFENTRY> <!-- *********************************************** --> <!-- *********************************************** --> <!-- *********************************************** --> <REFENTRY ID="SPI-SPIEXEC"> <REFMETA> <REFENTRYTITLE>SPI_exec</REFENTRYTITLE> <REFMISCINFO>SPI - Connection Management</REFMISCINFO> </REFMETA> <REFNAMEDIV> <REFNAME>SPI_exec </REFNAME> <REFPURPOSE> Creates an execution plan (parser+planner+optimizer) and executes a query. </REFPURPOSE> <INDEXTERM ID="IX-SPI-SPIEXEC-1"><PRIMARY>SPI</PRIMARY><SECONDARY>executing</SECONDARY></INDEXTERM> <INDEXTERM ID="IX-SPI-SPIEXEC-2"><PRIMARY>SPI_exec</PRIMARY></INDEXTERM> </REFNAMEDIV> <REFSYNOPSISDIV> <REFSYNOPSISDIVINFO> <DATE>1997-12-24</DATE> </REFSYNOPSISDIVINFO> <SYNOPSIS> SPI_exec(<REPLACEABLE CLASS="PARAMETER">query</REPLACEABLE>, <REPLACEABLE CLASS="PARAMETER">tcount</REPLACEABLE>) </SYNOPSIS> <REFSECT2 ID="R2-SPI-SPIEXEC-1"> <REFSECT2INFO> <DATE>1997-12-24</DATE> </REFSECT2INFO> <TITLE>Inputs </TITLE> <VARIABLELIST> <VARLISTENTRY> <TERM> char *<REPLACEABLE CLASS="PARAMETER">query</REPLACEABLE> </TERM> <LISTITEM> <PARA> String containing query plan </PARA> </LISTITEM> </VARLISTENTRY> <VARLISTENTRY> <TERM> int <REPLACEABLE CLASS="PARAMETER">tcount</REPLACEABLE> </TERM> <LISTITEM> <PARA> Maximum number of tuples to return </PARA> </LISTITEM> </VARLISTENTRY> </VARIABLELIST> </REFSECT2> <REFSECT2 ID="R2-SPI-SPIEXEC-2"> <REFSECT2INFO> <DATE>1997-12-24</DATE> </REFSECT2INFO> <TITLE>Outputs </TITLE> <VARIABLELIST> <VARLISTENTRY> <TERM>int </TERM> <LISTITEM> <PARA> <SimpleList> <Member> <ReturnValue>SPI_ERROR_UNCONNECTED</ReturnValue> if called from an un-connected procedure </Member> <Member> <ReturnValue>SPI_ERROR_ARGUMENT</ReturnValue> if query is NULL or <REPLACEABLE CLASS="PARAMETER">tcount</REPLACEABLE> < 0. </Member> <Member> <ReturnValue>SPI_ERROR_UNCONNECTED</ReturnValue> if procedure is unconnected. </Member> <Member> <ReturnValue>SPI_ERROR_COPY</ReturnValue> if COPY TO/FROM stdin. </Member> <Member> <ReturnValue>SPI_ERROR_CURSOR</ReturnValue> if DECLARE/CLOSE CURSOR, FETCH. </Member> <Member> <ReturnValue>SPI_ERROR_TRANSACTION</ReturnValue> if BEGIN/ABORT/END. </Member> <Member> <ReturnValue>SPI_ERROR_OPUNKNOWN</ReturnValue> if type of query is unknown (this shouldn't occur). </Member> </SimpleList> </para> <Para> If execution of your query was successful then one of the following (non-negative) values will be returned: <SimpleList> <Member> <ReturnValue>SPI_OK_UTILITY</ReturnValue> if some utility (e.g. CREATE TABLE ...) was executed </Member> <Member> <ReturnValue>SPI_OK_SELECT</ReturnValue> if SELECT (but not SELECT ... INTO!) was executed </Member> <Member> <ReturnValue>SPI_OK_SELINTO</ReturnValue> if SELECT ... INTO was executed </Member> <Member> <ReturnValue>SPI_OK_INSERT</ReturnValue> if INSERT (or INSERT ... SELECT) was executed </Member> <Member> <ReturnValue>SPI_OK_DELETE</ReturnValue> if DELETE was executed </Member> <Member> <ReturnValue>SPI_OK_UPDATE</ReturnValue> if UPDATE was executed </Member> </SimpleList> </PARA> </LISTITEM> </VARLISTENTRY> </VARIABLELIST> </REFSECT2> </REFSYNOPSISDIV> <REFSECT1 ID="R1-SPI-SPIEXEC-1"> <REFSECT1INFO> <DATE>1997-12-24</DATE> </REFSECT1INFO> <TITLE>Description </TITLE> <PARA> <FUNCTION>SPI_exec</FUNCTION> creates an execution plan (parser+planner+optimizer) and executes the query for <REPLACEABLE CLASS="PARAMETER">tcount</REPLACEABLE> tuples. </PARA> </REFSECT1> <REFSECT1 ID="R1-SPI-SPIEXEC-2"> <TITLE>Usage </TITLE> <PARA> 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 (much like a LIMIT clause). For example, <ProgramListing> SPI_exec ("INSERT INTO tab SELECT * FROM tab", 5); </ProgramListing> will allow at most 5 tuples to be inserted into table. If execution of your query was successful then a non-negative value will be returned. <Note> <Para> 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> </Note> </para> <Para> 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> is returned and SPI_processed > 0 then you may use global pointer SPITupleTable *SPI_tuptable to access the result tuples. </Para> <Para> <Function>SPI_exec</Function> may return one of the following (negative) values: <SimpleList> <Member> <ReturnValue>SPI_ERROR_ARGUMENT</ReturnValue> if query is NULL or <REPLACEABLE CLASS="PARAMETER">tcount</REPLACEABLE> < 0. </Member> <Member> <ReturnValue>SPI_ERROR_UNCONNECTED</ReturnValue> if procedure is unconnected. </Member> <Member> <ReturnValue>SPI_ERROR_COPY</ReturnValue> if COPY TO/FROM stdin. </Member> <Member> <ReturnValue>SPI_ERROR_CURSOR</ReturnValue> if DECLARE/CLOSE CURSOR, FETCH. </Member> <Member> <ReturnValue>SPI_ERROR_TRANSACTION</ReturnValue> if BEGIN/ABORT/END. </Member> <Member> <ReturnValue>SPI_ERROR_OPUNKNOWN</ReturnValue> if type of query is unknown (this shouldn't occur). </Member> </SimpleList> </PARA> </REFSECT1> <!-- <REFSECT1 ID="R1-SPI-SPIEXEC-3"> <TITLE>Algorithm </TITLE> <PARA> </PARA> </REFSECT1> --> <REFSECT1 ID="R1-SPI-SPIEXEC-4"> <TITLE>Structures </TITLE> <Para> If <ReturnValue>SPI_OK_SELECT</ReturnValue> is returned and SPI_processed > 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> <structfield>vals</> is an array of pointers to tuples (the number of useful entries is given by SPI_processed). <structfield>tupdesc</> is a tuple descriptor which you may pass to SPI functions dealing with tuples. <structfield>tuptabcxt</>, <structfield>alloced</>, and <structfield>free</> are internal fields not intended for use by SPI callers. </Para> <note> <Para> 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> <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> <!-- *********************************************** --> <!-- *********************************************** --> <!-- *********************************************** --> <REFENTRY ID="SPI-SPIPREPARE"> <REFMETA> <REFENTRYTITLE>SPI_prepare</REFENTRYTITLE> <REFMISCINFO>SPI - Plan Preparation</REFMISCINFO> </REFMETA> <REFNAMEDIV> <REFNAME>SPI_prepare </REFNAME> <REFPURPOSE> 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> </REFNAMEDIV> <REFSYNOPSISDIV> <REFSYNOPSISDIVINFO> <DATE>1997-12-24</DATE> </REFSYNOPSISDIVINFO> <SYNOPSIS> SPI_prepare(<REPLACEABLE CLASS="PARAMETER">query</REPLACEABLE>, <REPLACEABLE CLASS="PARAMETER">nargs</REPLACEABLE>, <REPLACEABLE CLASS="PARAMETER">argtypes</REPLACEABLE>) </SYNOPSIS> <REFSECT2 ID="R2-SPI-SPIPREPARE-1"> <REFSECT2INFO> <DATE>1997-12-24</DATE> </REFSECT2INFO> <TITLE>Inputs </TITLE> <VARIABLELIST> <VARLISTENTRY> <TERM> <REPLACEABLE CLASS="PARAMETER">query</REPLACEABLE> </TERM> <LISTITEM> <PARA> Query string </PARA> </LISTITEM> </VARLISTENTRY> <VARLISTENTRY> <TERM> <REPLACEABLE CLASS="PARAMETER">nargs</REPLACEABLE> </TERM> <LISTITEM> <PARA> Number of input parameters ($1 ... $nargs - as in SQL-functions) </PARA> </LISTITEM> </VARLISTENTRY> <VARLISTENTRY> <TERM> <REPLACEABLE CLASS="PARAMETER">argtypes</REPLACEABLE> </TERM> <LISTITEM> <PARA> Pointer to array of type <Acronym>OID</Acronym>s for input parameter types </PARA> </LISTITEM> </VARLISTENTRY> </VARIABLELIST> </REFSECT2> <REFSECT2 ID="R2-SPI-SPIPREPARE-2"> <REFSECT2INFO> <DATE>1997-12-24</DATE> </REFSECT2INFO> <TITLE>Outputs </TITLE> <VARIABLELIST> <VARLISTENTRY> <TERM>void * </TERM> <LISTITEM> <PARA> Pointer to an execution plan (parser+planner+optimizer) </PARA> </LISTITEM> </VARLISTENTRY> </VARIABLELIST> </REFSECT2> </REFSYNOPSISDIV> <REFSECT1 ID="R1-SPI-SPIPREPARE-1"> <REFSECT1INFO> <DATE>1997-12-24</DATE> </REFSECT1INFO> <TITLE>Description </TITLE> <PARA> <FUNCTION>SPI_prepare</FUNCTION> creates and returns an execution plan (parser+planner+optimizer) but doesn't execute the query. Should only be called from a connected procedure. </PARA> </REFSECT1> <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> 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> <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 data types 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. 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 a NULL plan. In both cases SPI_result will be set like the value returned by SPI_exec, except that it is set to <ReturnValue>SPI_ERROR_ARGUMENT</ReturnValue> if query is NULL or nargs < 0 or nargs > 0 && argtypes is NULL. </PARA> </REFSECT1> <!-- <REFSECT1 ID="R1-SPI-SPIPREPARE-3"> <TITLE>Algorithm </TITLE> <PARA><FUNCTION>SPI_prepare</FUNCTION> performs the following: TBD </PARA> </REFSECT1> --> <!-- <REFSECT1 ID="R1-SPI-SPIPREPARE-4"> <TITLE>Structures </TITLE> <PARA>None </PARA> </REFSECT1> --> </REFENTRY> <!-- *********************************************** --> <!-- *********************************************** --> <!-- *********************************************** --> <REFENTRY ID="SPI-SPIEXECP"> <REFMETA> <REFENTRYTITLE>SPI_execp</REFENTRYTITLE> <REFMISCINFO>SPI - Plan Execution</REFMISCINFO> </REFMETA> <REFNAMEDIV> <REFNAME>SPI_execp </REFNAME> <REFPURPOSE> 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> </REFNAMEDIV> <REFSYNOPSISDIV> <REFSYNOPSISDIVINFO> <DATE>1997-12-24</DATE> </REFSYNOPSISDIVINFO> <SYNOPSIS> SPI_execp(<REPLACEABLE CLASS="PARAMETER">plan</REPLACEABLE>, <REPLACEABLE CLASS="PARAMETER">values</REPLACEABLE>, <REPLACEABLE CLASS="PARAMETER">nulls</REPLACEABLE>, <REPLACEABLE CLASS="PARAMETER">tcount</REPLACEABLE>) </SYNOPSIS> <REFSECT2 ID="R2-SPI-SPIEXECP-1"> <REFSECT2INFO> <DATE>1997-12-24</DATE> </REFSECT2INFO> <TITLE>Inputs </TITLE> <VARIABLELIST> <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> <VARLISTENTRY> <TERM> int <REPLACEABLE CLASS="PARAMETER">tcount</REPLACEABLE> </TERM> <LISTITEM> <PARA> Number of tuples for which plan is to be executed </PARA> </LISTITEM> </VARLISTENTRY> </VARIABLELIST> </REFSECT2> <REFSECT2 ID="R2-SPI-SPIEXECP-2"> <REFSECT2INFO> <DATE>1997-12-24</DATE> </REFSECT2INFO> <TITLE>Outputs </TITLE> <VARIABLELIST> <VARLISTENTRY> <TERM>int </TERM> <LISTITEM> <PARA> Returns the same value as <Function>SPI_exec</Function> as well as <SimpleList> <Member> <ReturnValue>SPI_ERROR_ARGUMENT</ReturnValue> if <REPLACEABLE CLASS="PARAMETER">plan</REPLACEABLE> is NULL or <REPLACEABLE CLASS="PARAMETER">tcount</REPLACEABLE> < 0 </Member> <Member> <ReturnValue>SPI_ERROR_PARAM</ReturnValue> if <REPLACEABLE CLASS="PARAMETER">values</REPLACEABLE> is NULL and <REPLACEABLE CLASS="PARAMETER">plan</REPLACEABLE> was prepared with some parameters. </Member> </SimpleList> </para> </LISTITEM> </VARLISTENTRY> <VARLISTENTRY> <TERM>SPI_tuptable </TERM> <LISTITEM> <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-SPIEXECP-1"> <REFSECT1INFO> <DATE>1997-12-24</DATE> </REFSECT1INFO> <TITLE>Description </TITLE> <PARA> <FUNCTION>SPI_execp</FUNCTION> 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> </REFSECT1> <REFSECT1 ID="R1-SPI-SPIEXECP-2"> <TITLE>Usage </TITLE> <Para> If <REPLACEABLE CLASS="PARAMETER">nulls</REPLACEABLE> is NULL then <Function>SPI_execp</Function> assumes that all parameters (if any) are NOT NULL. <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-SPIEXECP-3"> <TITLE>Algorithm </TITLE> <PARA><FUNCTION>SPI_execp</FUNCTION> performs the following: TBD </PARA> </REFSECT1> --> <!-- <REFSECT1 ID="R1-SPI-SPIEXECP-4"> <TITLE>Structures </TITLE> <PARA>None </PARA> </REFSECT1> --> </REFENTRY> <!-- *********************************************** --> <!-- *********************************************** --> <!-- *********************************************** --> <REFENTRY ID="SPI-SPICURSOR-OPEN"> <REFMETA> <REFENTRYTITLE>SPI_cursor_open</REFENTRYTITLE> <REFMISCINFO>SPI - Cursor Support</REFMISCINFO> </REFMETA> <REFNAMEDIV> <REFNAME>SPI_cursor_open </REFNAME> <REFPURPOSE> Sets up a cursor using a plan created with <Function>SPI_prepare</Function> </REFPURPOSE> <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>2001-11-14</DATE> </REFSYNOPSISDIVINFO> <SYNOPSIS> 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-SPICURSOR-OPEN-1"> <REFSECT2INFO> <DATE>2001-11-14</DATE> </REFSECT2INFO> <TITLE>Inputs </TITLE> <VARIABLELIST> <VARLISTENTRY> <TERM> char *<REPLACEABLE CLASS="PARAMETER">name</REPLACEABLE> </TERM> <LISTITEM> <PARA> 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-SPICURSOR-OPEN-2"> <REFSECT2INFO> <DATE>2001-11-14</DATE> </REFSECT2INFO> <TITLE>Outputs </TITLE> <VARIABLELIST> <VARLISTENTRY> <TERM>Portal </TERM> <LISTITEM> <PARA> Pointer to Portal containing cursor, or NULL on error </para> </LISTITEM> </VARLISTENTRY> </VARIABLELIST> </REFSECT2> </REFSYNOPSISDIV> <REFSECT1 ID="R1-SPI-SPICURSOR-OPEN-1"> <REFSECT1INFO> <DATE>2001-11-14</DATE> </REFSECT1INFO> <TITLE>Description </TITLE> <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-SPICURSOR-OPEN-2"> <TITLE>Usage </TITLE> <Para> 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-SPICURSOR-OPEN-3"> <TITLE>Algorithm </TITLE> <PARA><FUNCTION>SPI_cursor_open</FUNCTION> performs the following: TBD </PARA> </REFSECT1> --> </REFENTRY> <!-- *********************************************** --> <!-- *********************************************** --> <!-- *********************************************** --> <REFENTRY ID="SPI-SPICURSOR-FIND"> <REFMETA> <REFENTRYTITLE>SPI_cursor_find</REFENTRYTITLE> <REFMISCINFO>SPI - Cursor Support</REFMISCINFO> </REFMETA> <REFNAMEDIV> <REFNAME>SPI_cursor_find </REFNAME> <REFPURPOSE> Finds an existing cursor (Portal) by name </REFPURPOSE> <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-11-14</DATE> </REFSYNOPSISDIVINFO> <SYNOPSIS> SPI_cursor_find(<REPLACEABLE CLASS="PARAMETER">name</REPLACEABLE>) </SYNOPSIS> <REFSECT2 ID="R2-SPI-SPICURSOR-FIND-1"> <REFSECT2INFO> <DATE>2001-11-14</DATE> </REFSECT2INFO> <TITLE>Inputs </TITLE> <VARIABLELIST> <VARLISTENTRY> <TERM> char *<REPLACEABLE CLASS="PARAMETER">name</REPLACEABLE> </TERM> <LISTITEM> <PARA> Name of portal </PARA> </LISTITEM> </VARLISTENTRY> </VARIABLELIST> </REFSECT2> <REFSECT2 ID="R2-SPI-SPICURSOR-FIND-2"> <REFSECT2INFO> <DATE>2001-11-14</DATE> </REFSECT2INFO> <TITLE>Outputs </TITLE> <VARIABLELIST> <VARLISTENTRY> <TERM>Portal </TERM> <LISTITEM> <PARA> Pointer to Portal with given name, or NULL if not found </para> </LISTITEM> </VARLISTENTRY> </VARIABLELIST> </REFSECT2> </REFSYNOPSISDIV> <REFSECT1 ID="R1-SPI-SPICURSOR-FIND-1"> <REFSECT1INFO> <DATE>2001-11-14</DATE> </REFSECT1INFO> <TITLE>Description </TITLE> <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-SPICURSOR-FIND-2"> <TITLE>Usage </TITLE> <Para> </PARA> </REFSECT1> --> <!-- <REFSECT1 ID="R1-SPI-SPICURSOR-FIND-3"> <TITLE>Algorithm </TITLE> <PARA><FUNCTION>SPI_cursor_find</FUNCTION> performs the following: TBD </PARA> </REFSECT1> --> </REFENTRY> <!-- *********************************************** --> <!-- *********************************************** --> <!-- *********************************************** --> <REFENTRY ID="SPI-SPICURSOR-FETCH"> <REFMETA> <REFENTRYTITLE>SPI_cursor_fetch</REFENTRYTITLE> <REFMISCINFO>SPI - Cursor Support</REFMISCINFO> </REFMETA> <REFNAMEDIV> <REFNAME>SPI_cursor_fetch </REFNAME> <REFPURPOSE> Fetches some rows from a cursor </REFPURPOSE> <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>2001-11-14</DATE> </REFSYNOPSISDIVINFO> <SYNOPSIS> SPI_cursor_fetch(<REPLACEABLE CLASS="PARAMETER">portal</REPLACEABLE>, <REPLACEABLE CLASS="PARAMETER">forward</REPLACEABLE>, <REPLACEABLE CLASS="PARAMETER">count</REPLACEABLE>) </SYNOPSIS> <REFSECT2 ID="R2-SPI-SPICURSOR-FETCH-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> <VARLISTENTRY> <TERM> bool <REPLACEABLE CLASS="PARAMETER">forward</REPLACEABLE> </TERM> <LISTITEM> <PARA> 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-SPICURSOR-FETCH-2"> <REFSECT2INFO> <DATE>2001-11-14</DATE> </REFSECT2INFO> <TITLE>Outputs </TITLE> <VARIABLELIST> <VARLISTENTRY> <TERM>SPI_tuptable </TERM> <LISTITEM> <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-SPICURSOR-FETCH-1"> <REFSECT1INFO> <DATE>2001-11-14</DATE> </REFSECT1INFO> <TITLE>Description </TITLE> <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-SPICURSOR-FETCH-2"> <TITLE>Usage </TITLE> <Para> </PARA> </REFSECT1> --> <!-- <REFSECT1 ID="R1-SPI-SPICURSOR-FETCH-3"> <TITLE>Algorithm </TITLE> <PARA><FUNCTION>SPI_cursor_fetch</FUNCTION> performs the following: TBD </PARA> </REFSECT1> --> </REFENTRY> <!-- *********************************************** --> <!-- *********************************************** --> <!-- *********************************************** --> <REFENTRY ID="SPI-SPICURSOR-MOVE"> <REFMETA> <REFENTRYTITLE>SPI_cursor_move</REFENTRYTITLE> <REFMISCINFO>SPI - Cursor Support</REFMISCINFO> </REFMETA> <REFNAMEDIV> <REFNAME>SPI_cursor_move </REFNAME> <REFPURPOSE> Moves a cursor </REFPURPOSE> <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>2001-11-14</DATE> </REFSYNOPSISDIVINFO> <SYNOPSIS> SPI_cursor_move(<REPLACEABLE CLASS="PARAMETER">portal</REPLACEABLE>, <REPLACEABLE CLASS="PARAMETER">forward</REPLACEABLE>, <REPLACEABLE CLASS="PARAMETER">count</REPLACEABLE>) </SYNOPSIS> <REFSECT2 ID="R2-SPI-SPICURSOR-MOVE-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> <VARLISTENTRY> <TERM> bool <REPLACEABLE CLASS="PARAMETER">forward</REPLACEABLE> </TERM> <LISTITEM> <PARA> True for move forward, false for move backward </PARA> </LISTITEM> </VARLISTENTRY> <VARLISTENTRY> <TERM> int <REPLACEABLE CLASS="PARAMETER">count</REPLACEABLE> </TERM> <LISTITEM> <PARA> Maximum number of rows to move </PARA> </LISTITEM> </VARLISTENTRY> </VARIABLELIST> </REFSECT2> <REFSECT2 ID="R2-SPI-SPICURSOR-MOVE-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-MOVE-1"> <REFSECT1INFO> <DATE>2001-11-14</DATE> </REFSECT1INFO> <TITLE>Description </TITLE> <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-SPICURSOR-MOVE-2"> <TITLE>Usage </TITLE> <Para> </PARA> </REFSECT1> --> <!-- <REFSECT1 ID="R1-SPI-SPICURSOR-MOVE-3"> <TITLE>Algorithm </TITLE> <PARA><FUNCTION>SPI_cursor_move</FUNCTION> performs the following: TBD </PARA> </REFSECT1> --> </REFENTRY> <!-- *********************************************** --> <!-- *********************************************** --> <!-- *********************************************** --> <REFENTRY ID="SPI-SPICURSOR-CLOSE"> <REFMETA> <REFENTRYTITLE>SPI_cursor_close</REFENTRYTITLE> <REFMISCINFO>SPI - Cursor Support</REFMISCINFO> </REFMETA> <REFNAMEDIV> <REFNAME>SPI_cursor_close </REFNAME> <REFPURPOSE> Closes a cursor </REFPURPOSE> <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>2001-11-14</DATE> </REFSYNOPSISDIVINFO> <SYNOPSIS> SPI_cursor_close(<REPLACEABLE CLASS="PARAMETER">portal</REPLACEABLE>) </SYNOPSIS> <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>PostgreSQL</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> <TITLE>Inputs </TITLE> <VARIABLELIST> <VARLISTENTRY> <TERM> TupleDesc <REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE> </TERM> <LISTITEM> <PARA> Input tuple description </PARA> </LISTITEM> </VARLISTENTRY> <VARLISTENTRY> <TERM> char * <REPLACEABLE CLASS="PARAMETER">fname</REPLACEABLE> </TERM> <LISTITEM> <PARA> Field name </PARA> </LISTITEM> </VARLISTENTRY> </VARIABLELIST> </REFSECT2> <REFSECT2 ID="R2-SPI-SPIFNUMBER-2"> <REFSECT2INFO> <DATE>1997-12-24</DATE> </REFSECT2INFO> <TITLE>Outputs </TITLE> <VARIABLELIST> <VARLISTENTRY> <TERM> int </TERM> <LISTITEM> <PARA> Attribute number <SimpleList> <Member> Valid one-based index number of attribute </Member> <Member> <ReturnValue>SPI_ERROR_NOATTRIBUTE</ReturnValue> if the named attribute is not found </Member> </SimpleList> </para> </LISTITEM> </VARLISTENTRY> </VARIABLELIST> </REFSECT2> </REFSYNOPSISDIV> <REFSECT1 ID="R1-SPI-SPIFNUMBER-1"> <REFSECT1INFO> <DATE>1997-12-24</DATE> </REFSECT1INFO> <TITLE>Description </TITLE> <PARA> <FUNCTION>SPI_fnumber</FUNCTION> returns the attribute number for the attribute with name in fname. </PARA> </REFSECT1> <REFSECT1 ID="R1-SPI-SPIFNUMBER-2"> <TITLE>Usage </TITLE> <Para> Attribute numbers are 1 based. </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 <= 0 is not correct unless system attributes should be rejected. </Para> </REFSECT1> <!-- <REFSECT1 ID="R1-SPI-SPIFNUMBER-3"> <TITLE>Algorithm </TITLE> <PARA> </PARA> </REFSECT1> --> <!-- <REFSECT1 ID="R1-SPI-SPIFNUMBER-4"> <TITLE>Structures </TITLE> <PARA>None </PARA> </REFSECT1> --> </REFENTRY> <!-- *********************************************** --> <!-- *********************************************** --> <!-- *********************************************** --> <REFENTRY ID="SPI-SPIFNAME"> <REFMETA> <REFENTRYTITLE>SPI_fname</REFENTRYTITLE> <REFMISCINFO>SPI - Tuple Information</REFMISCINFO> </REFMETA> <REFNAMEDIV> <REFNAME>SPI_fname </REFNAME> <REFPURPOSE> 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> </REFNAMEDIV> <REFSYNOPSISDIV> <REFSYNOPSISDIVINFO> <DATE>1997-12-24</DATE> </REFSYNOPSISDIVINFO> <SYNOPSIS> SPI_fname(<REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>, <REPLACEABLE CLASS="PARAMETER">fnumber</REPLACEABLE>) </SYNOPSIS> <REFSECT2 ID="R2-SPI-SPIFNAME-1"> <REFSECT2INFO> <DATE>1997-12-24</DATE> </REFSECT2INFO> <TITLE>Inputs </TITLE> <VARIABLELIST> <VARLISTENTRY> <TERM> TupleDesc <REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE> </TERM> <LISTITEM> <PARA> Input tuple description </PARA> </LISTITEM> </VARLISTENTRY> <VARLISTENTRY> <TERM> int <REPLACEABLE CLASS="PARAMETER">fnumber</REPLACEABLE> </TERM> <LISTITEM> <PARA> Attribute number </PARA> </LISTITEM> </VARLISTENTRY> </VARIABLELIST> </REFSECT2> <REFSECT2 ID="R2-SPI-SPIFNAME-2"> <REFSECT2INFO> <DATE>1997-12-24</DATE> </REFSECT2INFO> <TITLE>Outputs </TITLE> <VARIABLELIST> <VARLISTENTRY> <TERM> char * </TERM> <LISTITEM> <PARA> Attribute name <SimpleList> <Member> NULL if fnumber is out of range </Member> <Member> SPI_result set to <ReturnValue>SPI_ERROR_NOATTRIBUTE</ReturnValue> on error </Member> </SimpleList> </para> </LISTITEM> </VARLISTENTRY> </VARIABLELIST> </REFSECT2> </REFSYNOPSISDIV> <REFSECT1 ID="R1-SPI-SPIFNAME-1"> <REFSECT1INFO> <DATE>1997-12-24</DATE> </REFSECT1INFO> <TITLE>Description </TITLE> <PARA> <FUNCTION>SPI_fname</FUNCTION> returns the attribute name for the specified attribute. </PARA> </REFSECT1> <REFSECT1 ID="R1-SPI-SPIFNAME-2"> <TITLE>Usage </TITLE> <Para> Attribute numbers are 1 based. </PARA> </REFSECT1> <REFSECT1 ID="R1-SPI-SPIFNAME-3"> <TITLE>Algorithm </TITLE> <PARA> Returns a newly-allocated copy of the attribute name. (Use pfree() to release the copy when done with it.) </PARA> </REFSECT1> <!-- <REFSECT1 ID="R1-SPI-SPIFNAME-4"> <TITLE>Structures </TITLE> <PARA>None </PARA> </REFSECT1> --> </REFENTRY> <!-- *********************************************** --> <!-- *********************************************** --> <!-- *********************************************** --> <REFENTRY ID="SPI-SPIGETVALUE"> <REFMETA> <REFENTRYTITLE>SPI_getvalue</REFENTRYTITLE> <REFMISCINFO>SPI - Tuple Information</REFMISCINFO> </REFMETA> <REFNAMEDIV> <REFNAME>SPI_getvalue </REFNAME> <REFPURPOSE> Returns the string value of the specified attribute </REFPURPOSE> <INDEXTERM ID="IX-SPI-SPIGETVALUE-1"><PRIMARY>SPI</PRIMARY><SECONDARY>decoding tuples</SECONDARY></INDEXTERM> <INDEXTERM ID="IX-SPI-SPIGETVALUE-2"><PRIMARY>SPI_getvalue</PRIMARY></INDEXTERM> </REFNAMEDIV> <REFSYNOPSISDIV> <REFSYNOPSISDIVINFO> <DATE>1997-12-24</DATE> </REFSYNOPSISDIVINFO> <SYNOPSIS> SPI_getvalue(<REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE>, <REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>, <REPLACEABLE CLASS="PARAMETER">fnumber</REPLACEABLE>) </SYNOPSIS> <REFSECT2 ID="R2-SPI-SPIGETVALUE-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 examined </PARA> </LISTITEM> </VARLISTENTRY> <VARLISTENTRY> <TERM> TupleDesc <REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE> </TERM> <LISTITEM> <PARA> Input tuple description </PARA> </LISTITEM> </VARLISTENTRY> <VARLISTENTRY> <TERM> int <REPLACEABLE CLASS="PARAMETER">fnumber</REPLACEABLE> </TERM> <LISTITEM> <PARA> Attribute number </PARA> </LISTITEM> </VARLISTENTRY> </VARIABLELIST> </REFSECT2> <REFSECT2 ID="R2-SPI-SPIGETVALUE-2"> <REFSECT2INFO> <DATE>1997-12-24</DATE> </REFSECT2INFO> <TITLE>Outputs </TITLE> <VARIABLELIST> <VARLISTENTRY> <TERM> char * </TERM> <LISTITEM> <PARA> Attribute value or NULL if <SimpleList> <Member> attribute is NULL </Member> <Member> fnumber is out of range (SPI_result set to <ReturnValue>SPI_ERROR_NOATTRIBUTE</ReturnValue>) </Member> <Member> no output function available (SPI_result set to <ReturnValue>SPI_ERROR_NOOUTFUNC</ReturnValue>) </Member> </SimpleList> </para> </LISTITEM> </VARLISTENTRY> </VARIABLELIST> </REFSECT2> </REFSYNOPSISDIV> <REFSECT1 ID="R1-SPI-SPIGETVALUE-1"> <REFSECT1INFO> <DATE>1997-12-24</DATE> </REFSECT1INFO> <TITLE>Description </TITLE> <PARA> <FUNCTION>SPI_getvalue</FUNCTION> returns an external (string) representation of the value of the specified attribute. </PARA> </REFSECT1> <REFSECT1 ID="R1-SPI-SPIGETVALUE-2"> <TITLE>Usage </TITLE> <Para> Attribute numbers are 1 based. </PARA> </REFSECT1> <REFSECT1 ID="R1-SPI-SPIGETVALUE-3"> <TITLE>Algorithm </TITLE> <PARA> The result is returned as a palloc'd string. (Use pfree() to release the string when done with it.) </PARA> </REFSECT1> <!-- <REFSECT1 ID="R1-SPI-SPIGETVALUE-4"> <TITLE>Structures </TITLE> <PARA>None </PARA> </REFSECT1> --> </REFENTRY> <!-- *********************************************** --> <!-- *********************************************** --> <!-- *********************************************** --> <REFENTRY ID="SPI-SPIGETBINVAL"> <REFMETA> <REFENTRYTITLE>SPI_getbinval</REFENTRYTITLE> <REFMISCINFO>SPI - Tuple Information</REFMISCINFO> </REFMETA> <REFNAMEDIV> <REFNAME>SPI_getbinval </REFNAME> <REFPURPOSE> Returns the binary value of the specified attribute </REFPURPOSE> <INDEXTERM ID="IX-SPI-SPIGETBINVAL-1"><PRIMARY>SPI</PRIMARY><SECONDARY>decoding tuples</SECONDARY></INDEXTERM> <INDEXTERM ID="IX-SPI-SPIGETBINVAL-2"><PRIMARY>SPI_getbinval</PRIMARY></INDEXTERM> </REFNAMEDIV> <REFSYNOPSISDIV> <REFSYNOPSISDIVINFO> <DATE>1997-12-24</DATE> </REFSYNOPSISDIVINFO> <SYNOPSIS> SPI_getbinval(<REPLACEABLE CLASS="PARAMETER">tuple</REPLACEABLE>, <REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>, <REPLACEABLE CLASS="PARAMETER">fnumber</REPLACEABLE>, <REPLACEABLE CLASS="PARAMETER">isnull</REPLACEABLE>) </SYNOPSIS> <REFSECT2 ID="R2-SPI-SPIGETBINVAL-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 examined </PARA> </LISTITEM> </VARLISTENTRY> <VARLISTENTRY> <TERM> TupleDesc <REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE> </TERM> <LISTITEM> <PARA> Input tuple description </PARA> </LISTITEM> </VARLISTENTRY> <VARLISTENTRY> <TERM> int <REPLACEABLE CLASS="PARAMETER">fnumber</REPLACEABLE> </TERM> <LISTITEM> <PARA> Attribute number </PARA> </LISTITEM> </VARLISTENTRY> </VARIABLELIST> </REFSECT2> <REFSECT2 ID="R2-SPI-SPIGETBINVAL-2"> <REFSECT2INFO> <DATE>1997-12-24</DATE> </REFSECT2INFO> <TITLE>Outputs </TITLE> <VARIABLELIST> <VARLISTENTRY> <TERM> Datum </TERM> <LISTITEM> <PARA> Attribute binary value </PARA> </LISTITEM> </VARLISTENTRY> <VARLISTENTRY> <TERM> bool * <REPLACEABLE CLASS="PARAMETER">isnull</REPLACEABLE> </TERM> <LISTITEM> <PARA> flag for null value in attribute </PARA> </LISTITEM> </VARLISTENTRY> <VARLISTENTRY> <TERM> SPI_result </TERM> <LISTITEM> <PARA> <SimpleList> <Member> <ReturnValue>SPI_ERROR_NOATTRIBUTE</ReturnValue> </Member> </SimpleList> </PARA> </LISTITEM> </VARLISTENTRY> </VARIABLELIST> </REFSECT2> </REFSYNOPSISDIV> <REFSECT1 ID="R1-SPI-SPIGETBINVAL-1"> <REFSECT1INFO> <DATE>1997-12-24</DATE> </REFSECT1INFO> <TITLE>Description </TITLE> <PARA> <FUNCTION>SPI_getbinval</FUNCTION> returns the specified attribute's value in internal form (as a Datum). </PARA> </REFSECT1> <REFSECT1 ID="R1-SPI-SPIGETBINVAL-2"> <TITLE>Usage </TITLE> <Para> Attribute numbers are 1 based. </PARA> </REFSECT1> <REFSECT1 ID="R1-SPI-SPIGETBINVAL-3"> <TITLE>Algorithm </TITLE> <PARA> Does not allocate new space for the datum. In the case of a pass-by- reference data type, the Datum will be a pointer into the given tuple. </PARA> </REFSECT1> <!-- <REFSECT1 ID="R1-SPI-SPIGETBINVAL-4"> <TITLE>Structures </TITLE> <PARA>None </PARA> </REFSECT1> --> </REFENTRY> <!-- *********************************************** --> <!-- *********************************************** --> <!-- *********************************************** --> <REFENTRY ID="SPI-SPIGETTYPE"> <REFMETA> <REFENTRYTITLE>SPI_gettype</REFENTRYTITLE> <REFMISCINFO>SPI - Tuple Information</REFMISCINFO> </REFMETA> <REFNAMEDIV> <REFNAME>SPI_gettype </REFNAME> <REFPURPOSE> Returns the type name of the specified attribute </REFPURPOSE> <INDEXTERM ID="IX-SPI-SPIGETTYPE-1"><PRIMARY>SPI</PRIMARY><SECONDARY>decoding tuples</SECONDARY></INDEXTERM> <INDEXTERM ID="IX-SPI-SPIGETTYPE-2"><PRIMARY>SPI_gettype</PRIMARY></INDEXTERM> </REFNAMEDIV> <REFSYNOPSISDIV> <REFSYNOPSISDIVINFO> <DATE>1997-12-24</DATE> </REFSYNOPSISDIVINFO> <SYNOPSIS> SPI_gettype(<REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>, <REPLACEABLE CLASS="PARAMETER">fnumber</REPLACEABLE>) </SYNOPSIS> <REFSECT2 ID="R2-SPI-SPIGETTYPE-1"> <REFSECT2INFO> <DATE>1997-12-24</DATE> </REFSECT2INFO> <TITLE>Inputs </TITLE> <VARIABLELIST> <VARLISTENTRY> <TERM> TupleDesc <REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE> </TERM> <LISTITEM> <PARA> Input tuple description </PARA> </LISTITEM> </VARLISTENTRY> <VARLISTENTRY> <TERM> int <REPLACEABLE CLASS="PARAMETER">fnumber</REPLACEABLE> </TERM> <LISTITEM> <PARA> Attribute number </PARA> </LISTITEM> </VARLISTENTRY> </VARIABLELIST> </REFSECT2> <REFSECT2 ID="R2-SPI-SPIGETTYPE-2"> <REFSECT2INFO> <DATE>1997-12-24</DATE> </REFSECT2INFO> <TITLE>Outputs </TITLE> <VARIABLELIST> <VARLISTENTRY> <TERM> char * </TERM> <LISTITEM> <PARA> The type name for the specified attribute number </PARA> </LISTITEM> </VARLISTENTRY> <VARLISTENTRY> <TERM> SPI_result </TERM> <LISTITEM> <PARA> <SimpleList> <Member> <ReturnValue>SPI_ERROR_NOATTRIBUTE</ReturnValue> </Member> </SimpleList> </PARA> </LISTITEM> </VARLISTENTRY> </VARIABLELIST> </REFSECT2> </REFSYNOPSISDIV> <REFSECT1 ID="R1-SPI-SPIGETTYPE-1"> <REFSECT1INFO> <DATE>1997-12-24</DATE> </REFSECT1INFO> <TITLE>Description </TITLE> <PARA> <FUNCTION>SPI_gettype</FUNCTION> returns a copy of the type name for the specified attribute, or NULL on error. </PARA> </REFSECT1> <REFSECT1 ID="R1-SPI-SPIGETTYPE-2"> <TITLE>Usage </TITLE> <Para> Attribute numbers are 1 based. </PARA> </REFSECT1> <REFSECT1 ID="R1-SPI-SPIGETTYPE-3"> <TITLE>Algorithm </TITLE> <PARA> Returns a newly-allocated copy of the type name. (Use pfree() to release the copy when done with it.) </PARA> </REFSECT1> <!-- <REFSECT1 ID="R1-SPI-SPIGETTYPE-4"> <TITLE>Structures </TITLE> <PARA>None </PARA> </REFSECT1> --> </REFENTRY> <!-- *********************************************** --> <!-- *********************************************** --> <!-- *********************************************** --> <REFENTRY ID="SPI-SPIGETTYPEID"> <REFMETA> <REFENTRYTITLE>SPI_gettypeid</REFENTRYTITLE> <REFMISCINFO>SPI - Tuple Information</REFMISCINFO> </REFMETA> <REFNAMEDIV> <REFNAME>SPI_gettypeid </REFNAME> <REFPURPOSE> Returns the type <Acronym>OID</Acronym> of the specified attribute </REFPURPOSE> <INDEXTERM ID="IX-SPI-SPIGETTYPEID-1"><PRIMARY>SPI</PRIMARY><SECONDARY>decoding tuples</SECONDARY></INDEXTERM> <INDEXTERM ID="IX-SPI-SPIGETTYPEID-2"><PRIMARY>SPI_gettypeid</PRIMARY></INDEXTERM> </REFNAMEDIV> <REFSYNOPSISDIV> <REFSYNOPSISDIVINFO> <DATE>1997-12-24</DATE> </REFSYNOPSISDIVINFO> <SYNOPSIS> SPI_gettypeid(<REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>, <REPLACEABLE CLASS="PARAMETER">fnumber</REPLACEABLE>) </SYNOPSIS> <REFSECT2 ID="R2-SPI-SPIGETTYPEID-1"> <REFSECT2INFO> <DATE>1997-12-24</DATE> </REFSECT2INFO> <TITLE>Inputs </TITLE> <VARIABLELIST> <VARLISTENTRY> <TERM> TupleDesc <REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE> </TERM> <LISTITEM> <PARA> Input tuple description </PARA> </LISTITEM> </VARLISTENTRY> <VARLISTENTRY> <TERM> int <REPLACEABLE CLASS="PARAMETER">fnumber</REPLACEABLE> </TERM> <LISTITEM> <PARA> Attribute number </PARA> </LISTITEM> </VARLISTENTRY> </VARIABLELIST> </REFSECT2> <REFSECT2 ID="R2-SPI-SPIGETTYPEID-2"> <REFSECT2INFO> <DATE>1997-12-24</DATE> </REFSECT2INFO> <TITLE>Outputs </TITLE> <VARIABLELIST> <VARLISTENTRY> <TERM> <Acronym>OID</Acronym> </TERM> <LISTITEM> <PARA> The type <Acronym>OID</Acronym> for the specified attribute number </PARA> </LISTITEM> </VARLISTENTRY> <VARLISTENTRY> <TERM> SPI_result </TERM> <LISTITEM> <PARA> <SimpleList> <Member> <ReturnValue>SPI_ERROR_NOATTRIBUTE</ReturnValue> </Member> </SimpleList> </PARA> </LISTITEM> </VARLISTENTRY> </VARIABLELIST> </REFSECT2> </REFSYNOPSISDIV> <REFSECT1 ID="R1-SPI-SPIGETTYPEID-1"> <REFSECT1INFO> <DATE>1997-12-24</DATE> </REFSECT1INFO> <TITLE>Description </TITLE> <PARA> <FUNCTION>SPI_gettypeid</FUNCTION> returns the type <Acronym>OID</Acronym> for the specified attribute. </PARA> </REFSECT1> <REFSECT1 ID="R1-SPI-SPIGETTYPEID-2"> <TITLE>Usage </TITLE> <Para> Attribute numbers are 1 based. </PARA> </REFSECT1> <!-- <REFSECT1 ID="R1-SPI-SPIGETTYPEID-3"> <TITLE>Algorithm </TITLE> <PARA> TBD </PARA> </REFSECT1> --> <!-- <REFSECT1 ID="R1-SPI-SPIGETTYPEID-4"> <TITLE>Structures </TITLE> <PARA>None </PARA> </REFSECT1> --> </REFENTRY> <!-- *********************************************** --> <!-- *********************************************** --> <!-- *********************************************** --> <REFENTRY ID="SPI-SPIGETRELNAME"> <REFMETA> <REFENTRYTITLE>SPI_getrelname</REFENTRYTITLE> <REFMISCINFO>SPI - Tuple Information</REFMISCINFO> </REFMETA> <REFNAMEDIV> <REFNAME>SPI_getrelname </REFNAME> <REFPURPOSE> Returns the name of the specified relation </REFPURPOSE> <INDEXTERM ID="IX-SPI-SPIGETRELNAME-1"><PRIMARY>SPI</PRIMARY><SECONDARY>decoding tuples</SECONDARY></INDEXTERM> <INDEXTERM ID="IX-SPI-SPIGETRELNAME-2"><PRIMARY>SPI_getrelname</PRIMARY></INDEXTERM> </REFNAMEDIV> <REFSYNOPSISDIV> <REFSYNOPSISDIVINFO> <DATE>1997-12-24</DATE> </REFSYNOPSISDIVINFO> <SYNOPSIS> SPI_getrelname(<REPLACEABLE CLASS="PARAMETER">rel</REPLACEABLE>) </SYNOPSIS> <REFSECT2 ID="R2-SPI-SPIGETRELNAME-1"> <REFSECT2INFO> <DATE>1997-12-24</DATE> </REFSECT2INFO> <TITLE>Inputs </TITLE> <VARIABLELIST> <VARLISTENTRY> <TERM> Relation <REPLACEABLE CLASS="PARAMETER">rel</REPLACEABLE> </TERM> <LISTITEM> <PARA> Input relation </PARA> </LISTITEM> </VARLISTENTRY> </VARIABLELIST> </REFSECT2> <REFSECT2 ID="R2-SPI-SPIGETRELNAME-2"> <REFSECT2INFO> <DATE>1997-12-24</DATE> </REFSECT2INFO> <TITLE>Outputs </TITLE> <VARIABLELIST> <VARLISTENTRY> <TERM> char * </TERM> <LISTITEM> <PARA> The name of the specified relation </PARA> </LISTITEM> </VARLISTENTRY> </VARIABLELIST> </REFSECT2> </REFSYNOPSISDIV> <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>PostgreSQL</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 data type), 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 <= 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 <= 0 or > 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_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-SPIMODIFYTUPLE-2"> <TITLE>Usage </TITLE> <Para> 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-SPIMODIFYTUPLE-3"> <TITLE>Algorithm </TITLE> <PARA> </PARA> </REFSECT1> --> <!-- <REFSECT1 ID="R1-SPI-SPIMODIFYTUPLE-4"> <TITLE>Structures </TITLE> <PARA>None </PARA> </REFSECT1> --> </REFENTRY> <!-- *********************************************** --> <!-- *********************************************** --> <!-- *********************************************** --> <REFENTRY ID="SPI-SPIPALLOC"> <REFMETA> <REFENTRYTITLE>SPI_palloc</REFENTRYTITLE> <REFMISCINFO>SPI - Memory Management</REFMISCINFO> </REFMETA> <REFNAMEDIV> <REFNAME>SPI_palloc </REFNAME> <REFPURPOSE> Allocates memory in upper Executor context </REFPURPOSE> <INDEXTERM ID="IX-SPI-SPIPALLOC-1"><PRIMARY>SPI</PRIMARY><SECONDARY>allocating space</SECONDARY></INDEXTERM> <INDEXTERM ID="IX-SPI-SPIPALLOC-2"><PRIMARY>SPI_palloc</PRIMARY></INDEXTERM> </REFNAMEDIV> <REFSYNOPSISDIV> <REFSYNOPSISDIVINFO> <DATE>1997-12-24</DATE> </REFSYNOPSISDIVINFO> <SYNOPSIS> SPI_palloc(<REPLACEABLE CLASS="PARAMETER">size</REPLACEABLE>) </SYNOPSIS> <REFSECT2 ID="R2-SPI-SPIPALLOC-1"> <REFSECT2INFO> <DATE>1997-12-24</DATE> </REFSECT2INFO> <TITLE>Inputs </TITLE> <VARIABLELIST> <VARLISTENTRY> <TERM> Size <REPLACEABLE CLASS="PARAMETER">size</REPLACEABLE> </TERM> <LISTITEM> <PARA> Octet size of storage to allocate </PARA> </LISTITEM> </VARLISTENTRY> </VARIABLELIST> </REFSECT2> <REFSECT2 ID="R2-SPI-SPIPALLOC-2"> <REFSECT2INFO> <DATE>1997-12-24</DATE> </REFSECT2INFO> <TITLE>Outputs </TITLE> <VARIABLELIST> <VARLISTENTRY> <TERM> void * </TERM> <LISTITEM> <PARA> New storage space of specified size </PARA> </LISTITEM> </VARLISTENTRY> </VARIABLELIST> </REFSECT2> </REFSYNOPSISDIV> <REFSECT1 ID="R1-SPI-SPIPALLOC-1"> <REFSECT1INFO> <DATE>1997-12-24</DATE> </REFSECT1INFO> <TITLE>Description </TITLE> <PARA> <FUNCTION>SPI_palloc</FUNCTION> allocates memory in upper Executor context. </PARA> </REFSECT1> <REFSECT1 ID="R1-SPI-SPIPALLOC-2"> <TITLE>Usage </TITLE> <Para> TBD </PARA> </REFSECT1> <!-- <REFSECT1 ID="R1-SPI-SPIPALLOC-3"> <TITLE>Algorithm </TITLE> <PARA> TBD </PARA> </REFSECT1> --> <!-- <REFSECT1 ID="R1-SPI-SPIPALLOC-4"> <TITLE>Structures </TITLE> <PARA>None </PARA> </REFSECT1> --> </REFENTRY> <!-- *********************************************** --> <!-- *********************************************** --> <!-- *********************************************** --> <REFENTRY ID="SPI-SPIREPALLOC"> <REFMETA> <REFENTRYTITLE>SPI_repalloc</REFENTRYTITLE> <REFMISCINFO>SPI - Memory Management</REFMISCINFO> </REFMETA> <REFNAMEDIV> <REFNAME>SPI_repalloc </REFNAME> <REFPURPOSE> Re-allocates memory in upper Executor context </REFPURPOSE> <INDEXTERM ID="IX-SPI-SPIREPALLOC-1"><PRIMARY>SPI</PRIMARY><SECONDARY>allocating space</SECONDARY></INDEXTERM> <INDEXTERM ID="IX-SPI-SPIREPALLOC-2"><PRIMARY>SPI_repalloc</PRIMARY></INDEXTERM> </REFNAMEDIV> <REFSYNOPSISDIV> <REFSYNOPSISDIVINFO> <DATE>1997-12-24</DATE> </REFSYNOPSISDIVINFO> <SYNOPSIS> SPI_repalloc(<REPLACEABLE CLASS="PARAMETER">pointer</REPLACEABLE>, <REPLACEABLE CLASS="PARAMETER">size</REPLACEABLE>) </SYNOPSIS> <REFSECT2 ID="R2-SPI-SPIREPALLOC-1"> <REFSECT2INFO> <DATE>1997-12-24</DATE> </REFSECT2INFO> <TITLE>Inputs </TITLE> <VARIABLELIST> <VARLISTENTRY> <TERM> void * <REPLACEABLE CLASS="PARAMETER">pointer</REPLACEABLE> </TERM> <LISTITEM> <PARA> Pointer to existing storage </PARA> </LISTITEM> </VARLISTENTRY> <VARLISTENTRY> <TERM> Size <REPLACEABLE CLASS="PARAMETER">size</REPLACEABLE> </TERM> <LISTITEM> <PARA> Octet size of storage to allocate </PARA> </LISTITEM> </VARLISTENTRY> </VARIABLELIST> </REFSECT2> <REFSECT2 ID="R2-SPI-SPIREPALLOC-2"> <REFSECT2INFO> <DATE>1997-12-24</DATE> </REFSECT2INFO> <TITLE>Outputs </TITLE> <VARIABLELIST> <VARLISTENTRY> <TERM> void * </TERM> <LISTITEM> <PARA> New storage space of specified size with contents copied from existing area </PARA> </LISTITEM> </VARLISTENTRY> </VARIABLELIST> </REFSECT2> </REFSYNOPSISDIV> <REFSECT1 ID="R1-SPI-SPIREPALLOC-1"> <REFSECT1INFO> <DATE>1997-12-24</DATE> </REFSECT1INFO> <TITLE>Description </TITLE> <PARA> <FUNCTION>SPI_repalloc</FUNCTION> re-allocates memory in upper Executor context. </PARA> </REFSECT1> <REFSECT1 ID="R1-SPI-SPIREPALLOC-2"> <TITLE>Usage </TITLE> <Para> This function is no longer different from plain <FUNCTION>repalloc</FUNCTION>. It's kept just for backward compatibility of existing code. </PARA> </REFSECT1> <!-- <REFSECT1 ID="R1-SPI-SPIREPALLOC-3"> <TITLE>Algorithm </TITLE> <PARA> TBD </PARA> </REFSECT1> --> <!-- <REFSECT1 ID="R1-SPI-SPIREPALLOC-4"> <TITLE>Structures </TITLE> <PARA>None </PARA> </REFSECT1> --> </REFENTRY> <!-- *********************************************** --> <!-- *********************************************** --> <!-- *********************************************** --> <REFENTRY ID="SPI-SPIPFREE"> <REFMETA> <REFENTRYTITLE>SPI_pfree</REFENTRYTITLE> <REFMISCINFO>SPI - Memory Management</REFMISCINFO> </REFMETA> <REFNAMEDIV> <REFNAME>SPI_pfree </REFNAME> <REFPURPOSE> 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> </REFNAMEDIV> <REFSYNOPSISDIV> <REFSYNOPSISDIVINFO> <DATE>1997-12-24</DATE> </REFSYNOPSISDIVINFO> <SYNOPSIS> SPI_pfree(<REPLACEABLE CLASS="PARAMETER">pointer</REPLACEABLE>) </SYNOPSIS> <REFSECT2 ID="R2-SPI-SPIPFREE-1"> <REFSECT2INFO> <DATE>1997-12-24</DATE> </REFSECT2INFO> <TITLE>Inputs </TITLE> <VARIABLELIST> <VARLISTENTRY> <TERM> void * <REPLACEABLE CLASS="PARAMETER">pointer</REPLACEABLE> </TERM> <LISTITEM> <PARA> Pointer to existing storage </PARA> </LISTITEM> </VARLISTENTRY> </VARIABLELIST> </REFSECT2> <REFSECT2 ID="R2-SPI-SPIPFREE-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-SPIPFREE-1"> <REFSECT1INFO> <DATE>1997-12-24</DATE> </REFSECT1INFO> <TITLE>Description </TITLE> <PARA> <FUNCTION>SPI_pfree</FUNCTION> frees memory in upper Executor context. </PARA> </REFSECT1> <REFSECT1 ID="R1-SPI-SPIPFREE-2"> <TITLE>Usage </TITLE> <Para> This function is no longer different from plain <FUNCTION>pfree</FUNCTION>. It's kept just for backward compatibility of existing code. </PARA> </REFSECT1> </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> 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-SPIFREETUPLE-2"> <TITLE>Usage </TITLE> <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> <!-- *********************************************** --> <!-- *********************************************** --> <!-- *********************************************** --> <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> <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> <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> <!-- *********************************************** --> <!-- *********************************************** --> <!-- *********************************************** --> <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> <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> <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> <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> <Sect1 id="spi-visibility"> <Title>Visibility of Data Changes</Title> <Para> <ProductName>PostgreSQL</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. </Para> <Para> Changes made by query Q are visible to queries that are started after query Q, no matter whether they are started inside Q (during the execution of Q) or after Q is done. </Para> </Sect1> <Sect1 id="spi-examples"> <Title>Examples</Title> <Para> This example of SPI usage demonstrates the visibility rule. There are more complex examples in src/test/regress/regress.c and in contrib/spi. </Para> <Para> This is a very simple example of SPI usage. The procedure execq accepts an SQL-query in its first argument and tcount in its second, executes the query using SPI_exec and returns the number of tuples for which the query executed: <ProgramListing> #include "executor/spi.h" /* this is what you need to work with SPI */ int execq(text *sql, int cnt); int execq(text *sql, int cnt) { char *query; int ret; int proc; /* Convert given TEXT object to a C string */ query = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(sql))); SPI_connect(); ret = SPI_exec(query, cnt); proc = SPI_processed; /* * If this is SELECT and some tuple(s) fetched - * returns tuples to the caller via elog (INFO). */ if ( ret == SPI_OK_SELECT && SPI_processed > 0 ) { TupleDesc tupdesc = SPI_tuptable->tupdesc; SPITupleTable *tuptable = SPI_tuptable; char buf[8192]; int i,j; for (j = 0; j < proc; j++) { HeapTuple tuple = tuptable->vals[j]; for (i = 1, buf[0] = 0; i <= tupdesc->natts; i++) sprintf(buf + strlen (buf), " %s%s", SPI_getvalue(tuple, tupdesc, i), (i == tupdesc->natts) ? " " : " |"); elog (INFO, "EXECQ: %s", buf); } } SPI_finish(); pfree(query); return (proc); } </ProgramListing> </Para> <Para> Now, compile and create the function: <ProgramListing> CREATE FUNCTION execq (text, integer) RETURNS integer AS '...path_to_so' LANGUAGE C; </ProgramListing> <ProgramListing> vac=> SELECT execq('CREATE TABLE a (x INTEGER)', 0); execq ----- 0 (1 row) vac=> INSERT INTO a VALUES (execq('INSERT INTO a VALUES (0)',0)); INSERT 167631 1 vac=> SELECT execq('SELECT * FROM a',0); INFO: EXECQ: 0 <<< inserted by execq INFO: EXECQ: 1 <<< value returned by execq and inserted by upper INSERT execq ----- 2 (1 row) vac=> SELECT execq('INSERT INTO a SELECT x + 2 FROM a',1); execq ----- 1 (1 row) vac=> SELECT execq('SELECT * FROM a', 10); INFO: EXECQ: 0 INFO: EXECQ: 1 INFO: EXECQ: 2 <<< 0 + 2, only one tuple inserted - as specified execq ----- 3 <<< 10 is max value only, 3 is real # of tuples (1 row) vac=> DELETE FROM a; DELETE 3 vac=> INSERT INTO a VALUES (execq('SELECT * FROM a', 0) + 1); INSERT 167712 1 vac=> SELECT * FROM a; x - 1 <<< no tuples in a (0) + 1 (1 row) vac=> INSERT INTO a VALUES (execq('SELECT * FROM a', 0) + 1); INFO: EXECQ: 0 INSERT 167713 1 vac=> SELECT * FROM a; x - 1 2 <<< there was single tuple in a + 1 (2 rows) -- This demonstrates data changes visibility rule: vac=> INSERT INTO a SELECT execq('SELECT * FROM a', 0) * x FROM a; INFO: EXECQ: 1 INFO: EXECQ: 2 INFO: EXECQ: 1 INFO: EXECQ: 2 INFO: EXECQ: 2 INSERT 0 2 vac=> SELECT * FROM a; x - 1 2 2 <<< 2 tuples * 1 (x in first tuple) 6 <<< 3 tuples (2 + 1 just inserted) * 2 (x in second tuple) (4 rows) ^^^^^^^^ tuples visible to execq() in different invocations </ProgramListing> </Para> </Sect1> </Chapter>