1
/*-------------------------------------------------------------------------
4
* Utility and convenience functions for fmgr functions that return
5
* sets and/or composite types.
7
* Copyright (c) 2002-2005, PostgreSQL Global Development Group
10
* $PostgreSQL: pgsql/src/backend/utils/fmgr/funcapi.c,v 1.18 2005-01-01 05:43:08 momjian Exp $
12
*-------------------------------------------------------------------------
17
#include "catalog/pg_type.h"
18
#include "utils/syscache.h"
20
static void shutdown_MultiFuncCall(Datum arg);
24
* Create an empty FuncCallContext data structure
25
* and do some other basic Multi-function call setup
29
init_MultiFuncCall(PG_FUNCTION_ARGS)
31
FuncCallContext *retval;
34
* Bail if we're called in the wrong context
36
if (fcinfo->resultinfo == NULL || !IsA(fcinfo->resultinfo, ReturnSetInfo))
38
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
39
errmsg("set-valued function called in context that cannot accept a set")));
41
if (fcinfo->flinfo->fn_extra == NULL)
46
ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
49
* Allocate suitably long-lived space and zero it
51
retval = (FuncCallContext *)
52
MemoryContextAllocZero(fcinfo->flinfo->fn_mcxt,
53
sizeof(FuncCallContext));
56
* initialize the elements
58
retval->call_cntr = 0;
59
retval->max_calls = 0;
61
retval->user_fctx = NULL;
62
retval->attinmeta = NULL;
63
retval->tuple_desc = NULL;
64
retval->multi_call_memory_ctx = fcinfo->flinfo->fn_mcxt;
67
* save the pointer for cross-call use
69
fcinfo->flinfo->fn_extra = retval;
72
* Ensure we will get shut down cleanly if the exprcontext is not
75
RegisterExprContextCallback(rsi->econtext,
76
shutdown_MultiFuncCall,
77
PointerGetDatum(fcinfo->flinfo));
81
/* second and subsequent calls */
82
elog(ERROR, "init_MultiFuncCall may not be called more than once");
84
/* never reached, but keep compiler happy */
94
* Do Multi-function per-call setup
97
per_MultiFuncCall(PG_FUNCTION_ARGS)
99
FuncCallContext *retval = (FuncCallContext *) fcinfo->flinfo->fn_extra;
102
* Clear the TupleTableSlot, if present. This is for safety's sake:
103
* the Slot will be in a long-lived context (it better be, if the
104
* FuncCallContext is pointing to it), but in most usage patterns the
105
* tuples stored in it will be in the function's per-tuple context. So
106
* at the beginning of each call, the Slot will hold a dangling
107
* pointer to an already-recycled tuple. We clear it out here.
109
* Note: use of retval->slot is obsolete as of 8.0, and we expect that it
110
* will always be NULL. This is just here for backwards compatibility
111
* in case someone creates a slot anyway.
113
if (retval->slot != NULL)
114
ExecClearTuple(retval->slot);
121
* Clean up after init_MultiFuncCall
124
end_MultiFuncCall(PG_FUNCTION_ARGS, FuncCallContext *funcctx)
126
ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
128
/* Deregister the shutdown callback */
129
UnregisterExprContextCallback(rsi->econtext,
130
shutdown_MultiFuncCall,
131
PointerGetDatum(fcinfo->flinfo));
133
/* But use it to do the real work */
134
shutdown_MultiFuncCall(PointerGetDatum(fcinfo->flinfo));
138
* shutdown_MultiFuncCall
139
* Shutdown function to clean up after init_MultiFuncCall
142
shutdown_MultiFuncCall(Datum arg)
144
FmgrInfo *flinfo = (FmgrInfo *) DatumGetPointer(arg);
145
FuncCallContext *funcctx = (FuncCallContext *) flinfo->fn_extra;
147
/* unbind from flinfo */
148
flinfo->fn_extra = NULL;
151
* Caller is responsible to free up memory for individual struct
152
* elements other than att_in_funcinfo and elements.
154
if (funcctx->attinmeta != NULL)
155
pfree(funcctx->attinmeta);