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
This commit is contained in:
parent
a5a8110a86
commit
7ea5f1d7f1
@ -15,7 +15,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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;
|
natts = tupdesc->natts;
|
||||||
|
|
||||||
dvalues = (Datum *) palloc(natts * sizeof(Datum));
|
dvalues = (Datum *) palloc(natts * sizeof(Datum));
|
||||||
|
nulls = (char *) palloc(natts * sizeof(char));
|
||||||
|
|
||||||
/* Call the "in" function for each attribute */
|
/* Call the "in" function for each attribute */
|
||||||
for (i = 0; i < natts; i++)
|
for (i = 0; i < natts; i++)
|
||||||
@ -772,22 +773,18 @@ BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
|
|||||||
dvalues[i] = FunctionCall3(&attinfuncinfo, CStringGetDatum(values[i]),
|
dvalues[i] = FunctionCall3(&attinfuncinfo, CStringGetDatum(values[i]),
|
||||||
ObjectIdGetDatum(attelem),
|
ObjectIdGetDatum(attelem),
|
||||||
Int32GetDatum(atttypmod));
|
Int32GetDatum(atttypmod));
|
||||||
|
nulls[i] = ' ';
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
dvalues[i] = PointerGetDatum(NULL);
|
dvalues[i] = PointerGetDatum(NULL);
|
||||||
|
nulls[i] = 'n';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Form a tuple
|
* 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);
|
tuple = heap_formtuple(tupdesc, dvalues, nulls);
|
||||||
|
|
||||||
return tuple;
|
return tuple;
|
||||||
|
@ -52,7 +52,7 @@ init_MultiFuncCall(PG_FUNCTION_ARGS)
|
|||||||
retval->call_cntr = 0;
|
retval->call_cntr = 0;
|
||||||
retval->max_calls = 0;
|
retval->max_calls = 0;
|
||||||
retval->slot = NULL;
|
retval->slot = NULL;
|
||||||
retval->fctx = NULL;
|
retval->user_fctx = NULL;
|
||||||
retval->attinmeta = NULL;
|
retval->attinmeta = NULL;
|
||||||
retval->fmctx = fcinfo->flinfo->fn_mcxt;
|
retval->fmctx = fcinfo->flinfo->fn_mcxt;
|
||||||
|
|
||||||
@ -75,6 +75,23 @@ init_MultiFuncCall(PG_FUNCTION_ARGS)
|
|||||||
return retval;
|
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
|
* end_MultiFuncCall
|
||||||
* Clean up after init_MultiFuncCall
|
* Clean up after init_MultiFuncCall
|
||||||
|
@ -65,22 +65,57 @@ typedef struct
|
|||||||
*/
|
*/
|
||||||
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;
|
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;
|
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;
|
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;
|
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;
|
MemoryContext fmctx;
|
||||||
|
|
||||||
} FuncCallContext;
|
} FuncCallContext;
|
||||||
@ -137,7 +172,7 @@ extern void get_type_metadata(Oid typeid, Oid *attinfuncid, Oid *attelem);
|
|||||||
* Datum result;
|
* Datum result;
|
||||||
* <user defined declarations>
|
* <user defined declarations>
|
||||||
*
|
*
|
||||||
* if(SRF_IS_FIRSTPASS())
|
* if(SRF_IS_FIRSTCALL())
|
||||||
* {
|
* {
|
||||||
* <user defined code>
|
* <user defined code>
|
||||||
* funcctx = SRF_FIRSTCALL_INIT();
|
* funcctx = SRF_FIRSTCALL_INIT();
|
||||||
@ -148,7 +183,7 @@ extern void get_type_metadata(Oid typeid, Oid *attinfuncid, Oid *attelem);
|
|||||||
* <user defined code>
|
* <user defined code>
|
||||||
* }
|
* }
|
||||||
* <user defined code>
|
* <user defined code>
|
||||||
* funcctx = SRF_PERCALL_SETUP(funcctx);
|
* funcctx = SRF_PERCALL_SETUP();
|
||||||
* <user defined code>
|
* <user defined code>
|
||||||
*
|
*
|
||||||
* if (funcctx->call_cntr < funcctx->max_calls)
|
* 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 */
|
/* from funcapi.c */
|
||||||
extern FuncCallContext *init_MultiFuncCall(PG_FUNCTION_ARGS);
|
extern FuncCallContext *init_MultiFuncCall(PG_FUNCTION_ARGS);
|
||||||
|
extern FuncCallContext *per_MultiFuncCall(PG_FUNCTION_ARGS);
|
||||||
extern void end_MultiFuncCall(PG_FUNCTION_ARGS, FuncCallContext *funcctx);
|
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_FIRSTCALL_INIT() init_MultiFuncCall(fcinfo)
|
||||||
#define SRF_PERCALL_SETUP(_funcctx) \
|
#define SRF_PERCALL_SETUP() per_MultiFuncCall(fcinfo)
|
||||||
fcinfo->flinfo->fn_extra; \
|
|
||||||
if(_funcctx->slot != NULL) \
|
|
||||||
ExecClearTuple(_funcctx->slot)
|
|
||||||
#define SRF_RETURN_NEXT(_funcctx, _result) \
|
#define SRF_RETURN_NEXT(_funcctx, _result) \
|
||||||
do { \
|
do { \
|
||||||
ReturnSetInfo *rsi; \
|
ReturnSetInfo *rsi; \
|
||||||
|
Loading…
x
Reference in New Issue
Block a user