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