Index: doc/src/sgml/xfunc.sgml
===================================================================
RCS file: /opt/src/cvs/pgsql/doc/src/sgml/xfunc.sgml,v
retrieving revision 1.52
diff -c -r1.52 xfunc.sgml
*** doc/src/sgml/xfunc.sgml 20 Jun 2002 16:57:00 -0000 1.52
--- doc/src/sgml/xfunc.sgml 10 Jul 2002 22:53:23 -0000
***************
*** 1461,1472 ****
LANGUAGE C;
! 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.
--- 1461,1808 ----
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;
+
+
! See contrib/tablefunc for more examples of Table Functions.