PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
funcapi.c
Go to the documentation of this file.
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-2025, PostgreSQL Global Development Group
8 *
9 * IDENTIFICATION
10 * src/backend/utils/fmgr/funcapi.c
11 *
12 *-------------------------------------------------------------------------
13 */
14#include "postgres.h"
15
16#include "access/htup_details.h"
17#include "access/relation.h"
18#include "catalog/namespace.h"
19#include "catalog/pg_proc.h"
20#include "catalog/pg_type.h"
21#include "funcapi.h"
22#include "miscadmin.h"
23#include "nodes/nodeFuncs.h"
24#include "utils/array.h"
25#include "utils/builtins.h"
26#include "utils/lsyscache.h"
27#include "utils/memutils.h"
28#include "utils/regproc.h"
29#include "utils/rel.h"
30#include "utils/syscache.h"
31#include "utils/tuplestore.h"
32#include "utils/typcache.h"
33
34
35typedef struct polymorphic_actuals
36{
37 Oid anyelement_type; /* anyelement mapping, if known */
38 Oid anyarray_type; /* anyarray mapping, if known */
39 Oid anyrange_type; /* anyrange mapping, if known */
40 Oid anymultirange_type; /* anymultirange mapping, if known */
42
45 Node *call_expr,
46 ReturnSetInfo *rsinfo,
47 Oid *resultTypeId,
48 TupleDesc *resultTupleDesc);
53static bool resolve_polymorphic_tupdesc(TupleDesc tupdesc,
54 oidvector *declared_args,
55 Node *call_expr);
56static TypeFuncClass get_type_func_class(Oid typid, Oid *base_typeid);
57
58
59/*
60 * InitMaterializedSRF
61 *
62 * Helper function to build the state of a set-returning function used
63 * in the context of a single call with materialize mode. This code
64 * includes sanity checks on ReturnSetInfo, creates the Tuplestore and
65 * the TupleDesc used with the function and stores them into the
66 * function's ReturnSetInfo.
67 *
68 * "flags" can be set to MAT_SRF_USE_EXPECTED_DESC, to use the tuple
69 * descriptor coming from expectedDesc, which is the tuple descriptor
70 * expected by the caller. MAT_SRF_BLESS can be set to complete the
71 * information associated to the tuple descriptor, which is necessary
72 * in some cases where the tuple descriptor comes from a transient
73 * RECORD datatype.
74 */
75void
77{
78 bool random_access;
79 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
80 Tuplestorestate *tupstore;
81 MemoryContext old_context,
82 per_query_ctx;
83 TupleDesc stored_tupdesc;
84
85 /* check to see if caller supports returning a tuplestore */
86 if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
88 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
89 errmsg("set-valued function called in context that cannot accept a set")));
90 if (!(rsinfo->allowedModes & SFRM_Materialize) ||
91 ((flags & MAT_SRF_USE_EXPECTED_DESC) != 0 && rsinfo->expectedDesc == NULL))
93 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
94 errmsg("materialize mode required, but it is not allowed in this context")));
95
96 /*
97 * Store the tuplestore and the tuple descriptor in ReturnSetInfo. This
98 * must be done in the per-query memory context.
99 */
100 per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
101 old_context = MemoryContextSwitchTo(per_query_ctx);
102
103 /* build a tuple descriptor for our result type */
104 if ((flags & MAT_SRF_USE_EXPECTED_DESC) != 0)
105 stored_tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc);
106 else
107 {
108 if (get_call_result_type(fcinfo, NULL, &stored_tupdesc) != TYPEFUNC_COMPOSITE)
109 elog(ERROR, "return type must be a row type");
110 }
111
112 /* If requested, bless the tuple descriptor */
113 if ((flags & MAT_SRF_BLESS) != 0)
114 BlessTupleDesc(stored_tupdesc);
115
116 random_access = (rsinfo->allowedModes & SFRM_Materialize_Random) != 0;
117
118 tupstore = tuplestore_begin_heap(random_access, false, work_mem);
120 rsinfo->setResult = tupstore;
121 rsinfo->setDesc = stored_tupdesc;
122 MemoryContextSwitchTo(old_context);
123}
124
125
126/*
127 * init_MultiFuncCall
128 * Create an empty FuncCallContext data structure
129 * and do some other basic Multi-function call setup
130 * and error checking
131 */
134{
135 FuncCallContext *retval;
136
137 /*
138 * Bail if we're called in the wrong context
139 */
140 if (fcinfo->resultinfo == NULL || !IsA(fcinfo->resultinfo, ReturnSetInfo))
142 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
143 errmsg("set-valued function called in context that cannot accept a set")));
144
145 if (fcinfo->flinfo->fn_extra == NULL)
146 {
147 /*
148 * First call
149 */
150 ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
151 MemoryContext multi_call_ctx;
152
153 /*
154 * Create a suitably long-lived context to hold cross-call data
155 */
156 multi_call_ctx = AllocSetContextCreate(fcinfo->flinfo->fn_mcxt,
157 "SRF multi-call context",
159
160 /*
161 * Allocate suitably long-lived space and zero it
162 */
163 retval = (FuncCallContext *)
164 MemoryContextAllocZero(multi_call_ctx,
165 sizeof(FuncCallContext));
166
167 /*
168 * initialize the elements
169 */
170 retval->call_cntr = 0;
171 retval->max_calls = 0;
172 retval->user_fctx = NULL;
173 retval->attinmeta = NULL;
174 retval->tuple_desc = NULL;
175 retval->multi_call_memory_ctx = multi_call_ctx;
176
177 /*
178 * save the pointer for cross-call use
179 */
180 fcinfo->flinfo->fn_extra = retval;
181
182 /*
183 * Ensure we will get shut down cleanly if the exprcontext is not run
184 * to completion.
185 */
188 PointerGetDatum(fcinfo->flinfo));
189 }
190 else
191 {
192 /* second and subsequent calls */
193 elog(ERROR, "init_MultiFuncCall cannot be called more than once");
194
195 /* never reached, but keep compiler happy */
196 retval = NULL;
197 }
198
199 return retval;
200}
201
202/*
203 * per_MultiFuncCall
204 *
205 * Do Multi-function per-call setup
206 */
209{
210 FuncCallContext *retval = (FuncCallContext *) fcinfo->flinfo->fn_extra;
211
212 return retval;
213}
214
215/*
216 * end_MultiFuncCall
217 * Clean up after init_MultiFuncCall
218 */
219void
221{
222 ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
223
224 /* Deregister the shutdown callback */
227 PointerGetDatum(fcinfo->flinfo));
228
229 /* But use it to do the real work */
231}
232
233/*
234 * shutdown_MultiFuncCall
235 * Shutdown function to clean up after init_MultiFuncCall
236 */
237static void
239{
240 FmgrInfo *flinfo = (FmgrInfo *) DatumGetPointer(arg);
241 FuncCallContext *funcctx = (FuncCallContext *) flinfo->fn_extra;
242
243 /* unbind from flinfo */
244 flinfo->fn_extra = NULL;
245
246 /*
247 * Delete context that holds all multi-call data, including the
248 * FuncCallContext itself
249 */
251}
252
253
254/*
255 * get_call_result_type
256 * Given a function's call info record, determine the kind of datatype
257 * it is supposed to return. If resultTypeId isn't NULL, *resultTypeId
258 * receives the actual datatype OID (this is mainly useful for scalar
259 * result types). If resultTupleDesc isn't NULL, *resultTupleDesc
260 * receives a pointer to a TupleDesc when the result is of a composite
261 * type, or NULL when it's a scalar result.
262 *
263 * One hard case that this handles is resolution of actual rowtypes for
264 * functions returning RECORD (from either the function's OUT parameter
265 * list, or a ReturnSetInfo context node). TYPEFUNC_RECORD is returned
266 * only when we couldn't resolve the actual rowtype for lack of information.
267 *
268 * The other hard case that this handles is resolution of polymorphism.
269 * We will never return polymorphic pseudotypes (ANYELEMENT etc), either
270 * as a scalar result type or as a component of a rowtype.
271 *
272 * This function is relatively expensive --- in a function returning set,
273 * try to call it only the first time through.
274 */
277 Oid *resultTypeId,
278 TupleDesc *resultTupleDesc)
279{
280 return internal_get_result_type(fcinfo->flinfo->fn_oid,
281 fcinfo->flinfo->fn_expr,
282 (ReturnSetInfo *) fcinfo->resultinfo,
283 resultTypeId,
284 resultTupleDesc);
285}
286
287/*
288 * get_expr_result_type
289 * As above, but work from a calling expression node tree
290 *
291 * Beware of using this on the funcexpr of a RTE that has a coldeflist.
292 * The correct conclusion in such cases is always that the function returns
293 * RECORD with the columns defined by the coldeflist fields (funccolnames etc).
294 * If it does not, it's the executor's responsibility to catch the discrepancy
295 * at runtime; but code processing the query in advance of that point might
296 * come to inconsistent conclusions if it checks the actual expression.
297 */
300 Oid *resultTypeId,
301 TupleDesc *resultTupleDesc)
302{
303 TypeFuncClass result;
304
305 if (expr && IsA(expr, FuncExpr))
306 result = internal_get_result_type(((FuncExpr *) expr)->funcid,
307 expr,
308 NULL,
309 resultTypeId,
310 resultTupleDesc);
311 else if (expr && IsA(expr, OpExpr))
312 result = internal_get_result_type(get_opcode(((OpExpr *) expr)->opno),
313 expr,
314 NULL,
315 resultTypeId,
316 resultTupleDesc);
317 else if (expr && IsA(expr, RowExpr) &&
318 ((RowExpr *) expr)->row_typeid == RECORDOID)
319 {
320 /* We can resolve the record type by generating the tupdesc directly */
321 RowExpr *rexpr = (RowExpr *) expr;
322 TupleDesc tupdesc;
323 AttrNumber i = 1;
324 ListCell *lcc,
325 *lcn;
326
327 tupdesc = CreateTemplateTupleDesc(list_length(rexpr->args));
328 Assert(list_length(rexpr->args) == list_length(rexpr->colnames));
329 forboth(lcc, rexpr->args, lcn, rexpr->colnames)
330 {
331 Node *col = (Node *) lfirst(lcc);
332 char *colname = strVal(lfirst(lcn));
333
334 TupleDescInitEntry(tupdesc, i,
335 colname,
336 exprType(col),
337 exprTypmod(col),
338 0);
340 exprCollation(col));
341 i++;
342 }
343 if (resultTypeId)
344 *resultTypeId = rexpr->row_typeid;
345 if (resultTupleDesc)
346 *resultTupleDesc = BlessTupleDesc(tupdesc);
347 return TYPEFUNC_COMPOSITE;
348 }
349 else if (expr && IsA(expr, Const) &&
350 ((Const *) expr)->consttype == RECORDOID &&
351 !((Const *) expr)->constisnull)
352 {
353 /*
354 * When EXPLAIN'ing some queries with SEARCH/CYCLE clauses, we may
355 * need to resolve field names of a RECORD-type Const. The datum
356 * should contain a typmod that will tell us that.
357 */
358 HeapTupleHeader rec;
359 Oid tupType;
360 int32 tupTypmod;
361
362 rec = DatumGetHeapTupleHeader(((Const *) expr)->constvalue);
363 tupType = HeapTupleHeaderGetTypeId(rec);
364 tupTypmod = HeapTupleHeaderGetTypMod(rec);
365 if (resultTypeId)
366 *resultTypeId = tupType;
367 if (tupType != RECORDOID || tupTypmod >= 0)
368 {
369 /* Should be able to look it up */
370 if (resultTupleDesc)
371 *resultTupleDesc = lookup_rowtype_tupdesc_copy(tupType,
372 tupTypmod);
373 return TYPEFUNC_COMPOSITE;
374 }
375 else
376 {
377 /* This shouldn't really happen ... */
378 if (resultTupleDesc)
379 *resultTupleDesc = NULL;
380 return TYPEFUNC_RECORD;
381 }
382 }
383 else
384 {
385 /* handle as a generic expression; no chance to resolve RECORD */
386 Oid typid = exprType(expr);
387 Oid base_typid;
388
389 if (resultTypeId)
390 *resultTypeId = typid;
391 if (resultTupleDesc)
392 *resultTupleDesc = NULL;
393 result = get_type_func_class(typid, &base_typid);
394 if ((result == TYPEFUNC_COMPOSITE ||
395 result == TYPEFUNC_COMPOSITE_DOMAIN) &&
396 resultTupleDesc)
397 *resultTupleDesc = lookup_rowtype_tupdesc_copy(base_typid, -1);
398 }
399
400 return result;
401}
402
403/*
404 * get_func_result_type
405 * As above, but work from a function's OID only
406 *
407 * This will not be able to resolve pure-RECORD results nor polymorphism.
408 */
411 Oid *resultTypeId,
412 TupleDesc *resultTupleDesc)
413{
414 return internal_get_result_type(functionId,
415 NULL,
416 NULL,
417 resultTypeId,
418 resultTupleDesc);
419}
420
421/*
422 * internal_get_result_type -- workhorse code implementing all the above
423 *
424 * funcid must always be supplied. call_expr and rsinfo can be NULL if not
425 * available. We will return TYPEFUNC_RECORD, and store NULL into
426 * *resultTupleDesc, if we cannot deduce the complete result rowtype from
427 * the available information.
428 */
429static TypeFuncClass
431 Node *call_expr,
432 ReturnSetInfo *rsinfo,
433 Oid *resultTypeId,
434 TupleDesc *resultTupleDesc)
435{
436 TypeFuncClass result;
437 HeapTuple tp;
438 Form_pg_proc procform;
439 Oid rettype;
440 Oid base_rettype;
441 TupleDesc tupdesc;
442
443 /* First fetch the function's pg_proc row to inspect its rettype */
444 tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
445 if (!HeapTupleIsValid(tp))
446 elog(ERROR, "cache lookup failed for function %u", funcid);
447 procform = (Form_pg_proc) GETSTRUCT(tp);
448
449 rettype = procform->prorettype;
450
451 /* Check for OUT parameters defining a RECORD result */
453 if (tupdesc)
454 {
455 /*
456 * It has OUT parameters, so it's basically like a regular composite
457 * type, except we have to be able to resolve any polymorphic OUT
458 * parameters.
459 */
460 if (resultTypeId)
461 *resultTypeId = rettype;
462
463 if (resolve_polymorphic_tupdesc(tupdesc,
464 &procform->proargtypes,
465 call_expr))
466 {
467 if (tupdesc->tdtypeid == RECORDOID &&
468 tupdesc->tdtypmod < 0)
470 if (resultTupleDesc)
471 *resultTupleDesc = tupdesc;
472 result = TYPEFUNC_COMPOSITE;
473 }
474 else
475 {
476 if (resultTupleDesc)
477 *resultTupleDesc = NULL;
478 result = TYPEFUNC_RECORD;
479 }
480
481 ReleaseSysCache(tp);
482
483 return result;
484 }
485
486 /*
487 * If scalar polymorphic result, try to resolve it.
488 */
489 if (IsPolymorphicType(rettype))
490 {
491 Oid newrettype = exprType(call_expr);
492
493 if (newrettype == InvalidOid) /* this probably should not happen */
495 (errcode(ERRCODE_DATATYPE_MISMATCH),
496 errmsg("could not determine actual result type for function \"%s\" declared to return type %s",
497 NameStr(procform->proname),
498 format_type_be(rettype))));
499 rettype = newrettype;
500 }
501
502 if (resultTypeId)
503 *resultTypeId = rettype;
504 if (resultTupleDesc)
505 *resultTupleDesc = NULL; /* default result */
506
507 /* Classify the result type */
508 result = get_type_func_class(rettype, &base_rettype);
509 switch (result)
510 {
513 if (resultTupleDesc)
514 *resultTupleDesc = lookup_rowtype_tupdesc_copy(base_rettype, -1);
515 /* Named composite types can't have any polymorphic columns */
516 break;
517 case TYPEFUNC_SCALAR:
518 break;
519 case TYPEFUNC_RECORD:
520 /* We must get the tupledesc from call context */
521 if (rsinfo && IsA(rsinfo, ReturnSetInfo) &&
522 rsinfo->expectedDesc != NULL)
523 {
524 result = TYPEFUNC_COMPOSITE;
525 if (resultTupleDesc)
526 *resultTupleDesc = rsinfo->expectedDesc;
527 /* Assume no polymorphic columns here, either */
528 }
529 break;
530 default:
531 break;
532 }
533
534 ReleaseSysCache(tp);
535
536 return result;
537}
538
539/*
540 * get_expr_result_tupdesc
541 * Get a tupdesc describing the result of a composite-valued expression
542 *
543 * If expression is not composite or rowtype can't be determined, returns NULL
544 * if noError is true, else throws error.
545 *
546 * This is a simpler version of get_expr_result_type() for use when the caller
547 * is only interested in determinate rowtype results. As with that function,
548 * beware of using this on the funcexpr of a RTE that has a coldeflist.
549 */
551get_expr_result_tupdesc(Node *expr, bool noError)
552{
553 TupleDesc tupleDesc;
554 TypeFuncClass functypclass;
555
556 functypclass = get_expr_result_type(expr, NULL, &tupleDesc);
557
558 if (functypclass == TYPEFUNC_COMPOSITE ||
559 functypclass == TYPEFUNC_COMPOSITE_DOMAIN)
560 return tupleDesc;
561
562 if (!noError)
563 {
564 Oid exprTypeId = exprType(expr);
565
566 if (exprTypeId != RECORDOID)
568 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
569 errmsg("type %s is not composite",
570 format_type_be(exprTypeId))));
571 else
573 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
574 errmsg("record type has not been registered")));
575 }
576
577 return NULL;
578}
579
580/*
581 * Resolve actual type of ANYELEMENT from other polymorphic inputs
582 *
583 * Note: the error cases here and in the sibling functions below are not
584 * really user-facing; they could only occur if the function signature is
585 * incorrect or the parser failed to enforce consistency of the actual
586 * argument types. Hence, we don't sweat too much over the error messages.
587 */
588static void
590{
591 if (OidIsValid(actuals->anyarray_type))
592 {
593 /* Use the element type corresponding to actual type */
594 Oid array_base_type = getBaseType(actuals->anyarray_type);
595 Oid array_typelem = get_element_type(array_base_type);
596
597 if (!OidIsValid(array_typelem))
599 (errcode(ERRCODE_DATATYPE_MISMATCH),
600 errmsg("argument declared %s is not an array but type %s",
601 "anyarray",
602 format_type_be(array_base_type))));
603 actuals->anyelement_type = array_typelem;
604 }
605 else if (OidIsValid(actuals->anyrange_type))
606 {
607 /* Use the element type corresponding to actual type */
608 Oid range_base_type = getBaseType(actuals->anyrange_type);
609 Oid range_typelem = get_range_subtype(range_base_type);
610
611 if (!OidIsValid(range_typelem))
613 (errcode(ERRCODE_DATATYPE_MISMATCH),
614 errmsg("argument declared %s is not a range type but type %s",
615 "anyrange",
616 format_type_be(range_base_type))));
617 actuals->anyelement_type = range_typelem;
618 }
619 else if (OidIsValid(actuals->anymultirange_type))
620 {
621 /* Use the element type based on the multirange type */
622 Oid multirange_base_type;
623 Oid multirange_typelem;
624 Oid range_base_type;
625 Oid range_typelem;
626
627 multirange_base_type = getBaseType(actuals->anymultirange_type);
628 multirange_typelem = get_multirange_range(multirange_base_type);
629 if (!OidIsValid(multirange_typelem))
631 (errcode(ERRCODE_DATATYPE_MISMATCH),
632 errmsg("argument declared %s is not a multirange type but type %s",
633 "anymultirange",
634 format_type_be(multirange_base_type))));
635
636 range_base_type = getBaseType(multirange_typelem);
637 range_typelem = get_range_subtype(range_base_type);
638
639 if (!OidIsValid(range_typelem))
641 (errcode(ERRCODE_DATATYPE_MISMATCH),
642 errmsg("argument declared %s does not contain a range type but type %s",
643 "anymultirange",
644 format_type_be(range_base_type))));
645 actuals->anyelement_type = range_typelem;
646 }
647 else
648 elog(ERROR, "could not determine polymorphic type");
649}
650
651/*
652 * Resolve actual type of ANYARRAY from other polymorphic inputs
653 */
654static void
656{
657 /* If we don't know ANYELEMENT, resolve that first */
658 if (!OidIsValid(actuals->anyelement_type))
660
661 if (OidIsValid(actuals->anyelement_type))
662 {
663 /* Use the array type corresponding to actual type */
664 Oid array_typeid = get_array_type(actuals->anyelement_type);
665
666 if (!OidIsValid(array_typeid))
668 (errcode(ERRCODE_UNDEFINED_OBJECT),
669 errmsg("could not find array type for data type %s",
670 format_type_be(actuals->anyelement_type))));
671 actuals->anyarray_type = array_typeid;
672 }
673 else
674 elog(ERROR, "could not determine polymorphic type");
675}
676
677/*
678 * Resolve actual type of ANYRANGE from other polymorphic inputs
679 */
680static void
682{
683 /*
684 * We can't deduce a range type from other polymorphic array or base
685 * types, because there may be multiple range types with the same subtype,
686 * but we can deduce it from a polymorphic multirange type.
687 */
688 if (OidIsValid(actuals->anymultirange_type))
689 {
690 /* Use the element type based on the multirange type */
691 Oid multirange_base_type = getBaseType(actuals->anymultirange_type);
692 Oid multirange_typelem = get_multirange_range(multirange_base_type);
693
694 if (!OidIsValid(multirange_typelem))
696 (errcode(ERRCODE_DATATYPE_MISMATCH),
697 errmsg("argument declared %s is not a multirange type but type %s",
698 "anymultirange",
699 format_type_be(multirange_base_type))));
700 actuals->anyrange_type = multirange_typelem;
701 }
702 else
703 elog(ERROR, "could not determine polymorphic type");
704}
705
706/*
707 * Resolve actual type of ANYMULTIRANGE from other polymorphic inputs
708 */
709static void
711{
712 /*
713 * We can't deduce a multirange type from polymorphic array or base types,
714 * because there may be multiple range types with the same subtype, but we
715 * can deduce it from a polymorphic range type.
716 */
717 if (OidIsValid(actuals->anyrange_type))
718 {
719 Oid range_base_type = getBaseType(actuals->anyrange_type);
720 Oid multirange_typeid = get_range_multirange(range_base_type);
721
722 if (!OidIsValid(multirange_typeid))
724 (errcode(ERRCODE_UNDEFINED_OBJECT),
725 errmsg("could not find multirange type for data type %s",
726 format_type_be(actuals->anyrange_type))));
727 actuals->anymultirange_type = multirange_typeid;
728 }
729 else
730 elog(ERROR, "could not determine polymorphic type");
731}
732
733/*
734 * Given the result tuple descriptor for a function with OUT parameters,
735 * replace any polymorphic column types (ANYELEMENT etc) in the tupdesc
736 * with concrete data types deduced from the input arguments.
737 * declared_args is an oidvector of the function's declared input arg types
738 * (showing which are polymorphic), and call_expr is the call expression.
739 *
740 * Returns true if able to deduce all types, false if necessary information
741 * is not provided (call_expr is NULL or arg types aren't identifiable).
742 */
743static bool
745 Node *call_expr)
746{
747 int natts = tupdesc->natts;
748 int nargs = declared_args->dim1;
749 bool have_polymorphic_result = false;
750 bool have_anyelement_result = false;
751 bool have_anyarray_result = false;
752 bool have_anyrange_result = false;
753 bool have_anymultirange_result = false;
754 bool have_anycompatible_result = false;
755 bool have_anycompatible_array_result = false;
756 bool have_anycompatible_range_result = false;
757 bool have_anycompatible_multirange_result = false;
758 polymorphic_actuals poly_actuals;
759 polymorphic_actuals anyc_actuals;
760 Oid anycollation = InvalidOid;
761 Oid anycompatcollation = InvalidOid;
762 int i;
763
764 /* See if there are any polymorphic outputs; quick out if not */
765 for (i = 0; i < natts; i++)
766 {
767 switch (TupleDescAttr(tupdesc, i)->atttypid)
768 {
769 case ANYELEMENTOID:
770 case ANYNONARRAYOID:
771 case ANYENUMOID:
772 have_polymorphic_result = true;
773 have_anyelement_result = true;
774 break;
775 case ANYARRAYOID:
776 have_polymorphic_result = true;
777 have_anyarray_result = true;
778 break;
779 case ANYRANGEOID:
780 have_polymorphic_result = true;
781 have_anyrange_result = true;
782 break;
783 case ANYMULTIRANGEOID:
784 have_polymorphic_result = true;
785 have_anymultirange_result = true;
786 break;
787 case ANYCOMPATIBLEOID:
788 case ANYCOMPATIBLENONARRAYOID:
789 have_polymorphic_result = true;
790 have_anycompatible_result = true;
791 break;
792 case ANYCOMPATIBLEARRAYOID:
793 have_polymorphic_result = true;
794 have_anycompatible_array_result = true;
795 break;
796 case ANYCOMPATIBLERANGEOID:
797 have_polymorphic_result = true;
798 have_anycompatible_range_result = true;
799 break;
800 case ANYCOMPATIBLEMULTIRANGEOID:
801 have_polymorphic_result = true;
802 have_anycompatible_multirange_result = true;
803 break;
804 default:
805 break;
806 }
807 }
808 if (!have_polymorphic_result)
809 return true;
810
811 /*
812 * Otherwise, extract actual datatype(s) from input arguments. (We assume
813 * the parser already validated consistency of the arguments. Also, for
814 * the ANYCOMPATIBLE pseudotype family, we expect that all matching
815 * arguments were coerced to the selected common supertype, so that it
816 * doesn't matter which one's exposed type we look at.)
817 */
818 if (!call_expr)
819 return false; /* no hope */
820
821 memset(&poly_actuals, 0, sizeof(poly_actuals));
822 memset(&anyc_actuals, 0, sizeof(anyc_actuals));
823
824 for (i = 0; i < nargs; i++)
825 {
826 switch (declared_args->values[i])
827 {
828 case ANYELEMENTOID:
829 case ANYNONARRAYOID:
830 case ANYENUMOID:
831 if (!OidIsValid(poly_actuals.anyelement_type))
832 {
833 poly_actuals.anyelement_type =
834 get_call_expr_argtype(call_expr, i);
835 if (!OidIsValid(poly_actuals.anyelement_type))
836 return false;
837 }
838 break;
839 case ANYARRAYOID:
840 if (!OidIsValid(poly_actuals.anyarray_type))
841 {
842 poly_actuals.anyarray_type =
843 get_call_expr_argtype(call_expr, i);
844 if (!OidIsValid(poly_actuals.anyarray_type))
845 return false;
846 }
847 break;
848 case ANYRANGEOID:
849 if (!OidIsValid(poly_actuals.anyrange_type))
850 {
851 poly_actuals.anyrange_type =
852 get_call_expr_argtype(call_expr, i);
853 if (!OidIsValid(poly_actuals.anyrange_type))
854 return false;
855 }
856 break;
857 case ANYMULTIRANGEOID:
858 if (!OidIsValid(poly_actuals.anymultirange_type))
859 {
860 poly_actuals.anymultirange_type =
861 get_call_expr_argtype(call_expr, i);
862 if (!OidIsValid(poly_actuals.anymultirange_type))
863 return false;
864 }
865 break;
866 case ANYCOMPATIBLEOID:
867 case ANYCOMPATIBLENONARRAYOID:
868 if (!OidIsValid(anyc_actuals.anyelement_type))
869 {
870 anyc_actuals.anyelement_type =
871 get_call_expr_argtype(call_expr, i);
872 if (!OidIsValid(anyc_actuals.anyelement_type))
873 return false;
874 }
875 break;
876 case ANYCOMPATIBLEARRAYOID:
877 if (!OidIsValid(anyc_actuals.anyarray_type))
878 {
879 anyc_actuals.anyarray_type =
880 get_call_expr_argtype(call_expr, i);
881 if (!OidIsValid(anyc_actuals.anyarray_type))
882 return false;
883 }
884 break;
885 case ANYCOMPATIBLERANGEOID:
886 if (!OidIsValid(anyc_actuals.anyrange_type))
887 {
888 anyc_actuals.anyrange_type =
889 get_call_expr_argtype(call_expr, i);
890 if (!OidIsValid(anyc_actuals.anyrange_type))
891 return false;
892 }
893 break;
894 case ANYCOMPATIBLEMULTIRANGEOID:
895 if (!OidIsValid(anyc_actuals.anymultirange_type))
896 {
897 anyc_actuals.anymultirange_type =
898 get_call_expr_argtype(call_expr, i);
899 if (!OidIsValid(anyc_actuals.anymultirange_type))
900 return false;
901 }
902 break;
903 default:
904 break;
905 }
906 }
907
908 /* If needed, deduce one polymorphic type from others */
909 if (have_anyelement_result && !OidIsValid(poly_actuals.anyelement_type))
910 resolve_anyelement_from_others(&poly_actuals);
911
912 if (have_anyarray_result && !OidIsValid(poly_actuals.anyarray_type))
913 resolve_anyarray_from_others(&poly_actuals);
914
915 if (have_anyrange_result && !OidIsValid(poly_actuals.anyrange_type))
916 resolve_anyrange_from_others(&poly_actuals);
917
918 if (have_anymultirange_result && !OidIsValid(poly_actuals.anymultirange_type))
920
921 if (have_anycompatible_result && !OidIsValid(anyc_actuals.anyelement_type))
922 resolve_anyelement_from_others(&anyc_actuals);
923
924 if (have_anycompatible_array_result && !OidIsValid(anyc_actuals.anyarray_type))
925 resolve_anyarray_from_others(&anyc_actuals);
926
927 if (have_anycompatible_range_result && !OidIsValid(anyc_actuals.anyrange_type))
928 resolve_anyrange_from_others(&anyc_actuals);
929
930 if (have_anycompatible_multirange_result && !OidIsValid(anyc_actuals.anymultirange_type))
932
933 /*
934 * Identify the collation to use for polymorphic OUT parameters. (It'll
935 * necessarily be the same for both anyelement and anyarray, likewise for
936 * anycompatible and anycompatiblearray.) Note that range types are not
937 * collatable, so any possible internal collation of a range type is not
938 * considered here.
939 */
940 if (OidIsValid(poly_actuals.anyelement_type))
941 anycollation = get_typcollation(poly_actuals.anyelement_type);
942 else if (OidIsValid(poly_actuals.anyarray_type))
943 anycollation = get_typcollation(poly_actuals.anyarray_type);
944
945 if (OidIsValid(anyc_actuals.anyelement_type))
946 anycompatcollation = get_typcollation(anyc_actuals.anyelement_type);
947 else if (OidIsValid(anyc_actuals.anyarray_type))
948 anycompatcollation = get_typcollation(anyc_actuals.anyarray_type);
949
950 if (OidIsValid(anycollation) || OidIsValid(anycompatcollation))
951 {
952 /*
953 * The types are collatable, so consider whether to use a nondefault
954 * collation. We do so if we can identify the input collation used
955 * for the function.
956 */
957 Oid inputcollation = exprInputCollation(call_expr);
958
959 if (OidIsValid(inputcollation))
960 {
961 if (OidIsValid(anycollation))
962 anycollation = inputcollation;
963 if (OidIsValid(anycompatcollation))
964 anycompatcollation = inputcollation;
965 }
966 }
967
968 /* And finally replace the tuple column types as needed */
969 for (i = 0; i < natts; i++)
970 {
971 Form_pg_attribute att = TupleDescAttr(tupdesc, i);
972
973 switch (att->atttypid)
974 {
975 case ANYELEMENTOID:
976 case ANYNONARRAYOID:
977 case ANYENUMOID:
978 TupleDescInitEntry(tupdesc, i + 1,
979 NameStr(att->attname),
980 poly_actuals.anyelement_type,
981 -1,
982 0);
983 TupleDescInitEntryCollation(tupdesc, i + 1, anycollation);
984 break;
985 case ANYARRAYOID:
986 TupleDescInitEntry(tupdesc, i + 1,
987 NameStr(att->attname),
988 poly_actuals.anyarray_type,
989 -1,
990 0);
991 TupleDescInitEntryCollation(tupdesc, i + 1, anycollation);
992 break;
993 case ANYRANGEOID:
994 TupleDescInitEntry(tupdesc, i + 1,
995 NameStr(att->attname),
996 poly_actuals.anyrange_type,
997 -1,
998 0);
999 /* no collation should be attached to a range type */
1000 break;
1001 case ANYMULTIRANGEOID:
1002 TupleDescInitEntry(tupdesc, i + 1,
1003 NameStr(att->attname),
1004 poly_actuals.anymultirange_type,
1005 -1,
1006 0);
1007 /* no collation should be attached to a multirange type */
1008 break;
1009 case ANYCOMPATIBLEOID:
1010 case ANYCOMPATIBLENONARRAYOID:
1011 TupleDescInitEntry(tupdesc, i + 1,
1012 NameStr(att->attname),
1013 anyc_actuals.anyelement_type,
1014 -1,
1015 0);
1016 TupleDescInitEntryCollation(tupdesc, i + 1, anycompatcollation);
1017 break;
1018 case ANYCOMPATIBLEARRAYOID:
1019 TupleDescInitEntry(tupdesc, i + 1,
1020 NameStr(att->attname),
1021 anyc_actuals.anyarray_type,
1022 -1,
1023 0);
1024 TupleDescInitEntryCollation(tupdesc, i + 1, anycompatcollation);
1025 break;
1026 case ANYCOMPATIBLERANGEOID:
1027 TupleDescInitEntry(tupdesc, i + 1,
1028 NameStr(att->attname),
1029 anyc_actuals.anyrange_type,
1030 -1,
1031 0);
1032 /* no collation should be attached to a range type */
1033 break;
1034 case ANYCOMPATIBLEMULTIRANGEOID:
1035 TupleDescInitEntry(tupdesc, i + 1,
1036 NameStr(att->attname),
1037 anyc_actuals.anymultirange_type,
1038 -1,
1039 0);
1040 /* no collation should be attached to a multirange type */
1041 break;
1042 default:
1043 break;
1044 }
1045 }
1046
1047 return true;
1048}
1049
1050/*
1051 * Given the declared argument types and modes for a function, replace any
1052 * polymorphic types (ANYELEMENT etc) in argtypes[] with concrete data types
1053 * deduced from the input arguments found in call_expr.
1054 *
1055 * Returns true if able to deduce all types, false if necessary information
1056 * is not provided (call_expr is NULL or arg types aren't identifiable).
1057 *
1058 * This is the same logic as resolve_polymorphic_tupdesc, but with a different
1059 * argument representation, and slightly different output responsibilities.
1060 *
1061 * argmodes may be NULL, in which case all arguments are assumed to be IN mode.
1062 */
1063bool
1064resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes,
1065 Node *call_expr)
1066{
1067 bool have_polymorphic_result = false;
1068 bool have_anyelement_result = false;
1069 bool have_anyarray_result = false;
1070 bool have_anyrange_result = false;
1071 bool have_anymultirange_result = false;
1072 bool have_anycompatible_result = false;
1073 bool have_anycompatible_array_result = false;
1074 bool have_anycompatible_range_result = false;
1075 bool have_anycompatible_multirange_result = false;
1076 polymorphic_actuals poly_actuals;
1077 polymorphic_actuals anyc_actuals;
1078 int inargno;
1079 int i;
1080
1081 /*
1082 * First pass: resolve polymorphic inputs, check for outputs. As in
1083 * resolve_polymorphic_tupdesc, we rely on the parser to have enforced
1084 * type consistency and coerced ANYCOMPATIBLE args to a common supertype.
1085 */
1086 memset(&poly_actuals, 0, sizeof(poly_actuals));
1087 memset(&anyc_actuals, 0, sizeof(anyc_actuals));
1088 inargno = 0;
1089 for (i = 0; i < numargs; i++)
1090 {
1091 char argmode = argmodes ? argmodes[i] : PROARGMODE_IN;
1092
1093 switch (argtypes[i])
1094 {
1095 case ANYELEMENTOID:
1096 case ANYNONARRAYOID:
1097 case ANYENUMOID:
1098 if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
1099 {
1100 have_polymorphic_result = true;
1101 have_anyelement_result = true;
1102 }
1103 else
1104 {
1105 if (!OidIsValid(poly_actuals.anyelement_type))
1106 {
1107 poly_actuals.anyelement_type =
1108 get_call_expr_argtype(call_expr, inargno);
1109 if (!OidIsValid(poly_actuals.anyelement_type))
1110 return false;
1111 }
1112 argtypes[i] = poly_actuals.anyelement_type;
1113 }
1114 break;
1115 case ANYARRAYOID:
1116 if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
1117 {
1118 have_polymorphic_result = true;
1119 have_anyarray_result = true;
1120 }
1121 else
1122 {
1123 if (!OidIsValid(poly_actuals.anyarray_type))
1124 {
1125 poly_actuals.anyarray_type =
1126 get_call_expr_argtype(call_expr, inargno);
1127 if (!OidIsValid(poly_actuals.anyarray_type))
1128 return false;
1129 }
1130 argtypes[i] = poly_actuals.anyarray_type;
1131 }
1132 break;
1133 case ANYRANGEOID:
1134 if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
1135 {
1136 have_polymorphic_result = true;
1137 have_anyrange_result = true;
1138 }
1139 else
1140 {
1141 if (!OidIsValid(poly_actuals.anyrange_type))
1142 {
1143 poly_actuals.anyrange_type =
1144 get_call_expr_argtype(call_expr, inargno);
1145 if (!OidIsValid(poly_actuals.anyrange_type))
1146 return false;
1147 }
1148 argtypes[i] = poly_actuals.anyrange_type;
1149 }
1150 break;
1151 case ANYMULTIRANGEOID:
1152 if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
1153 {
1154 have_polymorphic_result = true;
1155 have_anymultirange_result = true;
1156 }
1157 else
1158 {
1159 if (!OidIsValid(poly_actuals.anymultirange_type))
1160 {
1161 poly_actuals.anymultirange_type =
1162 get_call_expr_argtype(call_expr, inargno);
1163 if (!OidIsValid(poly_actuals.anymultirange_type))
1164 return false;
1165 }
1166 argtypes[i] = poly_actuals.anymultirange_type;
1167 }
1168 break;
1169 case ANYCOMPATIBLEOID:
1170 case ANYCOMPATIBLENONARRAYOID:
1171 if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
1172 {
1173 have_polymorphic_result = true;
1174 have_anycompatible_result = true;
1175 }
1176 else
1177 {
1178 if (!OidIsValid(anyc_actuals.anyelement_type))
1179 {
1180 anyc_actuals.anyelement_type =
1181 get_call_expr_argtype(call_expr, inargno);
1182 if (!OidIsValid(anyc_actuals.anyelement_type))
1183 return false;
1184 }
1185 argtypes[i] = anyc_actuals.anyelement_type;
1186 }
1187 break;
1188 case ANYCOMPATIBLEARRAYOID:
1189 if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
1190 {
1191 have_polymorphic_result = true;
1192 have_anycompatible_array_result = true;
1193 }
1194 else
1195 {
1196 if (!OidIsValid(anyc_actuals.anyarray_type))
1197 {
1198 anyc_actuals.anyarray_type =
1199 get_call_expr_argtype(call_expr, inargno);
1200 if (!OidIsValid(anyc_actuals.anyarray_type))
1201 return false;
1202 }
1203 argtypes[i] = anyc_actuals.anyarray_type;
1204 }
1205 break;
1206 case ANYCOMPATIBLERANGEOID:
1207 if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
1208 {
1209 have_polymorphic_result = true;
1210 have_anycompatible_range_result = true;
1211 }
1212 else
1213 {
1214 if (!OidIsValid(anyc_actuals.anyrange_type))
1215 {
1216 anyc_actuals.anyrange_type =
1217 get_call_expr_argtype(call_expr, inargno);
1218 if (!OidIsValid(anyc_actuals.anyrange_type))
1219 return false;
1220 }
1221 argtypes[i] = anyc_actuals.anyrange_type;
1222 }
1223 break;
1224 case ANYCOMPATIBLEMULTIRANGEOID:
1225 if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
1226 {
1227 have_polymorphic_result = true;
1228 have_anycompatible_multirange_result = true;
1229 }
1230 else
1231 {
1232 if (!OidIsValid(anyc_actuals.anymultirange_type))
1233 {
1234 anyc_actuals.anymultirange_type =
1235 get_call_expr_argtype(call_expr, inargno);
1236 if (!OidIsValid(anyc_actuals.anymultirange_type))
1237 return false;
1238 }
1239 argtypes[i] = anyc_actuals.anymultirange_type;
1240 }
1241 break;
1242 default:
1243 break;
1244 }
1245 if (argmode != PROARGMODE_OUT && argmode != PROARGMODE_TABLE)
1246 inargno++;
1247 }
1248
1249 /* Done? */
1250 if (!have_polymorphic_result)
1251 return true;
1252
1253 /* If needed, deduce one polymorphic type from others */
1254 if (have_anyelement_result && !OidIsValid(poly_actuals.anyelement_type))
1255 resolve_anyelement_from_others(&poly_actuals);
1256
1257 if (have_anyarray_result && !OidIsValid(poly_actuals.anyarray_type))
1258 resolve_anyarray_from_others(&poly_actuals);
1259
1260 if (have_anyrange_result && !OidIsValid(poly_actuals.anyrange_type))
1261 resolve_anyrange_from_others(&poly_actuals);
1262
1263 if (have_anymultirange_result && !OidIsValid(poly_actuals.anymultirange_type))
1264 resolve_anymultirange_from_others(&poly_actuals);
1265
1266 if (have_anycompatible_result && !OidIsValid(anyc_actuals.anyelement_type))
1267 resolve_anyelement_from_others(&anyc_actuals);
1268
1269 if (have_anycompatible_array_result && !OidIsValid(anyc_actuals.anyarray_type))
1270 resolve_anyarray_from_others(&anyc_actuals);
1271
1272 if (have_anycompatible_range_result && !OidIsValid(anyc_actuals.anyrange_type))
1273 resolve_anyrange_from_others(&anyc_actuals);
1274
1275 if (have_anycompatible_multirange_result && !OidIsValid(anyc_actuals.anymultirange_type))
1276 resolve_anymultirange_from_others(&anyc_actuals);
1277
1278 /* And finally replace the output column types as needed */
1279 for (i = 0; i < numargs; i++)
1280 {
1281 switch (argtypes[i])
1282 {
1283 case ANYELEMENTOID:
1284 case ANYNONARRAYOID:
1285 case ANYENUMOID:
1286 argtypes[i] = poly_actuals.anyelement_type;
1287 break;
1288 case ANYARRAYOID:
1289 argtypes[i] = poly_actuals.anyarray_type;
1290 break;
1291 case ANYRANGEOID:
1292 argtypes[i] = poly_actuals.anyrange_type;
1293 break;
1294 case ANYMULTIRANGEOID:
1295 argtypes[i] = poly_actuals.anymultirange_type;
1296 break;
1297 case ANYCOMPATIBLEOID:
1298 case ANYCOMPATIBLENONARRAYOID:
1299 argtypes[i] = anyc_actuals.anyelement_type;
1300 break;
1301 case ANYCOMPATIBLEARRAYOID:
1302 argtypes[i] = anyc_actuals.anyarray_type;
1303 break;
1304 case ANYCOMPATIBLERANGEOID:
1305 argtypes[i] = anyc_actuals.anyrange_type;
1306 break;
1307 case ANYCOMPATIBLEMULTIRANGEOID:
1308 argtypes[i] = anyc_actuals.anymultirange_type;
1309 break;
1310 default:
1311 break;
1312 }
1313 }
1314
1315 return true;
1316}
1317
1318/*
1319 * get_type_func_class
1320 * Given the type OID, obtain its TYPEFUNC classification.
1321 * Also, if it's a domain, return the base type OID.
1322 *
1323 * This is intended to centralize a bunch of formerly ad-hoc code for
1324 * classifying types. The categories used here are useful for deciding
1325 * how to handle functions returning the datatype.
1326 */
1327static TypeFuncClass
1328get_type_func_class(Oid typid, Oid *base_typeid)
1329{
1330 *base_typeid = typid;
1331
1332 switch (get_typtype(typid))
1333 {
1334 case TYPTYPE_COMPOSITE:
1335 return TYPEFUNC_COMPOSITE;
1336 case TYPTYPE_BASE:
1337 case TYPTYPE_ENUM:
1338 case TYPTYPE_RANGE:
1339 case TYPTYPE_MULTIRANGE:
1340 return TYPEFUNC_SCALAR;
1341 case TYPTYPE_DOMAIN:
1342 *base_typeid = typid = getBaseType(typid);
1343 if (get_typtype(typid) == TYPTYPE_COMPOSITE)
1345 else /* domain base type can't be a pseudotype */
1346 return TYPEFUNC_SCALAR;
1347 case TYPTYPE_PSEUDO:
1348 if (typid == RECORDOID)
1349 return TYPEFUNC_RECORD;
1350
1351 /*
1352 * We treat VOID and CSTRING as legitimate scalar datatypes,
1353 * mostly for the convenience of the JDBC driver (which wants to
1354 * be able to do "SELECT * FROM foo()" for all legitimately
1355 * user-callable functions).
1356 */
1357 if (typid == VOIDOID || typid == CSTRINGOID)
1358 return TYPEFUNC_SCALAR;
1359 return TYPEFUNC_OTHER;
1360 }
1361 /* shouldn't get here, probably */
1362 return TYPEFUNC_OTHER;
1363}
1364
1365
1366/*
1367 * get_func_arg_info
1368 *
1369 * Fetch info about the argument types, names, and IN/OUT modes from the
1370 * pg_proc tuple. Return value is the total number of arguments.
1371 * Other results are palloc'd. *p_argtypes is always filled in, but
1372 * *p_argnames and *p_argmodes will be set NULL in the default cases
1373 * (no names, and all IN arguments, respectively).
1374 *
1375 * Note that this function simply fetches what is in the pg_proc tuple;
1376 * it doesn't do any interpretation of polymorphic types.
1377 */
1378int
1380 Oid **p_argtypes, char ***p_argnames, char **p_argmodes)
1381{
1382 Form_pg_proc procStruct = (Form_pg_proc) GETSTRUCT(procTup);
1383 Datum proallargtypes;
1384 Datum proargmodes;
1385 Datum proargnames;
1386 bool isNull;
1387 ArrayType *arr;
1388 int numargs;
1389 Datum *elems;
1390 int nelems;
1391 int i;
1392
1393 /* First discover the total number of parameters and get their types */
1394 proallargtypes = SysCacheGetAttr(PROCOID, procTup,
1395 Anum_pg_proc_proallargtypes,
1396 &isNull);
1397 if (!isNull)
1398 {
1399 /*
1400 * We expect the arrays to be 1-D arrays of the right types; verify
1401 * that. For the OID and char arrays, we don't need to use
1402 * deconstruct_array() since the array data is just going to look like
1403 * a C array of values.
1404 */
1405 arr = DatumGetArrayTypeP(proallargtypes); /* ensure not toasted */
1406 numargs = ARR_DIMS(arr)[0];
1407 if (ARR_NDIM(arr) != 1 ||
1408 numargs < 0 ||
1409 ARR_HASNULL(arr) ||
1410 ARR_ELEMTYPE(arr) != OIDOID)
1411 elog(ERROR, "proallargtypes is not a 1-D Oid array or it contains nulls");
1412 Assert(numargs >= procStruct->pronargs);
1413 *p_argtypes = (Oid *) palloc(numargs * sizeof(Oid));
1414 memcpy(*p_argtypes, ARR_DATA_PTR(arr),
1415 numargs * sizeof(Oid));
1416 }
1417 else
1418 {
1419 /* If no proallargtypes, use proargtypes */
1420 numargs = procStruct->proargtypes.dim1;
1421 Assert(numargs == procStruct->pronargs);
1422 *p_argtypes = (Oid *) palloc(numargs * sizeof(Oid));
1423 memcpy(*p_argtypes, procStruct->proargtypes.values,
1424 numargs * sizeof(Oid));
1425 }
1426
1427 /* Get argument names, if available */
1428 proargnames = SysCacheGetAttr(PROCOID, procTup,
1429 Anum_pg_proc_proargnames,
1430 &isNull);
1431 if (isNull)
1432 *p_argnames = NULL;
1433 else
1434 {
1435 deconstruct_array_builtin(DatumGetArrayTypeP(proargnames), TEXTOID,
1436 &elems, NULL, &nelems);
1437 if (nelems != numargs) /* should not happen */
1438 elog(ERROR, "proargnames must have the same number of elements as the function has arguments");
1439 *p_argnames = (char **) palloc(sizeof(char *) * numargs);
1440 for (i = 0; i < numargs; i++)
1441 (*p_argnames)[i] = TextDatumGetCString(elems[i]);
1442 }
1443
1444 /* Get argument modes, if available */
1445 proargmodes = SysCacheGetAttr(PROCOID, procTup,
1446 Anum_pg_proc_proargmodes,
1447 &isNull);
1448 if (isNull)
1449 *p_argmodes = NULL;
1450 else
1451 {
1452 arr = DatumGetArrayTypeP(proargmodes); /* ensure not toasted */
1453 if (ARR_NDIM(arr) != 1 ||
1454 ARR_DIMS(arr)[0] != numargs ||
1455 ARR_HASNULL(arr) ||
1456 ARR_ELEMTYPE(arr) != CHAROID)
1457 elog(ERROR, "proargmodes is not a 1-D char array of length %d or it contains nulls",
1458 numargs);
1459 *p_argmodes = (char *) palloc(numargs * sizeof(char));
1460 memcpy(*p_argmodes, ARR_DATA_PTR(arr),
1461 numargs * sizeof(char));
1462 }
1463
1464 return numargs;
1465}
1466
1467/*
1468 * get_func_trftypes
1469 *
1470 * Returns the number of transformed types used by the function.
1471 * If there are any, a palloc'd array of the type OIDs is returned
1472 * into *p_trftypes.
1473 */
1474int
1476 Oid **p_trftypes)
1477{
1478 Datum protrftypes;
1479 ArrayType *arr;
1480 int nelems;
1481 bool isNull;
1482
1483 protrftypes = SysCacheGetAttr(PROCOID, procTup,
1484 Anum_pg_proc_protrftypes,
1485 &isNull);
1486 if (!isNull)
1487 {
1488 /*
1489 * We expect the arrays to be 1-D arrays of the right types; verify
1490 * that. For the OID and char arrays, we don't need to use
1491 * deconstruct_array() since the array data is just going to look like
1492 * a C array of values.
1493 */
1494 arr = DatumGetArrayTypeP(protrftypes); /* ensure not toasted */
1495 nelems = ARR_DIMS(arr)[0];
1496 if (ARR_NDIM(arr) != 1 ||
1497 nelems < 0 ||
1498 ARR_HASNULL(arr) ||
1499 ARR_ELEMTYPE(arr) != OIDOID)
1500 elog(ERROR, "protrftypes is not a 1-D Oid array or it contains nulls");
1501 *p_trftypes = (Oid *) palloc(nelems * sizeof(Oid));
1502 memcpy(*p_trftypes, ARR_DATA_PTR(arr),
1503 nelems * sizeof(Oid));
1504
1505 return nelems;
1506 }
1507 else
1508 return 0;
1509}
1510
1511/*
1512 * get_func_input_arg_names
1513 *
1514 * Extract the names of input arguments only, given a function's
1515 * proargnames and proargmodes entries in Datum form.
1516 *
1517 * Returns the number of input arguments, which is the length of the
1518 * palloc'd array returned to *arg_names. Entries for unnamed args
1519 * are set to NULL. You don't get anything if proargnames is NULL.
1520 */
1521int
1522get_func_input_arg_names(Datum proargnames, Datum proargmodes,
1523 char ***arg_names)
1524{
1525 ArrayType *arr;
1526 int numargs;
1527 Datum *argnames;
1528 char *argmodes;
1529 char **inargnames;
1530 int numinargs;
1531 int i;
1532
1533 /* Do nothing if null proargnames */
1534 if (proargnames == PointerGetDatum(NULL))
1535 {
1536 *arg_names = NULL;
1537 return 0;
1538 }
1539
1540 /*
1541 * We expect the arrays to be 1-D arrays of the right types; verify that.
1542 * For proargmodes, we don't need to use deconstruct_array() since the
1543 * array data is just going to look like a C array of values.
1544 */
1545 arr = DatumGetArrayTypeP(proargnames); /* ensure not toasted */
1546 if (ARR_NDIM(arr) != 1 ||
1547 ARR_HASNULL(arr) ||
1548 ARR_ELEMTYPE(arr) != TEXTOID)
1549 elog(ERROR, "proargnames is not a 1-D text array or it contains nulls");
1550 deconstruct_array_builtin(arr, TEXTOID, &argnames, NULL, &numargs);
1551 if (proargmodes != PointerGetDatum(NULL))
1552 {
1553 arr = DatumGetArrayTypeP(proargmodes); /* ensure not toasted */
1554 if (ARR_NDIM(arr) != 1 ||
1555 ARR_DIMS(arr)[0] != numargs ||
1556 ARR_HASNULL(arr) ||
1557 ARR_ELEMTYPE(arr) != CHAROID)
1558 elog(ERROR, "proargmodes is not a 1-D char array of length %d or it contains nulls",
1559 numargs);
1560 argmodes = (char *) ARR_DATA_PTR(arr);
1561 }
1562 else
1563 argmodes = NULL;
1564
1565 /* zero elements probably shouldn't happen, but handle it gracefully */
1566 if (numargs <= 0)
1567 {
1568 *arg_names = NULL;
1569 return 0;
1570 }
1571
1572 /* extract input-argument names */
1573 inargnames = (char **) palloc(numargs * sizeof(char *));
1574 numinargs = 0;
1575 for (i = 0; i < numargs; i++)
1576 {
1577 if (argmodes == NULL ||
1578 argmodes[i] == PROARGMODE_IN ||
1579 argmodes[i] == PROARGMODE_INOUT ||
1580 argmodes[i] == PROARGMODE_VARIADIC)
1581 {
1582 char *pname = TextDatumGetCString(argnames[i]);
1583
1584 if (pname[0] != '\0')
1585 inargnames[numinargs] = pname;
1586 else
1587 inargnames[numinargs] = NULL;
1588 numinargs++;
1589 }
1590 }
1591
1592 *arg_names = inargnames;
1593 return numinargs;
1594}
1595
1596
1597/*
1598 * get_func_result_name
1599 *
1600 * If the function has exactly one output parameter, and that parameter
1601 * is named, return the name (as a palloc'd string). Else return NULL.
1602 *
1603 * This is used to determine the default output column name for functions
1604 * returning scalar types.
1605 */
1606char *
1608{
1609 char *result;
1610 HeapTuple procTuple;
1611 Datum proargmodes;
1612 Datum proargnames;
1613 ArrayType *arr;
1614 int numargs;
1615 char *argmodes;
1616 Datum *argnames;
1617 int numoutargs;
1618 int nargnames;
1619 int i;
1620
1621 /* First fetch the function's pg_proc row */
1622 procTuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(functionId));
1623 if (!HeapTupleIsValid(procTuple))
1624 elog(ERROR, "cache lookup failed for function %u", functionId);
1625
1626 /* If there are no named OUT parameters, return NULL */
1627 if (heap_attisnull(procTuple, Anum_pg_proc_proargmodes, NULL) ||
1628 heap_attisnull(procTuple, Anum_pg_proc_proargnames, NULL))
1629 result = NULL;
1630 else
1631 {
1632 /* Get the data out of the tuple */
1633 proargmodes = SysCacheGetAttrNotNull(PROCOID, procTuple,
1634 Anum_pg_proc_proargmodes);
1635 proargnames = SysCacheGetAttrNotNull(PROCOID, procTuple,
1636 Anum_pg_proc_proargnames);
1637
1638 /*
1639 * We expect the arrays to be 1-D arrays of the right types; verify
1640 * that. For the char array, we don't need to use deconstruct_array()
1641 * since the array data is just going to look like a C array of
1642 * values.
1643 */
1644 arr = DatumGetArrayTypeP(proargmodes); /* ensure not toasted */
1645 numargs = ARR_DIMS(arr)[0];
1646 if (ARR_NDIM(arr) != 1 ||
1647 numargs < 0 ||
1648 ARR_HASNULL(arr) ||
1649 ARR_ELEMTYPE(arr) != CHAROID)
1650 elog(ERROR, "proargmodes is not a 1-D char array or it contains nulls");
1651 argmodes = (char *) ARR_DATA_PTR(arr);
1652 arr = DatumGetArrayTypeP(proargnames); /* ensure not toasted */
1653 if (ARR_NDIM(arr) != 1 ||
1654 ARR_DIMS(arr)[0] != numargs ||
1655 ARR_HASNULL(arr) ||
1656 ARR_ELEMTYPE(arr) != TEXTOID)
1657 elog(ERROR, "proargnames is not a 1-D text array of length %d or it contains nulls",
1658 numargs);
1659 deconstruct_array_builtin(arr, TEXTOID, &argnames, NULL, &nargnames);
1660 Assert(nargnames == numargs);
1661
1662 /* scan for output argument(s) */
1663 result = NULL;
1664 numoutargs = 0;
1665 for (i = 0; i < numargs; i++)
1666 {
1667 if (argmodes[i] == PROARGMODE_IN ||
1668 argmodes[i] == PROARGMODE_VARIADIC)
1669 continue;
1670 Assert(argmodes[i] == PROARGMODE_OUT ||
1671 argmodes[i] == PROARGMODE_INOUT ||
1672 argmodes[i] == PROARGMODE_TABLE);
1673 if (++numoutargs > 1)
1674 {
1675 /* multiple out args, so forget it */
1676 result = NULL;
1677 break;
1678 }
1679 result = TextDatumGetCString(argnames[i]);
1680 if (result == NULL || result[0] == '\0')
1681 {
1682 /* Parameter is not named, so forget it */
1683 result = NULL;
1684 break;
1685 }
1686 }
1687 }
1688
1689 ReleaseSysCache(procTuple);
1690
1691 return result;
1692}
1693
1694
1695/*
1696 * build_function_result_tupdesc_t
1697 *
1698 * Given a pg_proc row for a function, return a tuple descriptor for the
1699 * result rowtype, or NULL if the function does not have OUT parameters.
1700 *
1701 * Note that this does not handle resolution of polymorphic types;
1702 * that is deliberate.
1703 */
1706{
1707 Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(procTuple);
1708 Datum proallargtypes;
1709 Datum proargmodes;
1710 Datum proargnames;
1711 bool isnull;
1712
1713 /* Return NULL if the function isn't declared to return RECORD */
1714 if (procform->prorettype != RECORDOID)
1715 return NULL;
1716
1717 /* If there are no OUT parameters, return NULL */
1718 if (heap_attisnull(procTuple, Anum_pg_proc_proallargtypes, NULL) ||
1719 heap_attisnull(procTuple, Anum_pg_proc_proargmodes, NULL))
1720 return NULL;
1721
1722 /* Get the data out of the tuple */
1723 proallargtypes = SysCacheGetAttrNotNull(PROCOID, procTuple,
1724 Anum_pg_proc_proallargtypes);
1725 proargmodes = SysCacheGetAttrNotNull(PROCOID, procTuple,
1726 Anum_pg_proc_proargmodes);
1727 proargnames = SysCacheGetAttr(PROCOID, procTuple,
1728 Anum_pg_proc_proargnames,
1729 &isnull);
1730 if (isnull)
1731 proargnames = PointerGetDatum(NULL); /* just to be sure */
1732
1733 return build_function_result_tupdesc_d(procform->prokind,
1734 proallargtypes,
1735 proargmodes,
1736 proargnames);
1737}
1738
1739/*
1740 * build_function_result_tupdesc_d
1741 *
1742 * Build a RECORD function's tupledesc from the pg_proc proallargtypes,
1743 * proargmodes, and proargnames arrays. This is split out for the
1744 * convenience of ProcedureCreate, which needs to be able to compute the
1745 * tupledesc before actually creating the function.
1746 *
1747 * For functions (but not for procedures), returns NULL if there are not at
1748 * least two OUT or INOUT arguments.
1749 */
1752 Datum proallargtypes,
1753 Datum proargmodes,
1754 Datum proargnames)
1755{
1756 TupleDesc desc;
1757 ArrayType *arr;
1758 int numargs;
1759 Oid *argtypes;
1760 char *argmodes;
1761 Datum *argnames = NULL;
1762 Oid *outargtypes;
1763 char **outargnames;
1764 int numoutargs;
1765 int nargnames;
1766 int i;
1767
1768 /* Can't have output args if columns are null */
1769 if (proallargtypes == PointerGetDatum(NULL) ||
1770 proargmodes == PointerGetDatum(NULL))
1771 return NULL;
1772
1773 /*
1774 * We expect the arrays to be 1-D arrays of the right types; verify that.
1775 * For the OID and char arrays, we don't need to use deconstruct_array()
1776 * since the array data is just going to look like a C array of values.
1777 */
1778 arr = DatumGetArrayTypeP(proallargtypes); /* ensure not toasted */
1779 numargs = ARR_DIMS(arr)[0];
1780 if (ARR_NDIM(arr) != 1 ||
1781 numargs < 0 ||
1782 ARR_HASNULL(arr) ||
1783 ARR_ELEMTYPE(arr) != OIDOID)
1784 elog(ERROR, "proallargtypes is not a 1-D Oid array or it contains nulls");
1785 argtypes = (Oid *) ARR_DATA_PTR(arr);
1786 arr = DatumGetArrayTypeP(proargmodes); /* ensure not toasted */
1787 if (ARR_NDIM(arr) != 1 ||
1788 ARR_DIMS(arr)[0] != numargs ||
1789 ARR_HASNULL(arr) ||
1790 ARR_ELEMTYPE(arr) != CHAROID)
1791 elog(ERROR, "proargmodes is not a 1-D char array of length %d or it contains nulls",
1792 numargs);
1793 argmodes = (char *) ARR_DATA_PTR(arr);
1794 if (proargnames != PointerGetDatum(NULL))
1795 {
1796 arr = DatumGetArrayTypeP(proargnames); /* ensure not toasted */
1797 if (ARR_NDIM(arr) != 1 ||
1798 ARR_DIMS(arr)[0] != numargs ||
1799 ARR_HASNULL(arr) ||
1800 ARR_ELEMTYPE(arr) != TEXTOID)
1801 elog(ERROR, "proargnames is not a 1-D text array of length %d or it contains nulls",
1802 numargs);
1803 deconstruct_array_builtin(arr, TEXTOID, &argnames, NULL, &nargnames);
1804 Assert(nargnames == numargs);
1805 }
1806
1807 /* zero elements probably shouldn't happen, but handle it gracefully */
1808 if (numargs <= 0)
1809 return NULL;
1810
1811 /* extract output-argument types and names */
1812 outargtypes = (Oid *) palloc(numargs * sizeof(Oid));
1813 outargnames = (char **) palloc(numargs * sizeof(char *));
1814 numoutargs = 0;
1815 for (i = 0; i < numargs; i++)
1816 {
1817 char *pname;
1818
1819 if (argmodes[i] == PROARGMODE_IN ||
1820 argmodes[i] == PROARGMODE_VARIADIC)
1821 continue;
1822 Assert(argmodes[i] == PROARGMODE_OUT ||
1823 argmodes[i] == PROARGMODE_INOUT ||
1824 argmodes[i] == PROARGMODE_TABLE);
1825 outargtypes[numoutargs] = argtypes[i];
1826 if (argnames)
1827 pname = TextDatumGetCString(argnames[i]);
1828 else
1829 pname = NULL;
1830 if (pname == NULL || pname[0] == '\0')
1831 {
1832 /* Parameter is not named, so gin up a column name */
1833 pname = psprintf("column%d", numoutargs + 1);
1834 }
1835 outargnames[numoutargs] = pname;
1836 numoutargs++;
1837 }
1838
1839 /*
1840 * If there is no output argument, or only one, the function does not
1841 * return tuples.
1842 */
1843 if (numoutargs < 2 && prokind != PROKIND_PROCEDURE)
1844 return NULL;
1845
1846 desc = CreateTemplateTupleDesc(numoutargs);
1847 for (i = 0; i < numoutargs; i++)
1848 {
1849 TupleDescInitEntry(desc, i + 1,
1850 outargnames[i],
1851 outargtypes[i],
1852 -1,
1853 0);
1854 }
1855
1856 return desc;
1857}
1858
1859
1860/*
1861 * RelationNameGetTupleDesc
1862 *
1863 * Given a (possibly qualified) relation name, build a TupleDesc.
1864 *
1865 * Note: while this works as advertised, it's seldom the best way to
1866 * build a tupdesc for a function's result type. It's kept around
1867 * only for backwards compatibility with existing user-written code.
1868 */
1871{
1872 RangeVar *relvar;
1873 Relation rel;
1874 TupleDesc tupdesc;
1875 List *relname_list;
1876
1877 /* Open relation and copy the tuple description */
1878 relname_list = stringToQualifiedNameList(relname, NULL);
1879 relvar = makeRangeVarFromNameList(relname_list);
1880 rel = relation_openrv(relvar, AccessShareLock);
1881 tupdesc = CreateTupleDescCopy(RelationGetDescr(rel));
1883
1884 return tupdesc;
1885}
1886
1887/*
1888 * TypeGetTupleDesc
1889 *
1890 * Given a type Oid, build a TupleDesc. (In most cases you should be
1891 * using get_call_result_type or one of its siblings instead of this
1892 * routine, so that you can handle OUT parameters, RECORD result type,
1893 * and polymorphic results.)
1894 *
1895 * If the type is composite, *and* a colaliases List is provided, *and*
1896 * the List is of natts length, use the aliases instead of the relation
1897 * attnames. (NB: this usage is deprecated since it may result in
1898 * creation of unnecessary transient record types.)
1899 *
1900 * If the type is a base type, a single item alias List is required.
1901 */
1903TypeGetTupleDesc(Oid typeoid, List *colaliases)
1904{
1905 Oid base_typeoid;
1906 TypeFuncClass functypclass = get_type_func_class(typeoid, &base_typeoid);
1907 TupleDesc tupdesc = NULL;
1908
1909 /*
1910 * Build a suitable tupledesc representing the output rows. We
1911 * intentionally do not support TYPEFUNC_COMPOSITE_DOMAIN here, as it's
1912 * unlikely that legacy callers of this obsolete function would be
1913 * prepared to apply domain constraints.
1914 */
1915 if (functypclass == TYPEFUNC_COMPOSITE)
1916 {
1917 /* Composite data type, e.g. a table's row type */
1918 tupdesc = lookup_rowtype_tupdesc_copy(base_typeoid, -1);
1919
1920 if (colaliases != NIL)
1921 {
1922 int natts = tupdesc->natts;
1923 int varattno;
1924
1925 /* does the list length match the number of attributes? */
1926 if (list_length(colaliases) != natts)
1927 ereport(ERROR,
1928 (errcode(ERRCODE_DATATYPE_MISMATCH),
1929 errmsg("number of aliases does not match number of columns")));
1930
1931 /* OK, use the aliases instead */
1932 for (varattno = 0; varattno < natts; varattno++)
1933 {
1934 char *label = strVal(list_nth(colaliases, varattno));
1935 Form_pg_attribute attr = TupleDescAttr(tupdesc, varattno);
1936
1937 if (label != NULL)
1938 namestrcpy(&(attr->attname), label);
1939 }
1940
1941 /* The tuple type is now an anonymous record type */
1942 tupdesc->tdtypeid = RECORDOID;
1943 tupdesc->tdtypmod = -1;
1944 }
1945 }
1946 else if (functypclass == TYPEFUNC_SCALAR)
1947 {
1948 /* Base data type, i.e. scalar */
1949 char *attname;
1950
1951 /* the alias list is required for base types */
1952 if (colaliases == NIL)
1953 ereport(ERROR,
1954 (errcode(ERRCODE_DATATYPE_MISMATCH),
1955 errmsg("no column alias was provided")));
1956
1957 /* the alias list length must be 1 */
1958 if (list_length(colaliases) != 1)
1959 ereport(ERROR,
1960 (errcode(ERRCODE_DATATYPE_MISMATCH),
1961 errmsg("number of aliases does not match number of columns")));
1962
1963 /* OK, get the column alias */
1964 attname = strVal(linitial(colaliases));
1965
1966 tupdesc = CreateTemplateTupleDesc(1);
1967 TupleDescInitEntry(tupdesc,
1968 (AttrNumber) 1,
1969 attname,
1970 typeoid,
1971 -1,
1972 0);
1973 }
1974 else if (functypclass == TYPEFUNC_RECORD)
1975 {
1976 /* XXX can't support this because typmod wasn't passed in ... */
1977 ereport(ERROR,
1978 (errcode(ERRCODE_DATATYPE_MISMATCH),
1979 errmsg("could not determine row description for function returning record")));
1980 }
1981 else
1982 {
1983 /* crummy error message, but parser should have caught this */
1984 elog(ERROR, "function in FROM has unsupported return type");
1985 }
1986
1987 return tupdesc;
1988}
1989
1990/*
1991 * extract_variadic_args
1992 *
1993 * Extract a set of argument values, types and NULL markers for a given
1994 * input function which makes use of a VARIADIC input whose argument list
1995 * depends on the caller context. When doing a VARIADIC call, the caller
1996 * has provided one argument made of an array of values, so deconstruct the
1997 * array data before using it for the next processing. If no VARIADIC call
1998 * is used, just fill in the status data based on all the arguments given
1999 * by the caller.
2000 *
2001 * This function returns the number of arguments generated, or -1 in the
2002 * case of "VARIADIC NULL".
2003 */
2004int
2005extract_variadic_args(FunctionCallInfo fcinfo, int variadic_start,
2006 bool convert_unknown, Datum **args, Oid **types,
2007 bool **nulls)
2008{
2009 bool variadic = get_fn_expr_variadic(fcinfo->flinfo);
2010 Datum *args_res;
2011 bool *nulls_res;
2012 Oid *types_res;
2013 int nargs,
2014 i;
2015
2016 *args = NULL;
2017 *types = NULL;
2018 *nulls = NULL;
2019
2020 if (variadic)
2021 {
2023 Oid element_type;
2024 bool typbyval;
2025 char typalign;
2026 int16 typlen;
2027
2028 Assert(PG_NARGS() == variadic_start + 1);
2029
2030 if (PG_ARGISNULL(variadic_start))
2031 return -1;
2032
2033 array_in = PG_GETARG_ARRAYTYPE_P(variadic_start);
2034 element_type = ARR_ELEMTYPE(array_in);
2035
2036 get_typlenbyvalalign(element_type,
2037 &typlen, &typbyval, &typalign);
2038 deconstruct_array(array_in, element_type, typlen, typbyval,
2039 typalign, &args_res, &nulls_res,
2040 &nargs);
2041
2042 /* All the elements of the array have the same type */
2043 types_res = (Oid *) palloc0(nargs * sizeof(Oid));
2044 for (i = 0; i < nargs; i++)
2045 types_res[i] = element_type;
2046 }
2047 else
2048 {
2049 nargs = PG_NARGS() - variadic_start;
2050 Assert(nargs > 0);
2051 nulls_res = (bool *) palloc0(nargs * sizeof(bool));
2052 args_res = (Datum *) palloc0(nargs * sizeof(Datum));
2053 types_res = (Oid *) palloc0(nargs * sizeof(Oid));
2054
2055 for (i = 0; i < nargs; i++)
2056 {
2057 nulls_res[i] = PG_ARGISNULL(i + variadic_start);
2058 types_res[i] = get_fn_expr_argtype(fcinfo->flinfo,
2059 i + variadic_start);
2060
2061 /*
2062 * Turn a constant (more or less literal) value that's of unknown
2063 * type into text if required. Unknowns come in as a cstring
2064 * pointer. Note: for functions declared as taking type "any", the
2065 * parser will not do any type conversion on unknown-type literals
2066 * (that is, undecorated strings or NULLs).
2067 */
2068 if (convert_unknown &&
2069 types_res[i] == UNKNOWNOID &&
2070 get_fn_expr_arg_stable(fcinfo->flinfo, i + variadic_start))
2071 {
2072 types_res[i] = TEXTOID;
2073
2074 if (PG_ARGISNULL(i + variadic_start))
2075 args_res[i] = (Datum) 0;
2076 else
2077 args_res[i] =
2078 CStringGetTextDatum(PG_GETARG_POINTER(i + variadic_start));
2079 }
2080 else
2081 {
2082 /* no conversion needed, just take the datum as given */
2083 args_res[i] = PG_GETARG_DATUM(i + variadic_start);
2084 }
2085
2086 if (!OidIsValid(types_res[i]) ||
2087 (convert_unknown && types_res[i] == UNKNOWNOID))
2088 ereport(ERROR,
2089 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2090 errmsg("could not determine data type for argument %d",
2091 i + 1)));
2092 }
2093 }
2094
2095 /* Fill in results */
2096 *args = args_res;
2097 *nulls = nulls_res;
2098 *types = types_res;
2099
2100 return nargs;
2101}
#define ARR_NDIM(a)
Definition: array.h:290
#define PG_GETARG_ARRAYTYPE_P(n)
Definition: array.h:263
#define ARR_DATA_PTR(a)
Definition: array.h:322
#define DatumGetArrayTypeP(X)
Definition: array.h:261
#define ARR_ELEMTYPE(a)
Definition: array.h:292
#define ARR_DIMS(a)
Definition: array.h:294
#define ARR_HASNULL(a)
Definition: array.h:291
void deconstruct_array(ArrayType *array, Oid elmtype, int elmlen, bool elmbyval, char elmalign, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3631
void deconstruct_array_builtin(ArrayType *array, Oid elmtype, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3697
Datum array_in(PG_FUNCTION_ARGS)
Definition: arrayfuncs.c:179
int16 AttrNumber
Definition: attnum.h:21
#define CStringGetTextDatum(s)
Definition: builtins.h:97
#define TextDatumGetCString(d)
Definition: builtins.h:98
#define NameStr(name)
Definition: c.h:717
int16_t int16
Definition: c.h:497
uint32 bits32
Definition: c.h:511
int32_t int32
Definition: c.h:498
#define OidIsValid(objectId)
Definition: c.h:746
struct typedefs * types
Definition: ecpg.c:30
int errcode(int sqlerrcode)
Definition: elog.c:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:226
#define ereport(elevel,...)
Definition: elog.h:149
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
Definition: execTuples.c:2260
void UnregisterExprContextCallback(ExprContext *econtext, ExprContextCallbackFunction function, Datum arg)
Definition: execUtils.c:990
void RegisterExprContextCallback(ExprContext *econtext, ExprContextCallbackFunction function, Datum arg)
Definition: execUtils.c:964
@ SFRM_Materialize_Random
Definition: execnodes.h:337
@ SFRM_Materialize
Definition: execnodes.h:336
bool get_fn_expr_arg_stable(FmgrInfo *flinfo, int argnum)
Definition: fmgr.c:1975
bool get_fn_expr_variadic(FmgrInfo *flinfo)
Definition: fmgr.c:2044
Oid get_call_expr_argtype(Node *expr, int argnum)
Definition: fmgr.c:1929
Oid get_fn_expr_argtype(FmgrInfo *flinfo, int argnum)
Definition: fmgr.c:1910
#define DatumGetHeapTupleHeader(X)
Definition: fmgr.h:295
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
#define PG_ARGISNULL(n)
Definition: fmgr.h:209
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:268
#define PG_NARGS()
Definition: fmgr.h:203
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
static TypeFuncClass get_type_func_class(Oid typid, Oid *base_typeid)
Definition: funcapi.c:1328
struct polymorphic_actuals polymorphic_actuals
void InitMaterializedSRF(FunctionCallInfo fcinfo, bits32 flags)
Definition: funcapi.c:76
static TypeFuncClass internal_get_result_type(Oid funcid, Node *call_expr, ReturnSetInfo *rsinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition: funcapi.c:430
int get_func_trftypes(HeapTuple procTup, Oid **p_trftypes)
Definition: funcapi.c:1475
TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple)
Definition: funcapi.c:1705
char * get_func_result_name(Oid functionId)
Definition: funcapi.c:1607
TupleDesc build_function_result_tupdesc_d(char prokind, Datum proallargtypes, Datum proargmodes, Datum proargnames)
Definition: funcapi.c:1751
bool resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes, Node *call_expr)
Definition: funcapi.c:1064
void end_MultiFuncCall(PG_FUNCTION_ARGS, FuncCallContext *funcctx)
Definition: funcapi.c:220
static void resolve_anyelement_from_others(polymorphic_actuals *actuals)
Definition: funcapi.c:589
int get_func_input_arg_names(Datum proargnames, Datum proargmodes, char ***arg_names)
Definition: funcapi.c:1522
int get_func_arg_info(HeapTuple procTup, Oid **p_argtypes, char ***p_argnames, char **p_argmodes)
Definition: funcapi.c:1379
static bool resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args, Node *call_expr)
Definition: funcapi.c:744
FuncCallContext * per_MultiFuncCall(PG_FUNCTION_ARGS)
Definition: funcapi.c:208
FuncCallContext * init_MultiFuncCall(PG_FUNCTION_ARGS)
Definition: funcapi.c:133
TupleDesc RelationNameGetTupleDesc(const char *relname)
Definition: funcapi.c:1870
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition: funcapi.c:276
int extract_variadic_args(FunctionCallInfo fcinfo, int variadic_start, bool convert_unknown, Datum **args, Oid **types, bool **nulls)
Definition: funcapi.c:2005
static void resolve_anyrange_from_others(polymorphic_actuals *actuals)
Definition: funcapi.c:681
static void shutdown_MultiFuncCall(Datum arg)
Definition: funcapi.c:238
TupleDesc get_expr_result_tupdesc(Node *expr, bool noError)
Definition: funcapi.c:551
static void resolve_anymultirange_from_others(polymorphic_actuals *actuals)
Definition: funcapi.c:710
TupleDesc TypeGetTupleDesc(Oid typeoid, List *colaliases)
Definition: funcapi.c:1903
TypeFuncClass get_func_result_type(Oid functionId, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition: funcapi.c:410
static void resolve_anyarray_from_others(polymorphic_actuals *actuals)
Definition: funcapi.c:655
TypeFuncClass get_expr_result_type(Node *expr, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition: funcapi.c:299
TypeFuncClass
Definition: funcapi.h:147
@ TYPEFUNC_SCALAR
Definition: funcapi.h:148
@ TYPEFUNC_COMPOSITE
Definition: funcapi.h:149
@ TYPEFUNC_RECORD
Definition: funcapi.h:151
@ TYPEFUNC_COMPOSITE_DOMAIN
Definition: funcapi.h:150
@ TYPEFUNC_OTHER
Definition: funcapi.h:152
#define MAT_SRF_BLESS
Definition: funcapi.h:297
#define MAT_SRF_USE_EXPECTED_DESC
Definition: funcapi.h:296
int work_mem
Definition: globals.c:132
Assert(PointerIsAligned(start, uint64))
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition: heaptuple.c:456
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
static int32 HeapTupleHeaderGetTypMod(const HeapTupleHeaderData *tup)
Definition: htup_details.h:516
static void * GETSTRUCT(const HeapTupleData *tuple)
Definition: htup_details.h:728
static Oid HeapTupleHeaderGetTypeId(const HeapTupleHeaderData *tup)
Definition: htup_details.h:504
int i
Definition: isn.c:77
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:81
#define AccessShareLock
Definition: lockdefs.h:36
Oid get_range_subtype(Oid rangeOid)
Definition: lsyscache.c:3547
Oid get_element_type(Oid typid)
Definition: lsyscache.c:2899
Oid get_multirange_range(Oid multirangeOid)
Definition: lsyscache.c:3623
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition: lsyscache.c:2411
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1425
Oid get_typcollation(Oid typid)
Definition: lsyscache.c:3196
Oid get_range_multirange(Oid rangeOid)
Definition: lsyscache.c:3598
char get_typtype(Oid typid)
Definition: lsyscache.c:2769
Oid getBaseType(Oid typid)
Definition: lsyscache.c:2661
Oid get_array_type(Oid typid)
Definition: lsyscache.c:2927
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:1290
void * palloc0(Size size)
Definition: mcxt.c:1970
void * palloc(Size size)
Definition: mcxt.c:1940
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:485
#define AllocSetContextCreate
Definition: memutils.h:149
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:190
void namestrcpy(Name name, const char *str)
Definition: name.c:233
RangeVar * makeRangeVarFromNameList(const List *names)
Definition: namespace.c:3554
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
Oid exprInputCollation(const Node *expr)
Definition: nodeFuncs.c:1076
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:301
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:821
#define IsA(nodeptr, _type_)
Definition: nodes.h:164
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
NameData attname
Definition: pg_attribute.h:41
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:202
void * arg
static char * label
NameData relname
Definition: pg_class.h:38
#define lfirst(lc)
Definition: pg_list.h:172
static int list_length(const List *l)
Definition: pg_list.h:152
#define NIL
Definition: pg_list.h:68
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:518
static void * list_nth(const List *list, int n)
Definition: pg_list.h:299
#define linitial(l)
Definition: pg_list.h:178
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:136
char typalign
Definition: pg_type.h:176
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:327
uintptr_t Datum
Definition: postgres.h:69
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:317
#define InvalidOid
Definition: postgres_ext.h:35
unsigned int Oid
Definition: postgres_ext.h:30
char * psprintf(const char *fmt,...)
Definition: psprintf.c:43
List * stringToQualifiedNameList(const char *string, Node *escontext)
Definition: regproc.c:1797
#define RelationGetDescr(relation)
Definition: rel.h:542
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:205
Relation relation_openrv(const RangeVar *relation, LOCKMODE lockmode)
Definition: relation.c:137
MemoryContext ecxt_per_query_memory
Definition: execnodes.h:275
Definition: fmgr.h:57
void * fn_extra
Definition: fmgr.h:64
fmNodePtr fn_expr
Definition: fmgr.h:66
Oid fn_oid
Definition: fmgr.h:59
void * user_fctx
Definition: funcapi.h:82
uint64 max_calls
Definition: funcapi.h:74
uint64 call_cntr
Definition: funcapi.h:65
AttInMetadata * attinmeta
Definition: funcapi.h:91
MemoryContext multi_call_memory_ctx
Definition: funcapi.h:101
TupleDesc tuple_desc
Definition: funcapi.h:112
fmNodePtr resultinfo
Definition: fmgr.h:89
FmgrInfo * flinfo
Definition: fmgr.h:87
Definition: pg_list.h:54
Definition: nodes.h:135
SetFunctionReturnMode returnMode
Definition: execnodes.h:355
ExprContext * econtext
Definition: execnodes.h:351
TupleDesc setDesc
Definition: execnodes.h:359
Tuplestorestate * setResult
Definition: execnodes.h:358
TupleDesc expectedDesc
Definition: execnodes.h:352
int allowedModes
Definition: execnodes.h:353
List * args
Definition: primnodes.h:1428
int32 tdtypmod
Definition: tupdesc.h:139
Oid tdtypeid
Definition: tupdesc.h:138
Definition: c.h:697
int dim1
Definition: c.h:702
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:704
Oid anymultirange_type
Definition: funcapi.c:40
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:600
Datum SysCacheGetAttrNotNull(int cacheId, HeapTuple tup, AttrNumber attributeNumber)
Definition: syscache.c:631
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:175
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:245
void TupleDescInitEntryCollation(TupleDesc desc, AttrNumber attributeNumber, Oid collationid)
Definition: tupdesc.c:1019
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:835
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:160
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition: tuplestore.c:330
void assign_record_type_typmod(TupleDesc tupDesc)
Definition: typcache.c:2042
TupleDesc lookup_rowtype_tupdesc_copy(Oid type_id, int32 typmod)
Definition: typcache.c:1956
#define strVal(v)
Definition: value.h:82