1 /*-------------------------------------------------------------------------
2 *
3 * funcapi.c
4 * Utility and convenience functions for fmgr functions that return
5 * sets and/or composite types, or deal with VARIADIC inputs.
6 *
7 * Copyright (c) 2002-2019, PostgreSQL Global Development Group
8 *
9 * IDENTIFICATION
10 * src/backend/utils/fmgr/funcapi.c
11 *
12 *-------------------------------------------------------------------------
13 */
14 #include "postgres.h"
15
16 #include "access/htup_details.h"
17 #include "access/relation.h"
18 #include "catalog/namespace.h"
19 #include "catalog/pg_proc.h"
20 #include "catalog/pg_type.h"
21 #include "funcapi.h"
22 #include "nodes/nodeFuncs.h"
23 #include "utils/array.h"
24 #include "utils/builtins.h"
25 #include "utils/lsyscache.h"
26 #include "utils/memutils.h"
27 #include "utils/regproc.h"
28 #include "utils/rel.h"
29 #include "utils/syscache.h"
30 #include "utils/typcache.h"
31
32
33 typedef struct polymorphic_actuals
34 {
35 Oid anyelement_type; /* anyelement mapping, if known */
36 Oid anyarray_type; /* anyarray mapping, if known */
37 Oid anyrange_type; /* anyrange mapping, if known */
38 } polymorphic_actuals;
39
40 static void shutdown_MultiFuncCall(Datum arg);
41 static TypeFuncClass internal_get_result_type(Oid funcid,
42 Node *call_expr,
43 ReturnSetInfo *rsinfo,
44 Oid *resultTypeId,
45 TupleDesc *resultTupleDesc);
46 static void resolve_anyelement_from_others(polymorphic_actuals *actuals);
47 static void resolve_anyarray_from_others(polymorphic_actuals *actuals);
48 static void resolve_anyrange_from_others(polymorphic_actuals *actuals);
49 static bool resolve_polymorphic_tupdesc(TupleDesc tupdesc,
50 oidvector *declared_args,
51 Node *call_expr);
52 static TypeFuncClass get_type_func_class(Oid typid, Oid *base_typeid);
53
54
55 /*
56 * init_MultiFuncCall
57 * Create an empty FuncCallContext data structure
58 * and do some other basic Multi-function call setup
59 * and error checking
60 */
61 FuncCallContext *
init_MultiFuncCall(PG_FUNCTION_ARGS)62 init_MultiFuncCall(PG_FUNCTION_ARGS)
63 {
64 FuncCallContext *retval;
65
66 /*
67 * Bail if we're called in the wrong context
68 */
69 if (fcinfo->resultinfo == NULL || !IsA(fcinfo->resultinfo, ReturnSetInfo))
70 ereport(ERROR,
71 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
72 errmsg("set-valued function called in context that cannot accept a set")));
73
74 if (fcinfo->flinfo->fn_extra == NULL)
75 {
76 /*
77 * First call
78 */
79 ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
80 MemoryContext multi_call_ctx;
81
82 /*
83 * Create a suitably long-lived context to hold cross-call data
84 */
85 multi_call_ctx = AllocSetContextCreate(fcinfo->flinfo->fn_mcxt,
86 "SRF multi-call context",
87 ALLOCSET_SMALL_SIZES);
88
89 /*
90 * Allocate suitably long-lived space and zero it
91 */
92 retval = (FuncCallContext *)
93 MemoryContextAllocZero(multi_call_ctx,
94 sizeof(FuncCallContext));
95
96 /*
97 * initialize the elements
98 */
99 retval->call_cntr = 0;
100 retval->max_calls = 0;
101 retval->user_fctx = NULL;
102 retval->attinmeta = NULL;
103 retval->tuple_desc = NULL;
104 retval->multi_call_memory_ctx = multi_call_ctx;
105
106 /*
107 * save the pointer for cross-call use
108 */
109 fcinfo->flinfo->fn_extra = retval;
110
111 /*
112 * Ensure we will get shut down cleanly if the exprcontext is not run
113 * to completion.
114 */
115 RegisterExprContextCallback(rsi->econtext,
116 shutdown_MultiFuncCall,
117 PointerGetDatum(fcinfo->flinfo));
118 }
119 else
120 {
121 /* second and subsequent calls */
122 elog(ERROR, "init_MultiFuncCall cannot be called more than once");
123
124 /* never reached, but keep compiler happy */
125 retval = NULL;
126 }
127
128 return retval;
129 }
130
131 /*
132 * per_MultiFuncCall
133 *
134 * Do Multi-function per-call setup
135 */
136 FuncCallContext *
per_MultiFuncCall(PG_FUNCTION_ARGS)137 per_MultiFuncCall(PG_FUNCTION_ARGS)
138 {
139 FuncCallContext *retval = (FuncCallContext *) fcinfo->flinfo->fn_extra;
140
141 return retval;
142 }
143
144 /*
145 * end_MultiFuncCall
146 * Clean up after init_MultiFuncCall
147 */
148 void
end_MultiFuncCall(PG_FUNCTION_ARGS,FuncCallContext * funcctx)149 end_MultiFuncCall(PG_FUNCTION_ARGS, FuncCallContext *funcctx)
150 {
151 ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
152
153 /* Deregister the shutdown callback */
154 UnregisterExprContextCallback(rsi->econtext,
155 shutdown_MultiFuncCall,
156 PointerGetDatum(fcinfo->flinfo));
157
158 /* But use it to do the real work */
159 shutdown_MultiFuncCall(PointerGetDatum(fcinfo->flinfo));
160 }
161
162 /*
163 * shutdown_MultiFuncCall
164 * Shutdown function to clean up after init_MultiFuncCall
165 */
166 static void
shutdown_MultiFuncCall(Datum arg)167 shutdown_MultiFuncCall(Datum arg)
168 {
169 FmgrInfo *flinfo = (FmgrInfo *) DatumGetPointer(arg);
170 FuncCallContext *funcctx = (FuncCallContext *) flinfo->fn_extra;
171
172 /* unbind from flinfo */
173 flinfo->fn_extra = NULL;
174
175 /*
176 * Delete context that holds all multi-call data, including the
177 * FuncCallContext itself
178 */
179 MemoryContextDelete(funcctx->multi_call_memory_ctx);
180 }
181
182
183 /*
184 * get_call_result_type
185 * Given a function's call info record, determine the kind of datatype
186 * it is supposed to return. If resultTypeId isn't NULL, *resultTypeId
187 * receives the actual datatype OID (this is mainly useful for scalar
188 * result types). If resultTupleDesc isn't NULL, *resultTupleDesc
189 * receives a pointer to a TupleDesc when the result is of a composite
190 * type, or NULL when it's a scalar result.
191 *
192 * One hard case that this handles is resolution of actual rowtypes for
193 * functions returning RECORD (from either the function's OUT parameter
194 * list, or a ReturnSetInfo context node). TYPEFUNC_RECORD is returned
195 * only when we couldn't resolve the actual rowtype for lack of information.
196 *
197 * The other hard case that this handles is resolution of polymorphism.
198 * We will never return polymorphic pseudotypes (ANYELEMENT etc), either
199 * as a scalar result type or as a component of a rowtype.
200 *
201 * This function is relatively expensive --- in a function returning set,
202 * try to call it only the first time through.
203 */
204 TypeFuncClass
get_call_result_type(FunctionCallInfo fcinfo,Oid * resultTypeId,TupleDesc * resultTupleDesc)205 get_call_result_type(FunctionCallInfo fcinfo,
206 Oid *resultTypeId,
207 TupleDesc *resultTupleDesc)
208 {
209 return internal_get_result_type(fcinfo->flinfo->fn_oid,
210 fcinfo->flinfo->fn_expr,
211 (ReturnSetInfo *) fcinfo->resultinfo,
212 resultTypeId,
213 resultTupleDesc);
214 }
215
216 /*
217 * get_expr_result_type
218 * As above, but work from a calling expression node tree
219 */
220 TypeFuncClass
get_expr_result_type(Node * expr,Oid * resultTypeId,TupleDesc * resultTupleDesc)221 get_expr_result_type(Node *expr,
222 Oid *resultTypeId,
223 TupleDesc *resultTupleDesc)
224 {
225 TypeFuncClass result;
226
227 if (expr && IsA(expr, FuncExpr))
228 result = internal_get_result_type(((FuncExpr *) expr)->funcid,
229 expr,
230 NULL,
231 resultTypeId,
232 resultTupleDesc);
233 else if (expr && IsA(expr, OpExpr))
234 result = internal_get_result_type(get_opcode(((OpExpr *) expr)->opno),
235 expr,
236 NULL,
237 resultTypeId,
238 resultTupleDesc);
239 else
240 {
241 /* handle as a generic expression; no chance to resolve RECORD */
242 Oid typid = exprType(expr);
243 Oid base_typid;
244
245 if (resultTypeId)
246 *resultTypeId = typid;
247 if (resultTupleDesc)
248 *resultTupleDesc = NULL;
249 result = get_type_func_class(typid, &base_typid);
250 if ((result == TYPEFUNC_COMPOSITE ||
251 result == TYPEFUNC_COMPOSITE_DOMAIN) &&
252 resultTupleDesc)
253 *resultTupleDesc = lookup_rowtype_tupdesc_copy(base_typid, -1);
254 }
255
256 return result;
257 }
258
259 /*
260 * get_func_result_type
261 * As above, but work from a function's OID only
262 *
263 * This will not be able to resolve pure-RECORD results nor polymorphism.
264 */
265 TypeFuncClass
get_func_result_type(Oid functionId,Oid * resultTypeId,TupleDesc * resultTupleDesc)266 get_func_result_type(Oid functionId,
267 Oid *resultTypeId,
268 TupleDesc *resultTupleDesc)
269 {
270 return internal_get_result_type(functionId,
271 NULL,
272 NULL,
273 resultTypeId,
274 resultTupleDesc);
275 }
276
277 /*
278 * internal_get_result_type -- workhorse code implementing all the above
279 *
280 * funcid must always be supplied. call_expr and rsinfo can be NULL if not
281 * available. We will return TYPEFUNC_RECORD, and store NULL into
282 * *resultTupleDesc, if we cannot deduce the complete result rowtype from
283 * the available information.
284 */
285 static TypeFuncClass
internal_get_result_type(Oid funcid,Node * call_expr,ReturnSetInfo * rsinfo,Oid * resultTypeId,TupleDesc * resultTupleDesc)286 internal_get_result_type(Oid funcid,
287 Node *call_expr,
288 ReturnSetInfo *rsinfo,
289 Oid *resultTypeId,
290 TupleDesc *resultTupleDesc)
291 {
292 TypeFuncClass result;
293 HeapTuple tp;
294 Form_pg_proc procform;
295 Oid rettype;
296 Oid base_rettype;
297 TupleDesc tupdesc;
298
299 /* First fetch the function's pg_proc row to inspect its rettype */
300 tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
301 if (!HeapTupleIsValid(tp))
302 elog(ERROR, "cache lookup failed for function %u", funcid);
303 procform = (Form_pg_proc) GETSTRUCT(tp);
304
305 rettype = procform->prorettype;
306
307 /* Check for OUT parameters defining a RECORD result */
308 tupdesc = build_function_result_tupdesc_t(tp);
309 if (tupdesc)
310 {
311 /*
312 * It has OUT parameters, so it's basically like a regular composite
313 * type, except we have to be able to resolve any polymorphic OUT
314 * parameters.
315 */
316 if (resultTypeId)
317 *resultTypeId = rettype;
318
319 if (resolve_polymorphic_tupdesc(tupdesc,
320 &procform->proargtypes,
321 call_expr))
322 {
323 if (tupdesc->tdtypeid == RECORDOID &&
324 tupdesc->tdtypmod < 0)
325 assign_record_type_typmod(tupdesc);
326 if (resultTupleDesc)
327 *resultTupleDesc = tupdesc;
328 result = TYPEFUNC_COMPOSITE;
329 }
330 else
331 {
332 if (resultTupleDesc)
333 *resultTupleDesc = NULL;
334 result = TYPEFUNC_RECORD;
335 }
336
337 ReleaseSysCache(tp);
338
339 return result;
340 }
341
342 /*
343 * If scalar polymorphic result, try to resolve it.
344 */
345 if (IsPolymorphicType(rettype))
346 {
347 Oid newrettype = exprType(call_expr);
348
349 if (newrettype == InvalidOid) /* this probably should not happen */
350 ereport(ERROR,
351 (errcode(ERRCODE_DATATYPE_MISMATCH),
352 errmsg("could not determine actual result type for function \"%s\" declared to return type %s",
353 NameStr(procform->proname),
354 format_type_be(rettype))));
355 rettype = newrettype;
356 }
357
358 if (resultTypeId)
359 *resultTypeId = rettype;
360 if (resultTupleDesc)
361 *resultTupleDesc = NULL; /* default result */
362
363 /* Classify the result type */
364 result = get_type_func_class(rettype, &base_rettype);
365 switch (result)
366 {
367 case TYPEFUNC_COMPOSITE:
368 case TYPEFUNC_COMPOSITE_DOMAIN:
369 if (resultTupleDesc)
370 *resultTupleDesc = lookup_rowtype_tupdesc_copy(base_rettype, -1);
371 /* Named composite types can't have any polymorphic columns */
372 break;
373 case TYPEFUNC_SCALAR:
374 break;
375 case TYPEFUNC_RECORD:
376 /* We must get the tupledesc from call context */
377 if (rsinfo && IsA(rsinfo, ReturnSetInfo) &&
378 rsinfo->expectedDesc != NULL)
379 {
380 result = TYPEFUNC_COMPOSITE;
381 if (resultTupleDesc)
382 *resultTupleDesc = rsinfo->expectedDesc;
383 /* Assume no polymorphic columns here, either */
384 }
385 break;
386 default:
387 break;
388 }
389
390 ReleaseSysCache(tp);
391
392 return result;
393 }
394
395 /*
396 * get_expr_result_tupdesc
397 * Get a tupdesc describing the result of a composite-valued expression
398 *
399 * If expression is not composite or rowtype can't be determined, returns NULL
400 * if noError is true, else throws error.
401 *
402 * This is a simpler version of get_expr_result_type() for use when the caller
403 * is only interested in determinate rowtype results.
404 */
405 TupleDesc
get_expr_result_tupdesc(Node * expr,bool noError)406 get_expr_result_tupdesc(Node *expr, bool noError)
407 {
408 TupleDesc tupleDesc;
409 TypeFuncClass functypclass;
410
411 functypclass = get_expr_result_type(expr, NULL, &tupleDesc);
412
413 if (functypclass == TYPEFUNC_COMPOSITE ||
414 functypclass == TYPEFUNC_COMPOSITE_DOMAIN)
415 return tupleDesc;
416
417 if (!noError)
418 {
419 Oid exprTypeId = exprType(expr);
420
421 if (exprTypeId != RECORDOID)
422 ereport(ERROR,
423 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
424 errmsg("type %s is not composite",
425 format_type_be(exprTypeId))));
426 else
427 ereport(ERROR,
428 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
429 errmsg("record type has not been registered")));
430 }
431
432 return NULL;
433 }
434
435 /*
436 * Resolve actual type of ANYELEMENT from other polymorphic inputs
437 *
438 * Note: the error cases here and in the sibling functions below are not
439 * really user-facing; they could only occur if the function signature is
440 * incorrect or the parser failed to enforce consistency of the actual
441 * argument types. Hence, we don't sweat too much over the error messages.
442 */
443 static void
resolve_anyelement_from_others(polymorphic_actuals * actuals)444 resolve_anyelement_from_others(polymorphic_actuals *actuals)
445 {
446 if (OidIsValid(actuals->anyarray_type))
447 {
448 /* Use the element type corresponding to actual type */
449 Oid array_base_type = getBaseType(actuals->anyarray_type);
450 Oid array_typelem = get_element_type(array_base_type);
451
452 if (!OidIsValid(array_typelem))
453 ereport(ERROR,
454 (errcode(ERRCODE_DATATYPE_MISMATCH),
455 errmsg("argument declared %s is not an array but type %s",
456 "anyarray",
457 format_type_be(array_base_type))));
458 actuals->anyelement_type = array_typelem;
459 }
460 else if (OidIsValid(actuals->anyrange_type))
461 {
462 /* Use the element type corresponding to actual type */
463 Oid range_base_type = getBaseType(actuals->anyrange_type);
464 Oid range_typelem = get_range_subtype(range_base_type);
465
466 if (!OidIsValid(range_typelem))
467 ereport(ERROR,
468 (errcode(ERRCODE_DATATYPE_MISMATCH),
469 errmsg("argument declared %s is not a range type but type %s",
470 "anyrange",
471 format_type_be(range_base_type))));
472 actuals->anyelement_type = range_typelem;
473 }
474 else
475 elog(ERROR, "could not determine polymorphic type");
476 }
477
478 /*
479 * Resolve actual type of ANYARRAY from other polymorphic inputs
480 */
481 static void
resolve_anyarray_from_others(polymorphic_actuals * actuals)482 resolve_anyarray_from_others(polymorphic_actuals *actuals)
483 {
484 /* If we don't know ANYELEMENT, resolve that first */
485 if (!OidIsValid(actuals->anyelement_type))
486 resolve_anyelement_from_others(actuals);
487
488 if (OidIsValid(actuals->anyelement_type))
489 {
490 /* Use the array type corresponding to actual type */
491 Oid array_typeid = get_array_type(actuals->anyelement_type);
492
493 if (!OidIsValid(array_typeid))
494 ereport(ERROR,
495 (errcode(ERRCODE_UNDEFINED_OBJECT),
496 errmsg("could not find array type for data type %s",
497 format_type_be(actuals->anyelement_type))));
498 actuals->anyarray_type = array_typeid;
499 }
500 else
501 elog(ERROR, "could not determine polymorphic type");
502 }
503
504 /*
505 * Resolve actual type of ANYRANGE from other polymorphic inputs
506 */
507 static void
resolve_anyrange_from_others(polymorphic_actuals * actuals)508 resolve_anyrange_from_others(polymorphic_actuals *actuals)
509 {
510 /*
511 * We can't deduce a range type from other polymorphic inputs, because
512 * there may be multiple range types with the same subtype.
513 */
514 elog(ERROR, "could not determine polymorphic type");
515 }
516
517 /*
518 * Given the result tuple descriptor for a function with OUT parameters,
519 * replace any polymorphic column types (ANYELEMENT etc) in the tupdesc
520 * with concrete data types deduced from the input arguments.
521 * declared_args is an oidvector of the function's declared input arg types
522 * (showing which are polymorphic), and call_expr is the call expression.
523 * Returns true if able to deduce all types, false if not.
524 */
525 static bool
resolve_polymorphic_tupdesc(TupleDesc tupdesc,oidvector * declared_args,Node * call_expr)526 resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
527 Node *call_expr)
528 {
529 int natts = tupdesc->natts;
530 int nargs = declared_args->dim1;
531 bool have_polymorphic_result = false;
532 bool have_anyelement_result = false;
533 bool have_anyarray_result = false;
534 bool have_anyrange_result = false;
535 polymorphic_actuals poly_actuals;
536 Oid anycollation = InvalidOid;
537 int i;
538
539 /* See if there are any polymorphic outputs; quick out if not */
540 for (i = 0; i < natts; i++)
541 {
542 switch (TupleDescAttr(tupdesc, i)->atttypid)
543 {
544 case ANYELEMENTOID:
545 case ANYNONARRAYOID:
546 case ANYENUMOID:
547 have_polymorphic_result = true;
548 have_anyelement_result = true;
549 break;
550 case ANYARRAYOID:
551 have_polymorphic_result = true;
552 have_anyarray_result = true;
553 break;
554 case ANYRANGEOID:
555 have_polymorphic_result = true;
556 have_anyrange_result = true;
557 break;
558 default:
559 break;
560 }
561 }
562 if (!have_polymorphic_result)
563 return true;
564
565 /*
566 * Otherwise, extract actual datatype(s) from input arguments. (We assume
567 * the parser already validated consistency of the arguments.)
568 */
569 if (!call_expr)
570 return false; /* no hope */
571
572 memset(&poly_actuals, 0, sizeof(poly_actuals));
573
574 for (i = 0; i < nargs; i++)
575 {
576 switch (declared_args->values[i])
577 {
578 case ANYELEMENTOID:
579 case ANYNONARRAYOID:
580 case ANYENUMOID:
581 if (!OidIsValid(poly_actuals.anyelement_type))
582 {
583 poly_actuals.anyelement_type =
584 get_call_expr_argtype(call_expr, i);
585 if (!OidIsValid(poly_actuals.anyelement_type))
586 return false;
587 }
588 break;
589 case ANYARRAYOID:
590 if (!OidIsValid(poly_actuals.anyarray_type))
591 {
592 poly_actuals.anyarray_type =
593 get_call_expr_argtype(call_expr, i);
594 if (!OidIsValid(poly_actuals.anyarray_type))
595 return false;
596 }
597 break;
598 case ANYRANGEOID:
599 if (!OidIsValid(poly_actuals.anyrange_type))
600 {
601 poly_actuals.anyrange_type =
602 get_call_expr_argtype(call_expr, i);
603 if (!OidIsValid(poly_actuals.anyrange_type))
604 return false;
605 }
606 break;
607 default:
608 break;
609 }
610 }
611
612 /* If needed, deduce one polymorphic type from others */
613 if (have_anyelement_result && !OidIsValid(poly_actuals.anyelement_type))
614 resolve_anyelement_from_others(&poly_actuals);
615
616 if (have_anyarray_result && !OidIsValid(poly_actuals.anyarray_type))
617 resolve_anyarray_from_others(&poly_actuals);
618
619 if (have_anyrange_result && !OidIsValid(poly_actuals.anyrange_type))
620 resolve_anyrange_from_others(&poly_actuals);
621
622 /*
623 * Identify the collation to use for polymorphic OUT parameters. (It'll
624 * necessarily be the same for both anyelement and anyarray.) Note that
625 * range types are not collatable, so any possible internal collation of a
626 * range type is not considered here.
627 */
628 if (OidIsValid(poly_actuals.anyelement_type))
629 anycollation = get_typcollation(poly_actuals.anyelement_type);
630 else if (OidIsValid(poly_actuals.anyarray_type))
631 anycollation = get_typcollation(poly_actuals.anyarray_type);
632
633 if (OidIsValid(anycollation))
634 {
635 /*
636 * The types are collatable, so consider whether to use a nondefault
637 * collation. We do so if we can identify the input collation used
638 * for the function.
639 */
640 Oid inputcollation = exprInputCollation(call_expr);
641
642 if (OidIsValid(inputcollation))
643 anycollation = inputcollation;
644 }
645
646 /* And finally replace the tuple column types as needed */
647 for (i = 0; i < natts; i++)
648 {
649 Form_pg_attribute att = TupleDescAttr(tupdesc, i);
650
651 switch (att->atttypid)
652 {
653 case ANYELEMENTOID:
654 case ANYNONARRAYOID:
655 case ANYENUMOID:
656 TupleDescInitEntry(tupdesc, i + 1,
657 NameStr(att->attname),
658 poly_actuals.anyelement_type,
659 -1,
660 0);
661 TupleDescInitEntryCollation(tupdesc, i + 1, anycollation);
662 break;
663 case ANYARRAYOID:
664 TupleDescInitEntry(tupdesc, i + 1,
665 NameStr(att->attname),
666 poly_actuals.anyarray_type,
667 -1,
668 0);
669 TupleDescInitEntryCollation(tupdesc, i + 1, anycollation);
670 break;
671 case ANYRANGEOID:
672 TupleDescInitEntry(tupdesc, i + 1,
673 NameStr(att->attname),
674 poly_actuals.anyrange_type,
675 -1,
676 0);
677 /* no collation should be attached to a range type */
678 break;
679 default:
680 break;
681 }
682 }
683
684 return true;
685 }
686
687 /*
688 * Given the declared argument types and modes for a function, replace any
689 * polymorphic types (ANYELEMENT etc) in argtypes[] with concrete data types
690 * deduced from the input arguments found in call_expr.
691 * Returns true if able to deduce all types, false if not.
692 *
693 * This is the same logic as resolve_polymorphic_tupdesc, but with a different
694 * argument representation, and slightly different output responsibilities.
695 *
696 * argmodes may be NULL, in which case all arguments are assumed to be IN mode.
697 */
698 bool
resolve_polymorphic_argtypes(int numargs,Oid * argtypes,char * argmodes,Node * call_expr)699 resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes,
700 Node *call_expr)
701 {
702 bool have_polymorphic_result = false;
703 bool have_anyelement_result = false;
704 bool have_anyarray_result = false;
705 bool have_anyrange_result = false;
706 polymorphic_actuals poly_actuals;
707 int inargno;
708 int i;
709
710 /*
711 * First pass: resolve polymorphic inputs, check for outputs. As in
712 * resolve_polymorphic_tupdesc, we rely on the parser to have enforced
713 * type consistency.
714 */
715 memset(&poly_actuals, 0, sizeof(poly_actuals));
716 inargno = 0;
717 for (i = 0; i < numargs; i++)
718 {
719 char argmode = argmodes ? argmodes[i] : PROARGMODE_IN;
720
721 switch (argtypes[i])
722 {
723 case ANYELEMENTOID:
724 case ANYNONARRAYOID:
725 case ANYENUMOID:
726 if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
727 {
728 have_polymorphic_result = true;
729 have_anyelement_result = true;
730 }
731 else
732 {
733 if (!OidIsValid(poly_actuals.anyelement_type))
734 {
735 poly_actuals.anyelement_type =
736 get_call_expr_argtype(call_expr, inargno);
737 if (!OidIsValid(poly_actuals.anyelement_type))
738 return false;
739 }
740 argtypes[i] = poly_actuals.anyelement_type;
741 }
742 break;
743 case ANYARRAYOID:
744 if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
745 {
746 have_polymorphic_result = true;
747 have_anyarray_result = true;
748 }
749 else
750 {
751 if (!OidIsValid(poly_actuals.anyarray_type))
752 {
753 poly_actuals.anyarray_type =
754 get_call_expr_argtype(call_expr, inargno);
755 if (!OidIsValid(poly_actuals.anyarray_type))
756 return false;
757 }
758 argtypes[i] = poly_actuals.anyarray_type;
759 }
760 break;
761 case ANYRANGEOID:
762 if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
763 {
764 have_polymorphic_result = true;
765 have_anyrange_result = true;
766 }
767 else
768 {
769 if (!OidIsValid(poly_actuals.anyrange_type))
770 {
771 poly_actuals.anyrange_type =
772 get_call_expr_argtype(call_expr, inargno);
773 if (!OidIsValid(poly_actuals.anyrange_type))
774 return false;
775 }
776 argtypes[i] = poly_actuals.anyrange_type;
777 }
778 break;
779 default:
780 break;
781 }
782 if (argmode != PROARGMODE_OUT && argmode != PROARGMODE_TABLE)
783 inargno++;
784 }
785
786 /* Done? */
787 if (!have_polymorphic_result)
788 return true;
789
790 /* If needed, deduce one polymorphic type from others */
791 if (have_anyelement_result && !OidIsValid(poly_actuals.anyelement_type))
792 resolve_anyelement_from_others(&poly_actuals);
793
794 if (have_anyarray_result && !OidIsValid(poly_actuals.anyarray_type))
795 resolve_anyarray_from_others(&poly_actuals);
796
797 if (have_anyrange_result && !OidIsValid(poly_actuals.anyrange_type))
798 resolve_anyrange_from_others(&poly_actuals);
799
800 /* And finally replace the output column types as needed */
801 for (i = 0; i < numargs; i++)
802 {
803 switch (argtypes[i])
804 {
805 case ANYELEMENTOID:
806 case ANYNONARRAYOID:
807 case ANYENUMOID:
808 argtypes[i] = poly_actuals.anyelement_type;
809 break;
810 case ANYARRAYOID:
811 argtypes[i] = poly_actuals.anyarray_type;
812 break;
813 case ANYRANGEOID:
814 argtypes[i] = poly_actuals.anyrange_type;
815 break;
816 default:
817 break;
818 }
819 }
820
821 return true;
822 }
823
824 /*
825 * get_type_func_class
826 * Given the type OID, obtain its TYPEFUNC classification.
827 * Also, if it's a domain, return the base type OID.
828 *
829 * This is intended to centralize a bunch of formerly ad-hoc code for
830 * classifying types. The categories used here are useful for deciding
831 * how to handle functions returning the datatype.
832 */
833 static TypeFuncClass
get_type_func_class(Oid typid,Oid * base_typeid)834 get_type_func_class(Oid typid, Oid *base_typeid)
835 {
836 *base_typeid = typid;
837
838 switch (get_typtype(typid))
839 {
840 case TYPTYPE_COMPOSITE:
841 return TYPEFUNC_COMPOSITE;
842 case TYPTYPE_BASE:
843 case TYPTYPE_ENUM:
844 case TYPTYPE_RANGE:
845 return TYPEFUNC_SCALAR;
846 case TYPTYPE_DOMAIN:
847 *base_typeid = typid = getBaseType(typid);
848 if (get_typtype(typid) == TYPTYPE_COMPOSITE)
849 return TYPEFUNC_COMPOSITE_DOMAIN;
850 else /* domain base type can't be a pseudotype */
851 return TYPEFUNC_SCALAR;
852 case TYPTYPE_PSEUDO:
853 if (typid == RECORDOID)
854 return TYPEFUNC_RECORD;
855
856 /*
857 * We treat VOID and CSTRING as legitimate scalar datatypes,
858 * mostly for the convenience of the JDBC driver (which wants to
859 * be able to do "SELECT * FROM foo()" for all legitimately
860 * user-callable functions).
861 */
862 if (typid == VOIDOID || typid == CSTRINGOID)
863 return TYPEFUNC_SCALAR;
864 return TYPEFUNC_OTHER;
865 }
866 /* shouldn't get here, probably */
867 return TYPEFUNC_OTHER;
868 }
869
870
871 /*
872 * get_func_arg_info
873 *
874 * Fetch info about the argument types, names, and IN/OUT modes from the
875 * pg_proc tuple. Return value is the total number of arguments.
876 * Other results are palloc'd. *p_argtypes is always filled in, but
877 * *p_argnames and *p_argmodes will be set NULL in the default cases
878 * (no names, and all IN arguments, respectively).
879 *
880 * Note that this function simply fetches what is in the pg_proc tuple;
881 * it doesn't do any interpretation of polymorphic types.
882 */
883 int
get_func_arg_info(HeapTuple procTup,Oid ** p_argtypes,char *** p_argnames,char ** p_argmodes)884 get_func_arg_info(HeapTuple procTup,
885 Oid **p_argtypes, char ***p_argnames, char **p_argmodes)
886 {
887 Form_pg_proc procStruct = (Form_pg_proc) GETSTRUCT(procTup);
888 Datum proallargtypes;
889 Datum proargmodes;
890 Datum proargnames;
891 bool isNull;
892 ArrayType *arr;
893 int numargs;
894 Datum *elems;
895 int nelems;
896 int i;
897
898 /* First discover the total number of parameters and get their types */
899 proallargtypes = SysCacheGetAttr(PROCOID, procTup,
900 Anum_pg_proc_proallargtypes,
901 &isNull);
902 if (!isNull)
903 {
904 /*
905 * We expect the arrays to be 1-D arrays of the right types; verify
906 * that. For the OID and char arrays, we don't need to use
907 * deconstruct_array() since the array data is just going to look like
908 * a C array of values.
909 */
910 arr = DatumGetArrayTypeP(proallargtypes); /* ensure not toasted */
911 numargs = ARR_DIMS(arr)[0];
912 if (ARR_NDIM(arr) != 1 ||
913 numargs < 0 ||
914 ARR_HASNULL(arr) ||
915 ARR_ELEMTYPE(arr) != OIDOID)
916 elog(ERROR, "proallargtypes is not a 1-D Oid array");
917 Assert(numargs >= procStruct->pronargs);
918 *p_argtypes = (Oid *) palloc(numargs * sizeof(Oid));
919 memcpy(*p_argtypes, ARR_DATA_PTR(arr),
920 numargs * sizeof(Oid));
921 }
922 else
923 {
924 /* If no proallargtypes, use proargtypes */
925 numargs = procStruct->proargtypes.dim1;
926 Assert(numargs == procStruct->pronargs);
927 *p_argtypes = (Oid *) palloc(numargs * sizeof(Oid));
928 memcpy(*p_argtypes, procStruct->proargtypes.values,
929 numargs * sizeof(Oid));
930 }
931
932 /* Get argument names, if available */
933 proargnames = SysCacheGetAttr(PROCOID, procTup,
934 Anum_pg_proc_proargnames,
935 &isNull);
936 if (isNull)
937 *p_argnames = NULL;
938 else
939 {
940 deconstruct_array(DatumGetArrayTypeP(proargnames),
941 TEXTOID, -1, false, 'i',
942 &elems, NULL, &nelems);
943 if (nelems != numargs) /* should not happen */
944 elog(ERROR, "proargnames must have the same number of elements as the function has arguments");
945 *p_argnames = (char **) palloc(sizeof(char *) * numargs);
946 for (i = 0; i < numargs; i++)
947 (*p_argnames)[i] = TextDatumGetCString(elems[i]);
948 }
949
950 /* Get argument modes, if available */
951 proargmodes = SysCacheGetAttr(PROCOID, procTup,
952 Anum_pg_proc_proargmodes,
953 &isNull);
954 if (isNull)
955 *p_argmodes = NULL;
956 else
957 {
958 arr = DatumGetArrayTypeP(proargmodes); /* ensure not toasted */
959 if (ARR_NDIM(arr) != 1 ||
960 ARR_DIMS(arr)[0] != numargs ||
961 ARR_HASNULL(arr) ||
962 ARR_ELEMTYPE(arr) != CHAROID)
963 elog(ERROR, "proargmodes is not a 1-D char array");
964 *p_argmodes = (char *) palloc(numargs * sizeof(char));
965 memcpy(*p_argmodes, ARR_DATA_PTR(arr),
966 numargs * sizeof(char));
967 }
968
969 return numargs;
970 }
971
972 /*
973 * get_func_trftypes
974 *
975 * Returns the number of transformed types used by the function.
976 * If there are any, a palloc'd array of the type OIDs is returned
977 * into *p_trftypes.
978 */
979 int
get_func_trftypes(HeapTuple procTup,Oid ** p_trftypes)980 get_func_trftypes(HeapTuple procTup,
981 Oid **p_trftypes)
982 {
983 Datum protrftypes;
984 ArrayType *arr;
985 int nelems;
986 bool isNull;
987
988 protrftypes = SysCacheGetAttr(PROCOID, procTup,
989 Anum_pg_proc_protrftypes,
990 &isNull);
991 if (!isNull)
992 {
993 /*
994 * We expect the arrays to be 1-D arrays of the right types; verify
995 * that. For the OID and char arrays, we don't need to use
996 * deconstruct_array() since the array data is just going to look like
997 * a C array of values.
998 */
999 arr = DatumGetArrayTypeP(protrftypes); /* ensure not toasted */
1000 nelems = ARR_DIMS(arr)[0];
1001 if (ARR_NDIM(arr) != 1 ||
1002 nelems < 0 ||
1003 ARR_HASNULL(arr) ||
1004 ARR_ELEMTYPE(arr) != OIDOID)
1005 elog(ERROR, "protrftypes is not a 1-D Oid array");
1006 *p_trftypes = (Oid *) palloc(nelems * sizeof(Oid));
1007 memcpy(*p_trftypes, ARR_DATA_PTR(arr),
1008 nelems * sizeof(Oid));
1009
1010 return nelems;
1011 }
1012 else
1013 return 0;
1014 }
1015
1016 /*
1017 * get_func_input_arg_names
1018 *
1019 * Extract the names of input arguments only, given a function's
1020 * proargnames and proargmodes entries in Datum form.
1021 *
1022 * Returns the number of input arguments, which is the length of the
1023 * palloc'd array returned to *arg_names. Entries for unnamed args
1024 * are set to NULL. You don't get anything if proargnames is NULL.
1025 */
1026 int
get_func_input_arg_names(Datum proargnames,Datum proargmodes,char *** arg_names)1027 get_func_input_arg_names(Datum proargnames, Datum proargmodes,
1028 char ***arg_names)
1029 {
1030 ArrayType *arr;
1031 int numargs;
1032 Datum *argnames;
1033 char *argmodes;
1034 char **inargnames;
1035 int numinargs;
1036 int i;
1037
1038 /* Do nothing if null proargnames */
1039 if (proargnames == PointerGetDatum(NULL))
1040 {
1041 *arg_names = NULL;
1042 return 0;
1043 }
1044
1045 /*
1046 * We expect the arrays to be 1-D arrays of the right types; verify that.
1047 * For proargmodes, we don't need to use deconstruct_array() since the
1048 * array data is just going to look like a C array of values.
1049 */
1050 arr = DatumGetArrayTypeP(proargnames); /* ensure not toasted */
1051 if (ARR_NDIM(arr) != 1 ||
1052 ARR_HASNULL(arr) ||
1053 ARR_ELEMTYPE(arr) != TEXTOID)
1054 elog(ERROR, "proargnames is not a 1-D text array");
1055 deconstruct_array(arr, TEXTOID, -1, false, 'i',
1056 &argnames, NULL, &numargs);
1057 if (proargmodes != PointerGetDatum(NULL))
1058 {
1059 arr = DatumGetArrayTypeP(proargmodes); /* ensure not toasted */
1060 if (ARR_NDIM(arr) != 1 ||
1061 ARR_DIMS(arr)[0] != numargs ||
1062 ARR_HASNULL(arr) ||
1063 ARR_ELEMTYPE(arr) != CHAROID)
1064 elog(ERROR, "proargmodes is not a 1-D char array");
1065 argmodes = (char *) ARR_DATA_PTR(arr);
1066 }
1067 else
1068 argmodes = NULL;
1069
1070 /* zero elements probably shouldn't happen, but handle it gracefully */
1071 if (numargs <= 0)
1072 {
1073 *arg_names = NULL;
1074 return 0;
1075 }
1076
1077 /* extract input-argument names */
1078 inargnames = (char **) palloc(numargs * sizeof(char *));
1079 numinargs = 0;
1080 for (i = 0; i < numargs; i++)
1081 {
1082 if (argmodes == NULL ||
1083 argmodes[i] == PROARGMODE_IN ||
1084 argmodes[i] == PROARGMODE_INOUT ||
1085 argmodes[i] == PROARGMODE_VARIADIC)
1086 {
1087 char *pname = TextDatumGetCString(argnames[i]);
1088
1089 if (pname[0] != '\0')
1090 inargnames[numinargs] = pname;
1091 else
1092 inargnames[numinargs] = NULL;
1093 numinargs++;
1094 }
1095 }
1096
1097 *arg_names = inargnames;
1098 return numinargs;
1099 }
1100
1101
1102 /*
1103 * get_func_result_name
1104 *
1105 * If the function has exactly one output parameter, and that parameter
1106 * is named, return the name (as a palloc'd string). Else return NULL.
1107 *
1108 * This is used to determine the default output column name for functions
1109 * returning scalar types.
1110 */
1111 char *
get_func_result_name(Oid functionId)1112 get_func_result_name(Oid functionId)
1113 {
1114 char *result;
1115 HeapTuple procTuple;
1116 Datum proargmodes;
1117 Datum proargnames;
1118 bool isnull;
1119 ArrayType *arr;
1120 int numargs;
1121 char *argmodes;
1122 Datum *argnames;
1123 int numoutargs;
1124 int nargnames;
1125 int i;
1126
1127 /* First fetch the function's pg_proc row */
1128 procTuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(functionId));
1129 if (!HeapTupleIsValid(procTuple))
1130 elog(ERROR, "cache lookup failed for function %u", functionId);
1131
1132 /* If there are no named OUT parameters, return NULL */
1133 if (heap_attisnull(procTuple, Anum_pg_proc_proargmodes, NULL) ||
1134 heap_attisnull(procTuple, Anum_pg_proc_proargnames, NULL))
1135 result = NULL;
1136 else
1137 {
1138 /* Get the data out of the tuple */
1139 proargmodes = SysCacheGetAttr(PROCOID, procTuple,
1140 Anum_pg_proc_proargmodes,
1141 &isnull);
1142 Assert(!isnull);
1143 proargnames = SysCacheGetAttr(PROCOID, procTuple,
1144 Anum_pg_proc_proargnames,
1145 &isnull);
1146 Assert(!isnull);
1147
1148 /*
1149 * We expect the arrays to be 1-D arrays of the right types; verify
1150 * that. For the char array, we don't need to use deconstruct_array()
1151 * since the array data is just going to look like a C array of
1152 * values.
1153 */
1154 arr = DatumGetArrayTypeP(proargmodes); /* ensure not toasted */
1155 numargs = ARR_DIMS(arr)[0];
1156 if (ARR_NDIM(arr) != 1 ||
1157 numargs < 0 ||
1158 ARR_HASNULL(arr) ||
1159 ARR_ELEMTYPE(arr) != CHAROID)
1160 elog(ERROR, "proargmodes is not a 1-D char array");
1161 argmodes = (char *) ARR_DATA_PTR(arr);
1162 arr = DatumGetArrayTypeP(proargnames); /* ensure not toasted */
1163 if (ARR_NDIM(arr) != 1 ||
1164 ARR_DIMS(arr)[0] != numargs ||
1165 ARR_HASNULL(arr) ||
1166 ARR_ELEMTYPE(arr) != TEXTOID)
1167 elog(ERROR, "proargnames is not a 1-D text array");
1168 deconstruct_array(arr, TEXTOID, -1, false, 'i',
1169 &argnames, NULL, &nargnames);
1170 Assert(nargnames == numargs);
1171
1172 /* scan for output argument(s) */
1173 result = NULL;
1174 numoutargs = 0;
1175 for (i = 0; i < numargs; i++)
1176 {
1177 if (argmodes[i] == PROARGMODE_IN ||
1178 argmodes[i] == PROARGMODE_VARIADIC)
1179 continue;
1180 Assert(argmodes[i] == PROARGMODE_OUT ||
1181 argmodes[i] == PROARGMODE_INOUT ||
1182 argmodes[i] == PROARGMODE_TABLE);
1183 if (++numoutargs > 1)
1184 {
1185 /* multiple out args, so forget it */
1186 result = NULL;
1187 break;
1188 }
1189 result = TextDatumGetCString(argnames[i]);
1190 if (result == NULL || result[0] == '\0')
1191 {
1192 /* Parameter is not named, so forget it */
1193 result = NULL;
1194 break;
1195 }
1196 }
1197 }
1198
1199 ReleaseSysCache(procTuple);
1200
1201 return result;
1202 }
1203
1204
1205 /*
1206 * build_function_result_tupdesc_t
1207 *
1208 * Given a pg_proc row for a function, return a tuple descriptor for the
1209 * result rowtype, or NULL if the function does not have OUT parameters.
1210 *
1211 * Note that this does not handle resolution of polymorphic types;
1212 * that is deliberate.
1213 */
1214 TupleDesc
build_function_result_tupdesc_t(HeapTuple procTuple)1215 build_function_result_tupdesc_t(HeapTuple procTuple)
1216 {
1217 Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(procTuple);
1218 Datum proallargtypes;
1219 Datum proargmodes;
1220 Datum proargnames;
1221 bool isnull;
1222
1223 /* Return NULL if the function isn't declared to return RECORD */
1224 if (procform->prorettype != RECORDOID)
1225 return NULL;
1226
1227 /* If there are no OUT parameters, return NULL */
1228 if (heap_attisnull(procTuple, Anum_pg_proc_proallargtypes, NULL) ||
1229 heap_attisnull(procTuple, Anum_pg_proc_proargmodes, NULL))
1230 return NULL;
1231
1232 /* Get the data out of the tuple */
1233 proallargtypes = SysCacheGetAttr(PROCOID, procTuple,
1234 Anum_pg_proc_proallargtypes,
1235 &isnull);
1236 Assert(!isnull);
1237 proargmodes = SysCacheGetAttr(PROCOID, procTuple,
1238 Anum_pg_proc_proargmodes,
1239 &isnull);
1240 Assert(!isnull);
1241 proargnames = SysCacheGetAttr(PROCOID, procTuple,
1242 Anum_pg_proc_proargnames,
1243 &isnull);
1244 if (isnull)
1245 proargnames = PointerGetDatum(NULL); /* just to be sure */
1246
1247 return build_function_result_tupdesc_d(procform->prokind,
1248 proallargtypes,
1249 proargmodes,
1250 proargnames);
1251 }
1252
1253 /*
1254 * build_function_result_tupdesc_d
1255 *
1256 * Build a RECORD function's tupledesc from the pg_proc proallargtypes,
1257 * proargmodes, and proargnames arrays. This is split out for the
1258 * convenience of ProcedureCreate, which needs to be able to compute the
1259 * tupledesc before actually creating the function.
1260 *
1261 * For functions (but not for procedures), returns NULL if there are not at
1262 * least two OUT or INOUT arguments.
1263 */
1264 TupleDesc
build_function_result_tupdesc_d(char prokind,Datum proallargtypes,Datum proargmodes,Datum proargnames)1265 build_function_result_tupdesc_d(char prokind,
1266 Datum proallargtypes,
1267 Datum proargmodes,
1268 Datum proargnames)
1269 {
1270 TupleDesc desc;
1271 ArrayType *arr;
1272 int numargs;
1273 Oid *argtypes;
1274 char *argmodes;
1275 Datum *argnames = NULL;
1276 Oid *outargtypes;
1277 char **outargnames;
1278 int numoutargs;
1279 int nargnames;
1280 int i;
1281
1282 /* Can't have output args if columns are null */
1283 if (proallargtypes == PointerGetDatum(NULL) ||
1284 proargmodes == PointerGetDatum(NULL))
1285 return NULL;
1286
1287 /*
1288 * We expect the arrays to be 1-D arrays of the right types; verify that.
1289 * For the OID and char arrays, we don't need to use deconstruct_array()
1290 * since the array data is just going to look like a C array of values.
1291 */
1292 arr = DatumGetArrayTypeP(proallargtypes); /* ensure not toasted */
1293 numargs = ARR_DIMS(arr)[0];
1294 if (ARR_NDIM(arr) != 1 ||
1295 numargs < 0 ||
1296 ARR_HASNULL(arr) ||
1297 ARR_ELEMTYPE(arr) != OIDOID)
1298 elog(ERROR, "proallargtypes is not a 1-D Oid array");
1299 argtypes = (Oid *) ARR_DATA_PTR(arr);
1300 arr = DatumGetArrayTypeP(proargmodes); /* ensure not toasted */
1301 if (ARR_NDIM(arr) != 1 ||
1302 ARR_DIMS(arr)[0] != numargs ||
1303 ARR_HASNULL(arr) ||
1304 ARR_ELEMTYPE(arr) != CHAROID)
1305 elog(ERROR, "proargmodes is not a 1-D char array");
1306 argmodes = (char *) ARR_DATA_PTR(arr);
1307 if (proargnames != PointerGetDatum(NULL))
1308 {
1309 arr = DatumGetArrayTypeP(proargnames); /* ensure not toasted */
1310 if (ARR_NDIM(arr) != 1 ||
1311 ARR_DIMS(arr)[0] != numargs ||
1312 ARR_HASNULL(arr) ||
1313 ARR_ELEMTYPE(arr) != TEXTOID)
1314 elog(ERROR, "proargnames is not a 1-D text array");
1315 deconstruct_array(arr, TEXTOID, -1, false, 'i',
1316 &argnames, NULL, &nargnames);
1317 Assert(nargnames == numargs);
1318 }
1319
1320 /* zero elements probably shouldn't happen, but handle it gracefully */
1321 if (numargs <= 0)
1322 return NULL;
1323
1324 /* extract output-argument types and names */
1325 outargtypes = (Oid *) palloc(numargs * sizeof(Oid));
1326 outargnames = (char **) palloc(numargs * sizeof(char *));
1327 numoutargs = 0;
1328 for (i = 0; i < numargs; i++)
1329 {
1330 char *pname;
1331
1332 if (argmodes[i] == PROARGMODE_IN ||
1333 argmodes[i] == PROARGMODE_VARIADIC)
1334 continue;
1335 Assert(argmodes[i] == PROARGMODE_OUT ||
1336 argmodes[i] == PROARGMODE_INOUT ||
1337 argmodes[i] == PROARGMODE_TABLE);
1338 outargtypes[numoutargs] = argtypes[i];
1339 if (argnames)
1340 pname = TextDatumGetCString(argnames[i]);
1341 else
1342 pname = NULL;
1343 if (pname == NULL || pname[0] == '\0')
1344 {
1345 /* Parameter is not named, so gin up a column name */
1346 pname = psprintf("column%d", numoutargs + 1);
1347 }
1348 outargnames[numoutargs] = pname;
1349 numoutargs++;
1350 }
1351
1352 /*
1353 * If there is no output argument, or only one, the function does not
1354 * return tuples.
1355 */
1356 if (numoutargs < 2 && prokind != PROKIND_PROCEDURE)
1357 return NULL;
1358
1359 desc = CreateTemplateTupleDesc(numoutargs);
1360 for (i = 0; i < numoutargs; i++)
1361 {
1362 TupleDescInitEntry(desc, i + 1,
1363 outargnames[i],
1364 outargtypes[i],
1365 -1,
1366 0);
1367 }
1368
1369 return desc;
1370 }
1371
1372
1373 /*
1374 * RelationNameGetTupleDesc
1375 *
1376 * Given a (possibly qualified) relation name, build a TupleDesc.
1377 *
1378 * Note: while this works as advertised, it's seldom the best way to
1379 * build a tupdesc for a function's result type. It's kept around
1380 * only for backwards compatibility with existing user-written code.
1381 */
1382 TupleDesc
RelationNameGetTupleDesc(const char * relname)1383 RelationNameGetTupleDesc(const char *relname)
1384 {
1385 RangeVar *relvar;
1386 Relation rel;
1387 TupleDesc tupdesc;
1388 List *relname_list;
1389
1390 /* Open relation and copy the tuple description */
1391 relname_list = stringToQualifiedNameList(relname);
1392 relvar = makeRangeVarFromNameList(relname_list);
1393 rel = relation_openrv(relvar, AccessShareLock);
1394 tupdesc = CreateTupleDescCopy(RelationGetDescr(rel));
1395 relation_close(rel, AccessShareLock);
1396
1397 return tupdesc;
1398 }
1399
1400 /*
1401 * TypeGetTupleDesc
1402 *
1403 * Given a type Oid, build a TupleDesc. (In most cases you should be
1404 * using get_call_result_type or one of its siblings instead of this
1405 * routine, so that you can handle OUT parameters, RECORD result type,
1406 * and polymorphic results.)
1407 *
1408 * If the type is composite, *and* a colaliases List is provided, *and*
1409 * the List is of natts length, use the aliases instead of the relation
1410 * attnames. (NB: this usage is deprecated since it may result in
1411 * creation of unnecessary transient record types.)
1412 *
1413 * If the type is a base type, a single item alias List is required.
1414 */
1415 TupleDesc
TypeGetTupleDesc(Oid typeoid,List * colaliases)1416 TypeGetTupleDesc(Oid typeoid, List *colaliases)
1417 {
1418 Oid base_typeoid;
1419 TypeFuncClass functypclass = get_type_func_class(typeoid, &base_typeoid);
1420 TupleDesc tupdesc = NULL;
1421
1422 /*
1423 * Build a suitable tupledesc representing the output rows. We
1424 * intentionally do not support TYPEFUNC_COMPOSITE_DOMAIN here, as it's
1425 * unlikely that legacy callers of this obsolete function would be
1426 * prepared to apply domain constraints.
1427 */
1428 if (functypclass == TYPEFUNC_COMPOSITE)
1429 {
1430 /* Composite data type, e.g. a table's row type */
1431 tupdesc = lookup_rowtype_tupdesc_copy(base_typeoid, -1);
1432
1433 if (colaliases != NIL)
1434 {
1435 int natts = tupdesc->natts;
1436 int varattno;
1437
1438 /* does the list length match the number of attributes? */
1439 if (list_length(colaliases) != natts)
1440 ereport(ERROR,
1441 (errcode(ERRCODE_DATATYPE_MISMATCH),
1442 errmsg("number of aliases does not match number of columns")));
1443
1444 /* OK, use the aliases instead */
1445 for (varattno = 0; varattno < natts; varattno++)
1446 {
1447 char *label = strVal(list_nth(colaliases, varattno));
1448 Form_pg_attribute attr = TupleDescAttr(tupdesc, varattno);
1449
1450 if (label != NULL)
1451 namestrcpy(&(attr->attname), label);
1452 }
1453
1454 /* The tuple type is now an anonymous record type */
1455 tupdesc->tdtypeid = RECORDOID;
1456 tupdesc->tdtypmod = -1;
1457 }
1458 }
1459 else if (functypclass == TYPEFUNC_SCALAR)
1460 {
1461 /* Base data type, i.e. scalar */
1462 char *attname;
1463
1464 /* the alias list is required for base types */
1465 if (colaliases == NIL)
1466 ereport(ERROR,
1467 (errcode(ERRCODE_DATATYPE_MISMATCH),
1468 errmsg("no column alias was provided")));
1469
1470 /* the alias list length must be 1 */
1471 if (list_length(colaliases) != 1)
1472 ereport(ERROR,
1473 (errcode(ERRCODE_DATATYPE_MISMATCH),
1474 errmsg("number of aliases does not match number of columns")));
1475
1476 /* OK, get the column alias */
1477 attname = strVal(linitial(colaliases));
1478
1479 tupdesc = CreateTemplateTupleDesc(1);
1480 TupleDescInitEntry(tupdesc,
1481 (AttrNumber) 1,
1482 attname,
1483 typeoid,
1484 -1,
1485 0);
1486 }
1487 else if (functypclass == TYPEFUNC_RECORD)
1488 {
1489 /* XXX can't support this because typmod wasn't passed in ... */
1490 ereport(ERROR,
1491 (errcode(ERRCODE_DATATYPE_MISMATCH),
1492 errmsg("could not determine row description for function returning record")));
1493 }
1494 else
1495 {
1496 /* crummy error message, but parser should have caught this */
1497 elog(ERROR, "function in FROM has unsupported return type");
1498 }
1499
1500 return tupdesc;
1501 }
1502
1503 /*
1504 * extract_variadic_args
1505 *
1506 * Extract a set of argument values, types and NULL markers for a given
1507 * input function which makes use of a VARIADIC input whose argument list
1508 * depends on the caller context. When doing a VARIADIC call, the caller
1509 * has provided one argument made of an array of values, so deconstruct the
1510 * array data before using it for the next processing. If no VARIADIC call
1511 * is used, just fill in the status data based on all the arguments given
1512 * by the caller.
1513 *
1514 * This function returns the number of arguments generated, or -1 in the
1515 * case of "VARIADIC NULL".
1516 */
1517 int
extract_variadic_args(FunctionCallInfo fcinfo,int variadic_start,bool convert_unknown,Datum ** args,Oid ** types,bool ** nulls)1518 extract_variadic_args(FunctionCallInfo fcinfo, int variadic_start,
1519 bool convert_unknown, Datum **args, Oid **types,
1520 bool **nulls)
1521 {
1522 bool variadic = get_fn_expr_variadic(fcinfo->flinfo);
1523 Datum *args_res;
1524 bool *nulls_res;
1525 Oid *types_res;
1526 int nargs,
1527 i;
1528
1529 *args = NULL;
1530 *types = NULL;
1531 *nulls = NULL;
1532
1533 if (variadic)
1534 {
1535 ArrayType *array_in;
1536 Oid element_type;
1537 bool typbyval;
1538 char typalign;
1539 int16 typlen;
1540
1541 Assert(PG_NARGS() == variadic_start + 1);
1542
1543 if (PG_ARGISNULL(variadic_start))
1544 return -1;
1545
1546 array_in = PG_GETARG_ARRAYTYPE_P(variadic_start);
1547 element_type = ARR_ELEMTYPE(array_in);
1548
1549 get_typlenbyvalalign(element_type,
1550 &typlen, &typbyval, &typalign);
1551 deconstruct_array(array_in, element_type, typlen, typbyval,
1552 typalign, &args_res, &nulls_res,
1553 &nargs);
1554
1555 /* All the elements of the array have the same type */
1556 types_res = (Oid *) palloc0(nargs * sizeof(Oid));
1557 for (i = 0; i < nargs; i++)
1558 types_res[i] = element_type;
1559 }
1560 else
1561 {
1562 nargs = PG_NARGS() - variadic_start;
1563 Assert(nargs > 0);
1564 nulls_res = (bool *) palloc0(nargs * sizeof(bool));
1565 args_res = (Datum *) palloc0(nargs * sizeof(Datum));
1566 types_res = (Oid *) palloc0(nargs * sizeof(Oid));
1567
1568 for (i = 0; i < nargs; i++)
1569 {
1570 nulls_res[i] = PG_ARGISNULL(i + variadic_start);
1571 types_res[i] = get_fn_expr_argtype(fcinfo->flinfo,
1572 i + variadic_start);
1573
1574 /*
1575 * Turn a constant (more or less literal) value that's of unknown
1576 * type into text if required. Unknowns come in as a cstring
1577 * pointer. Note: for functions declared as taking type "any", the
1578 * parser will not do any type conversion on unknown-type literals
1579 * (that is, undecorated strings or NULLs).
1580 */
1581 if (convert_unknown &&
1582 types_res[i] == UNKNOWNOID &&
1583 get_fn_expr_arg_stable(fcinfo->flinfo, i + variadic_start))
1584 {
1585 types_res[i] = TEXTOID;
1586
1587 if (PG_ARGISNULL(i + variadic_start))
1588 args_res[i] = (Datum) 0;
1589 else
1590 args_res[i] =
1591 CStringGetTextDatum(PG_GETARG_POINTER(i + variadic_start));
1592 }
1593 else
1594 {
1595 /* no conversion needed, just take the datum as given */
1596 args_res[i] = PG_GETARG_DATUM(i + variadic_start);
1597 }
1598
1599 if (!OidIsValid(types_res[i]) ||
1600 (convert_unknown && types_res[i] == UNKNOWNOID))
1601 ereport(ERROR,
1602 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1603 errmsg("could not determine data type for argument %d",
1604 i + 1)));
1605 }
1606 }
1607
1608 /* Fill in results */
1609 *args = args_res;
1610 *nulls = nulls_res;
1611 *types = types_res;
1612
1613 return nargs;
1614 }
1615