]> granicus.if.org Git - postgresql/blob - src/backend/utils/fmgr/funcapi.c
Here is a patch for the Table Function API. It fixes a bug found by Neil
[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, PostgreSQL Global Development Group
8  *
9  *-------------------------------------------------------------------------
10  */
11
12 #include "funcapi.h"
13 #include "catalog/pg_type.h"
14 #include "utils/syscache.h"
15
16 /*
17  * init_MultiFuncCall
18  * Create an empty FuncCallContext data structure
19  * and do some other basic Multi-function call setup
20  * and error checking
21  */
22 FuncCallContext *
23 init_MultiFuncCall(PG_FUNCTION_ARGS)
24 {
25         FuncCallContext *retval;
26
27         /*
28          * Bail if we're called in the wrong context
29          */
30         if (fcinfo->resultinfo == NULL || !IsA(fcinfo->resultinfo, ReturnSetInfo))
31                 elog(ERROR, "function called in context that does not accept a set result");
32
33         if (fcinfo->flinfo->fn_extra == NULL)
34         {
35                 /*
36                  * First call
37                  */
38                 MemoryContext oldcontext;
39
40                 /* switch to the appropriate memory context */
41                 oldcontext = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt);
42
43                 /*
44                  * allocate space and zero it
45                  */
46                 retval = (FuncCallContext *) palloc(sizeof(FuncCallContext));
47                 MemSet(retval, 0, sizeof(FuncCallContext));
48
49                 /*
50                  * initialize the elements
51                  */
52                 retval->call_cntr = 0;
53                 retval->max_calls = 0;
54                 retval->slot = NULL;
55                 retval->user_fctx = NULL;
56                 retval->attinmeta = NULL;
57                 retval->fmctx = fcinfo->flinfo->fn_mcxt;
58
59                 /*
60                  * save the pointer for cross-call use
61                  */
62                 fcinfo->flinfo->fn_extra = retval;
63
64                 /* back to the original memory context */
65                 MemoryContextSwitchTo(oldcontext);
66         }
67         else    /* second and subsequent calls */
68         {
69                 elog(ERROR, "init_MultiFuncCall may not be called more than once");
70
71                 /* never reached, but keep compiler happy */
72                 retval = NULL;
73         }
74
75         return retval;
76 }
77
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
95 /*
96  * end_MultiFuncCall
97  * Clean up after init_MultiFuncCall
98  */
99 void
100 end_MultiFuncCall(PG_FUNCTION_ARGS, FuncCallContext *funcctx)
101 {
102         MemoryContext oldcontext;
103
104         /* unbind from fcinfo */
105         fcinfo->flinfo->fn_extra = NULL;
106
107         /*
108          * Caller is responsible to free up memory for individual
109          * struct elements other than att_in_funcinfo and elements.
110          */
111         oldcontext = MemoryContextSwitchTo(funcctx->fmctx);
112
113         if (funcctx->attinmeta != NULL)
114                 pfree(funcctx->attinmeta);
115
116         pfree(funcctx);
117
118         MemoryContextSwitchTo(oldcontext);
119 }
120
121 void
122 get_type_metadata(Oid typeid, Oid *attinfuncid, Oid *attelem)
123 {
124         HeapTuple               typeTuple;
125         Form_pg_type    typtup;
126
127         typeTuple = SearchSysCache(TYPEOID,
128                                                            ObjectIdGetDatum(typeid),
129                                                            0, 0, 0);
130         if (!HeapTupleIsValid(typeTuple))
131                 elog(ERROR, "get_type_metadata: Cache lookup of type %u failed", typeid);
132
133         typtup = (Form_pg_type) GETSTRUCT(typeTuple);
134
135         *attinfuncid = typtup->typinput;
136         *attelem = typtup->typelem;
137
138         ReleaseSysCache(typeTuple);
139 }