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