Re: Table Function API patch (was Re: another SRF question) - Mailing list pgsql-patches
From | Bruce Momjian |
---|---|
Subject | Re: Table Function API patch (was Re: another SRF question) |
Date | |
Msg-id | 200207160600.g6G603u07764@candle.pha.pa.us Whole thread Raw |
In response to | Table Function API patch (was Re: another SRF question) (Joe Conway <mail@joeconway.com>) |
List | pgsql-patches |
Your patch has been added to the PostgreSQL unapplied patches list at: http://candle.pha.pa.us/cgi-bin/pgpatches I will try to apply it within the next 48 hours. --------------------------------------------------------------------------- Joe Conway wrote: > Neil Conway wrote: > > On Mon, Jul 08, 2002 at 03:52:24PM -0700, Joe Conway wrote: > >>Nice catch. Here's (I think) a proper fix. This assumes that if > >>(values[i] != NULL), the datum is the output of the appropriate "in" > >>function, otherwise the datum is NULL. It saves the extra pass through > >>the dvalues array too. > >> > >>I thought you might want to try it out now without waiting for the patch > >>to get into cvs. I tested it with a contrived test function and it > >>worked as desired. > > > > > > Great, seems to work fine here. Thanks for fixing that for me. > > > > 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. > > If there are no objections, please apply. > > Thanks, > > Joe > > > Index: src/backend/executor/execTuples.c > =================================================================== > RCS file: /opt/src/cvs/pgsql/src/backend/executor/execTuples.c,v > retrieving revision 1.53 > diff -c -r1.53 execTuples.c > *** src/backend/executor/execTuples.c 20 Jun 2002 20:29:27 -0000 1.53 > --- src/backend/executor/execTuples.c 8 Jul 2002 22:25:14 -0000 > *************** > *** 759,764 **** > --- 759,765 ---- > 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,793 **** > dvalues[i] = FunctionCall3(&attinfuncinfo, CStringGetDatum(values[i]), > ObjectIdGetDatum(attelem), > Int32GetDatum(atttypmod)); > } > else > dvalues[i] = PointerGetDatum(NULL); > } > > /* > * 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; > --- 773,790 ---- > dvalues[i] = FunctionCall3(&attinfuncinfo, CStringGetDatum(values[i]), > ObjectIdGetDatum(attelem), > Int32GetDatum(atttypmod)); > + nulls[i] = ' '; > } > else > + { > dvalues[i] = PointerGetDatum(NULL); > + nulls[i] = 'n'; > + } > } > > /* > * Form a tuple > */ > tuple = heap_formtuple(tupdesc, dvalues, nulls); > > return tuple; > Index: src/backend/utils/fmgr/funcapi.c > =================================================================== > RCS file: /opt/src/cvs/pgsql/src/backend/utils/fmgr/funcapi.c,v > retrieving revision 1.1 > diff -c -r1.1 funcapi.c > *** src/backend/utils/fmgr/funcapi.c 20 Jun 2002 20:37:00 -0000 1.1 > --- src/backend/utils/fmgr/funcapi.c 9 Jul 2002 18:21:15 -0000 > *************** > *** 52,58 **** > retval->call_cntr = 0; > retval->max_calls = 0; > retval->slot = NULL; > ! retval->fctx = NULL; > retval->attinmeta = NULL; > retval->fmctx = fcinfo->flinfo->fn_mcxt; > > --- 52,58 ---- > retval->call_cntr = 0; > retval->max_calls = 0; > retval->slot = NULL; > ! retval->user_fctx = NULL; > retval->attinmeta = NULL; > retval->fmctx = fcinfo->flinfo->fn_mcxt; > > *************** > *** 71,76 **** > --- 71,93 ---- > /* never reached, but keep compiler happy */ > retval = NULL; > } > + > + 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; > } > Index: src/include/funcapi.h > =================================================================== > RCS file: /opt/src/cvs/pgsql/src/include/funcapi.h,v > retrieving revision 1.2 > diff -c -r1.2 funcapi.h > *** src/include/funcapi.h 22 Jun 2002 04:08:07 -0000 1.2 > --- src/include/funcapi.h 9 Jul 2002 18:17:27 -0000 > *************** > *** 65,86 **** > */ > typedef struct > { > ! /* Number of times we've been called before */ > uint32 call_cntr; > > ! /* Maximum number of calls */ > uint32 max_calls; > > ! /* pointer to result slot */ > TupleTableSlot *slot; > > ! /* pointer to misc context info */ > ! void *fctx; > ! > ! /* pointer to struct containing arrays of attribute type input metainfo */ > AttInMetadata *attinmeta; > > ! /* memory context used to initialize structure */ > MemoryContext fmctx; > > } FuncCallContext; > --- 65,121 ---- > */ > 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; > *************** > *** 137,143 **** > * Datum result; > * <user defined declarations> > * > ! * if(SRF_IS_FIRSTPASS()) > * { > * <user defined code> > * funcctx = SRF_FIRSTCALL_INIT(); > --- 172,178 ---- > * Datum result; > * <user defined declarations> > * > ! * if(SRF_IS_FIRSTCALL()) > * { > * <user defined code> > * funcctx = SRF_FIRSTCALL_INIT(); > *************** > *** 148,154 **** > * <user defined code> > * } > * <user defined code> > ! * funcctx = SRF_PERCALL_SETUP(funcctx); > * <user defined code> > * > * if (funcctx->call_cntr < funcctx->max_calls) > --- 183,189 ---- > * <user defined code> > * } > * <user defined code> > ! * funcctx = SRF_PERCALL_SETUP(); > * <user defined code> > * > * if (funcctx->call_cntr < funcctx->max_calls) > *************** > *** 167,180 **** > > /* from funcapi.c */ > extern FuncCallContext *init_MultiFuncCall(PG_FUNCTION_ARGS); > extern void end_MultiFuncCall(PG_FUNCTION_ARGS, FuncCallContext *funcctx); > > ! #define SRF_IS_FIRSTPASS() (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_RETURN_NEXT(_funcctx, _result) \ > do { \ > ReturnSetInfo *rsi; \ > --- 202,213 ---- > > /* 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_FIRSTCALL() (fcinfo->flinfo->fn_extra == NULL) > #define SRF_FIRSTCALL_INIT() init_MultiFuncCall(fcinfo) > ! #define SRF_PERCALL_SETUP() per_MultiFuncCall(fcinfo) > #define SRF_RETURN_NEXT(_funcctx, _result) \ > do { \ > ReturnSetInfo *rsi; \ > > ---------------------------(end of broadcast)--------------------------- > TIP 1: subscribe and unsubscribe commands go to majordomo@postgresql.org -- Bruce Momjian | http://candle.pha.pa.us pgman@candle.pha.pa.us | (610) 853-3000 + If your life is a hard drive, | 830 Blythe Avenue + Christ can be your backup. | Drexel Hill, Pennsylvania 19026
pgsql-patches by date: