Skip to content

Commit 7ea5f1d

Browse files
committed
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
1 parent a5a8110 commit 7ea5f1d

File tree

3 files changed

+72
-25
lines changed

3 files changed

+72
-25
lines changed

src/backend/executor/execTuples.c

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
*
1616
*
1717
* IDENTIFICATION
18-
* $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.53 2002/06/20 20:29:27 momjian Exp $
18+
* $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.54 2002/07/18 04:40:30 momjian Exp $
1919
*
2020
*-------------------------------------------------------------------------
2121
*/
@@ -759,6 +759,7 @@ BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
759759
natts = tupdesc->natts;
760760

761761
dvalues = (Datum *) palloc(natts * sizeof(Datum));
762+
nulls = (char *) palloc(natts * sizeof(char));
762763

763764
/* Call the "in" function for each attribute */
764765
for (i = 0; i < natts; i++)
@@ -772,22 +773,18 @@ BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
772773
dvalues[i] = FunctionCall3(&attinfuncinfo, CStringGetDatum(values[i]),
773774
ObjectIdGetDatum(attelem),
774775
Int32GetDatum(atttypmod));
776+
nulls[i] = ' ';
775777
}
776778
else
779+
{
777780
dvalues[i] = PointerGetDatum(NULL);
781+
nulls[i] = 'n';
782+
}
778783
}
779784

780785
/*
781786
* Form a tuple
782787
*/
783-
nulls = (char *) palloc(natts * sizeof(char));
784-
for (i = 0; i < natts; i++)
785-
{
786-
if (DatumGetPointer(dvalues[i]) != NULL)
787-
nulls[i] = ' ';
788-
else
789-
nulls[i] = 'n';
790-
}
791788
tuple = heap_formtuple(tupdesc, dvalues, nulls);
792789

793790
return tuple;

src/backend/utils/fmgr/funcapi.c

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ init_MultiFuncCall(PG_FUNCTION_ARGS)
5252
retval->call_cntr = 0;
5353
retval->max_calls = 0;
5454
retval->slot = NULL;
55-
retval->fctx = NULL;
55+
retval->user_fctx = NULL;
5656
retval->attinmeta = NULL;
5757
retval->fmctx = fcinfo->flinfo->fn_mcxt;
5858

@@ -75,6 +75,23 @@ init_MultiFuncCall(PG_FUNCTION_ARGS)
7575
return retval;
7676
}
7777

78+
/*
79+
* per_MultiFuncCall
80+
*
81+
* Do Multi-function per-call setup
82+
*/
83+
FuncCallContext *
84+
per_MultiFuncCall(PG_FUNCTION_ARGS)
85+
{
86+
FuncCallContext *retval = (FuncCallContext *) fcinfo->flinfo->fn_extra;
87+
88+
/* make sure we start with a fresh slot */
89+
if(retval->slot != NULL)
90+
ExecClearTuple(retval->slot);
91+
92+
return retval;
93+
}
94+
7895
/*
7996
* end_MultiFuncCall
8097
* Clean up after init_MultiFuncCall

src/include/funcapi.h

Lines changed: 48 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -65,22 +65,57 @@ typedef struct
6565
*/
6666
typedef struct
6767
{
68-
/* Number of times we've been called before */
68+
/*
69+
* Number of times we've been called before.
70+
*
71+
* call_cntr is initialized to 0 for you by SRF_FIRSTCALL_INIT(), and
72+
* incremented for you every time SRF_RETURN_NEXT() is called.
73+
*/
6974
uint32 call_cntr;
7075

71-
/* Maximum number of calls */
76+
/*
77+
* OPTIONAL maximum number of calls
78+
*
79+
* max_calls is here for convenience ONLY and setting it is OPTIONAL.
80+
* If not set, you must provide alternative means to know when the
81+
* function is done.
82+
*/
7283
uint32 max_calls;
7384

74-
/* pointer to result slot */
85+
/*
86+
* OPTIONAL pointer to result slot
87+
*
88+
* slot is for use when returning tuples (i.e. composite data types)
89+
* and is not needed when returning base (i.e. scalar) data types.
90+
*/
7591
TupleTableSlot *slot;
7692

77-
/* pointer to misc context info */
78-
void *fctx;
79-
80-
/* pointer to struct containing arrays of attribute type input metainfo */
93+
/*
94+
* OPTIONAL pointer to misc user provided context info
95+
*
96+
* user_fctx is for use as a pointer to your own struct to retain
97+
* arbitrary context information between calls for your function.
98+
*/
99+
void *user_fctx;
100+
101+
/*
102+
* OPTIONAL pointer to struct containing arrays of attribute type input
103+
* metainfo
104+
*
105+
* attinmeta is for use when returning tuples (i.e. composite data types)
106+
* and is not needed when returning base (i.e. scalar) data types. It
107+
* is ONLY needed if you intend to use BuildTupleFromCStrings() to create
108+
* the return tuple.
109+
*/
81110
AttInMetadata *attinmeta;
82111

83-
/* memory context used to initialize structure */
112+
/*
113+
* memory context used to initialize structure
114+
*
115+
* fmctx is set by SRF_FIRSTCALL_INIT() for you, and used by
116+
* SRF_RETURN_DONE() for cleanup. It is primarily for internal use
117+
* by the API.
118+
*/
84119
MemoryContext fmctx;
85120

86121
} FuncCallContext;
@@ -137,7 +172,7 @@ extern void get_type_metadata(Oid typeid, Oid *attinfuncid, Oid *attelem);
137172
* Datum result;
138173
* <user defined declarations>
139174
*
140-
* if(SRF_IS_FIRSTPASS())
175+
* if(SRF_IS_FIRSTCALL())
141176
* {
142177
* <user defined code>
143178
* funcctx = SRF_FIRSTCALL_INIT();
@@ -148,7 +183,7 @@ extern void get_type_metadata(Oid typeid, Oid *attinfuncid, Oid *attelem);
148183
* <user defined code>
149184
* }
150185
* <user defined code>
151-
* funcctx = SRF_PERCALL_SETUP(funcctx);
186+
* funcctx = SRF_PERCALL_SETUP();
152187
* <user defined code>
153188
*
154189
* if (funcctx->call_cntr < funcctx->max_calls)
@@ -167,14 +202,12 @@ extern void get_type_metadata(Oid typeid, Oid *attinfuncid, Oid *attelem);
167202

168203
/* from funcapi.c */
169204
extern FuncCallContext *init_MultiFuncCall(PG_FUNCTION_ARGS);
205+
extern FuncCallContext *per_MultiFuncCall(PG_FUNCTION_ARGS);
170206
extern void end_MultiFuncCall(PG_FUNCTION_ARGS, FuncCallContext *funcctx);
171207

172-
#define SRF_IS_FIRSTPASS() (fcinfo->flinfo->fn_extra == NULL)
208+
#define SRF_IS_FIRSTCALL() (fcinfo->flinfo->fn_extra == NULL)
173209
#define SRF_FIRSTCALL_INIT() init_MultiFuncCall(fcinfo)
174-
#define SRF_PERCALL_SETUP(_funcctx) \
175-
fcinfo->flinfo->fn_extra; \
176-
if(_funcctx->slot != NULL) \
177-
ExecClearTuple(_funcctx->slot)
210+
#define SRF_PERCALL_SETUP() per_MultiFuncCall(fcinfo)
178211
#define SRF_RETURN_NEXT(_funcctx, _result) \
179212
do { \
180213
ReturnSetInfo *rsi; \

0 commit comments

Comments
 (0)