Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * fmgr.c
4 : : * The Postgres function manager.
5 : : *
6 : : * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7 : : * Portions Copyright (c) 1994, Regents of the University of California
8 : : *
9 : : *
10 : : * IDENTIFICATION
11 : : * src/backend/utils/fmgr/fmgr.c
12 : : *
13 : : *-------------------------------------------------------------------------
14 : : */
15 : :
16 : : #include "postgres.h"
17 : :
18 : : #include "access/detoast.h"
19 : : #include "catalog/pg_language.h"
20 : : #include "catalog/pg_proc.h"
21 : : #include "catalog/pg_type.h"
22 : : #include "executor/functions.h"
23 : : #include "lib/stringinfo.h"
24 : : #include "miscadmin.h"
25 : : #include "nodes/makefuncs.h"
26 : : #include "nodes/miscnodes.h"
27 : : #include "nodes/nodeFuncs.h"
28 : : #include "pgstat.h"
29 : : #include "utils/acl.h"
30 : : #include "utils/builtins.h"
31 : : #include "utils/fmgrtab.h"
32 : : #include "utils/guc.h"
33 : : #include "utils/lsyscache.h"
34 : : #include "utils/syscache.h"
35 : :
36 : : /*
37 : : * Hooks for function calls
38 : : */
39 : : PGDLLIMPORT needs_fmgr_hook_type needs_fmgr_hook = NULL;
40 : : PGDLLIMPORT fmgr_hook_type fmgr_hook = NULL;
41 : :
42 : : /*
43 : : * Hashtable for fast lookup of external C functions
44 : : */
45 : : typedef struct
46 : : {
47 : : /* fn_oid is the hash key and so must be first! */
48 : : Oid fn_oid; /* OID of an external C function */
49 : : TransactionId fn_xmin; /* for checking up-to-dateness */
50 : : ItemPointerData fn_tid;
51 : : PGFunction user_fn; /* the function's address */
52 : : const Pg_finfo_record *inforec; /* address of its info record */
53 : : } CFuncHashTabEntry;
54 : :
55 : : static HTAB *CFuncHash = NULL;
56 : :
57 : :
58 : : static void fmgr_info_cxt_security(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt,
59 : : bool ignore_security);
60 : : static void fmgr_info_C_lang(Oid functionId, FmgrInfo *finfo, HeapTuple procedureTuple);
61 : : static void fmgr_info_other_lang(Oid functionId, FmgrInfo *finfo, HeapTuple procedureTuple);
62 : : static CFuncHashTabEntry *lookup_C_func(HeapTuple procedureTuple);
63 : : static void record_C_func(HeapTuple procedureTuple,
64 : : PGFunction user_fn, const Pg_finfo_record *inforec);
65 : :
66 : : /* extern so it's callable via JIT */
67 : : extern Datum fmgr_security_definer(PG_FUNCTION_ARGS);
68 : :
69 : :
70 : : /*
71 : : * Lookup routines for builtin-function table. We can search by either Oid
72 : : * or name, but search by Oid is much faster.
73 : : */
74 : :
75 : : static const FmgrBuiltin *
8722 tgl@sss.pgh.pa.us 76 :CBC 17258136 : fmgr_isbuiltin(Oid id)
77 : : {
78 : : uint16 index;
79 : :
80 : : /* fast lookup only possible if original oid still assigned */
1922 81 [ + + ]: 17258136 : if (id > fmgr_last_builtin_oid)
2384 andres@anarazel.de 82 : 69838 : return NULL;
83 : :
84 : : /*
85 : : * Lookup function data. If there's a miss in that range it's likely a
86 : : * nonexistent function, returning NULL here will trigger an ERROR later.
87 : : */
88 : 17188298 : index = fmgr_builtin_oid_index[id];
89 [ + + ]: 17188298 : if (index == InvalidOidBuiltinMapping)
90 : 4600 : return NULL;
91 : :
92 : 17183698 : return &fmgr_builtins[index];
93 : : }
94 : :
95 : : /*
96 : : * Lookup a builtin by name. Note there can be more than one entry in
97 : : * the array with the same name, but they should all point to the same
98 : : * routine.
99 : : */
100 : : static const FmgrBuiltin *
8424 bruce@momjian.us 101 : 3305 : fmgr_lookupByName(const char *name)
102 : : {
103 : : int i;
104 : :
8722 tgl@sss.pgh.pa.us 105 [ + + ]: 4316619 : for (i = 0; i < fmgr_nbuiltins; i++)
106 : : {
107 [ + + ]: 4316616 : if (strcmp(name, fmgr_builtins[i].funcName) == 0)
108 : 3302 : return fmgr_builtins + i;
109 : : }
7403 neilc@samurai.com 110 : 3 : return NULL;
111 : : }
112 : :
113 : : /*
114 : : * This routine fills a FmgrInfo struct, given the OID
115 : : * of the function to be called.
116 : : *
117 : : * The caller's CurrentMemoryContext is used as the fn_mcxt of the info
118 : : * struct; this means that any subsidiary data attached to the info struct
119 : : * (either by fmgr_info itself, or later on by a function call handler)
120 : : * will be allocated in that context. The caller must ensure that this
121 : : * context is at least as long-lived as the info struct itself. This is
122 : : * not a problem in typical cases where the info struct is on the stack or
123 : : * in freshly-palloc'd space. However, if one intends to store an info
124 : : * struct in a long-lived table, it's better to use fmgr_info_cxt.
125 : : */
126 : : void
8722 tgl@sss.pgh.pa.us 127 : 16105034 : fmgr_info(Oid functionId, FmgrInfo *finfo)
128 : : {
4337 129 : 16105034 : fmgr_info_cxt_security(functionId, finfo, CurrentMemoryContext, false);
8226 130 : 16105034 : }
131 : :
132 : : /*
133 : : * Fill a FmgrInfo struct, specifying a memory context in which its
134 : : * subsidiary data should go.
135 : : */
136 : : void
137 : 1136444 : fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
138 : : {
8002 peter_e@gmx.net 139 : 1136444 : fmgr_info_cxt_security(functionId, finfo, mcxt, false);
140 : 1136444 : }
141 : :
142 : : /*
143 : : * This one does the actual work. ignore_security is ordinarily false
144 : : * but is set to true when we need to avoid recursion.
145 : : */
146 : : static void
147 : 17258136 : fmgr_info_cxt_security(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt,
148 : : bool ignore_security)
149 : : {
150 : : const FmgrBuiltin *fbp;
151 : : HeapTuple procedureTuple;
152 : : Form_pg_proc procedureStruct;
153 : : Datum prosrcdatum;
154 : : char *prosrc;
155 : :
156 : : /*
157 : : * fn_oid *must* be filled in last. Some code assumes that if fn_oid is
158 : : * valid, the whole struct is valid. Some FmgrInfo struct's do survive
159 : : * elogs.
160 : : */
8366 161 : 17258136 : finfo->fn_oid = InvalidOid;
8722 tgl@sss.pgh.pa.us 162 : 17258136 : finfo->fn_extra = NULL;
8226 163 : 17258136 : finfo->fn_mcxt = mcxt;
7677 164 : 17258136 : finfo->fn_expr = NULL; /* caller may set this later */
165 : :
8722 166 [ + + ]: 17258136 : if ((fbp = fmgr_isbuiltin(functionId)) != NULL)
167 : : {
168 : : /*
169 : : * Fast path for builtin functions: don't bother consulting pg_proc
170 : : */
171 : 17183698 : finfo->fn_nargs = fbp->nargs;
172 : 17183698 : finfo->fn_strict = fbp->strict;
8546 173 : 17183698 : finfo->fn_retset = fbp->retset;
2489 174 : 17183698 : finfo->fn_stats = TRACK_FUNC_ALL; /* ie, never track */
8546 175 : 17183698 : finfo->fn_addr = fbp->func;
8366 peter_e@gmx.net 176 : 17183698 : finfo->fn_oid = functionId;
8722 tgl@sss.pgh.pa.us 177 : 17183698 : return;
178 : : }
179 : :
180 : : /* Otherwise we need the pg_proc entry */
5173 rhaas@postgresql.org 181 : 74438 : procedureTuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(functionId));
8722 tgl@sss.pgh.pa.us 182 [ - + ]: 74438 : if (!HeapTupleIsValid(procedureTuple))
7569 tgl@sss.pgh.pa.us 183 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for function %u", functionId);
8722 tgl@sss.pgh.pa.us 184 :CBC 74438 : procedureStruct = (Form_pg_proc) GETSTRUCT(procedureTuple);
185 : :
186 : 74438 : finfo->fn_nargs = procedureStruct->pronargs;
187 : 74438 : finfo->fn_strict = procedureStruct->proisstrict;
8634 188 : 74438 : finfo->fn_retset = procedureStruct->proretset;
189 : :
190 : : /*
191 : : * If it has prosecdef set, non-null proconfig, or if a plugin wants to
192 : : * hook function entry/exit, use fmgr_security_definer call handler ---
193 : : * unless we are being called again by fmgr_security_definer or
194 : : * fmgr_info_other_lang.
195 : : *
196 : : * When using fmgr_security_definer, function stats tracking is always
197 : : * disabled at the outer level, and instead we set the flag properly in
198 : : * fmgr_security_definer's private flinfo and implement the tracking
199 : : * inside fmgr_security_definer. This loses the ability to charge the
200 : : * overhead of fmgr_security_definer to the function, but gains the
201 : : * ability to set the track_functions GUC as a local GUC parameter of an
202 : : * interesting function and have the right things happen.
203 : : */
6068 204 [ + + ]: 74438 : if (!ignore_security &&
205 [ + + ]: 57780 : (procedureStruct->prosecdef ||
2209 andrew@dunslane.net 206 [ + + - - ]: 57642 : !heap_attisnull(procedureTuple, Anum_pg_proc_proconfig, NULL) ||
4871 rhaas@postgresql.org 207 [ - + ]: 57620 : FmgrHookIsNeeded(functionId)))
208 : : {
8002 peter_e@gmx.net 209 : 160 : finfo->fn_addr = fmgr_security_definer;
2489 tgl@sss.pgh.pa.us 210 : 160 : finfo->fn_stats = TRACK_FUNC_ALL; /* ie, never track */
8366 peter_e@gmx.net 211 : 160 : finfo->fn_oid = functionId;
8550 tgl@sss.pgh.pa.us 212 : 160 : ReleaseSysCache(procedureTuple);
8722 213 : 160 : return;
214 : : }
215 : :
8546 216 [ + + + + ]: 74278 : switch (procedureStruct->prolang)
217 : : {
8722 218 : 1311 : case INTERNALlanguageId:
219 : :
220 : : /*
221 : : * For an ordinary builtin function, we should never get here
222 : : * because the fmgr_isbuiltin() search above will have succeeded.
223 : : * However, if the user has done a CREATE FUNCTION to create an
224 : : * alias for a builtin function, we can end up here. In that case
225 : : * we have to look up the function by name. The name of the
226 : : * internal function is stored in prosrc (it doesn't have to be
227 : : * the same as the name of the alias!)
228 : : */
386 dgustafsson@postgres 229 : 1311 : prosrcdatum = SysCacheGetAttrNotNull(PROCOID, procedureTuple,
230 : : Anum_pg_proc_prosrc);
5864 tgl@sss.pgh.pa.us 231 : 1311 : prosrc = TextDatumGetCString(prosrcdatum);
8722 232 : 1311 : fbp = fmgr_lookupByName(prosrc);
233 [ - + ]: 1311 : if (fbp == NULL)
7569 tgl@sss.pgh.pa.us 234 [ # # ]:UBC 0 : ereport(ERROR,
235 : : (errcode(ERRCODE_UNDEFINED_FUNCTION),
236 : : errmsg("internal function \"%s\" is not in internal lookup table",
237 : : prosrc)));
8722 tgl@sss.pgh.pa.us 238 :CBC 1311 : pfree(prosrc);
239 : : /* Should we check that nargs, strict, retset match the table? */
8546 240 : 1311 : finfo->fn_addr = fbp->func;
241 : : /* note this policy is also assumed in fast path above */
5813 242 : 1311 : finfo->fn_stats = TRACK_FUNC_ALL; /* ie, never track */
8722 243 : 1311 : break;
244 : :
245 : 46885 : case ClanguageId:
8366 peter_e@gmx.net 246 : 46885 : fmgr_info_C_lang(functionId, finfo, procedureTuple);
5813 tgl@sss.pgh.pa.us 247 : 46885 : finfo->fn_stats = TRACK_FUNC_PL; /* ie, track if ALL */
8722 248 : 46885 : break;
249 : :
250 : 9584 : case SQLlanguageId:
251 : 9584 : finfo->fn_addr = fmgr_sql;
5813 252 : 9584 : finfo->fn_stats = TRACK_FUNC_PL; /* ie, track if ALL */
8722 253 : 9584 : break;
254 : :
255 : 16498 : default:
8366 peter_e@gmx.net 256 : 16498 : fmgr_info_other_lang(functionId, finfo, procedureTuple);
5813 tgl@sss.pgh.pa.us 257 : 16498 : finfo->fn_stats = TRACK_FUNC_OFF; /* ie, track if not OFF */
8546 258 : 16498 : break;
259 : : }
260 : :
8366 peter_e@gmx.net 261 : 74278 : finfo->fn_oid = functionId;
8546 tgl@sss.pgh.pa.us 262 : 74278 : ReleaseSysCache(procedureTuple);
263 : : }
264 : :
265 : : /*
266 : : * Return module and C function name providing implementation of functionId.
267 : : *
268 : : * If *mod == NULL and *fn == NULL, no C symbol is known to implement
269 : : * function.
270 : : *
271 : : * If *mod == NULL and *fn != NULL, the function is implemented by a symbol in
272 : : * the main binary.
273 : : *
274 : : * If *mod != NULL and *fn != NULL the function is implemented in an extension
275 : : * shared object.
276 : : *
277 : : * The returned module and function names are pstrdup'ed into the current
278 : : * memory context.
279 : : */
280 : : void
2217 andres@anarazel.de 281 :UBC 0 : fmgr_symbol(Oid functionId, char **mod, char **fn)
282 : : {
283 : : HeapTuple procedureTuple;
284 : : Form_pg_proc procedureStruct;
285 : : Datum prosrcattr;
286 : : Datum probinattr;
287 : :
288 : 0 : procedureTuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(functionId));
289 [ # # ]: 0 : if (!HeapTupleIsValid(procedureTuple))
290 [ # # ]: 0 : elog(ERROR, "cache lookup failed for function %u", functionId);
291 : 0 : procedureStruct = (Form_pg_proc) GETSTRUCT(procedureTuple);
292 : :
293 [ # # ]: 0 : if (procedureStruct->prosecdef ||
2209 andrew@dunslane.net 294 [ # # # # ]: 0 : !heap_attisnull(procedureTuple, Anum_pg_proc_proconfig, NULL) ||
2217 andres@anarazel.de 295 [ # # ]: 0 : FmgrHookIsNeeded(functionId))
296 : : {
2180 tgl@sss.pgh.pa.us 297 : 0 : *mod = NULL; /* core binary */
2217 andres@anarazel.de 298 : 0 : *fn = pstrdup("fmgr_security_definer");
299 : 0 : ReleaseSysCache(procedureTuple);
300 : 0 : return;
301 : : }
302 : :
303 : : /* see fmgr_info_cxt_security for the individual cases */
304 [ # # # # ]: 0 : switch (procedureStruct->prolang)
305 : : {
306 : 0 : case INTERNALlanguageId:
386 dgustafsson@postgres 307 : 0 : prosrcattr = SysCacheGetAttrNotNull(PROCOID, procedureTuple,
308 : : Anum_pg_proc_prosrc);
309 : :
2180 tgl@sss.pgh.pa.us 310 : 0 : *mod = NULL; /* core binary */
2217 andres@anarazel.de 311 : 0 : *fn = TextDatumGetCString(prosrcattr);
312 : 0 : break;
313 : :
314 : 0 : case ClanguageId:
386 dgustafsson@postgres 315 : 0 : prosrcattr = SysCacheGetAttrNotNull(PROCOID, procedureTuple,
316 : : Anum_pg_proc_prosrc);
317 : :
318 : 0 : probinattr = SysCacheGetAttrNotNull(PROCOID, procedureTuple,
319 : : Anum_pg_proc_probin);
320 : :
321 : : /*
322 : : * No need to check symbol presence / API version here, already
323 : : * checked in fmgr_info_cxt_security.
324 : : */
2217 andres@anarazel.de 325 : 0 : *mod = TextDatumGetCString(probinattr);
326 : 0 : *fn = TextDatumGetCString(prosrcattr);
327 : 0 : break;
328 : :
329 : 0 : case SQLlanguageId:
2180 tgl@sss.pgh.pa.us 330 : 0 : *mod = NULL; /* core binary */
2217 andres@anarazel.de 331 : 0 : *fn = pstrdup("fmgr_sql");
332 : 0 : break;
333 : :
334 : 0 : default:
335 : 0 : *mod = NULL;
2180 tgl@sss.pgh.pa.us 336 : 0 : *fn = NULL; /* unknown, pass pointer */
2217 andres@anarazel.de 337 : 0 : break;
338 : : }
339 : :
340 : 0 : ReleaseSysCache(procedureTuple);
341 : : }
342 : :
343 : :
344 : : /*
345 : : * Special fmgr_info processing for C-language functions. Note that
346 : : * finfo->fn_oid is not valid yet.
347 : : */
348 : : static void
8366 peter_e@gmx.net 349 :CBC 46885 : fmgr_info_C_lang(Oid functionId, FmgrInfo *finfo, HeapTuple procedureTuple)
350 : : {
351 : : CFuncHashTabEntry *hashentry;
352 : : PGFunction user_fn;
353 : : const Pg_finfo_record *inforec;
354 : :
355 : : /*
356 : : * See if we have the function address cached already
357 : : */
7391 tgl@sss.pgh.pa.us 358 : 46885 : hashentry = lookup_C_func(procedureTuple);
359 [ + + ]: 46885 : if (hashentry)
360 : : {
361 : 43380 : user_fn = hashentry->user_fn;
362 : 43380 : inforec = hashentry->inforec;
363 : : }
364 : : else
365 : : {
366 : : Datum prosrcattr,
367 : : probinattr;
368 : : char *prosrcstring,
369 : : *probinstring;
370 : : void *libraryhandle;
371 : :
372 : : /*
373 : : * Get prosrc and probin strings (link symbol and library filename).
374 : : * While in general these columns might be null, that's not allowed
375 : : * for C-language functions.
376 : : */
386 dgustafsson@postgres 377 : 3505 : prosrcattr = SysCacheGetAttrNotNull(PROCOID, procedureTuple,
378 : : Anum_pg_proc_prosrc);
5864 tgl@sss.pgh.pa.us 379 : 3505 : prosrcstring = TextDatumGetCString(prosrcattr);
380 : :
386 dgustafsson@postgres 381 : 3505 : probinattr = SysCacheGetAttrNotNull(PROCOID, procedureTuple,
382 : : Anum_pg_proc_probin);
5864 tgl@sss.pgh.pa.us 383 : 3505 : probinstring = TextDatumGetCString(probinattr);
384 : :
385 : : /* Look up the function itself */
7391 386 : 3505 : user_fn = load_external_function(probinstring, prosrcstring, true,
387 : : &libraryhandle);
388 : :
389 : : /* Get the function information record (real or default) */
390 : 3505 : inforec = fetch_finfo_record(libraryhandle, prosrcstring);
391 : :
392 : : /* Cache the addresses for later calls */
393 : 3505 : record_C_func(procedureTuple, user_fn, inforec);
394 : :
395 : 3505 : pfree(prosrcstring);
396 : 3505 : pfree(probinstring);
397 : : }
398 : :
8546 399 [ + - ]: 46885 : switch (inforec->api_version)
400 : : {
401 : 46885 : case 1:
402 : : /* New style: call directly */
403 : 46885 : finfo->fn_addr = user_fn;
404 : 46885 : break;
8546 tgl@sss.pgh.pa.us 405 :UBC 0 : default:
406 : : /* Shouldn't get here if fetch_finfo_record did its job */
7569 407 [ # # ]: 0 : elog(ERROR, "unrecognized function API version: %d",
408 : : inforec->api_version);
409 : : break;
410 : : }
9143 tgl@sss.pgh.pa.us 411 :CBC 46885 : }
412 : :
413 : : /*
414 : : * Special fmgr_info processing for other-language functions. Note
415 : : * that finfo->fn_oid is not valid yet.
416 : : */
417 : : static void
8366 peter_e@gmx.net 418 : 16498 : fmgr_info_other_lang(Oid functionId, FmgrInfo *finfo, HeapTuple procedureTuple)
419 : : {
8546 tgl@sss.pgh.pa.us 420 : 16498 : Form_pg_proc procedureStruct = (Form_pg_proc) GETSTRUCT(procedureTuple);
421 : 16498 : Oid language = procedureStruct->prolang;
422 : : HeapTuple languageTuple;
423 : : Form_pg_language languageStruct;
424 : : FmgrInfo plfinfo;
425 : :
5173 rhaas@postgresql.org 426 : 16498 : languageTuple = SearchSysCache1(LANGOID, ObjectIdGetDatum(language));
8546 tgl@sss.pgh.pa.us 427 [ - + ]: 16498 : if (!HeapTupleIsValid(languageTuple))
7569 tgl@sss.pgh.pa.us 428 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for language %u", language);
8546 tgl@sss.pgh.pa.us 429 :CBC 16498 : languageStruct = (Form_pg_language) GETSTRUCT(languageTuple);
430 : :
431 : : /*
432 : : * Look up the language's call handler function, ignoring any attributes
433 : : * that would normally cause insertion of fmgr_security_definer. We need
434 : : * to get back a bare pointer to the actual C-language function.
435 : : */
4337 436 : 16498 : fmgr_info_cxt_security(languageStruct->lanplcallfoid, &plfinfo,
437 : : CurrentMemoryContext, true);
7915 peter_e@gmx.net 438 : 16498 : finfo->fn_addr = plfinfo.fn_addr;
439 : :
8546 tgl@sss.pgh.pa.us 440 : 16498 : ReleaseSysCache(languageTuple);
441 : 16498 : }
442 : :
443 : : /*
444 : : * Fetch and validate the information record for the given external function.
445 : : * The function is specified by a handle for the containing library
446 : : * (obtained from load_external_function) as well as the function name.
447 : : *
448 : : * If no info function exists for the given name an error is raised.
449 : : *
450 : : * This function is broken out of fmgr_info_C_lang so that fmgr_c_validator
451 : : * can validate the information record for a function not yet entered into
452 : : * pg_proc.
453 : : */
454 : : const Pg_finfo_record *
2557 455 : 5847 : fetch_finfo_record(void *filehandle, const char *funcname)
456 : : {
457 : : char *infofuncname;
458 : : PGFInfoFunction infofunc;
459 : : const Pg_finfo_record *inforec;
460 : :
3836 peter_e@gmx.net 461 : 5847 : infofuncname = psprintf("pg_finfo_%s", funcname);
462 : :
463 : : /* Try to look up the info function */
8226 tgl@sss.pgh.pa.us 464 : 5847 : infofunc = (PGFInfoFunction) lookup_external_function(filehandle,
465 : : infofuncname);
7403 neilc@samurai.com 466 [ - + ]: 5847 : if (infofunc == NULL)
467 : : {
2573 andres@anarazel.de 468 [ # # ]:UBC 0 : ereport(ERROR,
469 : : (errcode(ERRCODE_UNDEFINED_FUNCTION),
470 : : errmsg("could not find function information for function \"%s\"",
471 : : funcname),
472 : : errhint("SQL-callable functions need an accompanying PG_FUNCTION_INFO_V1(funcname).")));
473 : : return NULL; /* silence compiler */
474 : : }
475 : :
476 : : /* Found, so call it */
8424 bruce@momjian.us 477 :CBC 5847 : inforec = (*infofunc) ();
478 : :
479 : : /* Validate result as best we can */
8546 tgl@sss.pgh.pa.us 480 [ - + ]: 5847 : if (inforec == NULL)
7569 tgl@sss.pgh.pa.us 481 [ # # ]:UBC 0 : elog(ERROR, "null result from info function \"%s\"", infofuncname);
8546 tgl@sss.pgh.pa.us 482 [ + - ]:CBC 5847 : switch (inforec->api_version)
483 : : {
484 : 5847 : case 1:
485 : : /* OK, no additional fields to validate */
486 : 5847 : break;
8546 tgl@sss.pgh.pa.us 487 :UBC 0 : default:
7569 488 [ # # ]: 0 : ereport(ERROR,
489 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
490 : : errmsg("unrecognized API version %d reported by info function \"%s\"",
491 : : inforec->api_version, infofuncname)));
492 : : break;
493 : : }
494 : :
8546 tgl@sss.pgh.pa.us 495 :CBC 5847 : pfree(infofuncname);
496 : 5847 : return inforec;
497 : : }
498 : :
499 : :
500 : : /*-------------------------------------------------------------------------
501 : : * Routines for caching lookup information for external C functions.
502 : : *
503 : : * The routines in dfmgr.c are relatively slow, so we try to avoid running
504 : : * them more than once per external function per session. We use a hash table
505 : : * with the function OID as the lookup key.
506 : : *-------------------------------------------------------------------------
507 : : */
508 : :
509 : : /*
510 : : * lookup_C_func: try to find a C function in the hash table
511 : : *
512 : : * If an entry exists and is up to date, return it; else return NULL
513 : : */
514 : : static CFuncHashTabEntry *
7391 515 : 46885 : lookup_C_func(HeapTuple procedureTuple)
516 : : {
1972 andres@anarazel.de 517 : 46885 : Oid fn_oid = ((Form_pg_proc) GETSTRUCT(procedureTuple))->oid;
518 : : CFuncHashTabEntry *entry;
519 : :
7391 tgl@sss.pgh.pa.us 520 [ + + ]: 46885 : if (CFuncHash == NULL)
521 : 1764 : return NULL; /* no table yet */
522 : : entry = (CFuncHashTabEntry *)
523 : 45121 : hash_search(CFuncHash,
524 : : &fn_oid,
525 : : HASH_FIND,
526 : : NULL);
527 [ + + ]: 45121 : if (entry == NULL)
528 : 1740 : return NULL; /* no such entry */
3766 rhaas@postgresql.org 529 [ + + + - ]: 86761 : if (entry->fn_xmin == HeapTupleHeaderGetRawXmin(procedureTuple->t_data) &&
6274 tgl@sss.pgh.pa.us 530 : 43380 : ItemPointerEquals(&entry->fn_tid, &procedureTuple->t_self))
7391 531 : 43380 : return entry; /* OK */
532 : 1 : return NULL; /* entry is out of date */
533 : : }
534 : :
535 : : /*
536 : : * record_C_func: enter (or update) info about a C function in the hash table
537 : : */
538 : : static void
539 : 3505 : record_C_func(HeapTuple procedureTuple,
540 : : PGFunction user_fn, const Pg_finfo_record *inforec)
541 : : {
1789 542 : 3505 : Oid fn_oid = ((Form_pg_proc) GETSTRUCT(procedureTuple))->oid;
543 : : CFuncHashTabEntry *entry;
544 : : bool found;
545 : :
546 : : /* Create the hash table if it doesn't exist yet */
7391 547 [ + + ]: 3505 : if (CFuncHash == NULL)
548 : : {
549 : : HASHCTL hash_ctl;
550 : :
551 : 1764 : hash_ctl.keysize = sizeof(Oid);
552 : 1764 : hash_ctl.entrysize = sizeof(CFuncHashTabEntry);
553 : 1764 : CFuncHash = hash_create("CFuncHash",
554 : : 100,
555 : : &hash_ctl,
556 : : HASH_ELEM | HASH_BLOBS);
557 : : }
558 : :
559 : : entry = (CFuncHashTabEntry *)
560 : 3505 : hash_search(CFuncHash,
561 : : &fn_oid,
562 : : HASH_ENTER,
563 : : &found);
564 : : /* OID is already filled in */
3766 rhaas@postgresql.org 565 : 3505 : entry->fn_xmin = HeapTupleHeaderGetRawXmin(procedureTuple->t_data);
6274 tgl@sss.pgh.pa.us 566 : 3505 : entry->fn_tid = procedureTuple->t_self;
7391 567 : 3505 : entry->user_fn = user_fn;
568 : 3505 : entry->inforec = inforec;
569 : 3505 : }
570 : :
571 : :
572 : : /*
573 : : * Copy an FmgrInfo struct
574 : : *
575 : : * This is inherently somewhat bogus since we can't reliably duplicate
576 : : * language-dependent subsidiary info. We cheat by zeroing fn_extra,
577 : : * instead, meaning that subsidiary info will have to be recomputed.
578 : : */
579 : : void
8226 580 : 20063682 : fmgr_info_copy(FmgrInfo *dstinfo, FmgrInfo *srcinfo,
581 : : MemoryContext destcxt)
582 : : {
583 : 20063682 : memcpy(dstinfo, srcinfo, sizeof(FmgrInfo));
584 : 20063682 : dstinfo->fn_mcxt = destcxt;
2573 andres@anarazel.de 585 : 20063682 : dstinfo->fn_extra = NULL;
8226 tgl@sss.pgh.pa.us 586 : 20063682 : }
587 : :
588 : :
589 : : /*
590 : : * Specialized lookup routine for fmgr_internal_validator: given the alleged
591 : : * name of an internal function, return the OID of the function.
592 : : * If the name is not recognized, return InvalidOid.
593 : : */
594 : : Oid
8546 595 : 1994 : fmgr_internal_function(const char *proname)
596 : : {
8722 597 : 1994 : const FmgrBuiltin *fbp = fmgr_lookupByName(proname);
598 : :
599 [ + + ]: 1994 : if (fbp == NULL)
600 : 3 : return InvalidOid;
8546 601 : 1991 : return fbp->foid;
602 : : }
603 : :
604 : :
605 : : /*
606 : : * Support for security-definer and proconfig-using functions. We support
607 : : * both of these features using the same call handler, because they are
608 : : * often used together and it would be inefficient (as well as notationally
609 : : * messy) to have two levels of call handler involved.
610 : : */
611 : : struct fmgr_security_definer_cache
612 : : {
613 : : FmgrInfo flinfo; /* lookup info for target function */
614 : : Oid userid; /* userid to set, or InvalidOid */
615 : : List *configNames; /* GUC names to set, or NIL */
616 : : List *configHandles; /* GUC handles to set, or NIL */
617 : : List *configValues; /* GUC values to set, or NIL */
618 : : Datum arg; /* passthrough argument for plugin modules */
619 : : };
620 : :
621 : : /*
622 : : * Function handler for security-definer/proconfig/plugin-hooked functions.
623 : : * We extract the OID of the actual function and do a fmgr lookup again.
624 : : * Then we fetch the pg_proc row and copy the owner ID and proconfig fields.
625 : : * (All this info is cached for the duration of the current query.)
626 : : * To execute a call, we temporarily replace the flinfo with the cached
627 : : * and looked-up one, while keeping the outer fcinfo (which contains all
628 : : * the actual arguments, etc.) intact. This is not re-entrant, but then
629 : : * the fcinfo itself can't be used reentrantly anyway.
630 : : */
631 : : extern Datum
8002 peter_e@gmx.net 632 : 176 : fmgr_security_definer(PG_FUNCTION_ARGS)
633 : : {
634 : : Datum result;
635 : : struct fmgr_security_definer_cache *volatile fcache;
636 : : FmgrInfo *save_flinfo;
637 : : Oid save_userid;
638 : : int save_sec_context;
639 : : ListCell *lc1,
640 : : *lc2,
641 : : *lc3;
642 : : volatile int save_nestlevel;
643 : : PgStat_FunctionCallUsage fcusage;
644 : :
645 [ + + ]: 176 : if (!fcinfo->flinfo->fn_extra)
646 : : {
647 : : HeapTuple tuple;
648 : : Form_pg_proc procedureStruct;
649 : : Datum datum;
650 : : bool isnull;
651 : : MemoryContext oldcxt;
652 : :
6956 tgl@sss.pgh.pa.us 653 : 160 : fcache = MemoryContextAllocZero(fcinfo->flinfo->fn_mcxt,
654 : : sizeof(*fcache));
655 : :
8002 peter_e@gmx.net 656 : 160 : fmgr_info_cxt_security(fcinfo->flinfo->fn_oid, &fcache->flinfo,
657 : 160 : fcinfo->flinfo->fn_mcxt, true);
6102 tgl@sss.pgh.pa.us 658 : 160 : fcache->flinfo.fn_expr = fcinfo->flinfo->fn_expr;
659 : :
5173 rhaas@postgresql.org 660 : 160 : tuple = SearchSysCache1(PROCOID,
661 : 160 : ObjectIdGetDatum(fcinfo->flinfo->fn_oid));
8002 peter_e@gmx.net 662 [ - + ]: 160 : if (!HeapTupleIsValid(tuple))
7569 tgl@sss.pgh.pa.us 663 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for function %u",
664 : : fcinfo->flinfo->fn_oid);
6068 tgl@sss.pgh.pa.us 665 :CBC 160 : procedureStruct = (Form_pg_proc) GETSTRUCT(tuple);
666 : :
667 [ + + ]: 160 : if (procedureStruct->prosecdef)
668 : 138 : fcache->userid = procedureStruct->proowner;
669 : :
670 : 160 : datum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proconfig,
671 : : &isnull);
672 [ + + ]: 160 : if (!isnull)
673 : : {
674 : : ArrayType *array;
675 : : ListCell *lc;
676 : :
677 : 25 : oldcxt = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt);
248 jdavis@postgresql.or 678 :GNC 25 : array = DatumGetArrayTypeP(datum);
679 : 25 : TransformGUCArray(array, &fcache->configNames,
680 : 25 : &fcache->configValues);
681 : :
682 : : /* transform names to config handles to avoid lookup cost */
128 683 : 25 : fcache->configHandles = NIL;
684 [ + - + + : 50 : foreach(lc, fcache->configNames)
+ + ]
685 : : {
686 : 25 : char *name = (char *) lfirst(lc);
687 : :
688 : 25 : fcache->configHandles = lappend(fcache->configHandles,
689 : 25 : get_config_handle(name));
690 : : }
691 : :
6068 tgl@sss.pgh.pa.us 692 :CBC 25 : MemoryContextSwitchTo(oldcxt);
693 : : }
694 : :
8002 peter_e@gmx.net 695 : 160 : ReleaseSysCache(tuple);
696 : :
697 : 160 : fcinfo->flinfo->fn_extra = fcache;
698 : : }
699 : : else
700 : 16 : fcache = fcinfo->flinfo->fn_extra;
701 : :
702 : : /* GetUserIdAndSecContext is cheap enough that no harm in a wasted call */
5240 tgl@sss.pgh.pa.us 703 : 176 : GetUserIdAndSecContext(&save_userid, &save_sec_context);
247 michael@paquier.xyz 704 [ + + ]:GNC 176 : if (fcache->configNames != NIL) /* Need a new GUC nesting level */
6068 tgl@sss.pgh.pa.us 705 :CBC 41 : save_nestlevel = NewGUCNestLevel();
706 : : else
707 : 135 : save_nestlevel = 0; /* keep compiler quiet */
708 : :
5946 709 [ + + ]: 176 : if (OidIsValid(fcache->userid))
5240 710 : 154 : SetUserIdAndSecContext(fcache->userid,
711 : : save_sec_context | SECURITY_LOCAL_USERID_CHANGE);
712 : :
128 jdavis@postgresql.or 713 [ + + + + :GNC 214 : forthree(lc1, fcache->configNames,
+ + + + +
+ + + + +
+ - + - +
+ ]
714 : : lc2, fcache->configHandles,
715 : : lc3, fcache->configValues)
716 : : {
247 michael@paquier.xyz 717 [ + + ]: 41 : GucContext context = superuser() ? PGC_SUSET : PGC_USERSET;
718 : 41 : GucSource source = PGC_S_SESSION;
719 : 41 : GucAction action = GUC_ACTION_SAVE;
720 : 41 : char *name = lfirst(lc1);
128 jdavis@postgresql.or 721 : 41 : config_handle *handle = lfirst(lc2);
722 : 41 : char *value = lfirst(lc3);
723 : :
724 : 41 : (void) set_config_with_handle(name, handle, value,
725 : : context, source, GetUserId(),
726 : : action, true, 0, false);
727 : : }
728 : :
729 : : /* function manager hook */
4871 rhaas@postgresql.org 730 [ - + ]:CBC 173 : if (fmgr_hook)
4753 bruce@momjian.us 731 :UBC 0 : (*fmgr_hook) (FHET_START, &fcache->flinfo, &fcache->arg);
732 : :
733 : : /*
734 : : * We don't need to restore GUC or userid settings on error, because the
735 : : * ensuing xact or subxact abort will do that. The PG_TRY block is only
736 : : * needed to clean up the flinfo link.
737 : : */
5946 tgl@sss.pgh.pa.us 738 :CBC 173 : save_flinfo = fcinfo->flinfo;
739 : :
740 [ + + ]: 173 : PG_TRY();
741 : : {
742 : 173 : fcinfo->flinfo = &fcache->flinfo;
743 : :
744 : : /* See notes in fmgr_info_cxt_security */
5813 745 : 173 : pgstat_init_function_usage(fcinfo, &fcusage);
746 : :
7135 747 : 173 : result = FunctionCallInvoke(fcinfo);
748 : :
749 : : /*
750 : : * We could be calling either a regular or a set-returning function,
751 : : * so we have to test to see what finalize flag to use.
752 : : */
5813 753 : 168 : pgstat_end_function_usage(&fcusage,
5813 tgl@sss.pgh.pa.us 754 :UBC 0 : (fcinfo->resultinfo == NULL ||
5813 tgl@sss.pgh.pa.us 755 [ - + - - ]:CBC 168 : !IsA(fcinfo->resultinfo, ReturnSetInfo) ||
5813 tgl@sss.pgh.pa.us 756 [ # # ]:LBC (41) : ((ReturnSetInfo *) fcinfo->resultinfo)->isDone != ExprMultipleResult));
757 : : }
7135 tgl@sss.pgh.pa.us 758 :CBC 5 : PG_CATCH();
759 : : {
760 : 5 : fcinfo->flinfo = save_flinfo;
4871 rhaas@postgresql.org 761 [ - + ]: 5 : if (fmgr_hook)
4753 bruce@momjian.us 762 :UBC 0 : (*fmgr_hook) (FHET_ABORT, &fcache->flinfo, &fcache->arg);
7135 tgl@sss.pgh.pa.us 763 :CBC 5 : PG_RE_THROW();
764 : : }
765 [ - + ]: 168 : PG_END_TRY();
766 : :
8002 peter_e@gmx.net 767 : 168 : fcinfo->flinfo = save_flinfo;
768 : :
248 jdavis@postgresql.or 769 [ + + ]:GNC 168 : if (fcache->configNames != NIL)
6068 tgl@sss.pgh.pa.us 770 :CBC 34 : AtEOXact_GUC(true, save_nestlevel);
771 [ + + ]: 168 : if (OidIsValid(fcache->userid))
5240 772 : 153 : SetUserIdAndSecContext(save_userid, save_sec_context);
4871 rhaas@postgresql.org 773 [ - + ]: 168 : if (fmgr_hook)
4753 bruce@momjian.us 774 :UBC 0 : (*fmgr_hook) (FHET_END, &fcache->flinfo, &fcache->arg);
775 : :
8002 peter_e@gmx.net 776 :CBC 168 : return result;
777 : : }
778 : :
779 : :
780 : : /*-------------------------------------------------------------------------
781 : : * Support routines for callers of fmgr-compatible functions
782 : : *-------------------------------------------------------------------------
783 : : */
784 : :
785 : : /*
786 : : * These are for invocation of a specifically named function with a
787 : : * directly-computed parameter list. Note that neither arguments nor result
788 : : * are allowed to be NULL. Also, the function cannot be one that needs to
789 : : * look at FmgrInfo, since there won't be any.
790 : : */
791 : : Datum
4751 tgl@sss.pgh.pa.us 792 : 1405625 : DirectFunctionCall1Coll(PGFunction func, Oid collation, Datum arg1)
793 : : {
1905 andres@anarazel.de 794 : 1405625 : LOCAL_FCINFO(fcinfo, 1);
795 : : Datum result;
796 : :
797 : 1405625 : InitFunctionCallInfoData(*fcinfo, NULL, 1, collation, NULL, NULL);
798 : :
799 : 1405625 : fcinfo->args[0].value = arg1;
800 : 1405625 : fcinfo->args[0].isnull = false;
801 : :
802 : 1405625 : result = (*func) (fcinfo);
803 : :
804 : : /* Check for null result, since caller is clearly not expecting one */
805 [ - + ]: 1405598 : if (fcinfo->isnull)
7569 tgl@sss.pgh.pa.us 806 [ # # ]:UBC 0 : elog(ERROR, "function %p returned NULL", (void *) func);
807 : :
8722 tgl@sss.pgh.pa.us 808 :CBC 1405598 : return result;
809 : : }
810 : :
811 : : Datum
4751 812 : 19898010 : DirectFunctionCall2Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2)
813 : : {
1905 andres@anarazel.de 814 : 19898010 : LOCAL_FCINFO(fcinfo, 2);
815 : : Datum result;
816 : :
817 : 19898010 : InitFunctionCallInfoData(*fcinfo, NULL, 2, collation, NULL, NULL);
818 : :
819 : 19898010 : fcinfo->args[0].value = arg1;
820 : 19898010 : fcinfo->args[0].isnull = false;
821 : 19898010 : fcinfo->args[1].value = arg2;
822 : 19898010 : fcinfo->args[1].isnull = false;
823 : :
824 : 19898010 : result = (*func) (fcinfo);
825 : :
826 : : /* Check for null result, since caller is clearly not expecting one */
827 [ - + ]: 19897965 : if (fcinfo->isnull)
7569 tgl@sss.pgh.pa.us 828 [ # # ]:UBC 0 : elog(ERROR, "function %p returned NULL", (void *) func);
829 : :
8722 tgl@sss.pgh.pa.us 830 :CBC 19897965 : return result;
831 : : }
832 : :
833 : : Datum
4751 834 : 40934 : DirectFunctionCall3Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2,
835 : : Datum arg3)
836 : : {
1905 andres@anarazel.de 837 : 40934 : LOCAL_FCINFO(fcinfo, 3);
838 : : Datum result;
839 : :
840 : 40934 : InitFunctionCallInfoData(*fcinfo, NULL, 3, collation, NULL, NULL);
841 : :
842 : 40934 : fcinfo->args[0].value = arg1;
843 : 40934 : fcinfo->args[0].isnull = false;
844 : 40934 : fcinfo->args[1].value = arg2;
845 : 40934 : fcinfo->args[1].isnull = false;
846 : 40934 : fcinfo->args[2].value = arg3;
847 : 40934 : fcinfo->args[2].isnull = false;
848 : :
849 : 40934 : result = (*func) (fcinfo);
850 : :
851 : : /* Check for null result, since caller is clearly not expecting one */
852 [ - + ]: 40915 : if (fcinfo->isnull)
7569 tgl@sss.pgh.pa.us 853 [ # # ]:UBC 0 : elog(ERROR, "function %p returned NULL", (void *) func);
854 : :
8722 tgl@sss.pgh.pa.us 855 :CBC 40915 : return result;
856 : : }
857 : :
858 : : Datum
4751 859 : 478 : DirectFunctionCall4Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2,
860 : : Datum arg3, Datum arg4)
861 : : {
1905 andres@anarazel.de 862 : 478 : LOCAL_FCINFO(fcinfo, 4);
863 : : Datum result;
864 : :
865 : 478 : InitFunctionCallInfoData(*fcinfo, NULL, 4, collation, NULL, NULL);
866 : :
867 : 478 : fcinfo->args[0].value = arg1;
868 : 478 : fcinfo->args[0].isnull = false;
869 : 478 : fcinfo->args[1].value = arg2;
870 : 478 : fcinfo->args[1].isnull = false;
871 : 478 : fcinfo->args[2].value = arg3;
872 : 478 : fcinfo->args[2].isnull = false;
873 : 478 : fcinfo->args[3].value = arg4;
874 : 478 : fcinfo->args[3].isnull = false;
875 : :
876 : 478 : result = (*func) (fcinfo);
877 : :
878 : : /* Check for null result, since caller is clearly not expecting one */
879 [ - + ]: 478 : if (fcinfo->isnull)
7569 tgl@sss.pgh.pa.us 880 [ # # ]:UBC 0 : elog(ERROR, "function %p returned NULL", (void *) func);
881 : :
8722 tgl@sss.pgh.pa.us 882 :CBC 478 : return result;
883 : : }
884 : :
885 : : Datum
4751 886 : 2293 : DirectFunctionCall5Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2,
887 : : Datum arg3, Datum arg4, Datum arg5)
888 : : {
1905 andres@anarazel.de 889 : 2293 : LOCAL_FCINFO(fcinfo, 5);
890 : : Datum result;
891 : :
892 : 2293 : InitFunctionCallInfoData(*fcinfo, NULL, 5, collation, NULL, NULL);
893 : :
894 : 2293 : fcinfo->args[0].value = arg1;
895 : 2293 : fcinfo->args[0].isnull = false;
896 : 2293 : fcinfo->args[1].value = arg2;
897 : 2293 : fcinfo->args[1].isnull = false;
898 : 2293 : fcinfo->args[2].value = arg3;
899 : 2293 : fcinfo->args[2].isnull = false;
900 : 2293 : fcinfo->args[3].value = arg4;
901 : 2293 : fcinfo->args[3].isnull = false;
902 : 2293 : fcinfo->args[4].value = arg5;
903 : 2293 : fcinfo->args[4].isnull = false;
904 : :
905 : 2293 : result = (*func) (fcinfo);
906 : :
907 : : /* Check for null result, since caller is clearly not expecting one */
908 [ - + ]: 2290 : if (fcinfo->isnull)
7569 tgl@sss.pgh.pa.us 909 [ # # ]:UBC 0 : elog(ERROR, "function %p returned NULL", (void *) func);
910 : :
8722 tgl@sss.pgh.pa.us 911 :CBC 2290 : return result;
912 : : }
913 : :
914 : : Datum
4751 tgl@sss.pgh.pa.us 915 :UBC 0 : DirectFunctionCall6Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2,
916 : : Datum arg3, Datum arg4, Datum arg5,
917 : : Datum arg6)
918 : : {
1905 andres@anarazel.de 919 : 0 : LOCAL_FCINFO(fcinfo, 6);
920 : : Datum result;
921 : :
922 : 0 : InitFunctionCallInfoData(*fcinfo, NULL, 6, collation, NULL, NULL);
923 : :
924 : 0 : fcinfo->args[0].value = arg1;
925 : 0 : fcinfo->args[0].isnull = false;
926 : 0 : fcinfo->args[1].value = arg2;
927 : 0 : fcinfo->args[1].isnull = false;
928 : 0 : fcinfo->args[2].value = arg3;
929 : 0 : fcinfo->args[2].isnull = false;
930 : 0 : fcinfo->args[3].value = arg4;
931 : 0 : fcinfo->args[3].isnull = false;
932 : 0 : fcinfo->args[4].value = arg5;
933 : 0 : fcinfo->args[4].isnull = false;
934 : 0 : fcinfo->args[5].value = arg6;
935 : 0 : fcinfo->args[5].isnull = false;
936 : :
937 : 0 : result = (*func) (fcinfo);
938 : :
939 : : /* Check for null result, since caller is clearly not expecting one */
940 [ # # ]: 0 : if (fcinfo->isnull)
7569 tgl@sss.pgh.pa.us 941 [ # # ]: 0 : elog(ERROR, "function %p returned NULL", (void *) func);
942 : :
8722 943 : 0 : return result;
944 : : }
945 : :
946 : : Datum
4751 947 : 0 : DirectFunctionCall7Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2,
948 : : Datum arg3, Datum arg4, Datum arg5,
949 : : Datum arg6, Datum arg7)
950 : : {
1905 andres@anarazel.de 951 : 0 : LOCAL_FCINFO(fcinfo, 7);
952 : : Datum result;
953 : :
954 : 0 : InitFunctionCallInfoData(*fcinfo, NULL, 7, collation, NULL, NULL);
955 : :
956 : 0 : fcinfo->args[0].value = arg1;
957 : 0 : fcinfo->args[0].isnull = false;
958 : 0 : fcinfo->args[1].value = arg2;
959 : 0 : fcinfo->args[1].isnull = false;
960 : 0 : fcinfo->args[2].value = arg3;
961 : 0 : fcinfo->args[2].isnull = false;
962 : 0 : fcinfo->args[3].value = arg4;
963 : 0 : fcinfo->args[3].isnull = false;
964 : 0 : fcinfo->args[4].value = arg5;
965 : 0 : fcinfo->args[4].isnull = false;
966 : 0 : fcinfo->args[5].value = arg6;
967 : 0 : fcinfo->args[5].isnull = false;
968 : 0 : fcinfo->args[6].value = arg7;
969 : 0 : fcinfo->args[6].isnull = false;
970 : :
971 : 0 : result = (*func) (fcinfo);
972 : :
973 : : /* Check for null result, since caller is clearly not expecting one */
974 [ # # ]: 0 : if (fcinfo->isnull)
7569 tgl@sss.pgh.pa.us 975 [ # # ]: 0 : elog(ERROR, "function %p returned NULL", (void *) func);
976 : :
8722 977 : 0 : return result;
978 : : }
979 : :
980 : : Datum
4751 981 : 0 : DirectFunctionCall8Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2,
982 : : Datum arg3, Datum arg4, Datum arg5,
983 : : Datum arg6, Datum arg7, Datum arg8)
984 : : {
1905 andres@anarazel.de 985 : 0 : LOCAL_FCINFO(fcinfo, 8);
986 : : Datum result;
987 : :
988 : 0 : InitFunctionCallInfoData(*fcinfo, NULL, 8, collation, NULL, NULL);
989 : :
990 : 0 : fcinfo->args[0].value = arg1;
991 : 0 : fcinfo->args[0].isnull = false;
992 : 0 : fcinfo->args[1].value = arg2;
993 : 0 : fcinfo->args[1].isnull = false;
994 : 0 : fcinfo->args[2].value = arg3;
995 : 0 : fcinfo->args[2].isnull = false;
996 : 0 : fcinfo->args[3].value = arg4;
997 : 0 : fcinfo->args[3].isnull = false;
998 : 0 : fcinfo->args[4].value = arg5;
999 : 0 : fcinfo->args[4].isnull = false;
1000 : 0 : fcinfo->args[5].value = arg6;
1001 : 0 : fcinfo->args[5].isnull = false;
1002 : 0 : fcinfo->args[6].value = arg7;
1003 : 0 : fcinfo->args[6].isnull = false;
1004 : 0 : fcinfo->args[7].value = arg8;
1005 : 0 : fcinfo->args[7].isnull = false;
1006 : :
1007 : 0 : result = (*func) (fcinfo);
1008 : :
1009 : : /* Check for null result, since caller is clearly not expecting one */
1010 [ # # ]: 0 : if (fcinfo->isnull)
7569 tgl@sss.pgh.pa.us 1011 [ # # ]: 0 : elog(ERROR, "function %p returned NULL", (void *) func);
1012 : :
8722 1013 : 0 : return result;
1014 : : }
1015 : :
1016 : : Datum
4751 1017 : 0 : DirectFunctionCall9Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2,
1018 : : Datum arg3, Datum arg4, Datum arg5,
1019 : : Datum arg6, Datum arg7, Datum arg8,
1020 : : Datum arg9)
1021 : : {
1905 andres@anarazel.de 1022 : 0 : LOCAL_FCINFO(fcinfo, 9);
1023 : : Datum result;
1024 : :
1025 : 0 : InitFunctionCallInfoData(*fcinfo, NULL, 9, collation, NULL, NULL);
1026 : :
1027 : 0 : fcinfo->args[0].value = arg1;
1028 : 0 : fcinfo->args[0].isnull = false;
1029 : 0 : fcinfo->args[1].value = arg2;
1030 : 0 : fcinfo->args[1].isnull = false;
1031 : 0 : fcinfo->args[2].value = arg3;
1032 : 0 : fcinfo->args[2].isnull = false;
1033 : 0 : fcinfo->args[3].value = arg4;
1034 : 0 : fcinfo->args[3].isnull = false;
1035 : 0 : fcinfo->args[4].value = arg5;
1036 : 0 : fcinfo->args[4].isnull = false;
1037 : 0 : fcinfo->args[5].value = arg6;
1038 : 0 : fcinfo->args[5].isnull = false;
1039 : 0 : fcinfo->args[6].value = arg7;
1040 : 0 : fcinfo->args[6].isnull = false;
1041 : 0 : fcinfo->args[7].value = arg8;
1042 : 0 : fcinfo->args[7].isnull = false;
1043 : 0 : fcinfo->args[8].value = arg9;
1044 : 0 : fcinfo->args[8].isnull = false;
1045 : :
1046 : 0 : result = (*func) (fcinfo);
1047 : :
1048 : : /* Check for null result, since caller is clearly not expecting one */
1049 [ # # ]: 0 : if (fcinfo->isnull)
7569 tgl@sss.pgh.pa.us 1050 [ # # ]: 0 : elog(ERROR, "function %p returned NULL", (void *) func);
1051 : :
8722 1052 : 0 : return result;
1053 : : }
1054 : :
1055 : : /*
1056 : : * These functions work like the DirectFunctionCall functions except that
1057 : : * they use the flinfo parameter to initialise the fcinfo for the call.
1058 : : * It's recommended that the callee only use the fn_extra and fn_mcxt
1059 : : * fields, as other fields will typically describe the calling function
1060 : : * not the callee. Conversely, the calling function should not have
1061 : : * used fn_extra, unless its use is known to be compatible with the callee's.
1062 : : */
1063 : :
1064 : : Datum
2581 andrew@dunslane.net 1065 : 0 : CallerFInfoFunctionCall1(PGFunction func, FmgrInfo *flinfo, Oid collation, Datum arg1)
1066 : : {
1905 andres@anarazel.de 1067 : 0 : LOCAL_FCINFO(fcinfo, 1);
1068 : : Datum result;
1069 : :
1070 : 0 : InitFunctionCallInfoData(*fcinfo, flinfo, 1, collation, NULL, NULL);
1071 : :
1072 : 0 : fcinfo->args[0].value = arg1;
1073 : 0 : fcinfo->args[0].isnull = false;
1074 : :
1075 : 0 : result = (*func) (fcinfo);
1076 : :
1077 : : /* Check for null result, since caller is clearly not expecting one */
1078 [ # # ]: 0 : if (fcinfo->isnull)
2581 andrew@dunslane.net 1079 [ # # ]: 0 : elog(ERROR, "function %p returned NULL", (void *) func);
1080 : :
1081 : 0 : return result;
1082 : : }
1083 : :
1084 : : Datum
2581 andrew@dunslane.net 1085 :CBC 205034 : CallerFInfoFunctionCall2(PGFunction func, FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
1086 : : {
1905 andres@anarazel.de 1087 : 205034 : LOCAL_FCINFO(fcinfo, 2);
1088 : : Datum result;
1089 : :
1090 : 205034 : InitFunctionCallInfoData(*fcinfo, flinfo, 2, collation, NULL, NULL);
1091 : :
1092 : 205034 : fcinfo->args[0].value = arg1;
1093 : 205034 : fcinfo->args[0].isnull = false;
1094 : 205034 : fcinfo->args[1].value = arg2;
1095 : 205034 : fcinfo->args[1].isnull = false;
1096 : :
1097 : 205034 : result = (*func) (fcinfo);
1098 : :
1099 : : /* Check for null result, since caller is clearly not expecting one */
1100 [ - + ]: 205034 : if (fcinfo->isnull)
2581 andrew@dunslane.net 1101 [ # # ]:UBC 0 : elog(ERROR, "function %p returned NULL", (void *) func);
1102 : :
2581 andrew@dunslane.net 1103 :CBC 205034 : return result;
1104 : : }
1105 : :
1106 : : /*
1107 : : * These are for invocation of a previously-looked-up function with a
1108 : : * directly-computed parameter list. Note that neither arguments nor result
1109 : : * are allowed to be NULL.
1110 : : */
1111 : : Datum
1905 andres@anarazel.de 1112 : 2403639 : FunctionCall0Coll(FmgrInfo *flinfo, Oid collation)
1113 : : {
1114 : 2403639 : LOCAL_FCINFO(fcinfo, 0);
1115 : : Datum result;
1116 : :
1117 : 2403639 : InitFunctionCallInfoData(*fcinfo, flinfo, 0, collation, NULL, NULL);
1118 : :
1119 : 2403639 : result = FunctionCallInvoke(fcinfo);
1120 : :
1121 : : /* Check for null result, since caller is clearly not expecting one */
1122 [ - + ]: 2403639 : if (fcinfo->isnull)
1905 andres@anarazel.de 1123 [ # # ]:UBC 0 : elog(ERROR, "function %u returned NULL", flinfo->fn_oid);
1124 : :
1905 andres@anarazel.de 1125 :CBC 2403639 : return result;
1126 : : }
1127 : :
1128 : : Datum
4751 tgl@sss.pgh.pa.us 1129 : 46125309 : FunctionCall1Coll(FmgrInfo *flinfo, Oid collation, Datum arg1)
1130 : : {
1905 andres@anarazel.de 1131 : 46125309 : LOCAL_FCINFO(fcinfo, 1);
1132 : : Datum result;
1133 : :
1134 : 46125309 : InitFunctionCallInfoData(*fcinfo, flinfo, 1, collation, NULL, NULL);
1135 : :
1136 : 46125309 : fcinfo->args[0].value = arg1;
1137 : 46125309 : fcinfo->args[0].isnull = false;
1138 : :
1139 : 46125309 : result = FunctionCallInvoke(fcinfo);
1140 : :
1141 : : /* Check for null result, since caller is clearly not expecting one */
1142 [ - + ]: 46124986 : if (fcinfo->isnull)
1905 andres@anarazel.de 1143 [ # # ]:UBC 0 : elog(ERROR, "function %u returned NULL", flinfo->fn_oid);
1144 : :
8722 tgl@sss.pgh.pa.us 1145 :CBC 46124986 : return result;
1146 : : }
1147 : :
1148 : : Datum
4751 1149 : 371777124 : FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
1150 : : {
1905 andres@anarazel.de 1151 : 371777124 : LOCAL_FCINFO(fcinfo, 2);
1152 : : Datum result;
1153 : :
1154 : 371777124 : InitFunctionCallInfoData(*fcinfo, flinfo, 2, collation, NULL, NULL);
1155 : :
1156 : 371777124 : fcinfo->args[0].value = arg1;
1157 : 371777124 : fcinfo->args[0].isnull = false;
1158 : 371777124 : fcinfo->args[1].value = arg2;
1159 : 371777124 : fcinfo->args[1].isnull = false;
1160 : :
1161 : 371777124 : result = FunctionCallInvoke(fcinfo);
1162 : :
1163 : : /* Check for null result, since caller is clearly not expecting one */
1164 [ - + ]: 371777065 : if (fcinfo->isnull)
1905 andres@anarazel.de 1165 [ # # ]:UBC 0 : elog(ERROR, "function %u returned NULL", flinfo->fn_oid);
1166 : :
8722 tgl@sss.pgh.pa.us 1167 :CBC 371777065 : return result;
1168 : : }
1169 : :
1170 : : Datum
4751 1171 : 24148168 : FunctionCall3Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2,
1172 : : Datum arg3)
1173 : : {
1905 andres@anarazel.de 1174 : 24148168 : LOCAL_FCINFO(fcinfo, 3);
1175 : : Datum result;
1176 : :
1177 : 24148168 : InitFunctionCallInfoData(*fcinfo, flinfo, 3, collation, NULL, NULL);
1178 : :
1179 : 24148168 : fcinfo->args[0].value = arg1;
1180 : 24148168 : fcinfo->args[0].isnull = false;
1181 : 24148168 : fcinfo->args[1].value = arg2;
1182 : 24148168 : fcinfo->args[1].isnull = false;
1183 : 24148168 : fcinfo->args[2].value = arg3;
1184 : 24148168 : fcinfo->args[2].isnull = false;
1185 : :
1186 : 24148168 : result = FunctionCallInvoke(fcinfo);
1187 : :
1188 : : /* Check for null result, since caller is clearly not expecting one */
1189 [ - + ]: 24148168 : if (fcinfo->isnull)
1905 andres@anarazel.de 1190 [ # # ]:UBC 0 : elog(ERROR, "function %u returned NULL", flinfo->fn_oid);
1191 : :
8722 tgl@sss.pgh.pa.us 1192 :CBC 24148168 : return result;
1193 : : }
1194 : :
1195 : : Datum
4751 1196 : 864428 : FunctionCall4Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2,
1197 : : Datum arg3, Datum arg4)
1198 : : {
1905 andres@anarazel.de 1199 : 864428 : LOCAL_FCINFO(fcinfo, 4);
1200 : : Datum result;
1201 : :
1202 : 864428 : InitFunctionCallInfoData(*fcinfo, flinfo, 4, collation, NULL, NULL);
1203 : :
1204 : 864428 : fcinfo->args[0].value = arg1;
1205 : 864428 : fcinfo->args[0].isnull = false;
1206 : 864428 : fcinfo->args[1].value = arg2;
1207 : 864428 : fcinfo->args[1].isnull = false;
1208 : 864428 : fcinfo->args[2].value = arg3;
1209 : 864428 : fcinfo->args[2].isnull = false;
1210 : 864428 : fcinfo->args[3].value = arg4;
1211 : 864428 : fcinfo->args[3].isnull = false;
1212 : :
1213 : 864428 : result = FunctionCallInvoke(fcinfo);
1214 : :
1215 : : /* Check for null result, since caller is clearly not expecting one */
1216 [ - + ]: 864416 : if (fcinfo->isnull)
1905 andres@anarazel.de 1217 [ # # ]:UBC 0 : elog(ERROR, "function %u returned NULL", flinfo->fn_oid);
1218 : :
8722 tgl@sss.pgh.pa.us 1219 :CBC 864416 : return result;
1220 : : }
1221 : :
1222 : : Datum
4751 1223 : 1114672 : FunctionCall5Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2,
1224 : : Datum arg3, Datum arg4, Datum arg5)
1225 : : {
1905 andres@anarazel.de 1226 : 1114672 : LOCAL_FCINFO(fcinfo, 5);
1227 : : Datum result;
1228 : :
1229 : 1114672 : InitFunctionCallInfoData(*fcinfo, flinfo, 5, collation, NULL, NULL);
1230 : :
1231 : 1114672 : fcinfo->args[0].value = arg1;
1232 : 1114672 : fcinfo->args[0].isnull = false;
1233 : 1114672 : fcinfo->args[1].value = arg2;
1234 : 1114672 : fcinfo->args[1].isnull = false;
1235 : 1114672 : fcinfo->args[2].value = arg3;
1236 : 1114672 : fcinfo->args[2].isnull = false;
1237 : 1114672 : fcinfo->args[3].value = arg4;
1238 : 1114672 : fcinfo->args[3].isnull = false;
1239 : 1114672 : fcinfo->args[4].value = arg5;
1240 : 1114672 : fcinfo->args[4].isnull = false;
1241 : :
1242 : 1114672 : result = FunctionCallInvoke(fcinfo);
1243 : :
1244 : : /* Check for null result, since caller is clearly not expecting one */
1245 [ - + ]: 1114624 : if (fcinfo->isnull)
1905 andres@anarazel.de 1246 [ # # ]:UBC 0 : elog(ERROR, "function %u returned NULL", flinfo->fn_oid);
1247 : :
8722 tgl@sss.pgh.pa.us 1248 :CBC 1114624 : return result;
1249 : : }
1250 : :
1251 : : Datum
4751 1252 : 3431 : FunctionCall6Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2,
1253 : : Datum arg3, Datum arg4, Datum arg5,
1254 : : Datum arg6)
1255 : : {
1905 andres@anarazel.de 1256 : 3431 : LOCAL_FCINFO(fcinfo, 6);
1257 : : Datum result;
1258 : :
1259 : 3431 : InitFunctionCallInfoData(*fcinfo, flinfo, 6, collation, NULL, NULL);
1260 : :
1261 : 3431 : fcinfo->args[0].value = arg1;
1262 : 3431 : fcinfo->args[0].isnull = false;
1263 : 3431 : fcinfo->args[1].value = arg2;
1264 : 3431 : fcinfo->args[1].isnull = false;
1265 : 3431 : fcinfo->args[2].value = arg3;
1266 : 3431 : fcinfo->args[2].isnull = false;
1267 : 3431 : fcinfo->args[3].value = arg4;
1268 : 3431 : fcinfo->args[3].isnull = false;
1269 : 3431 : fcinfo->args[4].value = arg5;
1270 : 3431 : fcinfo->args[4].isnull = false;
1271 : 3431 : fcinfo->args[5].value = arg6;
1272 : 3431 : fcinfo->args[5].isnull = false;
1273 : :
1274 : 3431 : result = FunctionCallInvoke(fcinfo);
1275 : :
1276 : : /* Check for null result, since caller is clearly not expecting one */
1277 [ - + ]: 2261 : if (fcinfo->isnull)
1905 andres@anarazel.de 1278 [ # # ]:UBC 0 : elog(ERROR, "function %u returned NULL", flinfo->fn_oid);
1279 : :
8722 tgl@sss.pgh.pa.us 1280 :CBC 2261 : return result;
1281 : : }
1282 : :
1283 : : Datum
4751 1284 : 486400 : FunctionCall7Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2,
1285 : : Datum arg3, Datum arg4, Datum arg5,
1286 : : Datum arg6, Datum arg7)
1287 : : {
1905 andres@anarazel.de 1288 : 486400 : LOCAL_FCINFO(fcinfo, 7);
1289 : : Datum result;
1290 : :
1291 : 486400 : InitFunctionCallInfoData(*fcinfo, flinfo, 7, collation, NULL, NULL);
1292 : :
1293 : 486400 : fcinfo->args[0].value = arg1;
1294 : 486400 : fcinfo->args[0].isnull = false;
1295 : 486400 : fcinfo->args[1].value = arg2;
1296 : 486400 : fcinfo->args[1].isnull = false;
1297 : 486400 : fcinfo->args[2].value = arg3;
1298 : 486400 : fcinfo->args[2].isnull = false;
1299 : 486400 : fcinfo->args[3].value = arg4;
1300 : 486400 : fcinfo->args[3].isnull = false;
1301 : 486400 : fcinfo->args[4].value = arg5;
1302 : 486400 : fcinfo->args[4].isnull = false;
1303 : 486400 : fcinfo->args[5].value = arg6;
1304 : 486400 : fcinfo->args[5].isnull = false;
1305 : 486400 : fcinfo->args[6].value = arg7;
1306 : 486400 : fcinfo->args[6].isnull = false;
1307 : :
1308 : 486400 : result = FunctionCallInvoke(fcinfo);
1309 : :
1310 : : /* Check for null result, since caller is clearly not expecting one */
1311 [ - + ]: 486400 : if (fcinfo->isnull)
1905 andres@anarazel.de 1312 [ # # ]:UBC 0 : elog(ERROR, "function %u returned NULL", flinfo->fn_oid);
1313 : :
8722 tgl@sss.pgh.pa.us 1314 :CBC 486400 : return result;
1315 : : }
1316 : :
1317 : : Datum
4751 1318 : 18727 : FunctionCall8Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2,
1319 : : Datum arg3, Datum arg4, Datum arg5,
1320 : : Datum arg6, Datum arg7, Datum arg8)
1321 : : {
1905 andres@anarazel.de 1322 : 18727 : LOCAL_FCINFO(fcinfo, 8);
1323 : : Datum result;
1324 : :
1325 : 18727 : InitFunctionCallInfoData(*fcinfo, flinfo, 8, collation, NULL, NULL);
1326 : :
1327 : 18727 : fcinfo->args[0].value = arg1;
1328 : 18727 : fcinfo->args[0].isnull = false;
1329 : 18727 : fcinfo->args[1].value = arg2;
1330 : 18727 : fcinfo->args[1].isnull = false;
1331 : 18727 : fcinfo->args[2].value = arg3;
1332 : 18727 : fcinfo->args[2].isnull = false;
1333 : 18727 : fcinfo->args[3].value = arg4;
1334 : 18727 : fcinfo->args[3].isnull = false;
1335 : 18727 : fcinfo->args[4].value = arg5;
1336 : 18727 : fcinfo->args[4].isnull = false;
1337 : 18727 : fcinfo->args[5].value = arg6;
1338 : 18727 : fcinfo->args[5].isnull = false;
1339 : 18727 : fcinfo->args[6].value = arg7;
1340 : 18727 : fcinfo->args[6].isnull = false;
1341 : 18727 : fcinfo->args[7].value = arg8;
1342 : 18727 : fcinfo->args[7].isnull = false;
1343 : :
1344 : 18727 : result = FunctionCallInvoke(fcinfo);
1345 : :
1346 : : /* Check for null result, since caller is clearly not expecting one */
1347 [ - + ]: 18727 : if (fcinfo->isnull)
1905 andres@anarazel.de 1348 [ # # ]:UBC 0 : elog(ERROR, "function %u returned NULL", flinfo->fn_oid);
1349 : :
8722 tgl@sss.pgh.pa.us 1350 :CBC 18727 : return result;
1351 : : }
1352 : :
1353 : : Datum
4751 tgl@sss.pgh.pa.us 1354 :UBC 0 : FunctionCall9Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2,
1355 : : Datum arg3, Datum arg4, Datum arg5,
1356 : : Datum arg6, Datum arg7, Datum arg8,
1357 : : Datum arg9)
1358 : : {
1905 andres@anarazel.de 1359 : 0 : LOCAL_FCINFO(fcinfo, 9);
1360 : : Datum result;
1361 : :
1362 : 0 : InitFunctionCallInfoData(*fcinfo, flinfo, 9, collation, NULL, NULL);
1363 : :
1364 : 0 : fcinfo->args[0].value = arg1;
1365 : 0 : fcinfo->args[0].isnull = false;
1366 : 0 : fcinfo->args[1].value = arg2;
1367 : 0 : fcinfo->args[1].isnull = false;
1368 : 0 : fcinfo->args[2].value = arg3;
1369 : 0 : fcinfo->args[2].isnull = false;
1370 : 0 : fcinfo->args[3].value = arg4;
1371 : 0 : fcinfo->args[3].isnull = false;
1372 : 0 : fcinfo->args[4].value = arg5;
1373 : 0 : fcinfo->args[4].isnull = false;
1374 : 0 : fcinfo->args[5].value = arg6;
1375 : 0 : fcinfo->args[5].isnull = false;
1376 : 0 : fcinfo->args[6].value = arg7;
1377 : 0 : fcinfo->args[6].isnull = false;
1378 : 0 : fcinfo->args[7].value = arg8;
1379 : 0 : fcinfo->args[7].isnull = false;
1380 : 0 : fcinfo->args[8].value = arg9;
1381 : 0 : fcinfo->args[8].isnull = false;
1382 : :
1383 : 0 : result = FunctionCallInvoke(fcinfo);
1384 : :
1385 : : /* Check for null result, since caller is clearly not expecting one */
1386 [ # # ]: 0 : if (fcinfo->isnull)
1387 [ # # ]: 0 : elog(ERROR, "function %u returned NULL", flinfo->fn_oid);
1388 : :
8722 tgl@sss.pgh.pa.us 1389 : 0 : return result;
1390 : : }
1391 : :
1392 : :
1393 : : /*
1394 : : * These are for invocation of a function identified by OID with a
1395 : : * directly-computed parameter list. Note that neither arguments nor result
1396 : : * are allowed to be NULL. These are essentially fmgr_info() followed
1397 : : * by FunctionCallN(). If the same function is to be invoked repeatedly,
1398 : : * do the fmgr_info() once and then use FunctionCallN().
1399 : : */
1400 : : Datum
4751 tgl@sss.pgh.pa.us 1401 :CBC 2403639 : OidFunctionCall0Coll(Oid functionId, Oid collation)
1402 : : {
1403 : : FmgrInfo flinfo;
1404 : :
4802 1405 : 2403639 : fmgr_info(functionId, &flinfo);
1406 : :
1905 andres@anarazel.de 1407 : 2403639 : return FunctionCall0Coll(&flinfo, collation);
1408 : : }
1409 : :
1410 : : Datum
4751 tgl@sss.pgh.pa.us 1411 : 294853 : OidFunctionCall1Coll(Oid functionId, Oid collation, Datum arg1)
1412 : : {
1413 : : FmgrInfo flinfo;
1414 : :
8722 1415 : 294853 : fmgr_info(functionId, &flinfo);
1416 : :
1905 andres@anarazel.de 1417 : 294853 : return FunctionCall1Coll(&flinfo, collation, arg1);
1418 : : }
1419 : :
1420 : : Datum
4751 tgl@sss.pgh.pa.us 1421 : 498 : OidFunctionCall2Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2)
1422 : : {
1423 : : FmgrInfo flinfo;
1424 : :
8722 1425 : 498 : fmgr_info(functionId, &flinfo);
1426 : :
1905 andres@anarazel.de 1427 : 498 : return FunctionCall2Coll(&flinfo, collation, arg1, arg2);
1428 : : }
1429 : :
1430 : : Datum
4751 tgl@sss.pgh.pa.us 1431 : 2 : OidFunctionCall3Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2,
1432 : : Datum arg3)
1433 : : {
1434 : : FmgrInfo flinfo;
1435 : :
8722 1436 : 2 : fmgr_info(functionId, &flinfo);
1437 : :
1905 andres@anarazel.de 1438 : 2 : return FunctionCall3Coll(&flinfo, collation, arg1, arg2, arg3);
1439 : : }
1440 : :
1441 : : Datum
4751 tgl@sss.pgh.pa.us 1442 : 289756 : OidFunctionCall4Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2,
1443 : : Datum arg3, Datum arg4)
1444 : : {
1445 : : FmgrInfo flinfo;
1446 : :
8722 1447 : 289756 : fmgr_info(functionId, &flinfo);
1448 : :
1905 andres@anarazel.de 1449 : 289756 : return FunctionCall4Coll(&flinfo, collation, arg1, arg2, arg3, arg4);
1450 : : }
1451 : :
1452 : : Datum
4751 tgl@sss.pgh.pa.us 1453 : 96960 : OidFunctionCall5Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2,
1454 : : Datum arg3, Datum arg4, Datum arg5)
1455 : : {
1456 : : FmgrInfo flinfo;
1457 : :
8722 1458 : 96960 : fmgr_info(functionId, &flinfo);
1459 : :
1905 andres@anarazel.de 1460 : 96960 : return FunctionCall5Coll(&flinfo, collation, arg1, arg2, arg3, arg4, arg5);
1461 : : }
1462 : :
1463 : : Datum
4751 tgl@sss.pgh.pa.us 1464 : 3269 : OidFunctionCall6Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2,
1465 : : Datum arg3, Datum arg4, Datum arg5,
1466 : : Datum arg6)
1467 : : {
1468 : : FmgrInfo flinfo;
1469 : :
8722 1470 : 3269 : fmgr_info(functionId, &flinfo);
1471 : :
1905 andres@anarazel.de 1472 : 3269 : return FunctionCall6Coll(&flinfo, collation, arg1, arg2, arg3, arg4, arg5,
1473 : : arg6);
1474 : : }
1475 : :
1476 : : Datum
4751 tgl@sss.pgh.pa.us 1477 :UBC 0 : OidFunctionCall7Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2,
1478 : : Datum arg3, Datum arg4, Datum arg5,
1479 : : Datum arg6, Datum arg7)
1480 : : {
1481 : : FmgrInfo flinfo;
1482 : :
8722 1483 : 0 : fmgr_info(functionId, &flinfo);
1484 : :
1905 andres@anarazel.de 1485 : 0 : return FunctionCall7Coll(&flinfo, collation, arg1, arg2, arg3, arg4, arg5,
1486 : : arg6, arg7);
1487 : : }
1488 : :
1489 : : Datum
4751 tgl@sss.pgh.pa.us 1490 : 0 : OidFunctionCall8Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2,
1491 : : Datum arg3, Datum arg4, Datum arg5,
1492 : : Datum arg6, Datum arg7, Datum arg8)
1493 : : {
1494 : : FmgrInfo flinfo;
1495 : :
8722 1496 : 0 : fmgr_info(functionId, &flinfo);
1497 : :
1905 andres@anarazel.de 1498 : 0 : return FunctionCall8Coll(&flinfo, collation, arg1, arg2, arg3, arg4, arg5,
1499 : : arg6, arg7, arg8);
1500 : : }
1501 : :
1502 : : Datum
4751 tgl@sss.pgh.pa.us 1503 : 0 : OidFunctionCall9Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2,
1504 : : Datum arg3, Datum arg4, Datum arg5,
1505 : : Datum arg6, Datum arg7, Datum arg8,
1506 : : Datum arg9)
1507 : : {
1508 : : FmgrInfo flinfo;
1509 : :
8722 1510 : 0 : fmgr_info(functionId, &flinfo);
1511 : :
1905 andres@anarazel.de 1512 : 0 : return FunctionCall9Coll(&flinfo, collation, arg1, arg2, arg3, arg4, arg5,
1513 : : arg6, arg7, arg8, arg9);
1514 : : }
1515 : :
1516 : :
1517 : : /*
1518 : : * Special cases for convenient invocation of datatype I/O functions.
1519 : : */
1520 : :
1521 : : /*
1522 : : * Call a previously-looked-up datatype input function.
1523 : : *
1524 : : * "str" may be NULL to indicate we are reading a NULL. In this case
1525 : : * the caller should assume the result is NULL, but we'll call the input
1526 : : * function anyway if it's not strict. So this is almost but not quite
1527 : : * the same as FunctionCall3.
1528 : : */
1529 : : Datum
6585 tgl@sss.pgh.pa.us 1530 :CBC 18068975 : InputFunctionCall(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod)
1531 : : {
1905 andres@anarazel.de 1532 : 18068975 : LOCAL_FCINFO(fcinfo, 3);
1533 : : Datum result;
1534 : :
6585 tgl@sss.pgh.pa.us 1535 [ + + + + ]: 18068975 : if (str == NULL && flinfo->fn_strict)
1536 : 4009755 : return (Datum) 0; /* just return null result */
1537 : :
1905 andres@anarazel.de 1538 : 14059220 : InitFunctionCallInfoData(*fcinfo, flinfo, 3, InvalidOid, NULL, NULL);
1539 : :
1540 : 14059220 : fcinfo->args[0].value = CStringGetDatum(str);
1541 : 14059220 : fcinfo->args[0].isnull = false;
1542 : 14059220 : fcinfo->args[1].value = ObjectIdGetDatum(typioparam);
1543 : 14059220 : fcinfo->args[1].isnull = false;
1544 : 14059220 : fcinfo->args[2].value = Int32GetDatum(typmod);
1545 : 14059220 : fcinfo->args[2].isnull = false;
1546 : :
1547 : 14059220 : result = FunctionCallInvoke(fcinfo);
1548 : :
1549 : : /* Should get null result if and only if str is NULL */
6585 tgl@sss.pgh.pa.us 1550 [ - + ]: 14056919 : if (str == NULL)
1551 : : {
1905 andres@anarazel.de 1552 [ # # ]:LBC (18) : if (!fcinfo->isnull)
6585 tgl@sss.pgh.pa.us 1553 [ # # ]:UBC 0 : elog(ERROR, "input function %u returned non-NULL",
1554 : : flinfo->fn_oid);
1555 : : }
1556 : : else
1557 : : {
1905 andres@anarazel.de 1558 [ - + ]:CBC 14056919 : if (fcinfo->isnull)
6585 tgl@sss.pgh.pa.us 1559 [ # # ]:UBC 0 : elog(ERROR, "input function %u returned NULL",
1560 : : flinfo->fn_oid);
1561 : : }
1562 : :
6585 tgl@sss.pgh.pa.us 1563 :CBC 14056919 : return result;
1564 : : }
1565 : :
1566 : : /*
1567 : : * Call a previously-looked-up datatype input function, with non-exception
1568 : : * handling of "soft" errors.
1569 : : *
1570 : : * This is basically like InputFunctionCall, but the converted Datum is
1571 : : * returned into *result while the function result is true for success or
1572 : : * false for failure. Also, the caller may pass an ErrorSaveContext node.
1573 : : * (We declare that as "fmNodePtr" to avoid including nodes.h in fmgr.h.)
1574 : : *
1575 : : * If escontext points to an ErrorSaveContext, any "soft" errors detected by
1576 : : * the input function will be reported by filling the escontext struct and
1577 : : * returning false. (The caller can choose to test SOFT_ERROR_OCCURRED(),
1578 : : * but checking the function result instead is usually cheaper.)
1579 : : *
1580 : : * If escontext does not point to an ErrorSaveContext, errors are reported
1581 : : * via ereport(ERROR), so that there is no functional difference from
1582 : : * InputFunctionCall; the result will always be true if control returns.
1583 : : */
1584 : : bool
492 1585 : 2953087 : InputFunctionCallSafe(FmgrInfo *flinfo, char *str,
1586 : : Oid typioparam, int32 typmod,
1587 : : fmNodePtr escontext,
1588 : : Datum *result)
1589 : : {
1590 : 2953087 : LOCAL_FCINFO(fcinfo, 3);
1591 : :
1592 [ + + + + ]: 2953087 : if (str == NULL && flinfo->fn_strict)
1593 : : {
1594 : 2931 : *result = (Datum) 0; /* just return null result */
1595 : 2931 : return true;
1596 : : }
1597 : :
1598 : 2950156 : InitFunctionCallInfoData(*fcinfo, flinfo, 3, InvalidOid, escontext, NULL);
1599 : :
1600 : 2950156 : fcinfo->args[0].value = CStringGetDatum(str);
1601 : 2950156 : fcinfo->args[0].isnull = false;
1602 : 2950156 : fcinfo->args[1].value = ObjectIdGetDatum(typioparam);
1603 : 2950156 : fcinfo->args[1].isnull = false;
1604 : 2950156 : fcinfo->args[2].value = Int32GetDatum(typmod);
1605 : 2950156 : fcinfo->args[2].isnull = false;
1606 : :
1607 : 2950156 : *result = FunctionCallInvoke(fcinfo);
1608 : :
1609 : : /* Result value is garbage, and could be null, if an error was reported */
1610 [ + + + - : 2950021 : if (SOFT_ERROR_OCCURRED(escontext))
+ + ]
1611 : 752 : return false;
1612 : :
1613 : : /* Otherwise, should get null result if and only if str is NULL */
1614 [ + + ]: 2949269 : if (str == NULL)
1615 : : {
492 tgl@sss.pgh.pa.us 1616 [ - + ]:GBC 18 : if (!fcinfo->isnull)
492 tgl@sss.pgh.pa.us 1617 [ # # ]:UBC 0 : elog(ERROR, "input function %u returned non-NULL",
1618 : : flinfo->fn_oid);
1619 : : }
1620 : : else
1621 : : {
492 tgl@sss.pgh.pa.us 1622 [ - + ]:CBC 2949251 : if (fcinfo->isnull)
492 tgl@sss.pgh.pa.us 1623 [ # # ]:UBC 0 : elog(ERROR, "input function %u returned NULL",
1624 : : flinfo->fn_oid);
1625 : : }
1626 : :
492 tgl@sss.pgh.pa.us 1627 :CBC 2949269 : return true;
1628 : : }
1629 : :
1630 : : /*
1631 : : * Call a directly-named datatype input function, with non-exception
1632 : : * handling of "soft" errors.
1633 : : *
1634 : : * This is like InputFunctionCallSafe, except that it is given a direct
1635 : : * pointer to the C function to call. We assume that that function is
1636 : : * strict. Also, the function cannot be one that needs to
1637 : : * look at FmgrInfo, since there won't be any.
1638 : : */
1639 : : bool
490 1640 : 316885 : DirectInputFunctionCallSafe(PGFunction func, char *str,
1641 : : Oid typioparam, int32 typmod,
1642 : : fmNodePtr escontext,
1643 : : Datum *result)
1644 : : {
1645 : 316885 : LOCAL_FCINFO(fcinfo, 3);
1646 : :
1647 [ - + ]: 316885 : if (str == NULL)
1648 : : {
490 tgl@sss.pgh.pa.us 1649 :UBC 0 : *result = (Datum) 0; /* just return null result */
1650 : 0 : return true;
1651 : : }
1652 : :
490 tgl@sss.pgh.pa.us 1653 :CBC 316885 : InitFunctionCallInfoData(*fcinfo, NULL, 3, InvalidOid, escontext, NULL);
1654 : :
1655 : 316885 : fcinfo->args[0].value = CStringGetDatum(str);
1656 : 316885 : fcinfo->args[0].isnull = false;
1657 : 316885 : fcinfo->args[1].value = ObjectIdGetDatum(typioparam);
1658 : 316885 : fcinfo->args[1].isnull = false;
1659 : 316885 : fcinfo->args[2].value = Int32GetDatum(typmod);
1660 : 316885 : fcinfo->args[2].isnull = false;
1661 : :
1662 : 316885 : *result = (*func) (fcinfo);
1663 : :
1664 : : /* Result value is garbage, and could be null, if an error was reported */
1665 [ + + + - : 316885 : if (SOFT_ERROR_OCCURRED(escontext))
+ + ]
1666 : 144 : return false;
1667 : :
1668 : : /* Otherwise, shouldn't get null result */
1669 [ - + ]: 316741 : if (fcinfo->isnull)
490 tgl@sss.pgh.pa.us 1670 [ # # ]:UBC 0 : elog(ERROR, "input function %p returned NULL", (void *) func);
1671 : :
490 tgl@sss.pgh.pa.us 1672 :CBC 316741 : return true;
1673 : : }
1674 : :
1675 : : /*
1676 : : * Call a previously-looked-up datatype output function.
1677 : : *
1678 : : * Do not call this on NULL datums.
1679 : : *
1680 : : * This is currently little more than window dressing for FunctionCall1.
1681 : : */
1682 : : char *
6585 1683 : 20092659 : OutputFunctionCall(FmgrInfo *flinfo, Datum val)
1684 : : {
2714 1685 : 20092659 : return DatumGetCString(FunctionCall1(flinfo, val));
1686 : : }
1687 : :
1688 : : /*
1689 : : * Call a previously-looked-up datatype binary-input function.
1690 : : *
1691 : : * "buf" may be NULL to indicate we are reading a NULL. In this case
1692 : : * the caller should assume the result is NULL, but we'll call the receive
1693 : : * function anyway if it's not strict. So this is almost but not quite
1694 : : * the same as FunctionCall3.
1695 : : */
1696 : : Datum
6585 1697 : 155538 : ReceiveFunctionCall(FmgrInfo *flinfo, StringInfo buf,
1698 : : Oid typioparam, int32 typmod)
1699 : : {
1905 andres@anarazel.de 1700 : 155538 : LOCAL_FCINFO(fcinfo, 3);
1701 : : Datum result;
1702 : :
6585 tgl@sss.pgh.pa.us 1703 [ + + + - ]: 155538 : if (buf == NULL && flinfo->fn_strict)
1704 : 15 : return (Datum) 0; /* just return null result */
1705 : :
1905 andres@anarazel.de 1706 : 155523 : InitFunctionCallInfoData(*fcinfo, flinfo, 3, InvalidOid, NULL, NULL);
1707 : :
1708 : 155523 : fcinfo->args[0].value = PointerGetDatum(buf);
1709 : 155523 : fcinfo->args[0].isnull = false;
1710 : 155523 : fcinfo->args[1].value = ObjectIdGetDatum(typioparam);
1711 : 155523 : fcinfo->args[1].isnull = false;
1712 : 155523 : fcinfo->args[2].value = Int32GetDatum(typmod);
1713 : 155523 : fcinfo->args[2].isnull = false;
1714 : :
1715 : 155523 : result = FunctionCallInvoke(fcinfo);
1716 : :
1717 : : /* Should get null result if and only if buf is NULL */
6585 tgl@sss.pgh.pa.us 1718 [ - + ]: 155523 : if (buf == NULL)
1719 : : {
1905 andres@anarazel.de 1720 [ # # ]:UBC 0 : if (!fcinfo->isnull)
6585 tgl@sss.pgh.pa.us 1721 [ # # ]: 0 : elog(ERROR, "receive function %u returned non-NULL",
1722 : : flinfo->fn_oid);
1723 : : }
1724 : : else
1725 : : {
1905 andres@anarazel.de 1726 [ - + ]:CBC 155523 : if (fcinfo->isnull)
6585 tgl@sss.pgh.pa.us 1727 [ # # ]:UBC 0 : elog(ERROR, "receive function %u returned NULL",
1728 : : flinfo->fn_oid);
1729 : : }
1730 : :
6585 tgl@sss.pgh.pa.us 1731 :CBC 155523 : return result;
1732 : : }
1733 : :
1734 : : /*
1735 : : * Call a previously-looked-up datatype binary-output function.
1736 : : *
1737 : : * Do not call this on NULL datums.
1738 : : *
1739 : : * This is little more than window dressing for FunctionCall1, but it does
1740 : : * guarantee a non-toasted result, which strictly speaking the underlying
1741 : : * function doesn't.
1742 : : */
1743 : : bytea *
1744 : 123574 : SendFunctionCall(FmgrInfo *flinfo, Datum val)
1745 : : {
2714 1746 : 123574 : return DatumGetByteaP(FunctionCall1(flinfo, val));
1747 : : }
1748 : :
1749 : : /*
1750 : : * As above, for I/O functions identified by OID. These are only to be used
1751 : : * in seldom-executed code paths. They are not only slow but leak memory.
1752 : : */
1753 : : Datum
6585 1754 : 5434866 : OidInputFunctionCall(Oid functionId, char *str, Oid typioparam, int32 typmod)
1755 : : {
1756 : : FmgrInfo flinfo;
1757 : :
1758 : 5434866 : fmgr_info(functionId, &flinfo);
1759 : 5434866 : return InputFunctionCall(&flinfo, str, typioparam, typmod);
1760 : : }
1761 : :
1762 : : char *
1763 : 520012 : OidOutputFunctionCall(Oid functionId, Datum val)
1764 : : {
1765 : : FmgrInfo flinfo;
1766 : :
1767 : 520012 : fmgr_info(functionId, &flinfo);
1768 : 520012 : return OutputFunctionCall(&flinfo, val);
1769 : : }
1770 : :
1771 : : Datum
1772 : 155366 : OidReceiveFunctionCall(Oid functionId, StringInfo buf,
1773 : : Oid typioparam, int32 typmod)
1774 : : {
1775 : : FmgrInfo flinfo;
1776 : :
1777 : 155366 : fmgr_info(functionId, &flinfo);
1778 : 155366 : return ReceiveFunctionCall(&flinfo, buf, typioparam, typmod);
1779 : : }
1780 : :
1781 : : bytea *
1782 : 116108 : OidSendFunctionCall(Oid functionId, Datum val)
1783 : : {
1784 : : FmgrInfo flinfo;
1785 : :
1786 : 116108 : fmgr_info(functionId, &flinfo);
1787 : 116108 : return SendFunctionCall(&flinfo, val);
1788 : : }
1789 : :
1790 : :
1791 : : /*-------------------------------------------------------------------------
1792 : : * Support routines for standard maybe-pass-by-reference datatypes
1793 : : *
1794 : : * int8 and float8 can be passed by value if Datum is wide enough.
1795 : : * (For backwards-compatibility reasons, we allow pass-by-ref to be chosen
1796 : : * at compile time even if pass-by-val is possible.)
1797 : : *
1798 : : * Note: there is only one switch controlling the pass-by-value option for
1799 : : * both int8 and float8; this is to avoid making things unduly complicated
1800 : : * for the timestamp types, which might have either representation.
1801 : : *-------------------------------------------------------------------------
1802 : : */
1803 : :
1804 : : #ifndef USE_FLOAT8_BYVAL /* controls int8 too */
1805 : :
1806 : : Datum
1807 : : Int64GetDatum(int64 X)
1808 : : {
1809 : : int64 *retval = (int64 *) palloc(sizeof(int64));
1810 : :
1811 : : *retval = X;
1812 : : return PointerGetDatum(retval);
1813 : : }
1814 : :
1815 : : Datum
1816 : : Float8GetDatum(float8 X)
1817 : : {
1818 : : float8 *retval = (float8 *) palloc(sizeof(float8));
1819 : :
1820 : : *retval = X;
1821 : : return PointerGetDatum(retval);
1822 : : }
1823 : : #endif /* USE_FLOAT8_BYVAL */
1824 : :
1825 : :
1826 : : /*-------------------------------------------------------------------------
1827 : : * Support routines for toastable datatypes
1828 : : *-------------------------------------------------------------------------
1829 : : */
1830 : :
1831 : : struct varlena *
2489 1832 : 44914306 : pg_detoast_datum(struct varlena *datum)
1833 : : {
8683 1834 [ + + ]: 44914306 : if (VARATT_IS_EXTENDED(datum))
1654 rhaas@postgresql.org 1835 : 11700357 : return detoast_attr(datum);
1836 : : else
8683 tgl@sss.pgh.pa.us 1837 : 33213949 : return datum;
1838 : : }
1839 : :
1840 : : struct varlena *
2489 1841 : 2638468 : pg_detoast_datum_copy(struct varlena *datum)
1842 : : {
8683 1843 [ + + ]: 2638468 : if (VARATT_IS_EXTENDED(datum))
1654 rhaas@postgresql.org 1844 : 1397981 : return detoast_attr(datum);
1845 : : else
1846 : : {
1847 : : /* Make a modifiable copy of the varlena object */
8424 bruce@momjian.us 1848 : 1240487 : Size len = VARSIZE(datum);
8683 tgl@sss.pgh.pa.us 1849 : 1240487 : struct varlena *result = (struct varlena *) palloc(len);
1850 : :
1851 : 1240487 : memcpy(result, datum, len);
1852 : 1240487 : return result;
1853 : : }
1854 : : }
1855 : :
1856 : : struct varlena *
2489 1857 : 2178 : pg_detoast_datum_slice(struct varlena *datum, int32 first, int32 count)
1858 : : {
1859 : : /* Only get the specified portion from the toast rel */
1654 rhaas@postgresql.org 1860 : 2178 : return detoast_attr_slice(datum, first, count);
1861 : : }
1862 : :
1863 : : struct varlena *
2489 tgl@sss.pgh.pa.us 1864 : 96611067 : pg_detoast_datum_packed(struct varlena *datum)
1865 : : {
6218 1866 [ + + + + ]: 96611067 : if (VARATT_IS_COMPRESSED(datum) || VARATT_IS_EXTERNAL(datum))
1654 rhaas@postgresql.org 1867 : 21929 : return detoast_attr(datum);
1868 : : else
6218 tgl@sss.pgh.pa.us 1869 : 96589138 : return datum;
1870 : : }
1871 : :
1872 : : /*-------------------------------------------------------------------------
1873 : : * Support routines for extracting info from fn_expr parse tree
1874 : : *
1875 : : * These are needed by polymorphic functions, which accept multiple possible
1876 : : * input types and need help from the parser to know what they've got.
1877 : : * Also, some functions might be interested in whether a parameter is constant.
1878 : : * Functions taking VARIADIC ANY also need to know about the VARIADIC keyword.
1879 : : *-------------------------------------------------------------------------
1880 : : */
1881 : :
1882 : : /*
1883 : : * Get the actual type OID of the function return type
1884 : : *
1885 : : * Returns InvalidOid if information is not available
1886 : : */
1887 : : Oid
7593 1888 : 68199 : get_fn_expr_rettype(FmgrInfo *flinfo)
1889 : : {
1890 : : Node *expr;
1891 : :
1892 : : /*
1893 : : * can't return anything useful if we have no FmgrInfo or if its fn_expr
1894 : : * node has not been initialized
1895 : : */
1896 [ + - - + ]: 68199 : if (!flinfo || !flinfo->fn_expr)
7677 tgl@sss.pgh.pa.us 1897 :UBC 0 : return InvalidOid;
1898 : :
7593 tgl@sss.pgh.pa.us 1899 :CBC 68199 : expr = flinfo->fn_expr;
1900 : :
7677 1901 : 68199 : return exprType(expr);
1902 : : }
1903 : :
1904 : : /*
1905 : : * Get the actual type OID of a specific function argument (counting from 0)
1906 : : *
1907 : : * Returns InvalidOid if information is not available
1908 : : */
1909 : : Oid
7593 1910 : 957439 : get_fn_expr_argtype(FmgrInfo *flinfo, int argnum)
1911 : : {
1912 : : /*
1913 : : * can't return anything useful if we have no FmgrInfo or if its fn_expr
1914 : : * node has not been initialized
1915 : : */
1916 [ + - - + ]: 957439 : if (!flinfo || !flinfo->fn_expr)
7677 tgl@sss.pgh.pa.us 1917 :UBC 0 : return InvalidOid;
1918 : :
6954 tgl@sss.pgh.pa.us 1919 :CBC 957439 : return get_call_expr_argtype(flinfo->fn_expr, argnum);
1920 : : }
1921 : :
1922 : : /*
1923 : : * Get the actual type OID of a specific function argument (counting from 0),
1924 : : * but working from the calling expression tree instead of FmgrInfo
1925 : : *
1926 : : * Returns InvalidOid if information is not available
1927 : : */
1928 : : Oid
1929 : 960607 : get_call_expr_argtype(Node *expr, int argnum)
1930 : : {
1931 : : List *args;
1932 : : Oid argtype;
1933 : :
1934 [ - + ]: 960607 : if (expr == NULL)
6954 tgl@sss.pgh.pa.us 1935 :UBC 0 : return InvalidOid;
1936 : :
7677 tgl@sss.pgh.pa.us 1937 [ + + ]:CBC 960607 : if (IsA(expr, FuncExpr))
1938 : 960586 : args = ((FuncExpr *) expr)->args;
1939 [ + - ]: 21 : else if (IsA(expr, OpExpr))
1940 : 21 : args = ((OpExpr *) expr)->args;
7595 tgl@sss.pgh.pa.us 1941 [ # # ]:UBC 0 : else if (IsA(expr, DistinctExpr))
1942 : 0 : args = ((DistinctExpr *) expr)->args;
1943 [ # # ]: 0 : else if (IsA(expr, ScalarArrayOpExpr))
1944 : 0 : args = ((ScalarArrayOpExpr *) expr)->args;
1945 [ # # ]: 0 : else if (IsA(expr, NullIfExpr))
1946 : 0 : args = ((NullIfExpr *) expr)->args;
5586 1947 [ # # ]: 0 : else if (IsA(expr, WindowFunc))
1948 : 0 : args = ((WindowFunc *) expr)->args;
1949 : : else
7677 1950 : 0 : return InvalidOid;
1951 : :
7259 neilc@samurai.com 1952 [ + - - + ]:CBC 960607 : if (argnum < 0 || argnum >= list_length(args))
7677 tgl@sss.pgh.pa.us 1953 :UBC 0 : return InvalidOid;
1954 : :
7259 neilc@samurai.com 1955 :CBC 960607 : argtype = exprType((Node *) list_nth(args, argnum));
1956 : :
1957 : : /*
1958 : : * special hack for ScalarArrayOpExpr: what the underlying function will
1959 : : * actually get passed is the element type of the array.
1960 : : */
7595 tgl@sss.pgh.pa.us 1961 [ - + - - ]: 960607 : if (IsA(expr, ScalarArrayOpExpr) &&
1962 : : argnum == 1)
4924 tgl@sss.pgh.pa.us 1963 :UBC 0 : argtype = get_base_element_type(argtype);
1964 : :
7595 tgl@sss.pgh.pa.us 1965 :CBC 960607 : return argtype;
1966 : : }
1967 : :
1968 : : /*
1969 : : * Find out whether a specific function argument is constant for the
1970 : : * duration of a query
1971 : : *
1972 : : * Returns false if information is not available
1973 : : */
1974 : : bool
5586 1975 : 1636 : get_fn_expr_arg_stable(FmgrInfo *flinfo, int argnum)
1976 : : {
1977 : : /*
1978 : : * can't return anything useful if we have no FmgrInfo or if its fn_expr
1979 : : * node has not been initialized
1980 : : */
1981 [ + - - + ]: 1636 : if (!flinfo || !flinfo->fn_expr)
5586 tgl@sss.pgh.pa.us 1982 :UBC 0 : return false;
1983 : :
5586 tgl@sss.pgh.pa.us 1984 :CBC 1636 : return get_call_expr_arg_stable(flinfo->fn_expr, argnum);
1985 : : }
1986 : :
1987 : : /*
1988 : : * Find out whether a specific function argument is constant for the
1989 : : * duration of a query, but working from the calling expression tree
1990 : : *
1991 : : * Returns false if information is not available
1992 : : */
1993 : : bool
1994 : 1636 : get_call_expr_arg_stable(Node *expr, int argnum)
1995 : : {
1996 : : List *args;
1997 : : Node *arg;
1998 : :
1999 [ - + ]: 1636 : if (expr == NULL)
5586 tgl@sss.pgh.pa.us 2000 :UBC 0 : return false;
2001 : :
5586 tgl@sss.pgh.pa.us 2002 [ + + ]:CBC 1636 : if (IsA(expr, FuncExpr))
2003 : 1123 : args = ((FuncExpr *) expr)->args;
2004 [ - + ]: 513 : else if (IsA(expr, OpExpr))
5586 tgl@sss.pgh.pa.us 2005 :UBC 0 : args = ((OpExpr *) expr)->args;
5586 tgl@sss.pgh.pa.us 2006 [ - + ]:CBC 513 : else if (IsA(expr, DistinctExpr))
5586 tgl@sss.pgh.pa.us 2007 :UBC 0 : args = ((DistinctExpr *) expr)->args;
5586 tgl@sss.pgh.pa.us 2008 [ - + ]:CBC 513 : else if (IsA(expr, ScalarArrayOpExpr))
5586 tgl@sss.pgh.pa.us 2009 :UBC 0 : args = ((ScalarArrayOpExpr *) expr)->args;
5586 tgl@sss.pgh.pa.us 2010 [ - + ]:CBC 513 : else if (IsA(expr, NullIfExpr))
5586 tgl@sss.pgh.pa.us 2011 :UBC 0 : args = ((NullIfExpr *) expr)->args;
5586 tgl@sss.pgh.pa.us 2012 [ + - ]:CBC 513 : else if (IsA(expr, WindowFunc))
2013 : 513 : args = ((WindowFunc *) expr)->args;
2014 : : else
5586 tgl@sss.pgh.pa.us 2015 :UBC 0 : return false;
2016 : :
5586 tgl@sss.pgh.pa.us 2017 [ + - - + ]:CBC 1636 : if (argnum < 0 || argnum >= list_length(args))
5586 tgl@sss.pgh.pa.us 2018 :UBC 0 : return false;
2019 : :
5586 tgl@sss.pgh.pa.us 2020 :CBC 1636 : arg = (Node *) list_nth(args, argnum);
2021 : :
2022 : : /*
2023 : : * Either a true Const or an external Param will have a value that doesn't
2024 : : * change during the execution of the query. In future we might want to
2025 : : * consider other cases too, e.g. now().
2026 : : */
2027 [ + + ]: 1636 : if (IsA(arg, Const))
2028 : 1482 : return true;
2029 [ + + ]: 154 : if (IsA(arg, Param) &&
2030 [ - + ]: 2 : ((Param *) arg)->paramkind == PARAM_EXTERN)
5586 tgl@sss.pgh.pa.us 2031 :UBC 0 : return true;
2032 : :
5586 tgl@sss.pgh.pa.us 2033 :CBC 154 : return false;
2034 : : }
2035 : :
2036 : : /*
2037 : : * Get the VARIADIC flag from the function invocation
2038 : : *
2039 : : * Returns false (the default assumption) if information is not available
2040 : : *
2041 : : * Note this is generally only of interest to VARIADIC ANY functions
2042 : : */
2043 : : bool
4101 2044 : 14619 : get_fn_expr_variadic(FmgrInfo *flinfo)
2045 : : {
2046 : : Node *expr;
2047 : :
2048 : : /*
2049 : : * can't return anything useful if we have no FmgrInfo or if its fn_expr
2050 : : * node has not been initialized
2051 : : */
2052 [ + - - + ]: 14619 : if (!flinfo || !flinfo->fn_expr)
4101 tgl@sss.pgh.pa.us 2053 :UBC 0 : return false;
2054 : :
4101 tgl@sss.pgh.pa.us 2055 :CBC 14619 : expr = flinfo->fn_expr;
2056 : :
2057 [ + - ]: 14619 : if (IsA(expr, FuncExpr))
2058 : 14619 : return ((FuncExpr *) expr)->funcvariadic;
2059 : : else
4101 tgl@sss.pgh.pa.us 2060 :UBC 0 : return false;
2061 : : }
2062 : :
2063 : : /*
2064 : : * Set options to FmgrInfo of opclass support function.
2065 : : *
2066 : : * Opclass support functions are called outside of expressions. Thanks to that
2067 : : * we can use fn_expr to store opclass options as bytea constant.
2068 : : */
2069 : : void
1476 akorotkov@postgresql 2070 :CBC 498476 : set_fn_opclass_options(FmgrInfo *flinfo, bytea *options)
2071 : : {
2072 : 498476 : flinfo->fn_expr = (Node *) makeConst(BYTEAOID, -1, InvalidOid, -1,
2073 : : PointerGetDatum(options),
2074 : : options == NULL, false);
2075 : 498476 : }
2076 : :
2077 : : /*
2078 : : * Check if options are defined for opclass support function.
2079 : : */
2080 : : bool
2081 : 2729000 : has_fn_opclass_options(FmgrInfo *flinfo)
2082 : : {
2083 [ + - + - : 2729000 : if (flinfo && flinfo->fn_expr && IsA(flinfo->fn_expr, Const))
+ - ]
2084 : : {
2085 : 2729000 : Const *expr = (Const *) flinfo->fn_expr;
2086 : :
2087 [ + - ]: 2729000 : if (expr->consttype == BYTEAOID)
2088 : 2729000 : return !expr->constisnull;
2089 : : }
1476 akorotkov@postgresql 2090 :UBC 0 : return false;
2091 : : }
2092 : :
2093 : : /*
2094 : : * Get options for opclass support function.
2095 : : */
2096 : : bytea *
1476 akorotkov@postgresql 2097 :CBC 2834579 : get_fn_opclass_options(FmgrInfo *flinfo)
2098 : : {
2099 [ + - + - : 2834579 : if (flinfo && flinfo->fn_expr && IsA(flinfo->fn_expr, Const))
+ - ]
2100 : : {
2101 : 2834579 : Const *expr = (Const *) flinfo->fn_expr;
2102 : :
2103 [ + - ]: 2834579 : if (expr->consttype == BYTEAOID)
2104 [ + - ]: 2834579 : return expr->constisnull ? NULL : DatumGetByteaP(expr->constvalue);
2105 : : }
2106 : :
1476 akorotkov@postgresql 2107 [ # # ]:UBC 0 : ereport(ERROR,
2108 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2109 : : errmsg("operator class options info is absent in function call context")));
2110 : :
2111 : : return NULL;
2112 : : }
2113 : :
2114 : : /*-------------------------------------------------------------------------
2115 : : * Support routines for procedural language implementations
2116 : : *-------------------------------------------------------------------------
2117 : : */
2118 : :
2119 : : /*
2120 : : * Verify that a validator is actually associated with the language of a
2121 : : * particular function and that the user has access to both the language and
2122 : : * the function. All validators should call this before doing anything
2123 : : * substantial. Doing so ensures a user cannot achieve anything with explicit
2124 : : * calls to validators that he could not achieve with CREATE FUNCTION or by
2125 : : * simply calling an existing function.
2126 : : *
2127 : : * When this function returns false, callers should skip all validation work
2128 : : * and call PG_RETURN_VOID(). This never happens at present; it is reserved
2129 : : * for future expansion.
2130 : : *
2131 : : * In particular, checking that the validator corresponds to the function's
2132 : : * language allows untrusted language validators to assume they process only
2133 : : * superuser-chosen source code. (Untrusted language call handlers, by
2134 : : * definition, do assume that.) A user lacking the USAGE language privilege
2135 : : * would be unable to reach the validator through CREATE FUNCTION, so we check
2136 : : * that to block explicit calls as well. Checking the EXECUTE privilege on
2137 : : * the function is often superfluous, because most users can clone the
2138 : : * function to get an executable copy. It is meaningful against users with no
2139 : : * database TEMP right and no permanent schema CREATE right, thereby unable to
2140 : : * create any function. Also, if the function tracks persistent state by
2141 : : * function OID or name, validating the original function might permit more
2142 : : * mischief than creating and validating a clone thereof.
2143 : : */
2144 : : bool
3709 noah@leadboat.com 2145 :CBC 10367 : CheckFunctionValidatorAccess(Oid validatorOid, Oid functionOid)
2146 : : {
2147 : : HeapTuple procTup;
2148 : : HeapTuple langTup;
2149 : : Form_pg_proc procStruct;
2150 : : Form_pg_language langStruct;
2151 : : AclResult aclresult;
2152 : :
2153 : : /*
2154 : : * Get the function's pg_proc entry. Throw a user-facing error for bad
2155 : : * OID, because validators can be called with user-specified OIDs.
2156 : : */
2157 : 10367 : procTup = SearchSysCache1(PROCOID, ObjectIdGetDatum(functionOid));
2158 [ - + ]: 10367 : if (!HeapTupleIsValid(procTup))
2774 tgl@sss.pgh.pa.us 2159 [ # # ]:UBC 0 : ereport(ERROR,
2160 : : (errcode(ERRCODE_UNDEFINED_FUNCTION),
2161 : : errmsg("function with OID %u does not exist", functionOid)));
3709 noah@leadboat.com 2162 :CBC 10367 : procStruct = (Form_pg_proc) GETSTRUCT(procTup);
2163 : :
2164 : : /*
2165 : : * Fetch pg_language entry to know if this is the correct validation
2166 : : * function for that pg_proc entry.
2167 : : */
2168 : 10367 : langTup = SearchSysCache1(LANGOID, ObjectIdGetDatum(procStruct->prolang));
2169 [ - + ]: 10367 : if (!HeapTupleIsValid(langTup))
3709 noah@leadboat.com 2170 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for language %u", procStruct->prolang);
3709 noah@leadboat.com 2171 :CBC 10367 : langStruct = (Form_pg_language) GETSTRUCT(langTup);
2172 : :
2173 [ - + ]: 10367 : if (langStruct->lanvalidator != validatorOid)
3709 noah@leadboat.com 2174 [ # # ]:UBC 0 : ereport(ERROR,
2175 : : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2176 : : errmsg("language validation function %u called for language %u instead of %u",
2177 : : validatorOid, procStruct->prolang,
2178 : : langStruct->lanvalidator)));
2179 : :
2180 : : /* first validate that we have permissions to use the language */
518 peter@eisentraut.org 2181 :CBC 10367 : aclresult = object_aclcheck(LanguageRelationId, procStruct->prolang, GetUserId(),
2182 : : ACL_USAGE);
3709 noah@leadboat.com 2183 [ - + ]: 10367 : if (aclresult != ACLCHECK_OK)
2325 peter_e@gmx.net 2184 :UBC 0 : aclcheck_error(aclresult, OBJECT_LANGUAGE,
3709 noah@leadboat.com 2185 : 0 : NameStr(langStruct->lanname));
2186 : :
2187 : : /*
2188 : : * Check whether we are allowed to execute the function itself. If we can
2189 : : * execute it, there should be no possible side-effect of
2190 : : * compiling/validation that execution can't have.
2191 : : */
518 peter@eisentraut.org 2192 :CBC 10367 : aclresult = object_aclcheck(ProcedureRelationId, functionOid, GetUserId(), ACL_EXECUTE);
3709 noah@leadboat.com 2193 [ - + ]: 10367 : if (aclresult != ACLCHECK_OK)
2325 peter_e@gmx.net 2194 :UBC 0 : aclcheck_error(aclresult, OBJECT_FUNCTION, NameStr(procStruct->proname));
2195 : :
3709 noah@leadboat.com 2196 :CBC 10367 : ReleaseSysCache(procTup);
2197 : 10367 : ReleaseSysCache(langTup);
2198 : :
2199 : 10367 : return true;
2200 : : }
|