diff options
Diffstat (limited to 'doc/src')
| -rw-r--r-- | doc/src/sgml/spi.sgml | 6345 | 
1 files changed, 2496 insertions, 3849 deletions
| diff --git a/doc/src/sgml/spi.sgml b/doc/src/sgml/spi.sgml index b3c65204c44..f3b11b5a1c9 100644 --- a/doc/src/sgml/spi.sgml +++ b/doc/src/sgml/spi.sgml @@ -1,3821 +1,2462 @@  <!-- -$Header: /cvsroot/pgsql/doc/src/sgml/spi.sgml,v 1.25 2003/01/21 22:06:11 tgl Exp $ +$Header: /cvsroot/pgsql/doc/src/sgml/spi.sgml,v 1.26 2003/08/27 22:13:35 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> +<chapter id="spi"> + <title>Server Programming Interface</title> + + <indexterm zone="spi"> +  <primary>SPI</primary> + </indexterm> + + <para> +  The <firstterm>Server Programming Interface</firstterm> +  (<acronym>SPI</acronym>) gives users the ability to run +  <acronym>SQL</acronym> commands inside user-defined +  <acronym>C</acronym> functions.  <acronym>SPI</acronym> is a set of +  interface functions to simplify access to the parser, planner, +  optimizer, and executor. <acronym>SPI</acronym> also does some +  memory management. + </para> + + <para> +  To avoid misunderstanding we'll use the term <quote>function</quote> +  when we speak of <acronym>SPI</acronym> interface functions and +  <quote>procedure</quote> for user-defined C-functions, which may be +  using <acronym>SPI</acronym>. + </para> + + <para> +  Note that if during the execution of a procedure the transaction is +  aborted because of an error in a command, 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.  A +  related restriction is the inability to execute +  <command>BEGIN</command>, <command>COMMIT</command>, and +  <command>ROLLBACK</command> (transaction control statements) inside +  a procedure.  Both of these restrictions will probably be changed in +  the future. + </para> + + <para> +  <acronym>SPI</acronym> functions return a nonnegative result on +  success (either via a returned integer value or in the global +  variable <varname>SPI_result</varname>, as described below).  On +  error, a negative result or <symbol>NULL</symbol> will be returned. + </para> + + <para> +  Source code files that use SPI must include the header file +  <filename>executor/spi.h</filename>. + </para> + + <note> +  <para> +   The available procedural languages provide different means to +   execute SQL commands from procedures.  Some of these are modelled +   after SPI, so this documentation might be of use for those users as +   well. +  </para> + </note> + + +<sect1 id="spi-interface"> + <title>Interface Functions</title> + + <refentry id="spi-spi-connect"> +  <refmeta> +   <refentrytitle>SPI_connect</refentrytitle> +  </refmeta> + +  <refnamediv> +   <refname>SPI_connect</refname> +   <refpurpose>connect a procedure to the SPI manager</refpurpose> + </refnamediv> + + <indexterm><primary>SPI_connect</primary></indexterm> + + <refsynopsisdiv> +<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> -const 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 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 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> -const char * <REPLACEABLE CLASS="PARAMETER">query</REPLACEABLE> -</TERM> -<LISTITEM> -<PARA> -Query string -</PARA> -</LISTITEM> -</VARLISTENTRY> -<VARLISTENTRY> -<TERM> -int <REPLACEABLE CLASS="PARAMETER">nargs</REPLACEABLE> -</TERM> -<LISTITEM> -<PARA> -Number of input parameters ($1 ... $nargs - as in SQL-functions) -</PARA> -</LISTITEM> -</VARLISTENTRY> -<VARLISTENTRY> -<TERM> -Oid * <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> - -<!-- *********************************************** --> -<!-- *********************************************** --> -<!-- *********************************************** --> +</synopsis> + </refsynopsisdiv> -<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> -const 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> + <refsect1> +  <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 want to execute commands through SPI.  Some utility +   SPI functions may be called from unconnected procedures. +  </para> -<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> -const 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> -const 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> +  <para> +   If your procedure is already connected, +   <function>SPI_connect</function> will return the error code +   <returnvalue>SPI_ERROR_CONNECT</returnvalue>.  This could happen if +   a procedure that has called <function>SPI_connect</function> +   directly calls another procedure that calls +   <function>SPI_connect</function>.  While recursive calls to the +   <acronym>SPI</acronym> manager are permitted when an SQL command +   called through SPI invokes another function that uses +   <acronym>SPI</acronym>, directly nested calls to +   <function>SPI_connect</function> and +   <function>SPI_finish</function> are forbidden. +  </para> + </refsect1> + + <refsect1> +  <title>Return Value</title> + +  <variablelist> +   <varlistentry> +    <term><symbol>SPI_OK_CONNECT</symbol></term> +    <listitem> +     <para> +      on success +     </para> +    </listitem> +   </varlistentry> + +   <varlistentry> +    <term><symbol>SPI_ERROR_CONNECT</symbol></term> +    <listitem> +     <para> +      on error +     </para> +    </listitem> +   </varlistentry> +  </variablelist> + </refsect1> +</refentry> + +<!-- *********************************************** --> + +<refentry id="spi-spi-finish"> + <refmeta> +  <refentrytitle>SPI_finish</refentrytitle> + </refmeta> + + <refnamediv> +  <refname>SPI_finish</refname> +  <refpurpose>disconnect a procedure from the SPI manager</refpurpose> + </refnamediv> + + <indexterm><primary>SPI_finish</primary></indexterm> + + <refsynopsisdiv> +<synopsis> +int SPI_finish(void) +</synopsis> + </refsynopsisdiv> + + <refsect1> +  <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. +   You do not need to worry about making this happen, however, if you +   abort the transaction via <literal>elog(ERROR)</literal>.  In that +   case SPI will clean itself up automatically. +  </para> + +  <para> +   If <function>SPI_finish</function> is called without having a valid +   connection, it will return <symbol>SPI_ERROR_UNCONNECTED</symbol>. +   There is no fundamental problem with this; it means that the SPI +   manager has nothing to do. +  </para> + </refsect1> + + <refsect1> +  <title>Return Value</title> + +  <variablelist> +   <varlistentry> +    <term><symbol>SPI_OK_FINISH</symbol></term> +    <listitem> +     <para> +      if properly disconnected +     </para> +    </listitem> +   </varlistentry> + +   <varlistentry> +    <term><symbol>SPI_ERROR_UNCONNECTED</symbol></term> +    <listitem> +     <para> +      if called from an unconnected procedure +     </para> +    </listitem> +   </varlistentry> +  </variablelist> + </refsect1> +</refentry> + +<!-- *********************************************** --> + +<refentry id="spi-spi-exec"> + <refmeta> +  <refentrytitle>SPI_exec</refentrytitle> + </refmeta> + + <refnamediv> +  <refname>SPI_exec</refname> +  <refpurpose>execute a command</refpurpose> + </refnamediv> + + <indexterm><primary>SPI_exec</primary></indexterm> + + <refsynopsisdiv> +<synopsis> +int SPI_exec(const char * <parameter>command</parameter>, int <parameter>count</parameter>) +</synopsis> + </refsynopsisdiv> + + <refsect1> +  <title>Description</title> + +  <para> +   <function>SPI_exec</function> executes the specified SQL command +   for <parameter>count</parameter> rows. +  </para> + +  <para> +   This function should only be called from a connected procedure.  If +   <parameter>count</parameter> is zero then it executes the command +   for all rows that it applies to.  If <parameter>count</parameter> +   is greater than 0, then the number of rows for which the command +   will be executed is restricted (much like a +   <literal>LIMIT</literal> clause). For example, +<programlisting> +SPI_exec("INSERT INTO tab SELECT * FROM tab", 5); +</programlisting> +   will allow at most 5 rows to be inserted into the table. +  </para> + +  <para> +   You may pass multiple commands in one string, and the command may +   be rewritten by rules. <function>SPI_exec</function> returns the +   result for the command executed last. +  </para> + +  <para> +   The actual number of rows for which the (last) command was executed +   is returned in the global variable <varname>SPI_processed</varname> +   (unless the return value of the function is +   <symbol>SPI_OK_UTILITY</symbol>).  If the return value of the +   function is <symbol>SPI_OK_SELECT</symbol> then you may the use +   global pointer <literal>SPITupleTable *SPI_tuptable</literal> to +   access the result rows. +  </para> + +  <para> +   The structure <structname>SPITupleTable</structname> is defined +   thus: +<programlisting> +typedef struct +{ +    MemoryContext tuptabcxt;    /* memory context of result table */ +    uint32      alloced;        /* number of alloced vals */ +    uint32      free;           /* number of free vals */ +    TupleDesc   tupdesc;        /* row descriptor */ +    HeapTuple  *vals;           /* rows */ +} SPITupleTable; +</programlisting> +   <structfield>vals</> is an array of pointers to rows.  (The number +   of valid entries is given by <varname>SPI_processed</varname>). +   <structfield>tupdesc</> is a row descriptor which you may pass to +   SPI functions dealing with rows.  <structfield>tuptabcxt</>, +   <structfield>alloced</>, and <structfield>free</> are internal +   fields not intended for use by SPI callers. +  </para> + +  <para> +   <function>SPI_finish</function> frees all +   <structname>SPITupleTable</>s 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> + + <refsect1> +  <title>Arguments</title> + +  <variablelist> +   <varlistentry> +    <term><literal>const char * <parameter>command</parameter></literal></term> +    <listitem> +     <para> +      string containing command to execute +     </para> +    </listitem> +   </varlistentry> + +   <varlistentry> +    <term><literal>int <parameter>count</parameter></literal></term> +    <listitem> +     <para> +      maximum number of rows to process or return +     </para> +    </listitem> +   </varlistentry> +  </variablelist> + </refsect1> + + <refsect1> +  <title>Return Value</title> + +  <para> +   If the execution of the command was successful then one of the +   following (nonnegative) values will be returned: + +   <variablelist> +    <varlistentry> +     <term><symbol>SPI_OK_SELECT</symbol></term> +     <listitem> +      <para> +       if a <command>SELECT</command> (but not <command>SELECT +       ... INTO</>) was executed +      </para> +     </listitem> +    </varlistentry> + +    <varlistentry> +     <term><symbol>SPI_OK_SELINTO</symbol></term> +     <listitem> +      <para> +       if a <command>SELECT ... INTO</command> was executed +      </para> +     </listitem> +    </varlistentry> + +    <varlistentry> +     <term><symbol>SPI_OK_DELETE</symbol></term> +     <listitem> +      <para> +       if a <command>DELETE</command> was executed +      </para> +     </listitem> +    </varlistentry> + +    <varlistentry> +     <term><symbol>SPI_OK_INSERT</symbol></term> +     <listitem> +      <para> +       if an <command>INSERT</command> was executed +      </para> +     </listitem> +    </varlistentry> + +    <varlistentry> +     <term><symbol>SPI_OK_UPDATE</symbol></term> +     <listitem> +      <para> +       if an <command>UPDATE</command> was executed +      </para> +     </listitem> +    </varlistentry> + +    <varlistentry> +     <term><symbol>SPI_OK_UTILITY</symbol></term> +     <listitem> +      <para> +       if a utility command (e.g., <command>CREATE TABLE</command>) +       was executed +      </para> +     </listitem> +    </varlistentry> +   </variablelist> +  </para> + +  <para> +   On error, one of the following negative values is returned: + +   <variablelist> +    <varlistentry> +     <term><symbol>SPI_ERROR_ARGUMENT</symbol></term> +     <listitem> +      <para> +       if <parameter>command</parameter> is <symbol>NULL</symbol> or +       <parameter>count</parameter> is less than 0 +      </para> +     </listitem> +    </varlistentry> + +    <varlistentry> +     <term><symbol>SPI_ERROR_COPY</symbol></term> +     <listitem> +      <para> +       if <command>COPY TO stdout</> or <command>COPY FROM stdin</> +       was attempted +      </para> +     </listitem> +    </varlistentry> + +    <varlistentry> +     <term><symbol>SPI_ERROR_CURSOR</symbol></term> +     <listitem> +      <para> +       if <command>DECLARE</>, <command>CLOSE</>, or <command>FETCH</> +       was attempted +      </para> +     </listitem> +    </varlistentry> + +    <varlistentry> +     <term><symbol>SPI_ERROR_TRANSACTION</symbol></term> +     <listitem> +      <para> +       if <command>BEGIN</>, <command>COMMIT</>, or +       <command>ROLLBACK</> was attempted +      </para> +     </listitem> +    </varlistentry> + +    <varlistentry> +     <term><symbol>SPI_ERROR_OPUNKNOWN</symbol></term> +     <listitem> +      <para> +       if the command type is unknown (shouldn't happen) +      </para> +     </listitem> +    </varlistentry> + +    <varlistentry> +     <term><symbol>SPI_ERROR_UNCONNECTED</symbol></term> +     <listitem> +      <para> +       if called from an unconnected procedure +      </para> +     </listitem> +    </varlistentry> +   </variablelist> +  </para> + </refsect1> + + <refsect1> +  <title>Notes</title> + +  <para> +   The functions <function>SPI_exec</function>, +   <function>SPI_execp</function>, and +   <function>SPI_prepare</function> change both +   <varname>SPI_processed</varname> and +   <varname>SPI_tuptable</varname> (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 +   <function>SPI_exec</function> or <function>SPI_execp</function> +   across later calls. +  </para> + </refsect1> +</refentry> + +<!-- *********************************************** --> + +<refentry id="spi-spi-prepare"> + <refmeta> +  <refentrytitle>SPI_prepare</refentrytitle> + </refmeta> + + <refnamediv> +  <refname>SPI_prepare</refname> +  <refpurpose>prepare a plan for a command, without executing it yet</refpurpose> + </refnamediv> + + <indexterm><primary>SPI_prepare</primary></indexterm> + + <refsynopsisdiv> +<synopsis> +void * SPI_prepare(const char * <parameter>command</parameter>, int <parameter>nargs</parameter>, Oid * <parameter>argtypes</parameter>) +</synopsis> + </refsynopsisdiv> + + <refsect1> +  <title>Description</title> + +  <para> +   <function>SPI_prepare</function> creates and returns an execution +   plan for the specified command but doesn't execute the command. +   This function should only be called from a connected procedure. +  </para> + +  <para> +   When the same or a similar command is to be executed repeatedly, it +   may be advantageous to perform the planning only once. +   <function>SPI_prepare</function> converts a command string into an +   execution plan that can be executed repeatedly using +   <function>SPI_execp</function>. +  </para> + +  <para> +   A prepared command can be generalized by writing parameters +   (<literal>$1</>, <literal>$2</>, etc.) in place of what would be +   constants in a normal command.  The actual values of the parameters +   are then specified when <function>SPI_execp</function> is called. +   This allows the prepared command to be used over a wider range of +   situations than would be possible without parameters. +  </para> + +  <para> +   The plan returned by <function>SPI_prepare</function> can be used +   only in the current invocation of the procedure since +   <function>SPI_finish</function> frees memory allocated for a plan. +   But a plan can be saved for longer using the function +   <function>SPI_saveplan</function>. +  </para> + </refsect1> + + <refsect1> +  <title>Arguments</title> + +  <variablelist> +   <varlistentry> +    <term><literal>const char * <parameter>command</parameter></literal></term> +    <listitem> +     <para> +      command string +     </para> +    </listitem> +   </varlistentry> + +   <varlistentry> +    <term><literal>int <parameter>nargs</parameter></literal></term> +    <listitem> +     <para> +      number of input parameters (<literal>$1</>, <literal>$2</>, etc.) +     </para> +    </listitem> +   </varlistentry> + +   <varlistentry> +    <term><literal>Oid * <parameter>argtypes</parameter></literal></term> +    <listitem> +     <para> +      pointer to an array containing the <acronym>OID</acronym>s of +      the data types of the parameters +     </para> +    </listitem> +   </varlistentry> +  </variablelist> + </refsect1> + + <refsect1> +  <title>Return Value</title> + +  <para> +   <function>SPI_prepare</function> returns non-null pointer to an +   execution plan.  On error, <symbol>NULL</symbol> will be returned. +   In both cases, <varname>SPI_result</varname> will be set analogous +   to the value returned by <function>SPI_exec</function>, except that +   it is set to <symbol>SPI_ERROR_ARGUMENT</symbol> if +   <parameter>command</parameter> is <symbol>NULL</symbol>, or if +   <parameter>nargs</> is less than 0, or if <parameter>nargs</> is +   greater than 0 and <parameter>argtypes</> is <symbol>NULL</symbol>. +  </para> + </refsect1> + + <refsect1> +  <title>Notes</title> + +  <para> +   There is a disadvantage to using parameters: since the planner does +   not know the values that will be supplied for the parameters, it +   may make worse planning choices than it would make for a normal +   command with all constants visible. +  </para> + </refsect1> +</refentry> + +<!-- *********************************************** --> + +<refentry id="spi-spi-execp"> + <refmeta> +  <refentrytitle>SPI_execp</refentrytitle> + </refmeta> + + <refnamediv> +  <refname>SPI_execp</refname> +  <refpurpose>executes a plan prepared by <function>SPI_prepare</function></refpurpose> + </refnamediv> + + <indexterm><primary>SPI_execp</primary></indexterm> + + <refsynopsisdiv> +<synopsis> +int SPI_execp(void * <parameter>plan</parameter>, Datum * <parameter>values</parameter>, const char * <parameter>nulls</parameter>, int <parameter>count</parameter>) +</synopsis> + </refsynopsisdiv> + + <refsect1> +  <title>Description</title> + +  <para> +   <function>SPI_execp</function> executes a plan prepared by +   <function>SPI_prepare</function>.  <parameter>tcount</parameter> +   has the same interpretation as in <function>SPI_exec</function>. +  </para> + </refsect1> + + <refsect1> +  <title>Arguments</title> + +  <variablelist> +   <varlistentry> +    <term><literal>void * <parameter>plan</parameter></literal></term> +    <listitem> +     <para> +      execution plan (returned by <function>SPI_prepare</function>) +     </para> +    </listitem> +   </varlistentry> + +   <varlistentry> +    <term><literal>Datum *<parameter>values</parameter></literal></term> +    <listitem> +     <para> +      actual parameter values +     </para> +    </listitem> +   </varlistentry> + +   <varlistentry> +    <term><literal>const char * <parameter>nulls</parameter></literal></term> +    <listitem> +     <para> +      An array describing which parameters are null. +      <literal>n</literal> indicates a null value (entry in +      <parameter>values</> will be ignored); a space indicates a +      nonnull value (entry in <parameter>values</> is valid). +     </para> + +     <para> +      If <parameter>nulls</parameter> is <symbol>NULL</symbol> then +      <function>SPI_execp</function> assumes that no parameters are +      null. +     </para> +    </listitem> +   </varlistentry> + +   <varlistentry> +    <term><literal>int <parameter>count</parameter></literal></term> +    <listitem> +     <para> +      number of row for which plan is to be executed +     </para> +    </listitem> +   </varlistentry> +  </variablelist> + </refsect1> + + <refsect1> +  <title>Return Value</title> + +  <para> +   The return value is the same as for <function>SPI_exec</function> +   or one of the following: + +   <variablelist> +    <varlistentry> +     <term><symbol>SPI_ERROR_ARGUMENT</symbol></term> +     <listitem> +      <para> +       if <parameter>plan</parameter> is <symbol>NULL</symbol> or +       <parameter>count</parameter> is less than 0 +      </para> +     </listitem> +    </varlistentry> + +    <varlistentry> +     <term><symbol>SPI_ERROR_PARAM</symbol></term> +     <listitem> +      <para> +       if <parameter>values</parameter> is <symbol>NULL</symbol> and +       <parameter>plan</parameter> was prepared with some parameters +      </para> +     </listitem> +    </varlistentry> +   </variablelist> +  </para> + +  <para> +   <varname>SPI_processed</varname> and +   <varname>SPI_tuptable</varname> are set as in +   <function>SPI_exec</function> if successful. +  </para> + </refsect1> + + <refsect1> +  <title>Notes</title> + +  <para> +   If one of the objects (a table, function, etc.) referenced by the +   prepared plan is dropped during the session then the result of +   <function>SPI_execp</function> for this plan will be unpredictable. +  </para> + </refsect1> +</refentry> + +<!-- *********************************************** --> + +<refentry id="spi-spi-cursor-open"> + <refmeta> +  <refentrytitle>SPI_cursor_open</refentrytitle> + </refmeta> + + <refnamediv> +  <refname>SPI_cursor_open</refname> +  <refpurpose>set up a cursor using a plan created with <function>SPI_prepare</function></refpurpose> + </refnamediv> + + <indexterm><primary>SPI_cursor_open</primary></indexterm> + + <refsynopsisdiv> +<synopsis> +Portal SPI_cursor_open(const char * <parameter>name</parameter>, void * <parameter>plan</parameter>, Datum * <parameter>values</parameter>, const char * <parameter>nulls</parameter>) +</synopsis> + </refsynopsisdiv> + + <refsect1> +  <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> -const 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> -const 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> -const 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 +   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 row set as +   result. +  </para> + </refsect1> + + <refsect1> +  <title>Arguments</title> + +  <variablelist> +   <varlistentry> +    <term><literal>const char * <parameter>name</parameter></literal></term> +    <listitem> +     <para> +      name for portal, or <symbol>NULL</symbol> to let the system +      select a name +     </para> +    </listitem> +   </varlistentry> + +   <varlistentry> +    <term><literal>void * <parameter>plan</parameter></literal></term> +    <listitem> +     <para> +      execution plan (returned by <function>SPI_prepare</function>) +     </para> +    </listitem> +   </varlistentry> + +   <varlistentry> +    <term><literal>Datum * <parameter>values</parameter></literal></term> +    <listitem> +     <para> +      actual parameter values +     </para> +    </listitem> +   </varlistentry> + +   <varlistentry> +    <term><literal>const char *<parameter>nulls</parameter></literal></term> +    <listitem> +     <para> +      An array describing which parameters are null values. +      <literal>n</literal> indicates a null value (entry in +      <parameter>values</> will be ignored); a space indicates a +      nonnull value (entry in <parameter>values</> is valid).  If +      <parameter>nulls</parameter> is <symbol>NULL</> then +      <function>SPI_cursor_open</function> assumes that no parameters +      are null. +     </para> +    </listitem> +   </varlistentry> +  </variablelist> + </refsect1> + + <refsect1> +  <title>Return Value</title> + +  <para> +   pointer to portal containing the cursor, or <symbol>NULL</symbol> +   on error +  </para> + </refsect1> +</refentry> + +<!-- *********************************************** --> + +<refentry id="spi-spi-cursor-find"> + <refmeta> +  <refentrytitle>SPI_cursor_find</refentrytitle> + </refmeta> + + <refnamediv> +  <refname>SPI_cursor_find</refname> +  <refpurpose>find an existing cursor by name</refpurpose> + </refnamediv> + + <indexterm><primary>SPI_cursor_find</primary></indexterm> + + <refsynopsisdiv> +<synopsis> +Portal SPI_cursor_find(const char * <parameter>name</parameter>) +</synopsis> + </refsynopsisdiv> + + <refsect1> +  <title>Description</title> + +  <para> +   <function>SPI_cursor_find</function> finds an existing portal by +   name.  This is primarily useful to resolve a cursor name returned +   as text by some other function. +  </para> + </refsect1> + + <refsect1> +  <title>Arguments</title> + +  <variablelist> +   <varlistentry> +    <term><literal>const char * <parameter>name</parameter></literal></term> +    <listitem> +     <para> +      name of the portal +     </para> +    </listitem> +   </varlistentry> +  </variablelist> + </refsect1> + + <refsect1> +  <title>Return Value</title> + +  <para> +   pointer to the portal with the specified name, or +   <symbol>NULL</symbol> if none was found +  </para> + </refsect1> +</refentry> + +<!-- *********************************************** --> + +<refentry id="spi-spi-cursor-fetch"> + <refmeta> +  <refentrytitle>SPI_cursor_fetch</refentrytitle> + </refmeta> + + <refnamediv> +  <refname>SPI_cursor_fetch</refname> +  <refpurpose>fetch some rows from a cursor</refpurpose> + </refnamediv> + + <indexterm><primary>SPI_cursor_fetch</primary></indexterm> + + <refsynopsisdiv> +<synopsis> +void SPI_cursor_fetch(Portal <parameter>portal</parameter>, bool <parameter>forward</parameter>, int <parameter>count</parameter>) +</synopsis> + </refsynopsisdiv> + + <refsect1> +  <title>Description</title> + +  <para> +   <function>SPI_cursor_fetch</function> fetches some rows from a +   cursor.  This is equivalent to the SQL command <command>FETCH</>. +  </para> + </refsect1> + + <refsect1> +  <title>Arguments</title> + +  <variablelist> +   <varlistentry> +    <term><literal>Portal <parameter>portal</parameter></literal></term> +    <listitem> +     <para> +      portal containing the cursor +     </para> +    </listitem> +   </varlistentry> + +   <varlistentry> +    <term><literal>bool <parameter>forward</parameter></literal></term> +    <listitem> +     <para> +      true for fetch forward, false for fetch backward +     </para> +    </listitem> +   </varlistentry> + +   <varlistentry> +    <term><literal>int <parameter>count</parameter></literal></term> +    <listitem> +     <para> +      maximum number of rows to fetch +     </para> +    </listitem> +   </varlistentry> +  </variablelist> + </refsect1> + + <refsect1> +  <title>Return Value</title> + +  <para> +   <varname>SPI_processed</varname> and +   <varname>SPI_tuptable</varname> are set as in +   <function>SPI_exec</function> if successful. +  </para> + </refsect1> +</refentry> + +<!-- *********************************************** --> + +<refentry id="spi-spi-cursor-move"> + <refmeta> +  <refentrytitle>SPI_cursor_move</refentrytitle> + </refmeta> + + <refnamediv> +  <refname>SPI_cursor_move</refname> +  <refpurpose>move a cursor</refpurpose> + </refnamediv> + + <indexterm><primary>SPI_cursor_move</primary></indexterm> + + <refsynopsisdiv> +<synopsis> +void SPI_cursor_move(Portal <parameter>portal</parameter>, bool <parameter>forward</parameter>, int <parameter>count</parameter>) +</synopsis> + </refsynopsisdiv> + + <refsect1> +  <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> +  <title>Arguments</title> + +  <variablelist> +   <varlistentry> +    <term><literal>Portal <parameter>portal</parameter></literal></term> +    <listitem> +     <para> +      portal containing the cursor +     </para> +    </listitem> +   </varlistentry> + +   <varlistentry> +    <term><literal>bool <parameter>forward</parameter></literal></term> +    <listitem> +     <para> +      true for move forward, false for move backward +     </para> +    </listitem> +   </varlistentry> + +   <varlistentry> +    <term><literal>int <parameter>count</parameter></literal></term> +    <listitem> +     <para> +      maximum number of rows to move +     </para> +    </listitem> +   </varlistentry> +  </variablelist> + </refsect1> +</refentry> + +<!-- *********************************************** --> + +<refentry id="spi-spi-cursor-close"> + <refmeta> +  <refentrytitle>SPI_cursor_close</refentrytitle> + </refmeta> + + <refnamediv> +  <refname>SPI_cursor_close</refname> +  <refpurpose>close a cursor</refpurpose> + </refnamediv> + + <indexterm><primary>SPI_cursor_close</primary></indexterm> + + <refsynopsisdiv> +<synopsis> +void SPI_cursor_close(Portal <parameter>portal</parameter>) +</synopsis> + </refsynopsisdiv> + + <refsect1> +  <title>Description</title> + +  <para> +   <function>SPI_cursor_close</function> closes a previously created +   cursor and releases its portal storage. +  </para> + +  <para> +   All open cursors are closed automatically at the end of a +   transaction.  <function>SPI_cursor_close</function> need only be +   invoked if it is desirable to release resources sooner. +  </para> + </refsect1> + + <refsect1> +  <title>Arguments</title> + +  <variablelist> +   <varlistentry> +    <term><literal>Portal <parameter>portal</parameter></literal></term> +    <listitem> +     <para> +      portal containing the cursor +     </para> +    </listitem> +   </varlistentry> +  </variablelist> + </refsect1> +</refentry> + +<!-- *********************************************** --> + +<refentry id="spi-spi-saveplan"> + <refmeta> +  <refentrytitle>SPI_saveplan</refentrytitle> + </refmeta> + + <refnamediv> +  <refname>SPI_saveplan</refname> +  <refpurpose>save a plan</refpurpose> + </refnamediv> + + <indexterm><primary>SPI_saveplan</primary></indexterm> + + <refsynopsisdiv> +<synopsis> +void * SPI_saveplan(void * <parameter>plan</parameter>) +</synopsis> + </refsynopsisdiv> + + <refsect1> +  <title>Description</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.  This gives you the +   ability to reuse prepared plans in the subsequent invocations of +   your procedure in the current session.  You may save the pointer +   returned in a local variable.  Always check if this pointer is +   <symbol>NULL</symbol> or not either when preparing a plan or using +   an already prepared plan in <function>SPI_execp</function>. +  </para> + </refsect1> + + <refsect1> +  <title>Arguments</title> + +  <variablelist> +   <varlistentry> +    <term><literal>void * <parameter>plan</parameter></literal></term> +    <listitem> +     <para> +      the plan to be saved +     </para> +    </listitem> +   </varlistentry> +  </variablelist> + </refsect1> + + <refsect1> +  <title>Return Value</title> + +  <para> +   Pointer to the saved plan; <symbol>NULL</symbol> if unsuccessful. +   On error, <varname>SPI_result</varname> is set thus: + +   <variablelist> +    <varlistentry> +     <term><symbol>SPI_ERROR_ARGUMENT</symbol></term> +     <listitem> +      <para> +       if <parameter>plan</parameter> is <symbol>NULL</symbol> +      </para> +     </listitem> +    </varlistentry> + +    <varlistentry> +     <term><symbol>SPI_ERROR_UNCONNECTED</symbol></term> +     <listitem> +      <para> +       if called from an unconnected procedure +      </para> +     </listitem> +    </varlistentry> +   </variablelist> +  </para> + </refsect1> + + <refsect1> +  <title>Notes</title> + +  <para> +   If one of the objects (a table, function, etc.) referenced by the +   prepared plan is dropped during the session then the results of +   <function>SPI_execp</function> for this plan will be unpredictable. +  </para> + </refsect1> +</refentry> + +</sect1> + +<sect1 id="spi-interface-support"> + <title>Interface Support Functions</title> + + <para> +  The functions described here provide an interface for extracting +  information from result sets returned by <function>SPI_exec</> and +  other SPI functions. + </para> + + <para> +  All functions described in this section may be used by both +  connected and unconnected procedures. + </para> + +<!-- *********************************************** --> + +<refentry id="spi-spi-fname"> + <refmeta> +  <refentrytitle>SPI_fname</refentrytitle> + </refmeta> + + <refnamediv> +  <refname>SPI_fname</refname> +  <refpurpose>determine the column name for the specified column number</refpurpose> + </refnamediv> + + <indexterm><primary>SPI_fname</primary></indexterm> + + <refsynopsisdiv> +<synopsis> +char * SPI_fname(TupleDesc <parameter>rowdesc</parameter>, int <parameter>colnumber</parameter>) +</synopsis> + </refsynopsisdiv> + + <refsect1> +  <title>Description</title> + +  <para> +   <function>SPI_fname</function> returns the column name of the +   specified column.  (You can use <function>pfree</function> to +   release the copy of the name when you don't need it anymore.) +  </para> + </refsect1> + + <refsect1> +  <title>Arguments</title> + +  <variablelist> +   <varlistentry> +    <term><literal>TupleDesc <parameter>rowdesc</parameter></literal></term> +    <listitem> +     <para> +      input row description +     </para> +    </listitem> +   </varlistentry> + +   <varlistentry> +    <term><literal>int <parameter>colnumber</parameter></literal></term> +    <listitem> +     <para> +      column number (count starts at 1) +     </para> +    </listitem> +   </varlistentry> +  </variablelist> + </refsect1> + + <refsect1> +  <title>Return Value</title> + +  <para> +   The column name; <symbol>NULL</symbol> if +   <parameter>colnumber</parameter> is out of range. +   <varname>SPI_result</varname> set to +   <symbol>SPI_ERROR_NOATTRIBUTE</symbol> on error. +  </para> + </refsect1> +</refentry> + +<!-- *********************************************** --> + +<refentry id="spi-spi-fnumber"> + <refmeta> +  <refentrytitle>SPI_fnumber</refentrytitle> + </refmeta> + + <refnamediv> +  <refname>SPI_fnumber</refname> +  <refpurpose>determine the column number for the specified column name</refpurpose> + </refnamediv> + + <indexterm><primary>SPI_fnumber</primary></indexterm> + + <refsynopsisdiv> +<synopsis> +int SPI_fnumber(TupleDesc <parameter>rowdesc</parameter>, const char * <parameter>colname</parameter>) +</synopsis> + </refsynopsisdiv> + + <refsect1> +  <title>Description</title> + +  <para> +   <function>SPI_fnumber</function> returns the column number for the +   column with the specified name. +  </para> + +  <para> +   If <parameter>colname</parameter> refers to a system column (e.g., +   <literal>oid</>) then the appropriate negative column number will +   be returned.  The caller should be careful to test the return value +   for exact equality to <symbol>SPI_ERROR_NOATTRIBUTE</symbol> to +   detect an error; testing the result for less than or equal to 0 is +   not correct unless system columns should be rejected. +  </para> + </refsect1> + + <refsect1> +  <title>Arguments</title> + +  <variablelist> +   <varlistentry> +    <term><literal>TupleDesc <parameter>rowdesc</parameter></literal></term> +    <listitem> +     <para> +      input row description +     </para> +    </listitem> +   </varlistentry> + +   <varlistentry> +    <term><literal>const char * <parameter>colname</parameter></literal></term> +    <listitem> +     <para> +      column name +     </para> +    </listitem> +   </varlistentry> +  </variablelist> + </refsect1> + + <refsect1> +  <title>Return Value</title> + +  <para> +   Column number (count starts at 1), or +   <symbol>SPI_ERROR_NOATTRIBUTE</symbol> if the named column was not +   found. +  </para> + </refsect1> +</refentry> + +<!-- *********************************************** --> + +<refentry id="spi-spi-getvalue"> + <refmeta> +  <refentrytitle>SPI_getvalue</refentrytitle> + </refmeta> + + <refnamediv> +  <refname>SPI_getvalue</refname> +  <refpurpose>return the string value of the specified column</refpurpose> + </refnamediv> + + <indexterm><primary>SPI_getvalue</primary></indexterm> + + <refsynopsisdiv> +<synopsis> +char * SPI_getvalue(HeapTuple <parameter>row</parameter>, TupleDesc <parameter>rowdesc</parameter>, int <parameter>colnumber</parameter>) +</synopsis> + </refsynopsisdiv> + + <refsect1> +  <title>Description</title> + +  <para> +   <function>SPI_getvalue</function> returns the string representation +   of the value of the specified column. +  </para> + +  <para> +   The result is returned in memory allocated using +   <function>palloc</function>.  (You can use +   <function>pfree</function> to release the memory when you don't +   need it anymore.) +  </para> + </refsect1> + + <refsect1> +  <title>Arguments</title> + +  <variablelist> +   <varlistentry> +    <term><literal>HeapTuple <parameter>row</parameter></literal></term> +    <listitem> +     <para> +      input row to be examined +     </para> +    </listitem> +   </varlistentry> + +   <varlistentry> +    <term><literal>TupleDesc <parameter>rowdesc</parameter></literal></term> +    <listitem> +     <para> +      input row description +     </para> +    </listitem> +   </varlistentry> + +   <varlistentry> +    <term><literal>int <parameter>colnumber</parameter></literal></term> +    <listitem> +     <para> +      column number (count starts at 1) +     </para> +    </listitem> +   </varlistentry> +  </variablelist> + </refsect1> + + <refsect1> +  <title>Return Value</title> + +  <para> +   Column value, or <symbol>NULL</symbol> if the column is null, +   <parameter>colnumber</parameter> is out of range +   (<varname>SPI_result</varname> is set to +   <symbol>SPI_ERROR_NOATTRIBUTE</symbol>), or no no output function +   available (<varname>SPI_result</varname> is set to +   <symbol>SPI_ERROR_NOOUTFUNC</symbol>). +  </para> + </refsect1> +</refentry> + +<!-- *********************************************** --> + +<refentry id="spi-spi-getbinval"> + <refmeta> +  <refentrytitle>SPI_getbinval</refentrytitle> + </refmeta> + + <refnamediv> +  <refname>SPI_getbinval</refname> +  <refpurpose>return the binary value of the specified column</refpurpose> + </refnamediv> + + <indexterm><primary>SPI_getbinval</primary></indexterm> + + <refsynopsisdiv> +<synopsis> +Datum SPI_getbinval(HeapTuple <parameter>row</parameter>, TupleDesc <parameter>rowdesc</parameter>, int <parameter>colnumber</parameter>, bool * <parameter>isnull</parameter>) +</synopsis> + </refsynopsisdiv> + + <refsect1> +  <title>Description</title> + +  <para> +   <function>SPI_getbinval</function> returns the value of the +   specified column in the internal form (as type <type>Datum</type>). +  </para> + +  <para> +   This function does not allocate new space for the datum.  In the +   case of a pass-by-reference data type, the return value will be a +   pointer into the passed row. +  </para> + </refsect1> + + <refsect1> +  <title>Arguments</title> + +  <variablelist> +   <varlistentry> +    <term><literal>HeapTuple <parameter>row</parameter></literal></term> +    <listitem> +     <para> +      input row to be examined +     </para> +    </listitem> +   </varlistentry> + +   <varlistentry> +    <term><literal>TupleDesc <parameter>rowdesc</parameter></literal></term> +    <listitem> +     <para> +      input row description +     </para> +    </listitem> +   </varlistentry> + +   <varlistentry> +    <term><literal>int <parameter>rownumber</parameter></literal></term> +    <listitem> +     <para> +      column number (count starts at 1) +     </para> +    </listitem> +   </varlistentry> + +   <varlistentry> +    <term><literal>bool * <parameter>isnull</parameter></literal></term> +    <listitem> +     <para> +      flag for a null value in the column +     </para> +    </listitem> +   </varlistentry> +  </variablelist> + </refsect1> + + <refsect1> +  <title>Return Value</title> + +  <para> +   The binary value of the column is returned.  The variable pointed +   to by <parameter>isnull</parameter> is set to true if the column is +   null, else to false. +  </para> + +  <para> +   <varname>SPI_result</varname> is set to +   <symbol>SPI_ERROR_NOATTRIBUTE</symbol> on error. +  </para> + </refsect1> +</refentry> + +<!-- *********************************************** --> + +<refentry id="spi-spi-gettype"> + <refmeta> +  <refentrytitle>SPI_gettype</refentrytitle> + </refmeta> + + <refnamediv> +  <refname>SPI_gettype</refname> +  <refpurpose>return the data type name of the specified column</refpurpose> + </refnamediv> + + <indexterm><primary>SPI_gettype</primary></indexterm> + + <refsynopsisdiv> +<synopsis> +char * SPI_gettype(TupleDesc <parameter>rowdesc</parameter>, int <parameter>colnumber</parameter>) +</synopsis> + </refsynopsisdiv> + + <refsect1> +  <title>Description</title> + +  <para> +   <function>SPI_gettype</function> returns the data type name of the +   specified column.  (You can use <function>pfree</function> to +   release the copy of the name when you don't need it anymore.) +  </para> + </refsect1> + + <refsect1> +  <title>Arguments</title> + +  <variablelist> +   <varlistentry> +    <term><literal>TupleDesc <parameter>rowdesc</parameter></literal></term> +    <listitem> +     <para> +      input row description +     </para> +    </listitem> +   </varlistentry> + +   <varlistentry> +    <term><literal>int <parameter>colnumber</parameter></literal></term> +    <listitem> +     <para> +      column number (count starts at 1) +     </para> +    </listitem> +   </varlistentry> +  </variablelist> + </refsect1> + + <refsect1> +  <title>Return Value</title> + +  <para> +   The data type name of the specified column, or +   <symbol>NULL</symbol> on error.  <varname>SPI_result</varname> is +   set to <symbol>SPI_ERROR_NOATTRIBUTE</symbol> on error. +  </para> + </refsect1> +</refentry> + +<!-- *********************************************** --> + +<refentry id="spi-spi-gettypeid"> + <refmeta> +  <refentrytitle>SPI_gettypeid</refentrytitle> + </refmeta> + + <refnamediv> +  <refname>SPI_gettypeid</refname> +  <refpurpose>return the data type <acronym>OID</acronym> of the specified column</refpurpose> + </refnamediv> + + <indexterm><primary>SPI_gettypeid</primary></indexterm> + + <refsynopsisdiv> +<synopsis> +Oid SPI_gettypeid(TupleDesc <parameter>rowdesc</parameter>, int <parameter>colnumber</parameter>) +</synopsis> + </refsynopsisdiv> + + <refsect1> +  <title>Description</title> + +  <para> +   <function>SPI_gettypeid</function> returns the +   <acronym>OID</acronym> of the data type of the specified column. +  </para> + </refsect1> + + <refsect1> +  <title>Arguments</title> + +  <variablelist> +   <varlistentry> +    <term><literal>TupleDesc <parameter>rowdesc</parameter></literal></term> +    <listitem> +     <para> +      input row description +     </para> +    </listitem> +   </varlistentry> + +   <varlistentry> +    <term><literal>int <parameter>colnumber</parameter></literal></term> +    <listitem> +     <para> +      column number (count starts at 1) +     </para> +    </listitem> +   </varlistentry> +  </variablelist> + </refsect1> + + <refsect1> +  <title>Return Value</title> + +  <para> +   The <acronym>OID</acronym> of the data type of the specified column +   or <symbol>InvalidOid</symbol> on error.  On error, +   <varname>SPI_result</varname> is set to +   <symbol>SPI_ERROR_NOATTRIBUTE</symbol>. +  </para> + </refsect1> +</refentry> + +<!-- *********************************************** --> + +<refentry id="spi-spi-getrelname"> + <refmeta> +  <refentrytitle>SPI_getrelname</refentrytitle> + </refmeta> + + <refnamediv> +  <refname>SPI_getrelname</refname> +  <refpurpose>return the name of the specified relation</refpurpose> + </refnamediv> + + <indexterm><primary>SPI_getrelname</primary></indexterm> + + <refsynopsisdiv> +<synopsis> +char * SPI_getrelname(Relation <parameter>rel</parameter>) +</synopsis> + </refsynopsisdiv> + + <refsect1> +  <title>Description</title> + +  <para> +   <function>SPI_getrelname</function> returns the name of the +   specified relation.  (You can use <function>pfree</function> to +   release the copy of the name when you don't need it anymore.) +  </para> + </refsect1> + + <refsect1> +  <title>Arguments</title> + +  <variablelist> +   <varlistentry> +    <term><literal>Relation <parameter>rel</parameter></literal></term> +    <listitem> +     <para> +      input relation +     </para> +    </listitem> +   </varlistentry> +  </variablelist> + </refsect1> + + <refsect1> +  <title>Return Value</title> + +  <para> +   The name of the specified relation. +  </para> + </refsect1> +</refentry> + + </sect1> + + <sect1 id="spi-memory"> +  <title>Memory Management</title> + +  <para> +   <productname>PostgreSQL</productname> allocates memory within +   <firstterm>memory contexts</firstterm><indexterm><primary>memory +   context</primary></indexterm>, 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; instead +   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 object in allocated +   memory (such as a value of a pass-by-reference data type), you +   cannot allocate that memory using <function>palloc</function>, at +   least not while you are connected to SPI.  If you try, the object +   will be deallocated by <function>SPI_finish</function>, and your +   procedure will not work reliably.  To solve this problem, use +   <function>SPI_palloc</function> to allocate memory for your return +   object.  <function>SPI_palloc</function> allocates memory in the +   <quote>upper executor context</quote>, that is, the memory context +   that was current when <function>SPI_connect</function> was called, +   which is precisely the right context for return a value from your +   procedure. +  </para> + +  <para> +   If <function>SPI_palloc</function> is called while the procedure is +   not connected to SPI, then it acts the same as a normal +   <function>palloc</function>.  Before a procedure connects to the +   SPI manager, the current memory context is the upper executor +   context, so all allocations made by the procedure via +   <function>palloc</function> or by SPI utility functions are made in +   this context. +  </para> + +  <para> +   When <function>SPI_connect</function> is called, the private +   context of the procedure, which is created by +   <function>SPI_connect</function>, is made the current context.  All +   allocations made by <function>palloc</function>, +   <function>repalloc</function>, or SPI utility functions (except for +   <function>SPI_copytuple</function>, +   <function>SPI_copytupledesc</function>, +   <function>SPI_copytupleintoslot</function>, +   <function>SPI_modifytuple</function>, and +   <function>SPI_palloc</function>) are made in this context.  When a +   procedure disconnects from the SPI manager (via +   <function>SPI_finish</function>) the current context is restored to +   the upper executor context, and all allocations made in the +   procedure memory context are freed and cannot be used any more. +  </para> + +  <para> +   All functions described in this section may be used by both +   connected and unconnected procedures.  In an unconnected procedure, +   they act the same as the underlying ordinary server functions +   (<function>palloc</>, etc.). +  </para> + +<!-- *********************************************** --> + +<refentry id="spi-spi-palloc"> + <refmeta> +  <refentrytitle>SPI_palloc</refentrytitle> + </refmeta> + + <refnamediv> +  <refname>SPI_palloc</refname> +  <refpurpose>allocate memory in the upper executor context</refpurpose> + </refnamediv> + + <indexterm><primary>SPI_palloc</primary></indexterm> + + <refsynopsisdiv> +<synopsis> +void * SPI_palloc(Size <parameter>size</parameter>) +</synopsis> + </refsynopsisdiv> + + <refsect1> +  <title>Description</title> + +  <para> +   <function>SPI_palloc</function> allocates memory in the upper +   executor context. +  </para> + </refsect1> + + <refsect1> +  <title>Arguments</title> + +  <variablelist> +   <varlistentry> +    <term><literal>Size <parameter>size</parameter></literal></term> +    <listitem> +     <para> +      size in bytes of storage to allocate +     </para> +    </listitem> +   </varlistentry> +  </variablelist> + </refsect1> + + <refsect1> +  <title>Return Value</title> + +  <para> +   pointer to new storage space of the specified size +  </para> + </refsect1> +</refentry> + +<!-- *********************************************** --> + +<refentry id="spi-realloc"> + <refmeta> +  <refentrytitle>SPI_repalloc</refentrytitle> + </refmeta> + + <refnamediv> +  <refname>SPI_repalloc</refname> +  <refpurpose>reallocate memory in the upper executor context</refpurpose> + </refnamediv> + + <indexterm><primary>SPI_repalloc</primary></indexterm> + + <refsynopsisdiv> +<synopsis> +void * SPI_repalloc(void * <parameter>pointer</parameter>, Size <parameter>size</parameter>) +</synopsis> + </refsynopsisdiv> + + <refsect1> +  <title>Description</title> + +  <para> +   <function>SPI_repalloc</function> changes the size of a memory +   segment previously allocated using <function>SPI_palloc</function>. +  </para> + +  <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> +  <title>Arguments</title> + +  <variablelist> +   <varlistentry> +    <term><literal>void * <parameter>pointer</parameter></literal></term> +    <listitem> +     <para> +      pointer to existing storage to change +     </para> +    </listitem> +   </varlistentry> + +   <varlistentry> +    <term><literal>Size <parameter>size</parameter></literal></term> +    <listitem> +     <para> +      size in bytes of storage to allocate +     </para> +    </listitem> +   </varlistentry> +  </variablelist> + </refsect1> + + <refsect1> +  <title>Return Value</title> + +  <para> +   pointer to new storage space of specified size with the contents +   copied from the existing area +  </para> + </refsect1> +</refentry> + +<!-- *********************************************** --> + +<refentry id="spi-spi-pfree"> + <refmeta> +  <refentrytitle>SPI_pfree</refentrytitle> + </refmeta> + + <refnamediv> +  <refname>SPI_pfree</refname> +  <refpurpose>free memory in the upper executor context</refpurpose> + </refnamediv> + + <indexterm><primary>SPI_pfree</primary></indexterm> + + <refsynopsisdiv> +<synopsis> +void SPI_pfree(void * <parameter>pointer</parameter>) +</synopsis> + </refsynopsisdiv> + + <refsect1> +  <title>Description</title> + +  <para> +   <function>SPI_pfree</function> frees memory previously allocated +   using <function>SPI_palloc</function> or +   <function>SPI_repalloc</function>. +  </para> + +  <para> +   This function is no longer different from plain +   <function>pfree</function>.  It's kept just for backward +   compatibility of existing code. +  </para> + </refsect1> + + <refsect1> +  <title>Arguments</title> + +  <variablelist> +   <varlistentry> +    <term><literal>void * <parameter>pointer</parameter></literal></term> +    <listitem> +     <para> +      pointer to existing storage to free +     </para> +    </listitem> +   </varlistentry> +  </variablelist> + </refsect1> +</refentry> + +<!-- *********************************************** --> + +<refentry id="spi-spi-copytuple"> + <refmeta> +  <refentrytitle>SPI_copytuple</refentrytitle> + </refmeta> + + <refnamediv> +  <refname>SPI_copytuple</refname> +  <refpurpose>make a copy of a row in the upper executor context</refpurpose> + </refnamediv> + + <indexterm><primary>SPI_copytuple</primary></indexterm> + + <refsynopsisdiv> +<synopsis> +HeapTuple SPI_copytuple(HeapTuple <parameter>row</parameter>) +</synopsis> + </refsynopsisdiv> + + <refsect1> +  <title>Description</title> + +  <para> +   <function>SPI_copytuple</function> makes a copy of a row in the +   upper executor context. +  </para> + </refsect1> + + <refsect1> +  <title>Arguments</title> + +  <variablelist> +   <varlistentry> +    <term><literal>HeapTuple <parameter>row</parameter></literal></term> +    <listitem> +     <para> +      row to be copied +     </para> +    </listitem> +   </varlistentry> +  </variablelist> + </refsect1> + + <refsect1> +  <title>Return Value</title> + +  <para> +   the copied row; <symbol>NULL</symbol> only if +   <parameter>tuple</parameter> is <symbol>NULL</symbol> +  </para> + </refsect1> +</refentry> + +<!-- *********************************************** --> + +<refentry id="spi-spi-copytupledesc"> + <refmeta> +  <refentrytitle>SPI_copytupledesc</refentrytitle> + </refmeta> + + <refnamediv> +  <refname>SPI_copytupledesc</refname> +  <refpurpose>make a copy of a row descriptor in the upper executor context</refpurpose> + </refnamediv> + + <indexterm><primary>SPI_copytupledesc</primary></indexterm> + + <refsynopsisdiv> +<synopsis> +TupleDesc SPI_copytupledesc(TupleDesc <parameter>tupdesc</parameter>) +</synopsis> + </refsynopsisdiv> + + <refsect1> +  <title>Description</title> + +  <para> +   <function>SPI_copytupledesc</function> makes a copy of a row +   descriptor in the upper executor context. +  </para> + </refsect1> + + <refsect1> +  <title>Arguments</title> + +  <variablelist> +   <varlistentry> +    <term><literal>TupleDesc <parameter>tupdesc</parameter></literal></term> +    <listitem> +     <para> +      row descriptor to be copied +     </para> +    </listitem> +   </varlistentry> +  </variablelist> + </refsect1> + + <refsect1> +  <title>Return Value</title> + +  <para> +   the copied row descriptor; <symbol>NULL</symbol> only if +   <parameter>tupdesc</parameter> is <symbol>NULL</symbol> +  </para> + </refsect1> +</refentry> + +<!-- *********************************************** --> + +<refentry id="spi-spi-copytupleintoslot"> + <refmeta> +  <refentrytitle>SPI_copytupleintoslot</refentrytitle> + </refmeta> + + <refnamediv> +  <refname>SPI_copytupleintoslot</refname> +  <refpurpose>make a copy of a row and descriptor in the upper executor context</refpurpose> + </refnamediv> + + <indexterm><primary>SPI_copytupleintoslot</primary></indexterm> + + <refsynopsisdiv> +<synopsis> +TupleTableSlot * SPI_copytupleintoslot(HeapTuple <parameter>row</parameter>, TupleDesc <parameter>rowdesc</parameter>) +</synopsis> + </refsynopsisdiv> + + <refsect1> +  <title>Description</title> + +  <para> +   <function>SPI_copytupleintoslot</function> makes a copy of a row in +   the upper executor context, returning it in the form of a filled-in +   <type>TupleTableSlot</type> structure. +  </para> + </refsect1> + + <refsect1> +  <title>Arguments</title> + +  <variablelist> +   <varlistentry> +    <term><literal>HeapTuple <parameter>row</parameter></literal></term> +    <listitem> +     <para> +      row to be copied +     </para> +    </listitem> +   </varlistentry> + +   <varlistentry> +    <term><literal>TupleDesc <parameter>rowdesc</parameter></literal></term> +    <listitem> +     <para> +      row descriptor to be copied +     </para> +    </listitem> +   </varlistentry> +  </variablelist> + </refsect1> + + <refsect1> +  <title>Return Value</title> + +  <para> +   <type>TupleTableSlot</type> containing the copied row and +   descriptor; <symbol>NULL</symbol> only if +   <parameter>row</parameter> or <parameter>rowdesc</parameter> are +   <symbol>NULL</symbol> +  </para> + </refsect1> +</refentry> + +<!-- *********************************************** --> + +<refentry id="spi-spi-modifytuple"> + <refmeta> +  <refentrytitle>SPI_modifytuple</refentrytitle> + </refmeta> + + <refnamediv> +  <refname>SPI_modifytuple</refname> +  <refpurpose>create a row by replacing selected fields of a given row</refpurpose> + </refnamediv> + + <indexterm><primary>SPI_modifytuple</primary></indexterm> + + <refsynopsisdiv> +<synopsis> +HeapTuple SPI_modifytuple(Relation <parameter>rel</parameter>, HeapTuple <parameter>row</parameter>, <parameter>ncols</parameter>, <parameter>colnum</parameter>, Datum * <parameter>values</parameter>, const char * <parameter>nulls</parameter>) +</synopsis> + </refsynopsisdiv> + + <refsect1> +  <title>Description</title> + +  <para> +   <function>SPI_modifytuple</function> creates a new row by +   substituting new values for selected columns, copying the original +   row's columns at other positions.  The input row is not modified. +  </para> + </refsect1> + + <refsect1> +  <title>Arguments</title> + +  <variablelist> +   <varlistentry> +    <term><literal>Relation <parameter>rel</parameter></literal></term> +    <listitem> +     <para> +      Used only as the source of the row descriptor for the row. +      (Passing a relation rather than a row descriptor is a +      misfeature.) +     </para> +    </listitem> +   </varlistentry> + +   <varlistentry> +    <term><literal>HeapTuple <parameter>row</parameter></literal></term> +    <listitem> +     <para> +      row to be modified +     </para> +    </listitem> +   </varlistentry> + +   <varlistentry> +    <term><literal>int <parameter>ncols</parameter></literal></term> +    <listitem> +     <para> +      number of column numbers in the array +      <parameter>colnum</parameter> +     </para> +    </listitem> +   </varlistentry> + +   <varlistentry> +    <term><literal>int * <parameter>colnum</parameter></literal></term> +    <listitem> +     <para> +      array of the numbers of the columns that are to be changed +      (count starts at 1) +     </para> +    </listitem> +   </varlistentry> + +   <varlistentry> +    <term><literal>Datum * <parameter>values</parameter></literal></term> +    <listitem> +     <para> +      new values for the specified columns +     </para> +    </listitem> +   </varlistentry> + +   <varlistentry> +    <term><literal>const char * <parameter>Nulls</parameter></literal></term> +    <listitem> +     <para> +      which new values are null, if any (see <function>SPI_execp</function> for the format) +     </para> +    </listitem> +   </varlistentry> +  </variablelist> + </refsect1> + + <refsect1> +  <title>Return Value</title> + +  <para> +   new row with modifications, allocated in the upper executor +   context; <symbol>NULL</symbol> only if <parameter>row</parameter> +   is <symbol>NULL</symbol> +  </para> + +  <para> +   On error, <varname>SPI_result</varname> is set as follows: +   <variablelist> +    <varlistentry> +     <term><symbol>SPI_ERROR_ARGUMENT</symbol></term> +     <listitem> +      <para> +       if <parameter>rel</> is <symbol>NULL</>, or if +       <parameter>row</> is <symbol>NULL</>, or if <parameter>ncols</> +       is less than or equal to 0, or if <parameter>colnum</> is +       <symbol>NULL</>, or if <parameter>values</> is <symbol>NULL</>. +      </para> +     </listitem> +    </varlistentry> + +    <varlistentry> +     <term><symbol>SPI_ERROR_NOATTRIBUTE</symbol></term> +     <listitem> +      <para> +       if <parameter>colnum</> contains an invalid column number (less +       than or equal to 0 or greater than the number of column in +       <parameter>row</>) +      </para> +     </listitem> +    </varlistentry> +   </variablelist> +  </para> + </refsect1> +</refentry> + +<!-- *********************************************** --> + +<refentry id="spi-spi-freetuple"> + <refmeta> +  <refentrytitle>SPI_freetuple</refentrytitle> + </refmeta> + + <refnamediv> +  <refname>SPI_freetuple</refname> +  <refpurpose>frees a row allocated in the upper executor context</refpurpose> + </refnamediv> + + <indexterm><primary>SPI_freetuple</primary></indexterm> + + <refsynopsisdiv> +<synopsis> +void SPI_freetuple(HeapTuple <parameter>row</parameter>) +</synopsis> + </refsynopsisdiv> + + <refsect1> +  <title>Description</title> + +  <para> +   <function>SPI_freetuple</function> frees a row previously allocated +   in the upper executor context. +  </para> + +  <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> + + <refsect1> +  <title>Arguments</title> + +  <variablelist> +   <varlistentry> +    <term><literal>HeapTuple <parameter>row</parameter></literal></term> +    <listitem> +     <para> +      row to free +     </para> +    </listitem> +   </varlistentry> +  </variablelist> + </refsect1> +</refentry> + +<!-- *********************************************** --> + +<refentry id="spi-spi-freetupletable"> + <refmeta> +  <refentrytitle>SPI_freetuptable</refentrytitle> + </refmeta> + + <refnamediv> +  <refname>SPI_freetuptable</refname> +  <refpurpose>free a row set created by <function>SPI_exec</> or a similar function</refpurpose> + </refnamediv> + + <indexterm><primary>SPI_freetuptable</primary></indexterm> + + <refsynopsisdiv> +<synopsis> +void SPI_freetuptable(SPITupleTable * <parameter>tuptable</parameter>) +</synopsis> + </refsynopsisdiv> + + <refsect1> +  <title>Description</title> + +  <para> +   <function>SPI_freetuptable</function> frees a row set created by a +   prior SPI command execution function, such as +   <function>SPI_exec</>.  Therefore, this function is usually called +   with the global variable <varname>SPI_tupletable</varname> as +   argument. +  </para> + +  <para> +   This function is useful if a SPI procedure needs to execute +   multiple commands and does not want to keep the results of earlier +   commands around until it ends.  Note that any unfreed row sets will +   be freed anyway at <function>SPI_finish</>. +  </para> + </refsect1> + + <refsect1> +  <title>Arguments</title> + +  <variablelist> +   <varlistentry> +    <term><literal>SPITupleTable * <parameter>tuptable</parameter></literal></term> +    <listitem> +     <para> +      pointer to row set to free +     </para> +    </listitem> +   </varlistentry> +  </variablelist> + </refsect1> +</refentry> + +<!-- *********************************************** --> + +<refentry id="spi-spi-freeplan"> + <refmeta> +  <refentrytitle>SPI_freeplan</refentrytitle> + </refmeta> + + <refnamediv> +  <refname>SPI_freeplan</refname> +  <refpurpose>free a previously saved plan</refpurpose> + </refnamediv> + + <indexterm><primary>SPI_freeplan</primary></indexterm> + + <refsynopsisdiv> +<synopsis> +int SPI_freeplan(void *<parameter>plan</parameter>) +</synopsis> + </refsynopsisdiv> + + <refsect1> +  <title>Description</title> + +  <para> +   <function>SPI_freeplan</function> releases a command execution plan +   previously returned by <function>SPI_prepare</function> or saved by +   <function>SPI_saveplan</function>. +  </para> + </refsect1> + + <refsect1> +  <title>Arguments</title> + +  <variablelist> +   <varlistentry> +    <term><literal>void * <parameter>plan</parameter></literal></term> +    <listitem> +     <para> +      pointer to plan to free +     </para> +    </listitem> +   </varlistentry> +  </variablelist> + </refsect1> + + <refsect1> +  <title>Return Value</title> + +  <para> +   <symbol>SPI_ERROR_ARGUMENT</symbol> if <parameter>plan</parameter> +   is <symbol>NULL</symbol>. +  </para> + </refsect1> +</refentry> + + </sect1> + + <sect1 id="spi-visibility"> +  <title>Visibility of Data Changes</title> + +  <para> +   The following two rules govern the visibility of data changes in +   functions that use SPI (or any other C function): + +   <itemizedlist> +    <listitem> +     <para> +      During the execution of an SQL command, any data changes made by +      the command (or by function called by the command, including +      trigger functions) are invisible to the command.  For +      example, in command  <programlisting> -   INSERT INTO a SELECT * FROM a +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 */ +      the inserted rows are invisible to the <command>SELECT</command> +      part. +     </para> +    </listitem> + +    <listitem> +     <para> +      Changes made by a command C are visible to all commands that are +      started after C, no matter whether they are started inside C +      (during the execution of C) or after C is done. +     </para> +    </listitem> +   </itemizedlist> +  </para> + +  <para> +   The next section contains an example that illustrates the +   application of these rules. +  </para> + </sect1> + + <sect1 id="spi-examples"> +  <title>Examples</title> + +  <para> +   This section contains a very simple example of SPI usage. The +   procedure <function>execq</function> takes an SQL command as its +   first argument and a row count as its second, executes the command +   using <function>SPI_exec</function> and returns the number of rows +   that were processed by the command.  You can find more complex +   examples for SPI in the source tree in +   <filename>src/test/regress/regress.c</filename> and in +   <filename>contrib/spi</filename>. +  </para> + +<programlisting> +#include "executor/spi.h"  int execq(text *sql, int cnt);  int  execq(text *sql, int cnt)  { -    char *query; +    char *command;      int ret;      int proc; -    /* Convert given TEXT object to a C string */ -    query = DatumGetCString(DirectFunctionCall1(textout, -                                                PointerGetDatum(sql))); +    /* Convert given text object to a C string */ +    command = DatumGetCString(DirectFunctionCall1(textout, +                                                  PointerGetDatum(sql)));      SPI_connect(); -    ret = SPI_exec(query, cnt); +    ret = SPI_exec(command, cnt);      proc = SPI_processed;      /* -     * If this is SELECT and some tuple(s) fetched - -     * returns tuples to the caller via elog (INFO). +     * If this is a SELECT and some rows were fetched, +     * then the rows are printed via elog(INFO).       */ -    if ( ret == SPI_OK_SELECT && SPI_processed > 0 ) +    if (ret == SPI_OK_SELECT && SPI_processed > 0)      {          TupleDesc tupdesc = SPI_tuptable->tupdesc;          SPITupleTable *tuptable = SPI_tuptable;          char buf[8192]; -        int i,j; +        int i, j;          for (j = 0; j < proc; j++)          {              HeapTuple tuple = tuptable->vals[j];              for (i = 1, buf[0] = 0; i <= tupdesc->natts; i++) -                snprintf(buf + strlen (buf), sizeof(buf) - strlen(buf)," %s%s", +                snprintf(buf + strlen (buf), sizeof(buf) - strlen(buf), " %s%s",                          SPI_getvalue(tuple, tupdesc, i),                          (i == tupdesc->natts) ? " " : " |");              elog (INFO, "EXECQ: %s", buf); @@ -3823,99 +2464,105 @@ execq(text *sql, int cnt)      }      SPI_finish(); - -    pfree(query); +    pfree(command);      return (proc);  } -</ProgramListing> -</Para> +</programlisting> + +  <para> +   (This function uses call convention version 0, to make the example +   easier to understand.  In real applications you should user the new +   version 1 interface.) +  </para> -<Para> -   Now, compile and create the function: +  <para> +   This is how you declare the function after having compiled it into +   a shared library: -<ProgramListing> -CREATE FUNCTION execq (text, integer) RETURNS integer -    AS '...path_to_so' +<programlisting> +CREATE FUNCTION execq(text, integer) RETURNS integer +    AS '<replaceable>filename</replaceable>'      LANGUAGE C; -</ProgramListing> +</programlisting> +  </para> + +  <para> +   Here is a sample session: -<ProgramListing> -vac=> SELECT execq('CREATE TABLE a (x INTEGER)', 0); -execq ------ -    0 +<programlisting> +=> 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 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 +=> SELECT execq('SELECT * FROM a', 0); +INFO:  EXECQ:  0    -- inserted by execq +INFO:  EXECQ:  1    -- returned by execq and inserted by upper INSERT -execq ------ -    2 + execq +------- +     2  (1 row) -vac=> SELECT execq('INSERT INTO a SELECT x + 2 FROM a',1); -execq ------ -    1 +=> 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  +=> SELECT execq('SELECT * FROM a', 10); +INFO:  EXECQ:  0 +INFO:  EXECQ:  1 +INFO:  EXECQ:  2    -- 0 + 2, only one row inserted - as specified -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 + execq +------- +     3              -- 10 is the max value only, 3 is the real number of rows  (1 row) -vac=> DELETE FROM a; +=> DELETE FROM a;  DELETE 3 -vac=> INSERT INTO a VALUES (execq('SELECT * FROM a', 0) + 1); +=> 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 +=> SELECT * FROM a; + x +--- + 1                  -- no rows in a (0) + 1  (1 row) -vac=> INSERT INTO a VALUES (execq('SELECT * FROM a', 0) + 1); -INFO:  EXECQ:  0  +=> 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 +=> SELECT * FROM a; + x +--- + 1 + 2                  -- there was one row in a + 1  (2 rows) ---   This demonstrates data changes visibility rule: +-- This demonstrates the 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 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> +=> SELECT * FROM a; + x +--- + 1 + 2 + 2                  -- 2 rows * 1 (x in first row) + 6                  -- 3 rows (2 + 1 just inserted) * 2 (x in second row) +(4 rows)               ^^^^^^  +                       rows visible to execq() in different invocations +</programlisting> +  </para> + </sect1> +</chapter> | 
