Vadim Mikheev Transcribed 1998-01-16 Server Programming Interface The Server Programming Interface (SPI) gives users the ability to run SQL queries inside user-defined C functions. The available Procedural Languages (PL) give an alternate means to build functions that can execute queries. In fact, SPI is just a set of native interface functions to simplify access to the Parser, Planner, Optimizer and Executor. SPI also does some memory management. To avoid misunderstanding we'll use function to mean SPI interface functions and procedure for user-defined C-functions using SPI. Procedures which use SPI are called by the Executor. The SPI calls recursively invoke the Executor in turn to run queries. When the Executor is invoked recursively, it may itself call procedures which may make SPI calls. 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. A related restriction is the inability to execute BEGIN, END and ABORT (transaction control statements). This will also be changed in the future. If successful, SPI 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. Interface Functions SPI_connect SPI - Connection Management SPI_connect Connects your procedure to the SPI manager. SPIconnecting SPI_connect 1997-12-24 int SPI_connect(void) 1997-12-24 Inputs None 1997-12-24 Outputs int Return status SPI_OK_CONNECT if connected SPI_ERROR_CONNECT if not connected 1997-12-24 Description SPI_connect 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. If your procedure is already connected, SPI_connect will return an SPI_ERROR_CONNECT error. Note that this may happen if a procedure which has called SPI_connect directly calls another procedure which itself calls SPI_connect. While recursive calls to the SPI manager are permitted when an SPI query invokes another function which uses SPI, directly nested calls to SPI_connect and SPI_finish are forbidden. Usage Algorithm SPI_connect performs the following: Initializes the SPI internal structures for query execution and memory management. SPI_finish SPI - Connection Management SPI_finish Disconnects your procedure from the SPI manager. SPIdisconnecting SPI_finish 1997-12-24 SPI_finish(void) 1997-12-24 Inputs None 1997-12-24 Outputs int SPI_OK_FINISH if properly disconnected SPI_ERROR_UNCONNECTED if called from an un-connected procedure 1997-12-24 Description SPI_finish 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 may get the error return SPI_ERROR_UNCONNECTED if SPI_finish 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. Usage SPI_finish must 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. Algorithm SPI_finish performs the following: Disconnects your procedure from the SPI manager and frees all memory allocations made by your procedure via palloc since the SPI_connect. These allocations can't be used any more! See Memory management. SPI_exec SPI - Connection Management SPI_exec Creates an execution plan (parser+planner+optimizer) and executes a query. SPIexecuting SPI_exec 1997-12-24 SPI_exec(query, tcount) 1997-12-24 Inputs char *query String containing query plan int tcount Maximum number of tuples to return 1997-12-24 Outputs int SPI_ERROR_UNCONNECTED if called from an un-connected procedure SPI_ERROR_ARGUMENT if query is NULL or tcount < 0. SPI_ERROR_UNCONNECTED if procedure is unconnected. SPI_ERROR_COPY if COPY TO/FROM stdin. SPI_ERROR_CURSOR if DECLARE/CLOSE CURSOR, FETCH. SPI_ERROR_TRANSACTION if BEGIN/ABORT/END. SPI_ERROR_OPUNKNOWN if type of query is unknown (this shouldn't occur). If execution of your query was successful then one of the following (non-negative) values will be returned: SPI_OK_UTILITY if some utility (e.g. CREATE TABLE ...) was executed SPI_OK_SELECT if SELECT (but not SELECT ... INTO!) was executed SPI_OK_SELINTO if SELECT ... INTO was executed SPI_OK_INSERT if INSERT (or INSERT ... SELECT) was executed SPI_OK_DELETE if DELETE was executed SPI_OK_UPDATE if UPDATE was executed 1997-12-24 Description SPI_exec creates an execution plan (parser+planner+optimizer) and executes the query for tcount tuples. Usage This should only be called from a connected procedure. If tcount is zero then it executes the query for all tuples returned by the query scan. Using tcount > 0 you may restrict the number of tuples for which the query will be executed (much like a LIMIT clause). For example, SPI_exec ("INSERT INTO tab SELECT * FROM tab", 5); 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. You may pass multiple queries in one string or query string may be re-written by RULEs. SPI_exec returns the result for the last query executed. The actual number of tuples for which the (last) query was executed is returned in the global variable SPI_processed (if not SPI_OK_UTILITY). If SPI_OK_SELECT is returned then you may use global pointer SPITupleTable *SPI_tuptable to access the result tuples. SPI_exec may return one of the following (negative) values: SPI_ERROR_ARGUMENT if query is NULL or tcount < 0. SPI_ERROR_UNCONNECTED if procedure is unconnected. SPI_ERROR_COPY if COPY TO/FROM stdin. SPI_ERROR_CURSOR if DECLARE/CLOSE CURSOR, FETCH. SPI_ERROR_TRANSACTION if BEGIN/ABORT/END. SPI_ERROR_OPUNKNOWN if type of query is unknown (this shouldn't occur). Structures If SPI_OK_SELECT is returned then you may use the global pointer SPITupleTable *SPI_tuptable to access the selected tuples. Structure SPITupleTable is defined in spi.h: 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; vals is an array of pointers to tuples (the number of useful entries is given by SPI_processed). tupdesc is a tuple descriptor which you may pass to SPI functions dealing with tuples. tuptabcxt, alloced, and free are internal fields not intended for use by SPI callers. Functions SPI_exec, SPI_execp and SPI_prepare 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 SPI_exec or SPI_execp across later calls. SPI_finish frees all SPITupleTables allocated during the current procedure. You can free a particular result table earlier, if you are done with it, by calling SPI_freetuptable. SPI_prepare SPI - Plan Preparation SPI_prepare Prepares a plan for a query, without executing it yet SPIconnecting SPI_prepare 1997-12-24 SPI_prepare(query, nargs, argtypes) 1997-12-24 Inputs query Query string nargs Number of input parameters ($1 ... $nargs - as in SQL-functions) argtypes Pointer to array of type OIDs for input parameter types 1997-12-24 Outputs void * Pointer to an execution plan (parser+planner+optimizer) 1997-12-24 Description SPI_prepare creates and returns an execution plan (parser+planner+optimizer) but doesn't execute the query. Should only be called from a connected procedure. Usage When the same or similar query is to be executed repeatedly, it may be advantageous to perform query planning only once. SPI_prepare converts a query string into an execution plan that can be passed repeatedly to SPI_execp. 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 SPI_execp is called. This allows the prepared query to be used over a wider range of situations than would be possible without parameters. 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. If the query uses parameters, their number and data types must be specified in the call to SPI_prepare. The plan returned by SPI_prepare may be used only in current invocation of the procedure since SPI_finish frees memory allocated for a plan. But see SPI_saveplan to save a plan for longer. 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 SPI_ERROR_ARGUMENT if query is NULL or nargs < 0 or nargs > 0 && argtypes is NULL. SPI_execp SPI - Plan Execution SPI_execp Executes a plan from SPI_prepare SPIconnecting SPI_execp 1997-12-24 SPI_execp(plan, values, nulls, tcount) 1997-12-24 Inputs void *plan Execution plan Datum *values Actual parameter values char *nulls Array describing which parameters are NULLs n indicates NULL (values[] entry ignored) space indicates not NULL (values[] entry is valid) int tcount Number of tuples for which plan is to be executed 1997-12-24 Outputs int Returns the same value as SPI_exec as well as SPI_ERROR_ARGUMENT if plan is NULL or tcount < 0 SPI_ERROR_PARAM if values is NULL and plan was prepared with some parameters. SPI_tuptable initialized as in SPI_exec if successful SPI_processed initialized as in SPI_exec if successful 1997-12-24 Description SPI_execp executes a plan prepared by SPI_prepare. tcount has the same interpretation as in SPI_exec. Usage If nulls is NULL then SPI_execp assumes that all parameters (if any) are NOT NULL. 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 SPI_execp for this plan will be unpredictable. SPI_cursor_open SPI - Cursor Support SPI_cursor_open Sets up a cursor using a plan created with SPI_prepare SPIcursors SPI_cursor_open 2001-11-14 SPI_cursor_open(name, plan, values, nulls) 2001-11-14 Inputs char *name Name for portal, or NULL to let the system select a name void *plan Execution plan Datum *values Actual parameter values char *nulls Array describing which parameters are NULLs n indicates NULL (values[] entry ignored) space indicates not NULL (values[] entry is valid) 2001-11-14 Outputs Portal Pointer to Portal containing cursor, or NULL on error 2001-11-14 Description SPI_cursor_open sets up a cursor (internally, a Portal) that will execute a plan prepared by SPI_prepare. 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. Usage If nulls is NULL then SPI_cursor_open assumes that all parameters (if any) are NOT NULL. SPI_cursor_find SPI - Cursor Support SPI_cursor_find Finds an existing cursor (Portal) by name SPIcursors SPI_cursor_find 2001-11-14 SPI_cursor_find(name) 2001-11-14 Inputs char *name Name of portal 2001-11-14 Outputs Portal Pointer to Portal with given name, or NULL if not found 2001-11-14 Description SPI_cursor_find finds a pre-existing Portal by name. This is primarily useful to resolve a cursor name returned as text by some other function. SPI_cursor_fetch SPI - Cursor Support SPI_cursor_fetch Fetches some rows from a cursor SPIcursors SPI_cursor_fetch 2001-11-14 SPI_cursor_fetch(portal, forward, count) 2001-11-14 Inputs Portal portal Portal containing cursor bool forward True for fetch forward, false for fetch backward int count Maximum number of rows to fetch 2001-11-14 Outputs SPI_tuptable initialized as in SPI_exec if successful SPI_processed initialized as in SPI_exec if successful 2001-11-14 Description SPI_cursor_fetch fetches some (more) rows from a cursor. This is equivalent to the SQL command FETCH. SPI_cursor_move SPI - Cursor Support SPI_cursor_move Moves a cursor SPIcursors SPI_cursor_move 2001-11-14 SPI_cursor_move(portal, forward, count) 2001-11-14 Inputs Portal portal Portal containing cursor bool forward True for move forward, false for move backward int count Maximum number of rows to move 2001-11-14 Outputs None 2001-11-14 Description SPI_cursor_move skips over some number of rows in a cursor. This is equivalent to the SQL command MOVE. SPI_cursor_close SPI - Cursor Support SPI_cursor_close Closes a cursor SPIcursors SPI_cursor_close 2001-11-14 SPI_cursor_close(portal) 2001-11-14 Inputs Portal portal Portal containing cursor 2001-11-14 Outputs None 2001-11-14 Description SPI_cursor_close closes a previously created cursor and releases its Portal storage. Usage All open cursors are closed implicitly at transaction end. SPI_cursor_close need only be invoked if it is desirable to release resources sooner. SPI_saveplan SPI - Plan Storage SPI_saveplan Saves a passed plan SPIconnecting SPI_saveplan 1997-12-24 SPI_saveplan(plan) 1997-12-24 Inputs void *query Passed plan 1997-12-24 Outputs void * Execution plan location. NULL if unsuccessful. SPI_result SPI_ERROR_ARGUMENT if plan is NULL SPI_ERROR_UNCONNECTED if procedure is un-connected 1997-12-24 Description SPI_saveplan stores a plan prepared by SPI_prepare in safe memory protected from freeing by SPI_finish or the transaction manager. In the current version of PostgreSQL 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 SPI_execp to execute this saved plan. Usage SPI_saveplan saves a passed plan (prepared by SPI_prepare) in memory protected from freeing by SPI_finish 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). 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 SPI_execp for this plan will be unpredictable. Interface Support Functions The functions described here provide convenient interfaces for extracting information from tuple sets returned by SPI_exec and other SPI interface functions. All functions described in this section may be used by both connected and unconnected procedures. SPI_fnumber SPI - Tuple Information SPI_fnumber Finds the attribute number for specified attribute name SPIdecoding tuples SPI_fnumber 1997-12-24 SPI_fnumber(tupdesc, fname) 1997-12-24 Inputs TupleDesc tupdesc Input tuple description char * fname Field name 1997-12-24 Outputs int Attribute number Valid one-based index number of attribute SPI_ERROR_NOATTRIBUTE if the named attribute is not found 1997-12-24 Description SPI_fnumber returns the attribute number for the attribute with name in fname. Usage Attribute numbers are 1 based. If the given fname refers to a system attribute (eg, oid) then the appropriate negative attribute number will be returned. The caller should be careful to test for exact equality to SPI_ERROR_NOATTRIBUTE to detect error; testing for result <= 0 is not correct unless system attributes should be rejected. SPI_fname SPI - Tuple Information SPI_fname Finds the attribute name for the specified attribute number SPIdecoding tuples SPI_fname 1997-12-24 SPI_fname(tupdesc, fnumber) 1997-12-24 Inputs TupleDesc tupdesc Input tuple description int fnumber Attribute number 1997-12-24 Outputs char * Attribute name NULL if fnumber is out of range SPI_result set to SPI_ERROR_NOATTRIBUTE on error 1997-12-24 Description SPI_fname returns the attribute name for the specified attribute. Usage Attribute numbers are 1 based. Algorithm Returns a newly-allocated copy of the attribute name. (Use pfree() to release the copy when done with it.) SPI_getvalue SPI - Tuple Information SPI_getvalue Returns the string value of the specified attribute SPIdecoding tuples SPI_getvalue 1997-12-24 SPI_getvalue(tuple, tupdesc, fnumber) 1997-12-24 Inputs HeapTuple tuple Input tuple to be examined TupleDesc tupdesc Input tuple description int fnumber Attribute number 1997-12-24 Outputs char * Attribute value or NULL if attribute is NULL fnumber is out of range (SPI_result set to SPI_ERROR_NOATTRIBUTE) no output function available (SPI_result set to SPI_ERROR_NOOUTFUNC) 1997-12-24 Description SPI_getvalue returns an external (string) representation of the value of the specified attribute. Usage Attribute numbers are 1 based. Algorithm The result is returned as a palloc'd string. (Use pfree() to release the string when done with it.) SPI_getbinval SPI - Tuple Information SPI_getbinval Returns the binary value of the specified attribute SPIdecoding tuples SPI_getbinval 1997-12-24 SPI_getbinval(tuple, tupdesc, fnumber, isnull) 1997-12-24 Inputs HeapTuple tuple Input tuple to be examined TupleDesc tupdesc Input tuple description int fnumber Attribute number 1997-12-24 Outputs Datum Attribute binary value bool * isnull flag for null value in attribute SPI_result SPI_ERROR_NOATTRIBUTE 1997-12-24 Description SPI_getbinval returns the specified attribute's value in internal form (as a Datum). Usage Attribute numbers are 1 based. Algorithm 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. SPI_gettype SPI - Tuple Information SPI_gettype Returns the type name of the specified attribute SPIdecoding tuples SPI_gettype 1997-12-24 SPI_gettype(tupdesc, fnumber) 1997-12-24 Inputs TupleDesc tupdesc Input tuple description int fnumber Attribute number 1997-12-24 Outputs char * The type name for the specified attribute number SPI_result SPI_ERROR_NOATTRIBUTE 1997-12-24 Description SPI_gettype returns a copy of the type name for the specified attribute, or NULL on error. Usage Attribute numbers are 1 based. Algorithm Returns a newly-allocated copy of the type name. (Use pfree() to release the copy when done with it.) SPI_gettypeid SPI - Tuple Information SPI_gettypeid Returns the type OID of the specified attribute SPIdecoding tuples SPI_gettypeid 1997-12-24 SPI_gettypeid(tupdesc, fnumber) 1997-12-24 Inputs TupleDesc tupdesc Input tuple description int fnumber Attribute number 1997-12-24 Outputs OID The type OID for the specified attribute number SPI_result SPI_ERROR_NOATTRIBUTE 1997-12-24 Description SPI_gettypeid returns the type OID for the specified attribute. Usage Attribute numbers are 1 based. SPI_getrelname SPI - Tuple Information SPI_getrelname Returns the name of the specified relation SPIdecoding tuples SPI_getrelname 1997-12-24 SPI_getrelname(rel) 1997-12-24 Inputs Relation rel Input relation 1997-12-24 Outputs char * The name of the specified relation 1997-12-24 Description SPI_getrelname returns the name of the specified relation. Algorithm Returns a newly-allocated copy of the rel name. (Use pfree() to release the copy when done with it.) Memory Management PostgreSQL allocates memory within memory contexts, 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. palloc and related functions allocate memory from the current context. SPI_connect creates a new memory context and makes it current. SPI_finish restores the previous current memory context and destroys the context created by SPI_connect. These actions ensure that transient memory allocations made inside your procedure are reclaimed at procedure exit, avoiding memory leakage. 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 palloc, at least not while you are connected to SPI. If you try, the object will be deallocated during SPI_finish, and your procedure will not work reliably! To solve this problem, use SPI_palloc to allocate your return object. SPI_palloc allocates space from upper Executor memory --- that is, the memory context that was current when SPI_connect was called, which is precisely the right context for return values of your procedure. If called while not connected to SPI, SPI_palloc acts the same as plain palloc. 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 palloc or by SPI utility functions are made in this context. After SPI_connect is called, the current context is the procedure's private context made by SPI_connect. All allocations made via palloc/repalloc or by SPI utility functions (except for SPI_copytuple, SPI_copytupledesc, SPI_copytupleintoslot, SPI_modifytuple, and SPI_palloc) are made in this context. When a procedure disconnects from the SPI manager (via SPI_finish) 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! 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 (palloc etc). SPI_copytuple SPI - Tuple Copy SPI_copytuple Makes copy of tuple in upper Executor context SPIcopying tuples SPI_copytuple 1997-12-24 SPI_copytuple(tuple) 1997-12-24 Inputs HeapTuple tuple Input tuple to be copied 1997-12-24 Outputs HeapTuple Copied tuple non-NULL if tuple is not NULL and the copy was successful NULL only if tuple is NULL 1997-12-24 Description SPI_copytuple makes a copy of tuple in upper Executor context. Usage TBD SPI_copytupledesc SPI - Tuple Descriptor Copy SPI_copytupledesc Makes copy of tuple descriptor in upper Executor context SPIcopying tuple descriptors SPI_copytupledesc 2001-08-02 SPI_copytupledesc(tupdesc) 2001-08-02 Inputs TupleDesc tupdesc Input tuple descriptor to be copied 2001-08-02 Outputs TupleDesc Copied tuple descriptor non-NULL if tupdesc is not NULL and the copy was successful NULL only if tupdesc is NULL 2001-08-02 Description SPI_copytupledesc makes a copy of tupdesc in upper Executor context. Usage TBD SPI_copytupleintoslot SPI - Tuple and Descriptor Copy SPI_copytupleintoslot Makes copy of tuple and descriptor in upper Executor context SPIcopying tuples SPI_copytupleintoslot 1997-12-24 SPI_copytupleintoslot(tuple, tupdesc) 1997-12-24 Inputs HeapTuple tuple Input tuple to be copied TupleDesc tupdesc Input tuple descriptor to be copied 1997-12-24 Outputs TupleTableSlot * Tuple slot containing copied tuple and descriptor non-NULL if tuple and tupdesc are not NULL and the copy was successful NULL only if tuple or tupdesc is NULL 1997-12-24 Description SPI_copytupleintoslot makes a copy of tuple in upper Executor context, returning it in the form of a filled-in TupleTableSlot. Usage TBD SPI_modifytuple SPI - Tuple Modify SPI_modifytuple Creates a tuple by replacing selected fields of a given tuple SPImodifying tuples SPI_modifytuple 1997-12-24 SPI_modifytuple(rel, tuple, nattrs, attnum, Values, Nulls) 1997-12-24 Inputs Relation rel Used only as source of tuple descriptor for tuple. (Passing a relation rather than a tuple descriptor is a misfeature.) HeapTuple tuple Input tuple to be modified int nattrs Number of attribute numbers in attnum array int * attnum Array of numbers of the attributes that are to be changed Datum * Values New values for the attributes specified char * Nulls Which new values are NULL, if any 1997-12-24 Outputs HeapTuple New tuple with modifications non-NULL if tuple is not NULL and the modify was successful NULL only if tuple is NULL SPI_result SPI_ERROR_ARGUMENT if rel is NULL or tuple is NULL or natts <= 0 or attnum is NULL or Values is NULL. SPI_ERROR_NOATTRIBUTE if there is an invalid attribute number in attnum (attnum <= 0 or > number of attributes in tuple) 1997-12-24 Description SPI_modifytuple 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. Usage If successful, a pointer to the new tuple is returned. The new tuple is allocated in upper Executor context. SPI_palloc SPI - Memory Management SPI_palloc Allocates memory in upper Executor context SPIallocating space SPI_palloc 1997-12-24 SPI_palloc(size) 1997-12-24 Inputs Size size Octet size of storage to allocate 1997-12-24 Outputs void * New storage space of specified size 1997-12-24 Description SPI_palloc allocates memory in upper Executor context. Usage TBD SPI_repalloc SPI - Memory Management SPI_repalloc Re-allocates memory in upper Executor context SPIallocating space SPI_repalloc 1997-12-24 SPI_repalloc(pointer, size) 1997-12-24 Inputs void * pointer Pointer to existing storage Size size Octet size of storage to allocate 1997-12-24 Outputs void * New storage space of specified size with contents copied from existing area 1997-12-24 Description SPI_repalloc re-allocates memory in upper Executor context. Usage This function is no longer different from plain repalloc. It's kept just for backward compatibility of existing code. SPI_pfree SPI - Memory Management SPI_pfree Frees memory in upper Executor context SPIallocating space SPI_pfree 1997-12-24 SPI_pfree(pointer) 1997-12-24 Inputs void * pointer Pointer to existing storage 1997-12-24 Outputs None 1997-12-24 Description SPI_pfree frees memory in upper Executor context. Usage This function is no longer different from plain pfree. It's kept just for backward compatibility of existing code. SPI_freetuple SPI - Memory Management SPI_freetuple Frees a tuple allocated in upper Executor context SPIallocating space SPI_freetuple 1997-12-24 SPI_freetuple(pointer) 1997-12-24 Inputs HeapTuple pointer Pointer to allocated tuple 1997-12-24 Outputs None 1997-12-24 Description SPI_freetuple frees a tuple previously allocated in upper Executor context. Usage This function is no longer different from plain heap_freetuple. It's kept just for backward compatibility of existing code. SPI_freetuptable SPI - Memory Management SPI_freetuptable Frees a tuple set created by SPI_exec or similar function SPIallocating space SPI_freetuptable 2001-11-14 SPI_freetuptable(tuptable) 2001-11-14 Inputs SPITupleTable * tuptable Pointer to tuple table 2001-11-14 Outputs None 2001-11-14 Description SPI_freetuptable frees a tuple set created by a prior SPI query function, such as SPI_exec. Usage 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 SPI_finish. SPI_freeplan SPI - Memory Management SPI_freeplan Releases a previously saved plan SPIallocating space SPI_freeplan 2001-11-14 SPI_freeplan(plan) 2001-11-14 Inputs void *plan Passed plan 2001-11-14 Outputs int SPI_ERROR_ARGUMENT if plan is NULL 2001-11-14 Description SPI_freeplan releases a query plan previously returned by SPI_prepare or saved by SPI_saveplan. Visibility of Data Changes PostgreSQL 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 INSERT INTO a SELECT * FROM a 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. 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. Examples This example of SPI usage demonstrates the visibility rule. There are more complex examples in src/test/regress/regress.c and in contrib/spi. 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: #include "executor/spi.h" /* this is what you need to work with SPI */ int execq(text *sql, int cnt); int execq(text *sql, int cnt) { char *query; int ret; int proc; /* Convert given TEXT object to a C string */ query = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(sql))); SPI_connect(); ret = SPI_exec(query, cnt); proc = SPI_processed; /* * If this is SELECT and some tuple(s) fetched - * returns tuples to the caller via elog (INFO). */ if ( ret == SPI_OK_SELECT && SPI_processed > 0 ) { TupleDesc tupdesc = SPI_tuptable->tupdesc; SPITupleTable *tuptable = SPI_tuptable; char buf[8192]; int i,j; for (j = 0; j < proc; j++) { HeapTuple tuple = tuptable->vals[j]; for (i = 1, buf[0] = 0; i <= tupdesc->natts; i++) snprintf(buf + strlen (buf), sizeof(buf) - strlen(buf)," %s%s", SPI_getvalue(tuple, tupdesc, i), (i == tupdesc->natts) ? " " : " |"); elog (INFO, "EXECQ: %s", buf); } } SPI_finish(); pfree(query); return (proc); } Now, compile and create the function: CREATE FUNCTION execq (text, integer) RETURNS integer AS '...path_to_so' LANGUAGE C; vac=> SELECT execq('CREATE TABLE a (x INTEGER)', 0); execq ----- 0 (1 row) vac=> INSERT INTO a VALUES (execq('INSERT INTO a VALUES (0)',0)); INSERT 167631 1 vac=> SELECT execq('SELECT * FROM a',0); INFO: EXECQ: 0 <<< inserted by execq INFO: EXECQ: 1 <<< value returned by execq and inserted by upper INSERT execq ----- 2 (1 row) vac=> SELECT execq('INSERT INTO a SELECT x + 2 FROM a',1); execq ----- 1 (1 row) vac=> SELECT execq('SELECT * FROM a', 10); INFO: EXECQ: 0 INFO: EXECQ: 1 INFO: EXECQ: 2 <<< 0 + 2, only one tuple inserted - as specified execq ----- 3 <<< 10 is max value only, 3 is real # of tuples (1 row) vac=> DELETE FROM a; DELETE 3 vac=> INSERT INTO a VALUES (execq('SELECT * FROM a', 0) + 1); INSERT 167712 1 vac=> SELECT * FROM a; x - 1 <<< no tuples in a (0) + 1 (1 row) vac=> INSERT INTO a VALUES (execq('SELECT * FROM a', 0) + 1); INFO: EXECQ: 0 INSERT 167713 1 vac=> SELECT * FROM a; x - 1 2 <<< there was single tuple in a + 1 (2 rows) -- This demonstrates data changes visibility rule: vac=> INSERT INTO a SELECT execq('SELECT * FROM a', 0) * x FROM a; INFO: EXECQ: 1 INFO: EXECQ: 2 INFO: EXECQ: 1 INFO: EXECQ: 2 INFO: EXECQ: 2 INSERT 0 2 vac=> SELECT * FROM a; x - 1 2 2 <<< 2 tuples * 1 (x in first tuple) 6 <<< 3 tuples (2 + 1 just inserted) * 2 (x in second tuple) (4 rows) ^^^^^^^^ tuples visible to execq() in different invocations