]> granicus.if.org Git - postgresql/blob - src/backend/utils/fmgr/funcapi.c
Label CVS tip as 8.0devel instead of 7.5devel. Adjust various comments
[postgresql] / src / backend / utils / fmgr / funcapi.c
1 /*-------------------------------------------------------------------------
2  *
3  * funcapi.c
4  *        Utility and convenience functions for fmgr functions that return
5  *        sets and/or composite types.
6  *
7  * Copyright (c) 2002-2003, PostgreSQL Global Development Group
8  *
9  * IDENTIFICATION
10  *        $PostgreSQL: pgsql/src/backend/utils/fmgr/funcapi.c,v 1.15 2004/08/04 21:34:03 tgl Exp $
11  *
12  *-------------------------------------------------------------------------
13  */
14 #include "postgres.h"
15
16 #include "funcapi.h"
17 #include "catalog/pg_type.h"
18 #include "utils/syscache.h"
19
20 static void shutdown_MultiFuncCall(Datum arg);
21
22 /*
23  * init_MultiFuncCall
24  * Create an empty FuncCallContext data structure
25  * and do some other basic Multi-function call setup
26  * and error checking
27  */
28 FuncCallContext *
29 init_MultiFuncCall(PG_FUNCTION_ARGS)
30 {
31         FuncCallContext *retval;
32
33         /*
34          * Bail if we're called in the wrong context
35          */
36         if (fcinfo->resultinfo == NULL || !IsA(fcinfo->resultinfo, ReturnSetInfo))
37                 ereport(ERROR,
38                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
39                                  errmsg("set-valued function called in context that cannot accept a set")));
40
41         if (fcinfo->flinfo->fn_extra == NULL)
42         {
43                 /*
44                  * First call
45                  */
46                 ReturnSetInfo      *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
47
48                 /*
49                  * Allocate suitably long-lived space and zero it
50                  */
51                 retval = (FuncCallContext *)
52                         MemoryContextAllocZero(fcinfo->flinfo->fn_mcxt,
53                                                                    sizeof(FuncCallContext));
54
55                 /*
56                  * initialize the elements
57                  */
58                 retval->call_cntr = 0;
59                 retval->max_calls = 0;
60                 retval->slot = NULL;
61                 retval->user_fctx = NULL;
62                 retval->attinmeta = NULL;
63                 retval->tuple_desc = NULL;
64                 retval->multi_call_memory_ctx = fcinfo->flinfo->fn_mcxt;
65
66                 /*
67                  * save the pointer for cross-call use
68                  */
69                 fcinfo->flinfo->fn_extra = retval;
70
71                 /*
72                  * Ensure we will get shut down cleanly if the exprcontext is not
73                  * run to completion.
74                  */
75                 RegisterExprContextCallback(rsi->econtext,
76                                                                         shutdown_MultiFuncCall,
77                                                                         PointerGetDatum(fcinfo->flinfo));
78         }
79         else
80         {
81                 /* second and subsequent calls */
82                 elog(ERROR, "init_MultiFuncCall may not be called more than once");
83
84                 /* never reached, but keep compiler happy */
85                 retval = NULL;
86         }
87
88         return retval;
89 }
90
91 /*
92  * per_MultiFuncCall
93  *
94  * Do Multi-function per-call setup
95  */
96 FuncCallContext *
97 per_MultiFuncCall(PG_FUNCTION_ARGS)
98 {
99         FuncCallContext *retval = (FuncCallContext *) fcinfo->flinfo->fn_extra;
100
101         /*
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.
108          *
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.
112          */
113         if (retval->slot != NULL)
114                 ExecClearTuple(retval->slot);
115
116         return retval;
117 }
118
119 /*
120  * end_MultiFuncCall
121  * Clean up after init_MultiFuncCall
122  */
123 void
124 end_MultiFuncCall(PG_FUNCTION_ARGS, FuncCallContext *funcctx)
125 {
126         ReturnSetInfo      *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
127
128         /* Deregister the shutdown callback */
129         UnregisterExprContextCallback(rsi->econtext,
130                                                                   shutdown_MultiFuncCall,
131                                                                   PointerGetDatum(fcinfo->flinfo));
132
133         /* But use it to do the real work */
134         shutdown_MultiFuncCall(PointerGetDatum(fcinfo->flinfo));
135 }
136
137 /*
138  * shutdown_MultiFuncCall
139  * Shutdown function to clean up after init_MultiFuncCall
140  */
141 static void
142 shutdown_MultiFuncCall(Datum arg)
143 {
144         FmgrInfo *flinfo = (FmgrInfo *) DatumGetPointer(arg);
145         FuncCallContext *funcctx = (FuncCallContext *) flinfo->fn_extra;
146
147         /* unbind from flinfo */
148         flinfo->fn_extra = NULL;
149
150         /*
151          * Caller is responsible to free up memory for individual struct
152          * elements other than att_in_funcinfo and elements.
153          */
154         if (funcctx->attinmeta != NULL)
155                 pfree(funcctx->attinmeta);
156
157         pfree(funcctx);
158 }