Here (finally ;-)) is a doc patch covering the Table Function C API. It
authorBruce Momjian
Thu, 18 Jul 2002 04:47:17 +0000 (04:47 +0000)
committerBruce Momjian
Thu, 18 Jul 2002 04:47:17 +0000 (04:47 +0000)
reflects the changes in the tablefunc-fix patch that I sent in the other
day. It also refers to "see contrib/tablefunc for more examples", which
is next on my list of things to finish and submit.

Joe Conway

doc/src/sgml/xfunc.sgml

index 6de67ebf30ef3110591c1a3f876ff843421d49a2..bb7f742f69fbdaf9c94188b7203b1ec8f6c68fe8 100644 (file)
@@ -1,5 +1,5 @@
 
 
  
@@ -1459,14 +1459,350 @@ CREATE FUNCTION c_overpaid(emp, int4)
 RETURNS bool
 AS 'PGROOT/tutorial/funcs' 
 LANGUAGE C;
+
+    
+   
+
+   
+    Table Function API
+
+    
+     The Table Function API assists in the creation of a user defined
+     C Language table functions ().
+     Table functions are functions that produce a set of rows, made up of
+     either base (scalar) data types, or composite (multi-column) data types.
+     The API is split into two main components: support for returning
+     composite data types, and support for returning multiple rows
+     (set returning functions or SRFs).
+    
+
+    
+     The Table Function API relies on macros and functions to suppress most
+     of the complexity of building composite data types and return multiple
+     results.  In addition to the version-1 conventions discussed elsewhere,
+     a table function always requires the following:
+
+#include "funcapi.h"
+
+    
+
+    
+     The Table Function API support for returning composite data types
+     (or tuples) starts with the AttInMetadata struct. This struct holds
+     arrays of individual attribute information needed to create a tuple from
+     raw C strings. It also requires a copy of the TupleDesc. The information
+     carried here is derived from the TupleDesc, but it is stored here to
+     avoid redundant cpu cycles on each call to a Table Function.
+
+typedef struct
+{
+   /* full TupleDesc */
+   TupleDesc      tupdesc;
+
+   /* pointer to array of attribute "type"in finfo */
+   FmgrInfo       *attinfuncs;
+
+   /* pointer to array of attribute type typelem */
+   Oid            *attelems;
+
+   /* pointer to array of attribute type typtypmod */
+   int4           *atttypmods;
+
+}  AttInMetadata;
+
+     To assist you in populating this struct, several functions and a macro
+     are available. Use
+
+TupleDesc RelationNameGetTupleDesc(char *relname)
+
+     to get a TupleDesc based on the function's return type relation, or
+
+TupleDesc TypeGetTupleDesc(Oid typeoid, List *colaliases)
+
+     to get a TupleDesc based on the function's type oid. This can be used to
+     get a TupleDesc for a base (scalar), or composite (relation) type. Then
+
+AttInMetadata *TupleDescGetAttInMetadata(TupleDesc tupdesc)
+
+     will return a pointer to an AttInMetadata struct, initialized based on
+     the function's TupleDesc. AttInMetadata is be used in conjunction with
+     C strings to produce a properly formed tuple. The metadata is stored here
+     for use across calls to avoid redundant work.
+    
+
+    
+     In order to return a tuple you must create a tuple slot based on the
+     TupleDesc. You can use
+
+TupleTableSlot *TupleDescGetSlot(TupleDesc tupdesc)
+
+     to initialize this tuple slot, or obtain one through other (user provided)
+     means. The tuple slot is needed to create a Datum for return by the
+     function.
+    
+
+    
+     If desired,
+
+HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
+
+     can be used to build a HeapTuple given user data in C string form.
+     "values" is an array of C strings, one for each attribute of the return
+     tuple. The C strings should be in the form expected by the "in" function
+     of the attribute data type. For more information on this requirement,
+     see the individual data type "in" functions in the source code
+     (e.g. textin() for data type TEXT). In order to return a NULL value for
+     one of the attributes, the corresponding pointer in the "values" array
+     should be set to NULL.
+    
+
+    
+     Finally, in order to return a tuple using the SRF portion of the API
+     (described below), the tuple must be converted into a Datum. Use
+
+TupleGetDatum(TupleTableSlot *slot, HeapTuple tuple)
+
+     to get a Datum given a tuple and a slot.
+    
+
+    
+     The Table Function API support for set returning functions starts with
+     the FuncCallContext struct. This struct holds function context for
+     SRFs using fcinfo->flinfo->fn_extra to hold a pointer to it across calls.
+
+typedef struct
+{
+   /*
+    * Number of times we've been called before.
+    * 
+    * call_cntr is initialized to 0 for you by SRF_FIRSTCALL_INIT(), and
+    * incremented for you every time SRF_RETURN_NEXT() is called.
+    */
+   uint32          call_cntr;
+
+   /*
+    * OPTIONAL maximum number of calls
+    *
+    * max_calls is here for convenience ONLY and setting it is OPTIONAL.
+    * If not set, you must provide alternative means to know when the
+    * function is done.
+    */
+   uint32          max_calls;
+
+   /*
+    * OPTIONAL pointer to result slot
+    * 
+    * slot is for use when returning tuples (i.e. composite data types)
+    * and is not needed when returning base (i.e. scalar) data types.
+    */
+   TupleTableSlot *slot;
+
+   /*
+    * OPTIONAL pointer to misc user provided context info
+    * 
+    * user_fctx is for use as a pointer to your own struct to retain
+    * arbitrary context information between calls for your function.
+    */
+   void           *user_fctx;
+
+   /*
+    * OPTIONAL pointer to struct containing arrays of attribute type input
+    * metainfo
+    * 
+    * attinmeta is for use when returning tuples (i.e. composite data types)
+    * and is not needed when returning base (i.e. scalar) data types. It
+    * is ONLY needed if you intend to use BuildTupleFromCStrings() to create
+    * the return tuple.
+    */
+   AttInMetadata      *attinmeta;
+
+   /*
+    * memory context used to initialize structure
+    *
+    * fmctx is set by SRF_FIRSTCALL_INIT() for you, and used by
+    * SRF_RETURN_DONE() for cleanup. It is primarily for internal use
+    * by the API.
+    */
+   MemoryContext   fmctx;
+
+}  FuncCallContext;
+
+     To assist you in populating this struct, several functions and macros
+     are available. Use
+
+SRF_IS_FIRSTCALL()
+
+     to determine if your function has been called for the first or a
+     subsequent time. On the first call (only) use
+
+SRF_FIRSTCALL_INIT()
+
+     to initialize the FuncCallContext struct. On every function call,
+     including the first, use
+
+SRF_PERCALL_SETUP()
+
+     to properly set up for using the FuncCallContext struct and clearing
+     any previously returned data left over from the previous pass.
+    
+
+    
+     If your function has data to return, use
+
+SRF_RETURN_NEXT(funcctx, result)
+
+     to send it and prepare for the next call. Finally, when your function
+     is finished returning data, use
+
+SRF_RETURN_DONE(funcctx)
+
+     to clean up and end the SRF.
+    
+
+    
+     A complete pseudo-code example looks like the following:
+
+Datum
+my_Set_Returning_Function(PG_FUNCTION_ARGS)
+{
+   FuncCallContext    *funcctx;
+   Datum               result;
+
+   [user defined declarations]
+
+   if(SRF_IS_FIRSTCALL())
+   {
+       [user defined code]
+       funcctx = SRF_FIRSTCALL_INIT();
+       [if returning composite]
+           [obtain slot]
+           funcctx->slot = slot;
+       [endif returning composite]
+       [user defined code]
+   }
+   [user defined code]
+   funcctx = SRF_PERCALL_SETUP();
+   [user defined code]
+
+   if (funcctx->call_cntr < funcctx->max_calls)
+   {
+       [user defined code]
+       [obtain result Datum]
+       SRF_RETURN_NEXT(funcctx, result);
+   }
+   else
+   {
+       SRF_RETURN_DONE(funcctx);
+   }
+}
+
+    
+
+    
+     An example of a simple composite returning SRF looks like:
+
+PG_FUNCTION_INFO_V1(testpassbyval);
+Datum
+testpassbyval(PG_FUNCTION_ARGS)
+{
+   FuncCallContext    *funcctx;
+   int                 call_cntr;
+   int                 max_calls;
+   TupleDesc           tupdesc;
+   TupleTableSlot     *slot;
+   AttInMetadata      *attinmeta;
+
+   /* stuff done only on the first call of the function */
+   if(SRF_IS_FIRSTCALL())
+   {
+       /* create a function context for cross-call persistence */
+       funcctx = SRF_FIRSTCALL_INIT();
+
+       /* total number of tuples to be returned */
+       funcctx->max_calls = PG_GETARG_UINT32(0);
+
+       /*
+        * Build a tuple description for a __testpassbyval tuple
+        */
+       tupdesc = RelationNameGetTupleDesc("__testpassbyval");
+
+       /* allocate a slot for a tuple with this tupdesc */
+       slot = TupleDescGetSlot(tupdesc);
+
+       /* assign slot to function context */
+       funcctx->slot = slot;
+
+       /*
+        * Generate attribute metadata needed later to produce tuples from raw
+        * C strings
+        */
+       attinmeta = TupleDescGetAttInMetadata(tupdesc);
+       funcctx->attinmeta = attinmeta;
+    }
+
+   /* stuff done on every call of the function */
+   funcctx = SRF_PERCALL_SETUP();
+
+   call_cntr = funcctx->call_cntr;
+   max_calls = funcctx->max_calls;
+   slot = funcctx->slot;
+   attinmeta = funcctx->attinmeta;
+   if (call_cntr < max_calls)  /* do when there is more left to send */
+   {
+       char       **values;
+       HeapTuple   tuple;
+       Datum       result;
+
+       /*
+        * Prepare a values array for storage in our slot.
+        * This should be an array of C strings which will
+        * be processed later by the appropriate "in" functions.
+        */
+       values = (char **) palloc(3 * sizeof(char *));
+       values[0] = (char *) palloc(16 * sizeof(char));
+       values[1] = (char *) palloc(16 * sizeof(char));
+       values[2] = (char *) palloc(16 * sizeof(char));
+
+       snprintf(values[0], 16, "%d", 1 * PG_GETARG_INT32(1));
+       snprintf(values[1], 16, "%d", 2 * PG_GETARG_INT32(1));
+       snprintf(values[2], 16, "%d", 3 * PG_GETARG_INT32(1));
+
+       /* build a tuple */
+       tuple = BuildTupleFromCStrings(attinmeta, values);
+
+       /* make the tuple into a datum */
+       result = TupleGetDatum(slot, tuple);
+
+       /* Clean up */
+       pfree(values[0]);
+       pfree(values[1]);
+       pfree(values[2]);
+       pfree(values);
+
+       SRF_RETURN_NEXT(funcctx, result);
+   }
+   else    /* do when there is no more left */
+   {
+       SRF_RETURN_DONE(funcctx);
+   }
+}
+
+     with supporting SQL code of
+
+CREATE VIEW __testpassbyval AS
+  SELECT
+    0::INT4 AS f1,
+    0::INT4 AS f2,
+    0::INT4 AS f3;
+
+CREATE OR REPLACE FUNCTION testpassbyval(int4, int4) RETURNS setof __testpassbyval
+  AS 'MODULE_PATHNAME','testpassbyval' LANGUAGE 'c' IMMUTABLE STRICT;
 
     
 
     
-     While there are ways to construct new rows or modify  
-     existing rows from within a C function, these
-     are far too complex to discuss in this manual.
-     Consult the backend source code for examples.
+     See contrib/tablefunc for more examples of Table Functions.