From 7ea5f1d7f16e9771e90c020db93d7e8a9a3b22f5 Mon Sep 17 00:00:00 2001 From: Bruce Momjian Date: Thu, 18 Jul 2002 04:40:30 +0000 Subject: [PATCH] Here is a patch for the Table Function API. It fixes a bug found by Neil Conway (BuildTupleFromCStrings sets NULL for pass-by-value types when intended value is 0). It also implements some other improvements suggested by Neil. Joe Conway --- src/backend/executor/execTuples.c | 15 +++----- src/backend/utils/fmgr/funcapi.c | 19 +++++++++- src/include/funcapi.h | 61 ++++++++++++++++++++++++------- 3 files changed, 71 insertions(+), 24 deletions(-) diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c index 86a16ddb04..4f234f62b9 100644 --- a/src/backend/executor/execTuples.c +++ b/src/backend/executor/execTuples.c @@ -15,7 +15,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.53 2002/06/20 20:29:27 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.54 2002/07/18 04:40:30 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -759,6 +759,7 @@ BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values) natts = tupdesc->natts; dvalues = (Datum *) palloc(natts * sizeof(Datum)); + nulls = (char *) palloc(natts * sizeof(char)); /* Call the "in" function for each attribute */ for (i = 0; i < natts; i++) @@ -772,22 +773,18 @@ BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values) dvalues[i] = FunctionCall3(&attinfuncinfo, CStringGetDatum(values[i]), ObjectIdGetDatum(attelem), Int32GetDatum(atttypmod)); + nulls[i] = ' '; } else + { dvalues[i] = PointerGetDatum(NULL); + nulls[i] = 'n'; + } } /* * Form a tuple */ - nulls = (char *) palloc(natts * sizeof(char)); - for (i = 0; i < natts; i++) - { - if (DatumGetPointer(dvalues[i]) != NULL) - nulls[i] = ' '; - else - nulls[i] = 'n'; - } tuple = heap_formtuple(tupdesc, dvalues, nulls); return tuple; diff --git a/src/backend/utils/fmgr/funcapi.c b/src/backend/utils/fmgr/funcapi.c index bd65c3911c..a8d4e4fb5f 100644 --- a/src/backend/utils/fmgr/funcapi.c +++ b/src/backend/utils/fmgr/funcapi.c @@ -52,7 +52,7 @@ init_MultiFuncCall(PG_FUNCTION_ARGS) retval->call_cntr = 0; retval->max_calls = 0; retval->slot = NULL; - retval->fctx = NULL; + retval->user_fctx = NULL; retval->attinmeta = NULL; retval->fmctx = fcinfo->flinfo->fn_mcxt; @@ -75,6 +75,23 @@ init_MultiFuncCall(PG_FUNCTION_ARGS) return retval; } +/* + * per_MultiFuncCall + * + * Do Multi-function per-call setup + */ +FuncCallContext * +per_MultiFuncCall(PG_FUNCTION_ARGS) +{ + FuncCallContext *retval = (FuncCallContext *) fcinfo->flinfo->fn_extra; + + /* make sure we start with a fresh slot */ + if(retval->slot != NULL) + ExecClearTuple(retval->slot); + + return retval; +} + /* * end_MultiFuncCall * Clean up after init_MultiFuncCall diff --git a/src/include/funcapi.h b/src/include/funcapi.h index 351a7a420d..f00b93b865 100644 --- a/src/include/funcapi.h +++ b/src/include/funcapi.h @@ -65,22 +65,57 @@ typedef struct */ typedef struct { - /* Number of times we've been called before */ + /* + * 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; - /* Maximum number of calls */ + /* + * 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; - /* pointer to result slot */ + /* + * 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; - /* pointer to misc context info */ - void *fctx; + /* + * 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; - /* pointer to struct containing arrays of attribute type input metainfo */ + /* + * 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 */ + /* + * 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; @@ -137,7 +172,7 @@ extern void get_type_metadata(Oid typeid, Oid *attinfuncid, Oid *attelem); * Datum result; * * - * if(SRF_IS_FIRSTPASS()) + * if(SRF_IS_FIRSTCALL()) * { * * funcctx = SRF_FIRSTCALL_INIT(); @@ -148,7 +183,7 @@ extern void get_type_metadata(Oid typeid, Oid *attinfuncid, Oid *attelem); * * } * - * funcctx = SRF_PERCALL_SETUP(funcctx); + * funcctx = SRF_PERCALL_SETUP(); * * * if (funcctx->call_cntr < funcctx->max_calls) @@ -167,14 +202,12 @@ extern void get_type_metadata(Oid typeid, Oid *attinfuncid, Oid *attelem); /* from funcapi.c */ extern FuncCallContext *init_MultiFuncCall(PG_FUNCTION_ARGS); +extern FuncCallContext *per_MultiFuncCall(PG_FUNCTION_ARGS); extern void end_MultiFuncCall(PG_FUNCTION_ARGS, FuncCallContext *funcctx); -#define SRF_IS_FIRSTPASS() (fcinfo->flinfo->fn_extra == NULL) +#define SRF_IS_FIRSTCALL() (fcinfo->flinfo->fn_extra == NULL) #define SRF_FIRSTCALL_INIT() init_MultiFuncCall(fcinfo) -#define SRF_PERCALL_SETUP(_funcctx) \ - fcinfo->flinfo->fn_extra; \ - if(_funcctx->slot != NULL) \ - ExecClearTuple(_funcctx->slot) +#define SRF_PERCALL_SETUP() per_MultiFuncCall(fcinfo) #define SRF_RETURN_NEXT(_funcctx, _result) \ do { \ ReturnSetInfo *rsi; \