1 /*-------------------------------------------------------------------------
4 * Utility and convenience functions for fmgr functions that return
5 * sets and/or composite types.
7 * Copyright (c) 2002-2003, PostgreSQL Global Development Group
10 * $PostgreSQL: pgsql/src/backend/utils/fmgr/funcapi.c,v 1.15 2004/08/04 21:34:03 tgl 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
110 * it 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);