1 /*-------------------------------------------------------------------------
4 * Utility and convenience functions for fmgr functions that return
5 * sets and/or composite types, or deal with VARIADIC inputs.
7 * Copyright (c) 2002-2025, PostgreSQL Global Development Group
10 * src/backend/utils/fmgr/funcapi.c
12 *-------------------------------------------------------------------------
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"
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"
35 typedef struct polymorphic_actuals
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 */
41 } polymorphic_actuals
;
43 static void shutdown_MultiFuncCall(Datum arg
);
44 static TypeFuncClass
internal_get_result_type(Oid funcid
,
46 ReturnSetInfo
*rsinfo
,
48 TupleDesc
*resultTupleDesc
);
49 static void resolve_anyelement_from_others(polymorphic_actuals
*actuals
);
50 static void resolve_anyarray_from_others(polymorphic_actuals
*actuals
);
51 static void resolve_anyrange_from_others(polymorphic_actuals
*actuals
);
52 static void resolve_anymultirange_from_others(polymorphic_actuals
*actuals
);
53 static bool resolve_polymorphic_tupdesc(TupleDesc tupdesc
,
54 oidvector
*declared_args
,
56 static TypeFuncClass
get_type_func_class(Oid typid
, Oid
*base_typeid
);
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.
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
76 InitMaterializedSRF(FunctionCallInfo fcinfo
, bits32 flags
)
79 ReturnSetInfo
*rsinfo
= (ReturnSetInfo
*) fcinfo
->resultinfo
;
80 Tuplestorestate
*tupstore
;
81 MemoryContext old_context
,
83 TupleDesc stored_tupdesc
;
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")));
97 * Store the tuplestore and the tuple descriptor in ReturnSetInfo. This
98 * must be done in the per-query memory context.
100 per_query_ctx
= rsinfo
->econtext
->ecxt_per_query_memory
;
101 old_context
= MemoryContextSwitchTo(per_query_ctx
);
103 /* build a tuple descriptor for our result type */
104 if ((flags
& MAT_SRF_USE_EXPECTED_DESC
) != 0)
105 stored_tupdesc
= CreateTupleDescCopy(rsinfo
->expectedDesc
);
108 if (get_call_result_type(fcinfo
, NULL
, &stored_tupdesc
) != TYPEFUNC_COMPOSITE
)
109 elog(ERROR
, "return type must be a row type");
112 /* If requested, bless the tuple descriptor */
113 if ((flags
& MAT_SRF_BLESS
) != 0)
114 BlessTupleDesc(stored_tupdesc
);
116 random_access
= (rsinfo
->allowedModes
& SFRM_Materialize_Random
) != 0;
118 tupstore
= tuplestore_begin_heap(random_access
, false, work_mem
);
119 rsinfo
->returnMode
= SFRM_Materialize
;
120 rsinfo
->setResult
= tupstore
;
121 rsinfo
->setDesc
= stored_tupdesc
;
122 MemoryContextSwitchTo(old_context
);
128 * Create an empty FuncCallContext data structure
129 * and do some other basic Multi-function call setup
133 init_MultiFuncCall(PG_FUNCTION_ARGS
)
135 FuncCallContext
*retval
;
138 * Bail if we're called in the wrong context
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")));
145 if (fcinfo
->flinfo
->fn_extra
== NULL
)
150 ReturnSetInfo
*rsi
= (ReturnSetInfo
*) fcinfo
->resultinfo
;
151 MemoryContext multi_call_ctx
;
154 * Create a suitably long-lived context to hold cross-call data
156 multi_call_ctx
= AllocSetContextCreate(fcinfo
->flinfo
->fn_mcxt
,
157 "SRF multi-call context",
158 ALLOCSET_SMALL_SIZES
);
161 * Allocate suitably long-lived space and zero it
163 retval
= (FuncCallContext
*)
164 MemoryContextAllocZero(multi_call_ctx
,
165 sizeof(FuncCallContext
));
168 * initialize the elements
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
;
178 * save the pointer for cross-call use
180 fcinfo
->flinfo
->fn_extra
= retval
;
183 * Ensure we will get shut down cleanly if the exprcontext is not run
186 RegisterExprContextCallback(rsi
->econtext
,
187 shutdown_MultiFuncCall
,
188 PointerGetDatum(fcinfo
->flinfo
));
192 /* second and subsequent calls */
193 elog(ERROR
, "init_MultiFuncCall cannot be called more than once");
195 /* never reached, but keep compiler happy */
205 * Do Multi-function per-call setup
208 per_MultiFuncCall(PG_FUNCTION_ARGS
)
210 FuncCallContext
*retval
= (FuncCallContext
*) fcinfo
->flinfo
->fn_extra
;
217 * Clean up after init_MultiFuncCall
220 end_MultiFuncCall(PG_FUNCTION_ARGS
, FuncCallContext
*funcctx
)
222 ReturnSetInfo
*rsi
= (ReturnSetInfo
*) fcinfo
->resultinfo
;
224 /* Deregister the shutdown callback */
225 UnregisterExprContextCallback(rsi
->econtext
,
226 shutdown_MultiFuncCall
,
227 PointerGetDatum(fcinfo
->flinfo
));
229 /* But use it to do the real work */
230 shutdown_MultiFuncCall(PointerGetDatum(fcinfo
->flinfo
));
234 * shutdown_MultiFuncCall
235 * Shutdown function to clean up after init_MultiFuncCall
238 shutdown_MultiFuncCall(Datum arg
)
240 FmgrInfo
*flinfo
= (FmgrInfo
*) DatumGetPointer(arg
);
241 FuncCallContext
*funcctx
= (FuncCallContext
*) flinfo
->fn_extra
;
243 /* unbind from flinfo */
244 flinfo
->fn_extra
= NULL
;
247 * Delete context that holds all multi-call data, including the
248 * FuncCallContext itself
250 MemoryContextDelete(funcctx
->multi_call_memory_ctx
);
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.
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.
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.
272 * This function is relatively expensive --- in a function returning set,
273 * try to call it only the first time through.
276 get_call_result_type(FunctionCallInfo fcinfo
,
278 TupleDesc
*resultTupleDesc
)
280 return internal_get_result_type(fcinfo
->flinfo
->fn_oid
,
281 fcinfo
->flinfo
->fn_expr
,
282 (ReturnSetInfo
*) fcinfo
->resultinfo
,
288 * get_expr_result_type
289 * As above, but work from a calling expression node tree
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.
299 get_expr_result_type(Node
*expr
,
301 TupleDesc
*resultTupleDesc
)
303 TypeFuncClass result
;
305 if (expr
&& IsA(expr
, FuncExpr
))
306 result
= internal_get_result_type(((FuncExpr
*) expr
)->funcid
,
311 else if (expr
&& IsA(expr
, OpExpr
))
312 result
= internal_get_result_type(get_opcode(((OpExpr
*) expr
)->opno
),
317 else if (expr
&& IsA(expr
, RowExpr
) &&
318 ((RowExpr
*) expr
)->row_typeid
== RECORDOID
)
320 /* We can resolve the record type by generating the tupdesc directly */
321 RowExpr
*rexpr
= (RowExpr
*) expr
;
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
)
331 Node
*col
= (Node
*) lfirst(lcc
);
332 char *colname
= strVal(lfirst(lcn
));
334 TupleDescInitEntry(tupdesc
, i
,
339 TupleDescInitEntryCollation(tupdesc
, i
,
344 *resultTypeId
= rexpr
->row_typeid
;
346 *resultTupleDesc
= BlessTupleDesc(tupdesc
);
347 return TYPEFUNC_COMPOSITE
;
349 else if (expr
&& IsA(expr
, Const
) &&
350 ((Const
*) expr
)->consttype
== RECORDOID
&&
351 !((Const
*) expr
)->constisnull
)
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.
362 rec
= DatumGetHeapTupleHeader(((Const
*) expr
)->constvalue
);
363 tupType
= HeapTupleHeaderGetTypeId(rec
);
364 tupTypmod
= HeapTupleHeaderGetTypMod(rec
);
366 *resultTypeId
= tupType
;
367 if (tupType
!= RECORDOID
|| tupTypmod
>= 0)
369 /* Should be able to look it up */
371 *resultTupleDesc
= lookup_rowtype_tupdesc_copy(tupType
,
373 return TYPEFUNC_COMPOSITE
;
377 /* This shouldn't really happen ... */
379 *resultTupleDesc
= NULL
;
380 return TYPEFUNC_RECORD
;
385 /* handle as a generic expression; no chance to resolve RECORD */
386 Oid typid
= exprType(expr
);
390 *resultTypeId
= typid
;
392 *resultTupleDesc
= NULL
;
393 result
= get_type_func_class(typid
, &base_typid
);
394 if ((result
== TYPEFUNC_COMPOSITE
||
395 result
== TYPEFUNC_COMPOSITE_DOMAIN
) &&
397 *resultTupleDesc
= lookup_rowtype_tupdesc_copy(base_typid
, -1);
404 * get_func_result_type
405 * As above, but work from a function's OID only
407 * This will not be able to resolve pure-RECORD results nor polymorphism.
410 get_func_result_type(Oid functionId
,
412 TupleDesc
*resultTupleDesc
)
414 return internal_get_result_type(functionId
,
422 * internal_get_result_type -- workhorse code implementing all the above
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.
430 internal_get_result_type(Oid funcid
,
432 ReturnSetInfo
*rsinfo
,
434 TupleDesc
*resultTupleDesc
)
436 TypeFuncClass result
;
438 Form_pg_proc procform
;
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
);
449 rettype
= procform
->prorettype
;
451 /* Check for OUT parameters defining a RECORD result */
452 tupdesc
= build_function_result_tupdesc_t(tp
);
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
461 *resultTypeId
= rettype
;
463 if (resolve_polymorphic_tupdesc(tupdesc
,
464 &procform
->proargtypes
,
467 if (tupdesc
->tdtypeid
== RECORDOID
&&
468 tupdesc
->tdtypmod
< 0)
469 assign_record_type_typmod(tupdesc
);
471 *resultTupleDesc
= tupdesc
;
472 result
= TYPEFUNC_COMPOSITE
;
477 *resultTupleDesc
= NULL
;
478 result
= TYPEFUNC_RECORD
;
487 * If scalar polymorphic result, try to resolve it.
489 if (IsPolymorphicType(rettype
))
491 Oid newrettype
= exprType(call_expr
);
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
;
503 *resultTypeId
= rettype
;
505 *resultTupleDesc
= NULL
; /* default result */
507 /* Classify the result type */
508 result
= get_type_func_class(rettype
, &base_rettype
);
511 case TYPEFUNC_COMPOSITE
:
512 case TYPEFUNC_COMPOSITE_DOMAIN
:
514 *resultTupleDesc
= lookup_rowtype_tupdesc_copy(base_rettype
, -1);
515 /* Named composite types can't have any polymorphic columns */
517 case TYPEFUNC_SCALAR
:
519 case TYPEFUNC_RECORD
:
520 /* We must get the tupledesc from call context */
521 if (rsinfo
&& IsA(rsinfo
, ReturnSetInfo
) &&
522 rsinfo
->expectedDesc
!= NULL
)
524 result
= TYPEFUNC_COMPOSITE
;
526 *resultTupleDesc
= rsinfo
->expectedDesc
;
527 /* Assume no polymorphic columns here, either */
540 * get_expr_result_tupdesc
541 * Get a tupdesc describing the result of a composite-valued expression
543 * If expression is not composite or rowtype can't be determined, returns NULL
544 * if noError is true, else throws error.
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.
551 get_expr_result_tupdesc(Node
*expr
, bool noError
)
554 TypeFuncClass functypclass
;
556 functypclass
= get_expr_result_type(expr
, NULL
, &tupleDesc
);
558 if (functypclass
== TYPEFUNC_COMPOSITE
||
559 functypclass
== TYPEFUNC_COMPOSITE_DOMAIN
)
564 Oid exprTypeId
= exprType(expr
);
566 if (exprTypeId
!= RECORDOID
)
568 (errcode(ERRCODE_WRONG_OBJECT_TYPE
),
569 errmsg("type %s is not composite",
570 format_type_be(exprTypeId
))));
573 (errcode(ERRCODE_WRONG_OBJECT_TYPE
),
574 errmsg("record type has not been registered")));
581 * Resolve actual type of ANYELEMENT from other polymorphic inputs
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.
589 resolve_anyelement_from_others(polymorphic_actuals
*actuals
)
591 if (OidIsValid(actuals
->anyarray_type
))
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
);
597 if (!OidIsValid(array_typelem
))
599 (errcode(ERRCODE_DATATYPE_MISMATCH
),
600 errmsg("argument declared %s is not an array but type %s",
602 format_type_be(array_base_type
))));
603 actuals
->anyelement_type
= array_typelem
;
605 else if (OidIsValid(actuals
->anyrange_type
))
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
);
611 if (!OidIsValid(range_typelem
))
613 (errcode(ERRCODE_DATATYPE_MISMATCH
),
614 errmsg("argument declared %s is not a range type but type %s",
616 format_type_be(range_base_type
))));
617 actuals
->anyelement_type
= range_typelem
;
619 else if (OidIsValid(actuals
->anymultirange_type
))
621 /* Use the element type based on the multirange type */
622 Oid multirange_base_type
;
623 Oid multirange_typelem
;
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",
634 format_type_be(multirange_base_type
))));
636 range_base_type
= getBaseType(multirange_typelem
);
637 range_typelem
= get_range_subtype(range_base_type
);
639 if (!OidIsValid(range_typelem
))
641 (errcode(ERRCODE_DATATYPE_MISMATCH
),
642 errmsg("argument declared %s does not contain a range type but type %s",
644 format_type_be(range_base_type
))));
645 actuals
->anyelement_type
= range_typelem
;
648 elog(ERROR
, "could not determine polymorphic type");
652 * Resolve actual type of ANYARRAY from other polymorphic inputs
655 resolve_anyarray_from_others(polymorphic_actuals
*actuals
)
657 /* If we don't know ANYELEMENT, resolve that first */
658 if (!OidIsValid(actuals
->anyelement_type
))
659 resolve_anyelement_from_others(actuals
);
661 if (OidIsValid(actuals
->anyelement_type
))
663 /* Use the array type corresponding to actual type */
664 Oid array_typeid
= get_array_type(actuals
->anyelement_type
);
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
;
674 elog(ERROR
, "could not determine polymorphic type");
678 * Resolve actual type of ANYRANGE from other polymorphic inputs
681 resolve_anyrange_from_others(polymorphic_actuals
*actuals
)
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.
688 if (OidIsValid(actuals
->anymultirange_type
))
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
);
694 if (!OidIsValid(multirange_typelem
))
696 (errcode(ERRCODE_DATATYPE_MISMATCH
),
697 errmsg("argument declared %s is not a multirange type but type %s",
699 format_type_be(multirange_base_type
))));
700 actuals
->anyrange_type
= multirange_typelem
;
703 elog(ERROR
, "could not determine polymorphic type");
707 * Resolve actual type of ANYMULTIRANGE from other polymorphic inputs
710 resolve_anymultirange_from_others(polymorphic_actuals
*actuals
)
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.
717 if (OidIsValid(actuals
->anyrange_type
))
719 Oid range_base_type
= getBaseType(actuals
->anyrange_type
);
720 Oid multirange_typeid
= get_range_multirange(range_base_type
);
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
;
730 elog(ERROR
, "could not determine polymorphic type");
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.
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).
744 resolve_polymorphic_tupdesc(TupleDesc tupdesc
, oidvector
*declared_args
,
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
;
764 /* See if there are any polymorphic outputs; quick out if not */
765 for (i
= 0; i
< natts
; i
++)
767 switch (TupleDescAttr(tupdesc
, i
)->atttypid
)
772 have_polymorphic_result
= true;
773 have_anyelement_result
= true;
776 have_polymorphic_result
= true;
777 have_anyarray_result
= true;
780 have_polymorphic_result
= true;
781 have_anyrange_result
= true;
783 case ANYMULTIRANGEOID
:
784 have_polymorphic_result
= true;
785 have_anymultirange_result
= true;
787 case ANYCOMPATIBLEOID
:
788 case ANYCOMPATIBLENONARRAYOID
:
789 have_polymorphic_result
= true;
790 have_anycompatible_result
= true;
792 case ANYCOMPATIBLEARRAYOID
:
793 have_polymorphic_result
= true;
794 have_anycompatible_array_result
= true;
796 case ANYCOMPATIBLERANGEOID
:
797 have_polymorphic_result
= true;
798 have_anycompatible_range_result
= true;
800 case ANYCOMPATIBLEMULTIRANGEOID
:
801 have_polymorphic_result
= true;
802 have_anycompatible_multirange_result
= true;
808 if (!have_polymorphic_result
)
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.)
819 return false; /* no hope */
821 memset(&poly_actuals
, 0, sizeof(poly_actuals
));
822 memset(&anyc_actuals
, 0, sizeof(anyc_actuals
));
824 for (i
= 0; i
< nargs
; i
++)
826 switch (declared_args
->values
[i
])
831 if (!OidIsValid(poly_actuals
.anyelement_type
))
833 poly_actuals
.anyelement_type
=
834 get_call_expr_argtype(call_expr
, i
);
835 if (!OidIsValid(poly_actuals
.anyelement_type
))
840 if (!OidIsValid(poly_actuals
.anyarray_type
))
842 poly_actuals
.anyarray_type
=
843 get_call_expr_argtype(call_expr
, i
);
844 if (!OidIsValid(poly_actuals
.anyarray_type
))
849 if (!OidIsValid(poly_actuals
.anyrange_type
))
851 poly_actuals
.anyrange_type
=
852 get_call_expr_argtype(call_expr
, i
);
853 if (!OidIsValid(poly_actuals
.anyrange_type
))
857 case ANYMULTIRANGEOID
:
858 if (!OidIsValid(poly_actuals
.anymultirange_type
))
860 poly_actuals
.anymultirange_type
=
861 get_call_expr_argtype(call_expr
, i
);
862 if (!OidIsValid(poly_actuals
.anymultirange_type
))
866 case ANYCOMPATIBLEOID
:
867 case ANYCOMPATIBLENONARRAYOID
:
868 if (!OidIsValid(anyc_actuals
.anyelement_type
))
870 anyc_actuals
.anyelement_type
=
871 get_call_expr_argtype(call_expr
, i
);
872 if (!OidIsValid(anyc_actuals
.anyelement_type
))
876 case ANYCOMPATIBLEARRAYOID
:
877 if (!OidIsValid(anyc_actuals
.anyarray_type
))
879 anyc_actuals
.anyarray_type
=
880 get_call_expr_argtype(call_expr
, i
);
881 if (!OidIsValid(anyc_actuals
.anyarray_type
))
885 case ANYCOMPATIBLERANGEOID
:
886 if (!OidIsValid(anyc_actuals
.anyrange_type
))
888 anyc_actuals
.anyrange_type
=
889 get_call_expr_argtype(call_expr
, i
);
890 if (!OidIsValid(anyc_actuals
.anyrange_type
))
894 case ANYCOMPATIBLEMULTIRANGEOID
:
895 if (!OidIsValid(anyc_actuals
.anymultirange_type
))
897 anyc_actuals
.anymultirange_type
=
898 get_call_expr_argtype(call_expr
, i
);
899 if (!OidIsValid(anyc_actuals
.anymultirange_type
))
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
);
912 if (have_anyarray_result
&& !OidIsValid(poly_actuals
.anyarray_type
))
913 resolve_anyarray_from_others(&poly_actuals
);
915 if (have_anyrange_result
&& !OidIsValid(poly_actuals
.anyrange_type
))
916 resolve_anyrange_from_others(&poly_actuals
);
918 if (have_anymultirange_result
&& !OidIsValid(poly_actuals
.anymultirange_type
))
919 resolve_anymultirange_from_others(&poly_actuals
);
921 if (have_anycompatible_result
&& !OidIsValid(anyc_actuals
.anyelement_type
))
922 resolve_anyelement_from_others(&anyc_actuals
);
924 if (have_anycompatible_array_result
&& !OidIsValid(anyc_actuals
.anyarray_type
))
925 resolve_anyarray_from_others(&anyc_actuals
);
927 if (have_anycompatible_range_result
&& !OidIsValid(anyc_actuals
.anyrange_type
))
928 resolve_anyrange_from_others(&anyc_actuals
);
930 if (have_anycompatible_multirange_result
&& !OidIsValid(anyc_actuals
.anymultirange_type
))
931 resolve_anymultirange_from_others(&anyc_actuals
);
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
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
);
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
);
950 if (OidIsValid(anycollation
) || OidIsValid(anycompatcollation
))
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
957 Oid inputcollation
= exprInputCollation(call_expr
);
959 if (OidIsValid(inputcollation
))
961 if (OidIsValid(anycollation
))
962 anycollation
= inputcollation
;
963 if (OidIsValid(anycompatcollation
))
964 anycompatcollation
= inputcollation
;
968 /* And finally replace the tuple column types as needed */
969 for (i
= 0; i
< natts
; i
++)
971 Form_pg_attribute att
= TupleDescAttr(tupdesc
, i
);
973 switch (att
->atttypid
)
978 TupleDescInitEntry(tupdesc
, i
+ 1,
979 NameStr(att
->attname
),
980 poly_actuals
.anyelement_type
,
983 TupleDescInitEntryCollation(tupdesc
, i
+ 1, anycollation
);
986 TupleDescInitEntry(tupdesc
, i
+ 1,
987 NameStr(att
->attname
),
988 poly_actuals
.anyarray_type
,
991 TupleDescInitEntryCollation(tupdesc
, i
+ 1, anycollation
);
994 TupleDescInitEntry(tupdesc
, i
+ 1,
995 NameStr(att
->attname
),
996 poly_actuals
.anyrange_type
,
999 /* no collation should be attached to a range type */
1001 case ANYMULTIRANGEOID
:
1002 TupleDescInitEntry(tupdesc
, i
+ 1,
1003 NameStr(att
->attname
),
1004 poly_actuals
.anymultirange_type
,
1007 /* no collation should be attached to a multirange type */
1009 case ANYCOMPATIBLEOID
:
1010 case ANYCOMPATIBLENONARRAYOID
:
1011 TupleDescInitEntry(tupdesc
, i
+ 1,
1012 NameStr(att
->attname
),
1013 anyc_actuals
.anyelement_type
,
1016 TupleDescInitEntryCollation(tupdesc
, i
+ 1, anycompatcollation
);
1018 case ANYCOMPATIBLEARRAYOID
:
1019 TupleDescInitEntry(tupdesc
, i
+ 1,
1020 NameStr(att
->attname
),
1021 anyc_actuals
.anyarray_type
,
1024 TupleDescInitEntryCollation(tupdesc
, i
+ 1, anycompatcollation
);
1026 case ANYCOMPATIBLERANGEOID
:
1027 TupleDescInitEntry(tupdesc
, i
+ 1,
1028 NameStr(att
->attname
),
1029 anyc_actuals
.anyrange_type
,
1032 /* no collation should be attached to a range type */
1034 case ANYCOMPATIBLEMULTIRANGEOID
:
1035 TupleDescInitEntry(tupdesc
, i
+ 1,
1036 NameStr(att
->attname
),
1037 anyc_actuals
.anymultirange_type
,
1040 /* no collation should be attached to a multirange type */
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.
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).
1058 * This is the same logic as resolve_polymorphic_tupdesc, but with a different
1059 * argument representation, and slightly different output responsibilities.
1061 * argmodes may be NULL, in which case all arguments are assumed to be IN mode.
1064 resolve_polymorphic_argtypes(int numargs
, Oid
*argtypes
, char *argmodes
,
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
;
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.
1086 memset(&poly_actuals
, 0, sizeof(poly_actuals
));
1087 memset(&anyc_actuals
, 0, sizeof(anyc_actuals
));
1089 for (i
= 0; i
< numargs
; i
++)
1091 char argmode
= argmodes
? argmodes
[i
] : PROARGMODE_IN
;
1093 switch (argtypes
[i
])
1096 case ANYNONARRAYOID
:
1098 if (argmode
== PROARGMODE_OUT
|| argmode
== PROARGMODE_TABLE
)
1100 have_polymorphic_result
= true;
1101 have_anyelement_result
= true;
1105 if (!OidIsValid(poly_actuals
.anyelement_type
))
1107 poly_actuals
.anyelement_type
=
1108 get_call_expr_argtype(call_expr
, inargno
);
1109 if (!OidIsValid(poly_actuals
.anyelement_type
))
1112 argtypes
[i
] = poly_actuals
.anyelement_type
;
1116 if (argmode
== PROARGMODE_OUT
|| argmode
== PROARGMODE_TABLE
)
1118 have_polymorphic_result
= true;
1119 have_anyarray_result
= true;
1123 if (!OidIsValid(poly_actuals
.anyarray_type
))
1125 poly_actuals
.anyarray_type
=
1126 get_call_expr_argtype(call_expr
, inargno
);
1127 if (!OidIsValid(poly_actuals
.anyarray_type
))
1130 argtypes
[i
] = poly_actuals
.anyarray_type
;
1134 if (argmode
== PROARGMODE_OUT
|| argmode
== PROARGMODE_TABLE
)
1136 have_polymorphic_result
= true;
1137 have_anyrange_result
= true;
1141 if (!OidIsValid(poly_actuals
.anyrange_type
))
1143 poly_actuals
.anyrange_type
=
1144 get_call_expr_argtype(call_expr
, inargno
);
1145 if (!OidIsValid(poly_actuals
.anyrange_type
))
1148 argtypes
[i
] = poly_actuals
.anyrange_type
;
1151 case ANYMULTIRANGEOID
:
1152 if (argmode
== PROARGMODE_OUT
|| argmode
== PROARGMODE_TABLE
)
1154 have_polymorphic_result
= true;
1155 have_anymultirange_result
= true;
1159 if (!OidIsValid(poly_actuals
.anymultirange_type
))
1161 poly_actuals
.anymultirange_type
=
1162 get_call_expr_argtype(call_expr
, inargno
);
1163 if (!OidIsValid(poly_actuals
.anymultirange_type
))
1166 argtypes
[i
] = poly_actuals
.anymultirange_type
;
1169 case ANYCOMPATIBLEOID
:
1170 case ANYCOMPATIBLENONARRAYOID
:
1171 if (argmode
== PROARGMODE_OUT
|| argmode
== PROARGMODE_TABLE
)
1173 have_polymorphic_result
= true;
1174 have_anycompatible_result
= true;
1178 if (!OidIsValid(anyc_actuals
.anyelement_type
))
1180 anyc_actuals
.anyelement_type
=
1181 get_call_expr_argtype(call_expr
, inargno
);
1182 if (!OidIsValid(anyc_actuals
.anyelement_type
))
1185 argtypes
[i
] = anyc_actuals
.anyelement_type
;
1188 case ANYCOMPATIBLEARRAYOID
:
1189 if (argmode
== PROARGMODE_OUT
|| argmode
== PROARGMODE_TABLE
)
1191 have_polymorphic_result
= true;
1192 have_anycompatible_array_result
= true;
1196 if (!OidIsValid(anyc_actuals
.anyarray_type
))
1198 anyc_actuals
.anyarray_type
=
1199 get_call_expr_argtype(call_expr
, inargno
);
1200 if (!OidIsValid(anyc_actuals
.anyarray_type
))
1203 argtypes
[i
] = anyc_actuals
.anyarray_type
;
1206 case ANYCOMPATIBLERANGEOID
:
1207 if (argmode
== PROARGMODE_OUT
|| argmode
== PROARGMODE_TABLE
)
1209 have_polymorphic_result
= true;
1210 have_anycompatible_range_result
= true;
1214 if (!OidIsValid(anyc_actuals
.anyrange_type
))
1216 anyc_actuals
.anyrange_type
=
1217 get_call_expr_argtype(call_expr
, inargno
);
1218 if (!OidIsValid(anyc_actuals
.anyrange_type
))
1221 argtypes
[i
] = anyc_actuals
.anyrange_type
;
1224 case ANYCOMPATIBLEMULTIRANGEOID
:
1225 if (argmode
== PROARGMODE_OUT
|| argmode
== PROARGMODE_TABLE
)
1227 have_polymorphic_result
= true;
1228 have_anycompatible_multirange_result
= true;
1232 if (!OidIsValid(anyc_actuals
.anymultirange_type
))
1234 anyc_actuals
.anymultirange_type
=
1235 get_call_expr_argtype(call_expr
, inargno
);
1236 if (!OidIsValid(anyc_actuals
.anymultirange_type
))
1239 argtypes
[i
] = anyc_actuals
.anymultirange_type
;
1245 if (argmode
!= PROARGMODE_OUT
&& argmode
!= PROARGMODE_TABLE
)
1250 if (!have_polymorphic_result
)
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
);
1257 if (have_anyarray_result
&& !OidIsValid(poly_actuals
.anyarray_type
))
1258 resolve_anyarray_from_others(&poly_actuals
);
1260 if (have_anyrange_result
&& !OidIsValid(poly_actuals
.anyrange_type
))
1261 resolve_anyrange_from_others(&poly_actuals
);
1263 if (have_anymultirange_result
&& !OidIsValid(poly_actuals
.anymultirange_type
))
1264 resolve_anymultirange_from_others(&poly_actuals
);
1266 if (have_anycompatible_result
&& !OidIsValid(anyc_actuals
.anyelement_type
))
1267 resolve_anyelement_from_others(&anyc_actuals
);
1269 if (have_anycompatible_array_result
&& !OidIsValid(anyc_actuals
.anyarray_type
))
1270 resolve_anyarray_from_others(&anyc_actuals
);
1272 if (have_anycompatible_range_result
&& !OidIsValid(anyc_actuals
.anyrange_type
))
1273 resolve_anyrange_from_others(&anyc_actuals
);
1275 if (have_anycompatible_multirange_result
&& !OidIsValid(anyc_actuals
.anymultirange_type
))
1276 resolve_anymultirange_from_others(&anyc_actuals
);
1278 /* And finally replace the output column types as needed */
1279 for (i
= 0; i
< numargs
; i
++)
1281 switch (argtypes
[i
])
1284 case ANYNONARRAYOID
:
1286 argtypes
[i
] = poly_actuals
.anyelement_type
;
1289 argtypes
[i
] = poly_actuals
.anyarray_type
;
1292 argtypes
[i
] = poly_actuals
.anyrange_type
;
1294 case ANYMULTIRANGEOID
:
1295 argtypes
[i
] = poly_actuals
.anymultirange_type
;
1297 case ANYCOMPATIBLEOID
:
1298 case ANYCOMPATIBLENONARRAYOID
:
1299 argtypes
[i
] = anyc_actuals
.anyelement_type
;
1301 case ANYCOMPATIBLEARRAYOID
:
1302 argtypes
[i
] = anyc_actuals
.anyarray_type
;
1304 case ANYCOMPATIBLERANGEOID
:
1305 argtypes
[i
] = anyc_actuals
.anyrange_type
;
1307 case ANYCOMPATIBLEMULTIRANGEOID
:
1308 argtypes
[i
] = anyc_actuals
.anymultirange_type
;
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.
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.
1327 static TypeFuncClass
1328 get_type_func_class(Oid typid
, Oid
*base_typeid
)
1330 *base_typeid
= typid
;
1332 switch (get_typtype(typid
))
1334 case TYPTYPE_COMPOSITE
:
1335 return TYPEFUNC_COMPOSITE
;
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
)
1344 return TYPEFUNC_COMPOSITE_DOMAIN
;
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
;
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).
1357 if (typid
== VOIDOID
|| typid
== CSTRINGOID
)
1358 return TYPEFUNC_SCALAR
;
1359 return TYPEFUNC_OTHER
;
1361 /* shouldn't get here, probably */
1362 return TYPEFUNC_OTHER
;
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).
1375 * Note that this function simply fetches what is in the pg_proc tuple;
1376 * it doesn't do any interpretation of polymorphic types.
1379 get_func_arg_info(HeapTuple procTup
,
1380 Oid
**p_argtypes
, char ***p_argnames
, char **p_argmodes
)
1382 Form_pg_proc procStruct
= (Form_pg_proc
) GETSTRUCT(procTup
);
1383 Datum proallargtypes
;
1393 /* First discover the total number of parameters and get their types */
1394 proallargtypes
= SysCacheGetAttr(PROCOID
, procTup
,
1395 Anum_pg_proc_proallargtypes
,
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.
1405 arr
= DatumGetArrayTypeP(proallargtypes
); /* ensure not toasted */
1406 numargs
= ARR_DIMS(arr
)[0];
1407 if (ARR_NDIM(arr
) != 1 ||
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
));
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
));
1427 /* Get argument names, if available */
1428 proargnames
= SysCacheGetAttr(PROCOID
, procTup
,
1429 Anum_pg_proc_proargnames
,
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
]);
1444 /* Get argument modes, if available */
1445 proargmodes
= SysCacheGetAttr(PROCOID
, procTup
,
1446 Anum_pg_proc_proargmodes
,
1452 arr
= DatumGetArrayTypeP(proargmodes
); /* ensure not toasted */
1453 if (ARR_NDIM(arr
) != 1 ||
1454 ARR_DIMS(arr
)[0] != numargs
||
1456 ARR_ELEMTYPE(arr
) != CHAROID
)
1457 elog(ERROR
, "proargmodes is not a 1-D char array of length %d or it contains nulls",
1459 *p_argmodes
= (char *) palloc(numargs
* sizeof(char));
1460 memcpy(*p_argmodes
, ARR_DATA_PTR(arr
),
1461 numargs
* sizeof(char));
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
1475 get_func_trftypes(HeapTuple procTup
,
1483 protrftypes
= SysCacheGetAttr(PROCOID
, procTup
,
1484 Anum_pg_proc_protrftypes
,
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.
1494 arr
= DatumGetArrayTypeP(protrftypes
); /* ensure not toasted */
1495 nelems
= ARR_DIMS(arr
)[0];
1496 if (ARR_NDIM(arr
) != 1 ||
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
));
1512 * get_func_input_arg_names
1514 * Extract the names of input arguments only, given a function's
1515 * proargnames and proargmodes entries in Datum form.
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.
1522 get_func_input_arg_names(Datum proargnames
, Datum proargmodes
,
1533 /* Do nothing if null proargnames */
1534 if (proargnames
== PointerGetDatum(NULL
))
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.
1545 arr
= DatumGetArrayTypeP(proargnames
); /* ensure not toasted */
1546 if (ARR_NDIM(arr
) != 1 ||
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
))
1553 arr
= DatumGetArrayTypeP(proargmodes
); /* ensure not toasted */
1554 if (ARR_NDIM(arr
) != 1 ||
1555 ARR_DIMS(arr
)[0] != numargs
||
1557 ARR_ELEMTYPE(arr
) != CHAROID
)
1558 elog(ERROR
, "proargmodes is not a 1-D char array of length %d or it contains nulls",
1560 argmodes
= (char *) ARR_DATA_PTR(arr
);
1565 /* zero elements probably shouldn't happen, but handle it gracefully */
1572 /* extract input-argument names */
1573 inargnames
= (char **) palloc(numargs
* sizeof(char *));
1575 for (i
= 0; i
< numargs
; i
++)
1577 if (argmodes
== NULL
||
1578 argmodes
[i
] == PROARGMODE_IN
||
1579 argmodes
[i
] == PROARGMODE_INOUT
||
1580 argmodes
[i
] == PROARGMODE_VARIADIC
)
1582 char *pname
= TextDatumGetCString(argnames
[i
]);
1584 if (pname
[0] != '\0')
1585 inargnames
[numinargs
] = pname
;
1587 inargnames
[numinargs
] = NULL
;
1592 *arg_names
= inargnames
;
1598 * get_func_result_name
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.
1603 * This is used to determine the default output column name for functions
1604 * returning scalar types.
1607 get_func_result_name(Oid functionId
)
1610 HeapTuple procTuple
;
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
);
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
))
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
);
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
1644 arr
= DatumGetArrayTypeP(proargmodes
); /* ensure not toasted */
1645 numargs
= ARR_DIMS(arr
)[0];
1646 if (ARR_NDIM(arr
) != 1 ||
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
||
1656 ARR_ELEMTYPE(arr
) != TEXTOID
)
1657 elog(ERROR
, "proargnames is not a 1-D text array of length %d or it contains nulls",
1659 deconstruct_array_builtin(arr
, TEXTOID
, &argnames
, NULL
, &nargnames
);
1660 Assert(nargnames
== numargs
);
1662 /* scan for output argument(s) */
1665 for (i
= 0; i
< numargs
; i
++)
1667 if (argmodes
[i
] == PROARGMODE_IN
||
1668 argmodes
[i
] == PROARGMODE_VARIADIC
)
1670 Assert(argmodes
[i
] == PROARGMODE_OUT
||
1671 argmodes
[i
] == PROARGMODE_INOUT
||
1672 argmodes
[i
] == PROARGMODE_TABLE
);
1673 if (++numoutargs
> 1)
1675 /* multiple out args, so forget it */
1679 result
= TextDatumGetCString(argnames
[i
]);
1680 if (result
== NULL
|| result
[0] == '\0')
1682 /* Parameter is not named, so forget it */
1689 ReleaseSysCache(procTuple
);
1696 * build_function_result_tupdesc_t
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.
1701 * Note that this does not handle resolution of polymorphic types;
1702 * that is deliberate.
1705 build_function_result_tupdesc_t(HeapTuple procTuple
)
1707 Form_pg_proc procform
= (Form_pg_proc
) GETSTRUCT(procTuple
);
1708 Datum proallargtypes
;
1713 /* Return NULL if the function isn't declared to return RECORD */
1714 if (procform
->prorettype
!= RECORDOID
)
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
))
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
,
1731 proargnames
= PointerGetDatum(NULL
); /* just to be sure */
1733 return build_function_result_tupdesc_d(procform
->prokind
,
1740 * build_function_result_tupdesc_d
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.
1747 * For functions (but not for procedures), returns NULL if there are not at
1748 * least two OUT or INOUT arguments.
1751 build_function_result_tupdesc_d(char prokind
,
1752 Datum proallargtypes
,
1761 Datum
*argnames
= NULL
;
1768 /* Can't have output args if columns are null */
1769 if (proallargtypes
== PointerGetDatum(NULL
) ||
1770 proargmodes
== PointerGetDatum(NULL
))
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.
1778 arr
= DatumGetArrayTypeP(proallargtypes
); /* ensure not toasted */
1779 numargs
= ARR_DIMS(arr
)[0];
1780 if (ARR_NDIM(arr
) != 1 ||
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
||
1790 ARR_ELEMTYPE(arr
) != CHAROID
)
1791 elog(ERROR
, "proargmodes is not a 1-D char array of length %d or it contains nulls",
1793 argmodes
= (char *) ARR_DATA_PTR(arr
);
1794 if (proargnames
!= PointerGetDatum(NULL
))
1796 arr
= DatumGetArrayTypeP(proargnames
); /* ensure not toasted */
1797 if (ARR_NDIM(arr
) != 1 ||
1798 ARR_DIMS(arr
)[0] != numargs
||
1800 ARR_ELEMTYPE(arr
) != TEXTOID
)
1801 elog(ERROR
, "proargnames is not a 1-D text array of length %d or it contains nulls",
1803 deconstruct_array_builtin(arr
, TEXTOID
, &argnames
, NULL
, &nargnames
);
1804 Assert(nargnames
== numargs
);
1807 /* zero elements probably shouldn't happen, but handle it gracefully */
1811 /* extract output-argument types and names */
1812 outargtypes
= (Oid
*) palloc(numargs
* sizeof(Oid
));
1813 outargnames
= (char **) palloc(numargs
* sizeof(char *));
1815 for (i
= 0; i
< numargs
; i
++)
1819 if (argmodes
[i
] == PROARGMODE_IN
||
1820 argmodes
[i
] == PROARGMODE_VARIADIC
)
1822 Assert(argmodes
[i
] == PROARGMODE_OUT
||
1823 argmodes
[i
] == PROARGMODE_INOUT
||
1824 argmodes
[i
] == PROARGMODE_TABLE
);
1825 outargtypes
[numoutargs
] = argtypes
[i
];
1827 pname
= TextDatumGetCString(argnames
[i
]);
1830 if (pname
== NULL
|| pname
[0] == '\0')
1832 /* Parameter is not named, so gin up a column name */
1833 pname
= psprintf("column%d", numoutargs
+ 1);
1835 outargnames
[numoutargs
] = pname
;
1840 * If there is no output argument, or only one, the function does not
1843 if (numoutargs
< 2 && prokind
!= PROKIND_PROCEDURE
)
1846 desc
= CreateTemplateTupleDesc(numoutargs
);
1847 for (i
= 0; i
< numoutargs
; i
++)
1849 TupleDescInitEntry(desc
, i
+ 1,
1861 * RelationNameGetTupleDesc
1863 * Given a (possibly qualified) relation name, build a TupleDesc.
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.
1870 RelationNameGetTupleDesc(const char *relname
)
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
));
1882 relation_close(rel
, AccessShareLock
);
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.)
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.)
1900 * If the type is a base type, a single item alias List is required.
1903 TypeGetTupleDesc(Oid typeoid
, List
*colaliases
)
1906 TypeFuncClass functypclass
= get_type_func_class(typeoid
, &base_typeoid
);
1907 TupleDesc tupdesc
= NULL
;
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.
1915 if (functypclass
== TYPEFUNC_COMPOSITE
)
1917 /* Composite data type, e.g. a table's row type */
1918 tupdesc
= lookup_rowtype_tupdesc_copy(base_typeoid
, -1);
1920 if (colaliases
!= NIL
)
1922 int natts
= tupdesc
->natts
;
1925 /* does the list length match the number of attributes? */
1926 if (list_length(colaliases
) != natts
)
1928 (errcode(ERRCODE_DATATYPE_MISMATCH
),
1929 errmsg("number of aliases does not match number of columns")));
1931 /* OK, use the aliases instead */
1932 for (varattno
= 0; varattno
< natts
; varattno
++)
1934 char *label
= strVal(list_nth(colaliases
, varattno
));
1935 Form_pg_attribute attr
= TupleDescAttr(tupdesc
, varattno
);
1938 namestrcpy(&(attr
->attname
), label
);
1941 /* The tuple type is now an anonymous record type */
1942 tupdesc
->tdtypeid
= RECORDOID
;
1943 tupdesc
->tdtypmod
= -1;
1946 else if (functypclass
== TYPEFUNC_SCALAR
)
1948 /* Base data type, i.e. scalar */
1951 /* the alias list is required for base types */
1952 if (colaliases
== NIL
)
1954 (errcode(ERRCODE_DATATYPE_MISMATCH
),
1955 errmsg("no column alias was provided")));
1957 /* the alias list length must be 1 */
1958 if (list_length(colaliases
) != 1)
1960 (errcode(ERRCODE_DATATYPE_MISMATCH
),
1961 errmsg("number of aliases does not match number of columns")));
1963 /* OK, get the column alias */
1964 attname
= strVal(linitial(colaliases
));
1966 tupdesc
= CreateTemplateTupleDesc(1);
1967 TupleDescInitEntry(tupdesc
,
1974 else if (functypclass
== TYPEFUNC_RECORD
)
1976 /* XXX can't support this because typmod wasn't passed in ... */
1978 (errcode(ERRCODE_DATATYPE_MISMATCH
),
1979 errmsg("could not determine row description for function returning record")));
1983 /* crummy error message, but parser should have caught this */
1984 elog(ERROR
, "function in FROM has unsupported return type");
1991 * extract_variadic_args
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
2001 * This function returns the number of arguments generated, or -1 in the
2002 * case of "VARIADIC NULL".
2005 extract_variadic_args(FunctionCallInfo fcinfo
, int variadic_start
,
2006 bool convert_unknown
, Datum
**args
, Oid
**types
,
2009 bool variadic
= get_fn_expr_variadic(fcinfo
->flinfo
);
2022 ArrayType
*array_in
;
2028 Assert(PG_NARGS() == variadic_start
+ 1);
2030 if (PG_ARGISNULL(variadic_start
))
2033 array_in
= PG_GETARG_ARRAYTYPE_P(variadic_start
);
2034 element_type
= ARR_ELEMTYPE(array_in
);
2036 get_typlenbyvalalign(element_type
,
2037 &typlen
, &typbyval
, &typalign
);
2038 deconstruct_array(array_in
, element_type
, typlen
, typbyval
,
2039 typalign
, &args_res
, &nulls_res
,
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
;
2049 nargs
= PG_NARGS() - variadic_start
;
2051 nulls_res
= (bool *) palloc0(nargs
* sizeof(bool));
2052 args_res
= (Datum
*) palloc0(nargs
* sizeof(Datum
));
2053 types_res
= (Oid
*) palloc0(nargs
* sizeof(Oid
));
2055 for (i
= 0; i
< nargs
; i
++)
2057 nulls_res
[i
] = PG_ARGISNULL(i
+ variadic_start
);
2058 types_res
[i
] = get_fn_expr_argtype(fcinfo
->flinfo
,
2059 i
+ variadic_start
);
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).
2068 if (convert_unknown
&&
2069 types_res
[i
] == UNKNOWNOID
&&
2070 get_fn_expr_arg_stable(fcinfo
->flinfo
, i
+ variadic_start
))
2072 types_res
[i
] = TEXTOID
;
2074 if (PG_ARGISNULL(i
+ variadic_start
))
2075 args_res
[i
] = (Datum
) 0;
2078 CStringGetTextDatum(PG_GETARG_POINTER(i
+ variadic_start
));
2082 /* no conversion needed, just take the datum as given */
2083 args_res
[i
] = PG_GETARG_DATUM(i
+ variadic_start
);
2086 if (!OidIsValid(types_res
[i
]) ||
2087 (convert_unknown
&& types_res
[i
] == UNKNOWNOID
))
2089 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
2090 errmsg("could not determine data type for argument %d",
2095 /* Fill in results */