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