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