PostgreSQL Source Code git master
Loading...
Searching...
No Matches
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-2026, 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
53static bool resolve_polymorphic_tupdesc(TupleDesc tupdesc,
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;
80 Tuplestorestate *tupstore;
84
85 /* check to see if caller supports returning a tuplestore */
86 if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
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))
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;
102
103 /* build a tuple descriptor for our result type */
104 if ((flags & MAT_SRF_USE_EXPECTED_DESC) != 0)
106 else
107 {
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)
115
116 random_access = (rsinfo->allowedModes & SFRM_Materialize_Random) != 0;
117
118 tupstore = tuplestore_begin_heap(random_access, false, work_mem);
119 rsinfo->returnMode = SFRM_Materialize;
120 rsinfo->setResult = tupstore;
121 rsinfo->setDesc = stored_tupdesc;
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))
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;
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 *)
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;
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);
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 */
250 MemoryContextDelete(funcctx->multi_call_memory_ctx);
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 */
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 */
302{
303 TypeFuncClass result;
304
305 if (expr && IsA(expr, FuncExpr))
306 result = internal_get_result_type(((FuncExpr *) expr)->funcid,
307 expr,
308 NULL,
311 else if (expr && IsA(expr, OpExpr))
312 result = internal_get_result_type(get_opcode(((OpExpr *) expr)->opno),
313 expr,
314 NULL,
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),
338 0);
341 i++;
342 }
343 TupleDescFinalize(tupdesc);
344
345 if (resultTypeId)
346 *resultTypeId = rexpr->row_typeid;
347 if (resultTupleDesc)
349 return TYPEFUNC_COMPOSITE;
350 }
351 else if (expr && IsA(expr, Const) &&
352 ((Const *) expr)->consttype == RECORDOID &&
353 !((Const *) expr)->constisnull)
354 {
355 /*
356 * When EXPLAIN'ing some queries with SEARCH/CYCLE clauses, we may
357 * need to resolve field names of a RECORD-type Const. The datum
358 * should contain a typmod that will tell us that.
359 */
360 HeapTupleHeader rec;
361 Oid tupType;
363
364 rec = DatumGetHeapTupleHeader(((Const *) expr)->constvalue);
367 if (resultTypeId)
369 if (tupType != RECORDOID || tupTypmod >= 0)
370 {
371 /* Should be able to look it up */
372 if (resultTupleDesc)
374 tupTypmod);
375 return TYPEFUNC_COMPOSITE;
376 }
377 else
378 {
379 /* This shouldn't really happen ... */
380 if (resultTupleDesc)
382 return TYPEFUNC_RECORD;
383 }
384 }
385 else
386 {
387 /* handle as a generic expression; no chance to resolve RECORD */
388 Oid typid = exprType(expr);
389 Oid base_typid;
390
391 if (resultTypeId)
392 *resultTypeId = typid;
393 if (resultTupleDesc)
395 result = get_type_func_class(typid, &base_typid);
396 if ((result == TYPEFUNC_COMPOSITE ||
397 result == TYPEFUNC_COMPOSITE_DOMAIN) &&
400 }
401
402 return result;
403}
404
405/*
406 * get_func_result_type
407 * As above, but work from a function's OID only
408 *
409 * This will not be able to resolve pure-RECORD results nor polymorphism.
410 */
422
423/*
424 * internal_get_result_type -- workhorse code implementing all the above
425 *
426 * funcid must always be supplied. call_expr and rsinfo can be NULL if not
427 * available. We will return TYPEFUNC_RECORD, and store NULL into
428 * *resultTupleDesc, if we cannot deduce the complete result rowtype from
429 * the available information.
430 */
431static TypeFuncClass
437{
438 TypeFuncClass result;
439 HeapTuple tp;
441 Oid rettype;
443 TupleDesc tupdesc;
444
445 /* First fetch the function's pg_proc row to inspect its rettype */
447 if (!HeapTupleIsValid(tp))
448 elog(ERROR, "cache lookup failed for function %u", funcid);
450
451 rettype = procform->prorettype;
452
453 /* Check for OUT parameters defining a RECORD result */
455 if (tupdesc)
456 {
457 /*
458 * It has OUT parameters, so it's basically like a regular composite
459 * type, except we have to be able to resolve any polymorphic OUT
460 * parameters.
461 */
462 if (resultTypeId)
463 *resultTypeId = rettype;
464
465 if (resolve_polymorphic_tupdesc(tupdesc,
466 &procform->proargtypes,
467 call_expr))
468 {
469 if (tupdesc->tdtypeid == RECORDOID &&
470 tupdesc->tdtypmod < 0)
472 if (resultTupleDesc)
473 *resultTupleDesc = tupdesc;
474 result = TYPEFUNC_COMPOSITE;
475 }
476 else
477 {
478 if (resultTupleDesc)
480 result = TYPEFUNC_RECORD;
481 }
482
483 ReleaseSysCache(tp);
484
485 return result;
486 }
487
488 /*
489 * If scalar polymorphic result, try to resolve it.
490 */
491 if (IsPolymorphicType(rettype))
492 {
494
495 if (newrettype == InvalidOid) /* this probably should not happen */
498 errmsg("could not determine actual result type for function \"%s\" declared to return type %s",
499 NameStr(procform->proname),
500 format_type_be(rettype))));
501 rettype = newrettype;
502 }
503
504 if (resultTypeId)
505 *resultTypeId = rettype;
506 if (resultTupleDesc)
507 *resultTupleDesc = NULL; /* default result */
508
509 /* Classify the result type */
510 result = get_type_func_class(rettype, &base_rettype);
511 switch (result)
512 {
515 if (resultTupleDesc)
517 /* Named composite types can't have any polymorphic columns */
518 break;
519 case TYPEFUNC_SCALAR:
520 break;
521 case TYPEFUNC_RECORD:
522 /* We must get the tupledesc from call context */
523 if (rsinfo && IsA(rsinfo, ReturnSetInfo) &&
524 rsinfo->expectedDesc != NULL)
525 {
526 result = TYPEFUNC_COMPOSITE;
527 if (resultTupleDesc)
528 *resultTupleDesc = rsinfo->expectedDesc;
529 /* Assume no polymorphic columns here, either */
530 }
531 break;
532 default:
533 break;
534 }
535
536 ReleaseSysCache(tp);
537
538 return result;
539}
540
541/*
542 * get_expr_result_tupdesc
543 * Get a tupdesc describing the result of a composite-valued expression
544 *
545 * If expression is not composite or rowtype can't be determined, returns NULL
546 * if noError is true, else throws error.
547 *
548 * This is a simpler version of get_expr_result_type() for use when the caller
549 * is only interested in determinate rowtype results. As with that function,
550 * beware of using this on the funcexpr of a RTE that has a coldeflist.
551 */
554{
557
559
562 return tupleDesc;
563
564 if (!noError)
565 {
566 Oid exprTypeId = exprType(expr);
567
568 if (exprTypeId != RECORDOID)
571 errmsg("type %s is not composite",
573 else
576 errmsg("record type has not been registered")));
577 }
578
579 return NULL;
580}
581
582/*
583 * Resolve actual type of ANYELEMENT from other polymorphic inputs
584 *
585 * Note: the error cases here and in the sibling functions below are not
586 * really user-facing; they could only occur if the function signature is
587 * incorrect or the parser failed to enforce consistency of the actual
588 * argument types. Hence, we don't sweat too much over the error messages.
589 */
590static void
592{
593 if (OidIsValid(actuals->anyarray_type))
594 {
595 /* Use the element type corresponding to actual type */
596 Oid array_base_type = getBaseType(actuals->anyarray_type);
598
602 errmsg("argument declared %s is not an array but type %s",
603 "anyarray",
605 actuals->anyelement_type = array_typelem;
606 }
607 else if (OidIsValid(actuals->anyrange_type))
608 {
609 /* Use the element type corresponding to actual type */
610 Oid range_base_type = getBaseType(actuals->anyrange_type);
612
616 errmsg("argument declared %s is not a range type but type %s",
617 "anyrange",
619 actuals->anyelement_type = range_typelem;
620 }
621 else if (OidIsValid(actuals->anymultirange_type))
622 {
623 /* Use the element type based on the multirange type */
628
629 multirange_base_type = getBaseType(actuals->anymultirange_type);
634 errmsg("argument declared %s is not a multirange type but type %s",
635 "anymultirange",
637
640
644 errmsg("argument declared %s does not contain a range type but type %s",
645 "anymultirange",
647 actuals->anyelement_type = range_typelem;
648 }
649 else
650 elog(ERROR, "could not determine polymorphic type");
651}
652
653/*
654 * Resolve actual type of ANYARRAY from other polymorphic inputs
655 */
656static void
658{
659 /* If we don't know ANYELEMENT, resolve that first */
660 if (!OidIsValid(actuals->anyelement_type))
662
663 if (OidIsValid(actuals->anyelement_type))
664 {
665 /* Use the array type corresponding to actual type */
666 Oid array_typeid = get_array_type(actuals->anyelement_type);
667
671 errmsg("could not find array type for data type %s",
672 format_type_be(actuals->anyelement_type))));
673 actuals->anyarray_type = array_typeid;
674 }
675 else
676 elog(ERROR, "could not determine polymorphic type");
677}
678
679/*
680 * Resolve actual type of ANYRANGE from other polymorphic inputs
681 */
682static void
684{
685 /*
686 * We can't deduce a range type from other polymorphic array or base
687 * types, because there may be multiple range types with the same subtype,
688 * but we can deduce it from a polymorphic multirange type.
689 */
690 if (OidIsValid(actuals->anymultirange_type))
691 {
692 /* Use the element type based on the multirange type */
693 Oid multirange_base_type = getBaseType(actuals->anymultirange_type);
695
699 errmsg("argument declared %s is not a multirange type but type %s",
700 "anymultirange",
702 actuals->anyrange_type = multirange_typelem;
703 }
704 else
705 elog(ERROR, "could not determine polymorphic type");
706}
707
708/*
709 * Resolve actual type of ANYMULTIRANGE from other polymorphic inputs
710 */
711static void
713{
714 /*
715 * We can't deduce a multirange type from polymorphic array or base types,
716 * because there may be multiple range types with the same subtype, but we
717 * can deduce it from a polymorphic range type.
718 */
719 if (OidIsValid(actuals->anyrange_type))
720 {
721 Oid range_base_type = getBaseType(actuals->anyrange_type);
723
727 errmsg("could not find multirange type for data type %s",
728 format_type_be(actuals->anyrange_type))));
729 actuals->anymultirange_type = multirange_typeid;
730 }
731 else
732 elog(ERROR, "could not determine polymorphic type");
733}
734
735/*
736 * Given the result tuple descriptor for a function with OUT parameters,
737 * replace any polymorphic column types (ANYELEMENT etc) in the tupdesc
738 * with concrete data types deduced from the input arguments.
739 * declared_args is an oidvector of the function's declared input arg types
740 * (showing which are polymorphic), and call_expr is the call expression.
741 *
742 * Returns true if able to deduce all types, false if necessary information
743 * is not provided (call_expr is NULL or arg types aren't identifiable).
744 */
745static bool
748{
749 int natts = tupdesc->natts;
750 int nargs = declared_args->dim1;
751 bool have_polymorphic_result = false;
752 bool have_anyelement_result = false;
753 bool have_anyarray_result = false;
754 bool have_anyrange_result = false;
755 bool have_anymultirange_result = false;
756 bool have_anycompatible_result = false;
764 int i;
765
766 /* See if there are any polymorphic outputs; quick out if not */
767 for (i = 0; i < natts; i++)
768 {
769 switch (TupleDescAttr(tupdesc, i)->atttypid)
770 {
771 case ANYELEMENTOID:
772 case ANYNONARRAYOID:
773 case ANYENUMOID:
776 break;
777 case ANYARRAYOID:
780 break;
781 case ANYRANGEOID:
784 break;
785 case ANYMULTIRANGEOID:
788 break;
789 case ANYCOMPATIBLEOID:
793 break;
797 break;
801 break;
805 break;
806 default:
807 break;
808 }
809 }
811 return true;
812
813 /*
814 * Otherwise, extract actual datatype(s) from input arguments. (We assume
815 * the parser already validated consistency of the arguments. Also, for
816 * the ANYCOMPATIBLE pseudotype family, we expect that all matching
817 * arguments were coerced to the selected common supertype, so that it
818 * doesn't matter which one's exposed type we look at.)
819 */
820 if (!call_expr)
821 return false; /* no hope */
822
823 memset(&poly_actuals, 0, sizeof(poly_actuals));
824 memset(&anyc_actuals, 0, sizeof(anyc_actuals));
825
826 for (i = 0; i < nargs; i++)
827 {
828 switch (declared_args->values[i])
829 {
830 case ANYELEMENTOID:
831 case ANYNONARRAYOID:
832 case ANYENUMOID:
833 if (!OidIsValid(poly_actuals.anyelement_type))
834 {
835 poly_actuals.anyelement_type =
837 if (!OidIsValid(poly_actuals.anyelement_type))
838 return false;
839 }
840 break;
841 case ANYARRAYOID:
842 if (!OidIsValid(poly_actuals.anyarray_type))
843 {
844 poly_actuals.anyarray_type =
846 if (!OidIsValid(poly_actuals.anyarray_type))
847 return false;
848 }
849 break;
850 case ANYRANGEOID:
851 if (!OidIsValid(poly_actuals.anyrange_type))
852 {
853 poly_actuals.anyrange_type =
855 if (!OidIsValid(poly_actuals.anyrange_type))
856 return false;
857 }
858 break;
859 case ANYMULTIRANGEOID:
860 if (!OidIsValid(poly_actuals.anymultirange_type))
861 {
862 poly_actuals.anymultirange_type =
864 if (!OidIsValid(poly_actuals.anymultirange_type))
865 return false;
866 }
867 break;
868 case ANYCOMPATIBLEOID:
870 if (!OidIsValid(anyc_actuals.anyelement_type))
871 {
872 anyc_actuals.anyelement_type =
874 if (!OidIsValid(anyc_actuals.anyelement_type))
875 return false;
876 }
877 break;
879 if (!OidIsValid(anyc_actuals.anyarray_type))
880 {
881 anyc_actuals.anyarray_type =
883 if (!OidIsValid(anyc_actuals.anyarray_type))
884 return false;
885 }
886 break;
888 if (!OidIsValid(anyc_actuals.anyrange_type))
889 {
890 anyc_actuals.anyrange_type =
892 if (!OidIsValid(anyc_actuals.anyrange_type))
893 return false;
894 }
895 break;
897 if (!OidIsValid(anyc_actuals.anymultirange_type))
898 {
899 anyc_actuals.anymultirange_type =
901 if (!OidIsValid(anyc_actuals.anymultirange_type))
902 return false;
903 }
904 break;
905 default:
906 break;
907 }
908 }
909
910 /* If needed, deduce one polymorphic type from others */
911 if (have_anyelement_result && !OidIsValid(poly_actuals.anyelement_type))
913
914 if (have_anyarray_result && !OidIsValid(poly_actuals.anyarray_type))
916
917 if (have_anyrange_result && !OidIsValid(poly_actuals.anyrange_type))
919
920 if (have_anymultirange_result && !OidIsValid(poly_actuals.anymultirange_type))
922
923 if (have_anycompatible_result && !OidIsValid(anyc_actuals.anyelement_type))
925
928
931
934
935 /*
936 * Identify the collation to use for polymorphic OUT parameters. (It'll
937 * necessarily be the same for both anyelement and anyarray, likewise for
938 * anycompatible and anycompatiblearray.) Note that range types are not
939 * collatable, so any possible internal collation of a range type is not
940 * considered here.
941 */
942 if (OidIsValid(poly_actuals.anyelement_type))
943 anycollation = get_typcollation(poly_actuals.anyelement_type);
944 else if (OidIsValid(poly_actuals.anyarray_type))
946
947 if (OidIsValid(anyc_actuals.anyelement_type))
949 else if (OidIsValid(anyc_actuals.anyarray_type))
951
953 {
954 /*
955 * The types are collatable, so consider whether to use a nondefault
956 * collation. We do so if we can identify the input collation used
957 * for the function.
958 */
960
962 {
967 }
968 }
969
970 /* And finally replace the tuple column types as needed */
971 for (i = 0; i < natts; i++)
972 {
974
975 switch (att->atttypid)
976 {
977 case ANYELEMENTOID:
978 case ANYNONARRAYOID:
979 case ANYENUMOID:
980 TupleDescInitEntry(tupdesc, i + 1,
981 NameStr(att->attname),
982 poly_actuals.anyelement_type,
983 -1,
984 0);
986 break;
987 case ANYARRAYOID:
988 TupleDescInitEntry(tupdesc, i + 1,
989 NameStr(att->attname),
990 poly_actuals.anyarray_type,
991 -1,
992 0);
994 break;
995 case ANYRANGEOID:
996 TupleDescInitEntry(tupdesc, i + 1,
997 NameStr(att->attname),
998 poly_actuals.anyrange_type,
999 -1,
1000 0);
1001 /* no collation should be attached to a range type */
1002 break;
1003 case ANYMULTIRANGEOID:
1004 TupleDescInitEntry(tupdesc, i + 1,
1005 NameStr(att->attname),
1006 poly_actuals.anymultirange_type,
1007 -1,
1008 0);
1009 /* no collation should be attached to a multirange type */
1010 break;
1011 case ANYCOMPATIBLEOID:
1013 TupleDescInitEntry(tupdesc, i + 1,
1014 NameStr(att->attname),
1015 anyc_actuals.anyelement_type,
1016 -1,
1017 0);
1019 break;
1021 TupleDescInitEntry(tupdesc, i + 1,
1022 NameStr(att->attname),
1023 anyc_actuals.anyarray_type,
1024 -1,
1025 0);
1027 break;
1029 TupleDescInitEntry(tupdesc, i + 1,
1030 NameStr(att->attname),
1031 anyc_actuals.anyrange_type,
1032 -1,
1033 0);
1034 /* no collation should be attached to a range type */
1035 break;
1037 TupleDescInitEntry(tupdesc, i + 1,
1038 NameStr(att->attname),
1039 anyc_actuals.anymultirange_type,
1040 -1,
1041 0);
1042 /* no collation should be attached to a multirange type */
1043 break;
1044 default:
1045 break;
1046 }
1047 }
1048
1049 TupleDescFinalize(tupdesc);
1050 return true;
1051}
1052
1053/*
1054 * Given the declared argument types and modes for a function, replace any
1055 * polymorphic types (ANYELEMENT etc) in argtypes[] with concrete data types
1056 * deduced from the input arguments found in call_expr.
1057 *
1058 * Returns true if able to deduce all types, false if necessary information
1059 * is not provided (call_expr is NULL or arg types aren't identifiable).
1060 *
1061 * This is the same logic as resolve_polymorphic_tupdesc, but with a different
1062 * argument representation, and slightly different output responsibilities.
1063 *
1064 * argmodes may be NULL, in which case all arguments are assumed to be IN mode.
1065 */
1066bool
1067resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes,
1068 Node *call_expr)
1069{
1070 bool have_polymorphic_result = false;
1071 bool have_anyelement_result = false;
1072 bool have_anyarray_result = false;
1073 bool have_anyrange_result = false;
1074 bool have_anymultirange_result = false;
1075 bool have_anycompatible_result = false;
1081 int inargno;
1082 int i;
1083
1084 /*
1085 * First pass: resolve polymorphic inputs, check for outputs. As in
1086 * resolve_polymorphic_tupdesc, we rely on the parser to have enforced
1087 * type consistency and coerced ANYCOMPATIBLE args to a common supertype.
1088 */
1089 memset(&poly_actuals, 0, sizeof(poly_actuals));
1090 memset(&anyc_actuals, 0, sizeof(anyc_actuals));
1091 inargno = 0;
1092 for (i = 0; i < numargs; i++)
1093 {
1095
1096 switch (argtypes[i])
1097 {
1098 case ANYELEMENTOID:
1099 case ANYNONARRAYOID:
1100 case ANYENUMOID:
1102 {
1105 }
1106 else
1107 {
1108 if (!OidIsValid(poly_actuals.anyelement_type))
1109 {
1110 poly_actuals.anyelement_type =
1112 if (!OidIsValid(poly_actuals.anyelement_type))
1113 return false;
1114 }
1115 argtypes[i] = poly_actuals.anyelement_type;
1116 }
1117 break;
1118 case ANYARRAYOID:
1120 {
1122 have_anyarray_result = true;
1123 }
1124 else
1125 {
1126 if (!OidIsValid(poly_actuals.anyarray_type))
1127 {
1128 poly_actuals.anyarray_type =
1130 if (!OidIsValid(poly_actuals.anyarray_type))
1131 return false;
1132 }
1133 argtypes[i] = poly_actuals.anyarray_type;
1134 }
1135 break;
1136 case ANYRANGEOID:
1138 {
1140 have_anyrange_result = true;
1141 }
1142 else
1143 {
1144 if (!OidIsValid(poly_actuals.anyrange_type))
1145 {
1146 poly_actuals.anyrange_type =
1148 if (!OidIsValid(poly_actuals.anyrange_type))
1149 return false;
1150 }
1151 argtypes[i] = poly_actuals.anyrange_type;
1152 }
1153 break;
1154 case ANYMULTIRANGEOID:
1156 {
1159 }
1160 else
1161 {
1162 if (!OidIsValid(poly_actuals.anymultirange_type))
1163 {
1164 poly_actuals.anymultirange_type =
1166 if (!OidIsValid(poly_actuals.anymultirange_type))
1167 return false;
1168 }
1169 argtypes[i] = poly_actuals.anymultirange_type;
1170 }
1171 break;
1172 case ANYCOMPATIBLEOID:
1175 {
1178 }
1179 else
1180 {
1181 if (!OidIsValid(anyc_actuals.anyelement_type))
1182 {
1183 anyc_actuals.anyelement_type =
1185 if (!OidIsValid(anyc_actuals.anyelement_type))
1186 return false;
1187 }
1188 argtypes[i] = anyc_actuals.anyelement_type;
1189 }
1190 break;
1193 {
1196 }
1197 else
1198 {
1199 if (!OidIsValid(anyc_actuals.anyarray_type))
1200 {
1201 anyc_actuals.anyarray_type =
1203 if (!OidIsValid(anyc_actuals.anyarray_type))
1204 return false;
1205 }
1206 argtypes[i] = anyc_actuals.anyarray_type;
1207 }
1208 break;
1211 {
1214 }
1215 else
1216 {
1217 if (!OidIsValid(anyc_actuals.anyrange_type))
1218 {
1219 anyc_actuals.anyrange_type =
1221 if (!OidIsValid(anyc_actuals.anyrange_type))
1222 return false;
1223 }
1224 argtypes[i] = anyc_actuals.anyrange_type;
1225 }
1226 break;
1229 {
1232 }
1233 else
1234 {
1235 if (!OidIsValid(anyc_actuals.anymultirange_type))
1236 {
1237 anyc_actuals.anymultirange_type =
1239 if (!OidIsValid(anyc_actuals.anymultirange_type))
1240 return false;
1241 }
1242 argtypes[i] = anyc_actuals.anymultirange_type;
1243 }
1244 break;
1245 default:
1246 break;
1247 }
1249 inargno++;
1250 }
1251
1252 /* Done? */
1254 return true;
1255
1256 /* If needed, deduce one polymorphic type from others */
1257 if (have_anyelement_result && !OidIsValid(poly_actuals.anyelement_type))
1259
1260 if (have_anyarray_result && !OidIsValid(poly_actuals.anyarray_type))
1262
1263 if (have_anyrange_result && !OidIsValid(poly_actuals.anyrange_type))
1265
1266 if (have_anymultirange_result && !OidIsValid(poly_actuals.anymultirange_type))
1268
1269 if (have_anycompatible_result && !OidIsValid(anyc_actuals.anyelement_type))
1271
1274
1277
1280
1281 /* And finally replace the output column types as needed */
1282 for (i = 0; i < numargs; i++)
1283 {
1284 switch (argtypes[i])
1285 {
1286 case ANYELEMENTOID:
1287 case ANYNONARRAYOID:
1288 case ANYENUMOID:
1289 argtypes[i] = poly_actuals.anyelement_type;
1290 break;
1291 case ANYARRAYOID:
1292 argtypes[i] = poly_actuals.anyarray_type;
1293 break;
1294 case ANYRANGEOID:
1295 argtypes[i] = poly_actuals.anyrange_type;
1296 break;
1297 case ANYMULTIRANGEOID:
1298 argtypes[i] = poly_actuals.anymultirange_type;
1299 break;
1300 case ANYCOMPATIBLEOID:
1302 argtypes[i] = anyc_actuals.anyelement_type;
1303 break;
1305 argtypes[i] = anyc_actuals.anyarray_type;
1306 break;
1308 argtypes[i] = anyc_actuals.anyrange_type;
1309 break;
1311 argtypes[i] = anyc_actuals.anymultirange_type;
1312 break;
1313 default:
1314 break;
1315 }
1316 }
1317
1318 return true;
1319}
1320
1321/*
1322 * get_type_func_class
1323 * Given the type OID, obtain its TYPEFUNC classification.
1324 * Also, if it's a domain, return the base type OID.
1325 *
1326 * This is intended to centralize a bunch of formerly ad-hoc code for
1327 * classifying types. The categories used here are useful for deciding
1328 * how to handle functions returning the datatype.
1329 */
1330static TypeFuncClass
1332{
1333 *base_typeid = typid;
1334
1335 switch (get_typtype(typid))
1336 {
1337 case TYPTYPE_COMPOSITE:
1338 return TYPEFUNC_COMPOSITE;
1339 case TYPTYPE_BASE:
1340 case TYPTYPE_ENUM:
1341 case TYPTYPE_RANGE:
1342 case TYPTYPE_MULTIRANGE:
1343 return TYPEFUNC_SCALAR;
1344 case TYPTYPE_DOMAIN:
1345 *base_typeid = typid = getBaseType(typid);
1346 if (get_typtype(typid) == TYPTYPE_COMPOSITE)
1348 else /* domain base type can't be a pseudotype */
1349 return TYPEFUNC_SCALAR;
1350 case TYPTYPE_PSEUDO:
1351 if (typid == RECORDOID)
1352 return TYPEFUNC_RECORD;
1353
1354 /*
1355 * We treat VOID and CSTRING as legitimate scalar datatypes,
1356 * mostly for the convenience of the JDBC driver (which wants to
1357 * be able to do "SELECT * FROM foo()" for all legitimately
1358 * user-callable functions).
1359 */
1360 if (typid == VOIDOID || typid == CSTRINGOID)
1361 return TYPEFUNC_SCALAR;
1362 return TYPEFUNC_OTHER;
1363 }
1364 /* shouldn't get here, probably */
1365 return TYPEFUNC_OTHER;
1366}
1367
1368
1369/*
1370 * get_func_arg_info
1371 *
1372 * Fetch info about the argument types, names, and IN/OUT modes from the
1373 * pg_proc tuple. Return value is the total number of arguments.
1374 * Other results are palloc'd. *p_argtypes is always filled in, but
1375 * *p_argnames and *p_argmodes will be set NULL in the default cases
1376 * (no names, and all IN arguments, respectively).
1377 *
1378 * Note that this function simply fetches what is in the pg_proc tuple;
1379 * it doesn't do any interpretation of polymorphic types.
1380 */
1381int
1383 Oid **p_argtypes, char ***p_argnames, char **p_argmodes)
1384{
1389 bool isNull;
1390 ArrayType *arr;
1391 int numargs;
1392 Datum *elems;
1393 int nelems;
1394 int i;
1395
1396 /* First discover the total number of parameters and get their types */
1399 &isNull);
1400 if (!isNull)
1401 {
1402 /*
1403 * We expect the arrays to be 1-D arrays of the right types; verify
1404 * that. For the OID and char arrays, we don't need to use
1405 * deconstruct_array() since the array data is just going to look like
1406 * a C array of values.
1407 */
1408 arr = DatumGetArrayTypeP(proallargtypes); /* ensure not toasted */
1409 numargs = ARR_DIMS(arr)[0];
1410 if (ARR_NDIM(arr) != 1 ||
1411 numargs < 0 ||
1412 ARR_HASNULL(arr) ||
1413 ARR_ELEMTYPE(arr) != OIDOID)
1414 elog(ERROR, "proallargtypes is not a 1-D Oid array or it contains nulls");
1415 Assert(numargs >= procStruct->pronargs);
1416 *p_argtypes = (Oid *) palloc(numargs * sizeof(Oid));
1418 numargs * sizeof(Oid));
1419 }
1420 else
1421 {
1422 /* If no proallargtypes, use proargtypes */
1423 numargs = procStruct->proargtypes.dim1;
1424 Assert(numargs == procStruct->pronargs);
1425 *p_argtypes = (Oid *) palloc(numargs * sizeof(Oid));
1426 memcpy(*p_argtypes, procStruct->proargtypes.values,
1427 numargs * sizeof(Oid));
1428 }
1429
1430 /* Get argument names, if available */
1433 &isNull);
1434 if (isNull)
1435 *p_argnames = NULL;
1436 else
1437 {
1439 &elems, NULL, &nelems);
1440 if (nelems != numargs) /* should not happen */
1441 elog(ERROR, "proargnames must have the same number of elements as the function has arguments");
1442 *p_argnames = palloc_array(char *, numargs);
1443 for (i = 0; i < numargs; i++)
1444 (*p_argnames)[i] = TextDatumGetCString(elems[i]);
1445 }
1446
1447 /* Get argument modes, if available */
1450 &isNull);
1451 if (isNull)
1452 *p_argmodes = NULL;
1453 else
1454 {
1455 arr = DatumGetArrayTypeP(proargmodes); /* ensure not toasted */
1456 if (ARR_NDIM(arr) != 1 ||
1457 ARR_DIMS(arr)[0] != numargs ||
1458 ARR_HASNULL(arr) ||
1459 ARR_ELEMTYPE(arr) != CHAROID)
1460 elog(ERROR, "proargmodes is not a 1-D char array of length %d or it contains nulls",
1461 numargs);
1462 *p_argmodes = (char *) palloc(numargs * sizeof(char));
1464 numargs * sizeof(char));
1465 }
1466
1467 return numargs;
1468}
1469
1470/*
1471 * get_func_trftypes
1472 *
1473 * Returns the number of transformed types used by the function.
1474 * If there are any, a palloc'd array of the type OIDs is returned
1475 * into *p_trftypes.
1476 */
1477int
1479 Oid **p_trftypes)
1480{
1482 ArrayType *arr;
1483 int nelems;
1484 bool isNull;
1485
1488 &isNull);
1489 if (!isNull)
1490 {
1491 /*
1492 * We expect the arrays to be 1-D arrays of the right types; verify
1493 * that. For the OID and char arrays, we don't need to use
1494 * deconstruct_array() since the array data is just going to look like
1495 * a C array of values.
1496 */
1497 arr = DatumGetArrayTypeP(protrftypes); /* ensure not toasted */
1498 nelems = ARR_DIMS(arr)[0];
1499 if (ARR_NDIM(arr) != 1 ||
1500 nelems < 0 ||
1501 ARR_HASNULL(arr) ||
1502 ARR_ELEMTYPE(arr) != OIDOID)
1503 elog(ERROR, "protrftypes is not a 1-D Oid array or it contains nulls");
1504 *p_trftypes = (Oid *) palloc(nelems * sizeof(Oid));
1506 nelems * sizeof(Oid));
1507
1508 return nelems;
1509 }
1510 else
1511 return 0;
1512}
1513
1514/*
1515 * get_func_input_arg_names
1516 *
1517 * Extract the names of input arguments only, given a function's
1518 * proargnames and proargmodes entries in Datum form.
1519 *
1520 * Returns the number of input arguments, which is the length of the
1521 * palloc'd array returned to *arg_names. Entries for unnamed args
1522 * are set to NULL. You don't get anything if proargnames is NULL.
1523 */
1524int
1526 char ***arg_names)
1527{
1528 ArrayType *arr;
1529 int numargs;
1530 Datum *argnames;
1531 char *argmodes;
1532 char **inargnames;
1533 int numinargs;
1534 int i;
1535
1536 /* Do nothing if null proargnames */
1538 {
1539 *arg_names = NULL;
1540 return 0;
1541 }
1542
1543 /*
1544 * We expect the arrays to be 1-D arrays of the right types; verify that.
1545 * For proargmodes, we don't need to use deconstruct_array() since the
1546 * array data is just going to look like a C array of values.
1547 */
1548 arr = DatumGetArrayTypeP(proargnames); /* ensure not toasted */
1549 if (ARR_NDIM(arr) != 1 ||
1550 ARR_HASNULL(arr) ||
1551 ARR_ELEMTYPE(arr) != TEXTOID)
1552 elog(ERROR, "proargnames is not a 1-D text array or it contains nulls");
1553 deconstruct_array_builtin(arr, TEXTOID, &argnames, NULL, &numargs);
1555 {
1556 arr = DatumGetArrayTypeP(proargmodes); /* ensure not toasted */
1557 if (ARR_NDIM(arr) != 1 ||
1558 ARR_DIMS(arr)[0] != numargs ||
1559 ARR_HASNULL(arr) ||
1560 ARR_ELEMTYPE(arr) != CHAROID)
1561 elog(ERROR, "proargmodes is not a 1-D char array of length %d or it contains nulls",
1562 numargs);
1563 argmodes = (char *) ARR_DATA_PTR(arr);
1564 }
1565 else
1566 argmodes = NULL;
1567
1568 /* zero elements probably shouldn't happen, but handle it gracefully */
1569 if (numargs <= 0)
1570 {
1571 *arg_names = NULL;
1572 return 0;
1573 }
1574
1575 /* extract input-argument names */
1576 inargnames = (char **) palloc(numargs * sizeof(char *));
1577 numinargs = 0;
1578 for (i = 0; i < numargs; i++)
1579 {
1580 if (argmodes == NULL ||
1581 argmodes[i] == PROARGMODE_IN ||
1584 {
1585 char *pname = TextDatumGetCString(argnames[i]);
1586
1587 if (pname[0] != '\0')
1589 else
1591 numinargs++;
1592 }
1593 }
1594
1596 return numinargs;
1597}
1598
1599
1600/*
1601 * get_func_result_name
1602 *
1603 * If the function has exactly one output parameter, and that parameter
1604 * is named, return the name (as a palloc'd string). Else return NULL.
1605 *
1606 * This is used to determine the default output column name for functions
1607 * returning scalar types.
1608 */
1609char *
1611{
1612 char *result;
1616 ArrayType *arr;
1617 int numargs;
1618 char *argmodes;
1619 Datum *argnames;
1620 int numoutargs;
1621 int nargnames;
1622 int i;
1623
1624 /* First fetch the function's pg_proc row */
1627 elog(ERROR, "cache lookup failed for function %u", functionId);
1628
1629 /* If there are no named OUT parameters, return NULL */
1632 result = NULL;
1633 else
1634 {
1635 /* Get the data out of the tuple */
1640
1641 /*
1642 * We expect the arrays to be 1-D arrays of the right types; verify
1643 * that. For the char array, we don't need to use deconstruct_array()
1644 * since the array data is just going to look like a C array of
1645 * values.
1646 */
1647 arr = DatumGetArrayTypeP(proargmodes); /* ensure not toasted */
1648 numargs = ARR_DIMS(arr)[0];
1649 if (ARR_NDIM(arr) != 1 ||
1650 numargs < 0 ||
1651 ARR_HASNULL(arr) ||
1652 ARR_ELEMTYPE(arr) != CHAROID)
1653 elog(ERROR, "proargmodes is not a 1-D char array or it contains nulls");
1654 argmodes = (char *) ARR_DATA_PTR(arr);
1655 arr = DatumGetArrayTypeP(proargnames); /* ensure not toasted */
1656 if (ARR_NDIM(arr) != 1 ||
1657 ARR_DIMS(arr)[0] != numargs ||
1658 ARR_HASNULL(arr) ||
1659 ARR_ELEMTYPE(arr) != TEXTOID)
1660 elog(ERROR, "proargnames is not a 1-D text array of length %d or it contains nulls",
1661 numargs);
1662 deconstruct_array_builtin(arr, TEXTOID, &argnames, NULL, &nargnames);
1663 Assert(nargnames == numargs);
1664
1665 /* scan for output argument(s) */
1666 result = NULL;
1667 numoutargs = 0;
1668 for (i = 0; i < numargs; i++)
1669 {
1670 if (argmodes[i] == PROARGMODE_IN ||
1672 continue;
1676 if (++numoutargs > 1)
1677 {
1678 /* multiple out args, so forget it */
1679 result = NULL;
1680 break;
1681 }
1682 result = TextDatumGetCString(argnames[i]);
1683 if (result == NULL || result[0] == '\0')
1684 {
1685 /* Parameter is not named, so forget it */
1686 result = NULL;
1687 break;
1688 }
1689 }
1690 }
1691
1693
1694 return result;
1695}
1696
1697
1698/*
1699 * build_function_result_tupdesc_t
1700 *
1701 * Given a pg_proc row for a function, return a tuple descriptor for the
1702 * result rowtype, or NULL if the function does not have OUT parameters.
1703 *
1704 * Note that this does not handle resolution of polymorphic types;
1705 * that is deliberate.
1706 */
1709{
1714 bool isnull;
1715
1716 /* Return NULL if the function isn't declared to return RECORD */
1717 if (procform->prorettype != RECORDOID)
1718 return NULL;
1719
1720 /* If there are no OUT parameters, return NULL */
1723 return NULL;
1724
1725 /* Get the data out of the tuple */
1732 &isnull);
1733 if (isnull)
1734 proargnames = PointerGetDatum(NULL); /* just to be sure */
1735
1739 proargnames);
1740}
1741
1742/*
1743 * build_function_result_tupdesc_d
1744 *
1745 * Build a RECORD function's tupledesc from the pg_proc proallargtypes,
1746 * proargmodes, and proargnames arrays. This is split out for the
1747 * convenience of ProcedureCreate, which needs to be able to compute the
1748 * tupledesc before actually creating the function.
1749 *
1750 * For functions (but not for procedures), returns NULL if there are not at
1751 * least two OUT or INOUT arguments.
1752 */
1758{
1759 TupleDesc desc;
1760 ArrayType *arr;
1761 int numargs;
1762 Oid *argtypes;
1763 char *argmodes;
1764 Datum *argnames = NULL;
1766 char **outargnames;
1767 int numoutargs;
1768 int nargnames;
1769 int i;
1770
1771 /* Can't have output args if columns are null */
1774 return NULL;
1775
1776 /*
1777 * We expect the arrays to be 1-D arrays of the right types; verify that.
1778 * For the OID and char arrays, we don't need to use deconstruct_array()
1779 * since the array data is just going to look like a C array of values.
1780 */
1781 arr = DatumGetArrayTypeP(proallargtypes); /* ensure not toasted */
1782 numargs = ARR_DIMS(arr)[0];
1783 if (ARR_NDIM(arr) != 1 ||
1784 numargs < 0 ||
1785 ARR_HASNULL(arr) ||
1786 ARR_ELEMTYPE(arr) != OIDOID)
1787 elog(ERROR, "proallargtypes is not a 1-D Oid array or it contains nulls");
1788 argtypes = (Oid *) ARR_DATA_PTR(arr);
1789 arr = DatumGetArrayTypeP(proargmodes); /* ensure not toasted */
1790 if (ARR_NDIM(arr) != 1 ||
1791 ARR_DIMS(arr)[0] != numargs ||
1792 ARR_HASNULL(arr) ||
1793 ARR_ELEMTYPE(arr) != CHAROID)
1794 elog(ERROR, "proargmodes is not a 1-D char array of length %d or it contains nulls",
1795 numargs);
1796 argmodes = (char *) ARR_DATA_PTR(arr);
1798 {
1799 arr = DatumGetArrayTypeP(proargnames); /* ensure not toasted */
1800 if (ARR_NDIM(arr) != 1 ||
1801 ARR_DIMS(arr)[0] != numargs ||
1802 ARR_HASNULL(arr) ||
1803 ARR_ELEMTYPE(arr) != TEXTOID)
1804 elog(ERROR, "proargnames is not a 1-D text array of length %d or it contains nulls",
1805 numargs);
1806 deconstruct_array_builtin(arr, TEXTOID, &argnames, NULL, &nargnames);
1807 Assert(nargnames == numargs);
1808 }
1809
1810 /* zero elements probably shouldn't happen, but handle it gracefully */
1811 if (numargs <= 0)
1812 return NULL;
1813
1814 /* extract output-argument types and names */
1815 outargtypes = (Oid *) palloc(numargs * sizeof(Oid));
1816 outargnames = (char **) palloc(numargs * sizeof(char *));
1817 numoutargs = 0;
1818 for (i = 0; i < numargs; i++)
1819 {
1820 char *pname;
1821
1822 if (argmodes[i] == PROARGMODE_IN ||
1824 continue;
1828 outargtypes[numoutargs] = argtypes[i];
1829 if (argnames)
1830 pname = TextDatumGetCString(argnames[i]);
1831 else
1832 pname = NULL;
1833 if (pname == NULL || pname[0] == '\0')
1834 {
1835 /* Parameter is not named, so gin up a column name */
1836 pname = psprintf("column%d", numoutargs + 1);
1837 }
1839 numoutargs++;
1840 }
1841
1842 /*
1843 * If there is no output argument, or only one, the function does not
1844 * return tuples.
1845 */
1846 if (numoutargs < 2 && prokind != PROKIND_PROCEDURE)
1847 return NULL;
1848
1850 for (i = 0; i < numoutargs; i++)
1851 {
1852 TupleDescInitEntry(desc, i + 1,
1853 outargnames[i],
1854 outargtypes[i],
1855 -1,
1856 0);
1857 }
1858
1859 TupleDescFinalize(desc);
1860
1861 return desc;
1862}
1863
1864
1865/*
1866 * RelationNameGetTupleDesc
1867 *
1868 * Given a (possibly qualified) relation name, build a TupleDesc.
1869 *
1870 * Note: while this works as advertised, it's seldom the best way to
1871 * build a tupdesc for a function's result type. It's kept around
1872 * only for backwards compatibility with existing user-written code.
1873 */
1876{
1878 Relation rel;
1879 TupleDesc tupdesc;
1881
1882 /* Open relation and copy the tuple description */
1886 tupdesc = CreateTupleDescCopy(RelationGetDescr(rel));
1888
1889 return tupdesc;
1890}
1891
1892/*
1893 * TypeGetTupleDesc
1894 *
1895 * Given a type Oid, build a TupleDesc. (In most cases you should be
1896 * using get_call_result_type or one of its siblings instead of this
1897 * routine, so that you can handle OUT parameters, RECORD result type,
1898 * and polymorphic results.)
1899 *
1900 * If the type is composite, *and* a colaliases List is provided, *and*
1901 * the List is of natts length, use the aliases instead of the relation
1902 * attnames. (NB: this usage is deprecated since it may result in
1903 * creation of unnecessary transient record types.)
1904 *
1905 * If the type is a base type, a single item alias List is required.
1906 */
1909{
1912 TupleDesc tupdesc = NULL;
1913
1914 /*
1915 * Build a suitable tupledesc representing the output rows. We
1916 * intentionally do not support TYPEFUNC_COMPOSITE_DOMAIN here, as it's
1917 * unlikely that legacy callers of this obsolete function would be
1918 * prepared to apply domain constraints.
1919 */
1921 {
1922 /* Composite data type, e.g. a table's row type */
1924
1925 if (colaliases != NIL)
1926 {
1927 int natts = tupdesc->natts;
1928 int varattno;
1929
1930 /* does the list length match the number of attributes? */
1931 if (list_length(colaliases) != natts)
1932 ereport(ERROR,
1934 errmsg("number of aliases does not match number of columns")));
1935
1936 /* OK, use the aliases instead */
1937 for (varattno = 0; varattno < natts; varattno++)
1938 {
1939 char *label = strVal(list_nth(colaliases, varattno));
1940 Form_pg_attribute attr = TupleDescAttr(tupdesc, varattno);
1941
1942 if (label != NULL)
1943 namestrcpy(&(attr->attname), label);
1944 }
1945
1946 /* The tuple type is now an anonymous record type */
1947 tupdesc->tdtypeid = RECORDOID;
1948 tupdesc->tdtypmod = -1;
1949 }
1950 }
1951 else if (functypclass == TYPEFUNC_SCALAR)
1952 {
1953 /* Base data type, i.e. scalar */
1954 char *attname;
1955
1956 /* the alias list is required for base types */
1957 if (colaliases == NIL)
1958 ereport(ERROR,
1960 errmsg("no column alias was provided")));
1961
1962 /* the alias list length must be 1 */
1963 if (list_length(colaliases) != 1)
1964 ereport(ERROR,
1966 errmsg("number of aliases does not match number of columns")));
1967
1968 /* OK, get the column alias */
1970
1971 tupdesc = CreateTemplateTupleDesc(1);
1972 TupleDescInitEntry(tupdesc,
1973 (AttrNumber) 1,
1974 attname,
1975 typeoid,
1976 -1,
1977 0);
1978 TupleDescFinalize(tupdesc);
1979 }
1980 else if (functypclass == TYPEFUNC_RECORD)
1981 {
1982 /* XXX can't support this because typmod wasn't passed in ... */
1983 ereport(ERROR,
1985 errmsg("could not determine row description for function returning record")));
1986 }
1987 else
1988 {
1989 /* crummy error message, but parser should have caught this */
1990 elog(ERROR, "function in FROM has unsupported return type");
1991 }
1992
1993 return tupdesc;
1994}
1995
1996/*
1997 * extract_variadic_args
1998 *
1999 * Extract a set of argument values, types and NULL markers for a given
2000 * input function which makes use of a VARIADIC input whose argument list
2001 * depends on the caller context. When doing a VARIADIC call, the caller
2002 * has provided one argument made of an array of values, so deconstruct the
2003 * array data before using it for the next processing. If no VARIADIC call
2004 * is used, just fill in the status data based on all the arguments given
2005 * by the caller.
2006 *
2007 * This function returns the number of arguments generated, or -1 in the
2008 * case of "VARIADIC NULL".
2009 */
2010int
2012 bool convert_unknown, Datum **args, Oid **types,
2013 bool **nulls)
2014{
2015 bool variadic = get_fn_expr_variadic(fcinfo->flinfo);
2016 Datum *args_res;
2017 bool *nulls_res;
2018 Oid *types_res;
2019 int nargs,
2020 i;
2021
2022 *args = NULL;
2023 *types = NULL;
2024 *nulls = NULL;
2025
2026 if (variadic)
2027 {
2029 Oid element_type;
2030 bool typbyval;
2031 char typalign;
2032 int16 typlen;
2033
2034 Assert(PG_NARGS() == variadic_start + 1);
2035
2037 return -1;
2038
2040 element_type = ARR_ELEMTYPE(array_in);
2041
2042 get_typlenbyvalalign(element_type,
2043 &typlen, &typbyval, &typalign);
2044 deconstruct_array(array_in, element_type, typlen, typbyval,
2046 &nargs);
2047
2048 /* All the elements of the array have the same type */
2049 types_res = (Oid *) palloc0(nargs * sizeof(Oid));
2050 for (i = 0; i < nargs; i++)
2051 types_res[i] = element_type;
2052 }
2053 else
2054 {
2055 nargs = PG_NARGS() - variadic_start;
2056 Assert(nargs > 0);
2057 nulls_res = (bool *) palloc0(nargs * sizeof(bool));
2058 args_res = (Datum *) palloc0(nargs * sizeof(Datum));
2059 types_res = (Oid *) palloc0(nargs * sizeof(Oid));
2060
2061 for (i = 0; i < nargs; i++)
2062 {
2065 i + variadic_start);
2066
2067 /*
2068 * Turn a constant (more or less literal) value that's of unknown
2069 * type into text if required. Unknowns come in as a cstring
2070 * pointer. Note: for functions declared as taking type "any", the
2071 * parser will not do any type conversion on unknown-type literals
2072 * (that is, undecorated strings or NULLs).
2073 */
2074 if (convert_unknown &&
2075 types_res[i] == UNKNOWNOID &&
2077 {
2078 types_res[i] = TEXTOID;
2079
2081 args_res[i] = (Datum) 0;
2082 else
2083 args_res[i] =
2085 }
2086 else
2087 {
2088 /* no conversion needed, just take the datum as given */
2090 }
2091
2092 if (!OidIsValid(types_res[i]) ||
2094 ereport(ERROR,
2096 errmsg("could not determine data type for argument %d",
2097 i + 1)));
2098 }
2099 }
2100
2101 /* Fill in results */
2102 *args = args_res;
2103 *nulls = nulls_res;
2104 *types = types_res;
2105
2106 return nargs;
2107}
#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
Datum array_in(PG_FUNCTION_ARGS)
Definition arrayfuncs.c:181
void deconstruct_array_builtin(const ArrayType *array, Oid elmtype, Datum **elemsp, bool **nullsp, int *nelemsp)
void deconstruct_array(const ArrayType *array, Oid elmtype, int elmlen, bool elmbyval, char elmalign, Datum **elemsp, bool **nullsp, int *nelemsp)
int16 AttrNumber
Definition attnum.h:21
#define CStringGetTextDatum(s)
Definition builtins.h:98
#define TextDatumGetCString(d)
Definition builtins.h:99
#define NameStr(name)
Definition c.h:837
#define Assert(condition)
Definition c.h:945
int16_t int16
Definition c.h:613
uint32 bits32
Definition c.h:627
int32_t int32
Definition c.h:614
#define OidIsValid(objectId)
Definition c.h:860
struct typedefs * types
Definition ecpg.c:30
Datum arg
Definition elog.c:1322
int errcode(int sqlerrcode)
Definition elog.c:874
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
#define ereport(elevel,...)
Definition elog.h:150
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
void UnregisterExprContextCallback(ExprContext *econtext, ExprContextCallbackFunction function, Datum arg)
Definition execUtils.c:994
void RegisterExprContextCallback(ExprContext *econtext, ExprContextCallbackFunction function, Datum arg)
Definition execUtils.c:968
@ SFRM_Materialize_Random
Definition execnodes.h:353
@ SFRM_Materialize
Definition execnodes.h:352
#define palloc_array(type, count)
Definition fe_memutils.h:76
bool get_fn_expr_arg_stable(FmgrInfo *flinfo, int argnum)
Definition fmgr.c:1941
bool get_fn_expr_variadic(FmgrInfo *flinfo)
Definition fmgr.c:2010
Oid get_call_expr_argtype(Node *expr, int argnum)
Definition fmgr.c:1895
Oid get_fn_expr_argtype(FmgrInfo *flinfo, int argnum)
Definition fmgr.c:1876
#define DatumGetHeapTupleHeader(X)
Definition fmgr.h:296
#define PG_GETARG_POINTER(n)
Definition fmgr.h:277
#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)
static TypeFuncClass get_type_func_class(Oid typid, Oid *base_typeid)
Definition funcapi.c:1331
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:432
int get_func_trftypes(HeapTuple procTup, Oid **p_trftypes)
Definition funcapi.c:1478
TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple)
Definition funcapi.c:1708
char * get_func_result_name(Oid functionId)
Definition funcapi.c:1610
TupleDesc build_function_result_tupdesc_d(char prokind, Datum proallargtypes, Datum proargmodes, Datum proargnames)
Definition funcapi.c:1754
bool resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes, Node *call_expr)
Definition funcapi.c:1067
void end_MultiFuncCall(PG_FUNCTION_ARGS, FuncCallContext *funcctx)
Definition funcapi.c:220
static void resolve_anyelement_from_others(polymorphic_actuals *actuals)
Definition funcapi.c:591
int get_func_input_arg_names(Datum proargnames, Datum proargmodes, char ***arg_names)
Definition funcapi.c:1525
int get_func_arg_info(HeapTuple procTup, Oid **p_argtypes, char ***p_argnames, char **p_argmodes)
Definition funcapi.c:1382
static bool resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args, Node *call_expr)
Definition funcapi.c:746
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:1875
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:2011
static void resolve_anyrange_from_others(polymorphic_actuals *actuals)
Definition funcapi.c:683
static void shutdown_MultiFuncCall(Datum arg)
Definition funcapi.c:238
TupleDesc get_expr_result_tupdesc(Node *expr, bool noError)
Definition funcapi.c:553
static void resolve_anymultirange_from_others(polymorphic_actuals *actuals)
Definition funcapi.c:712
TupleDesc TypeGetTupleDesc(Oid typeoid, List *colaliases)
Definition funcapi.c:1908
TypeFuncClass get_func_result_type(Oid functionId, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition funcapi.c:412
static void resolve_anyarray_from_others(polymorphic_actuals *actuals)
Definition funcapi.c:657
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:131
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)
static void * GETSTRUCT(const HeapTupleData *tuple)
static Oid HeapTupleHeaderGetTypeId(const HeapTupleHeaderData *tup)
int i
Definition isn.c:77
#define AccessShareLock
Definition lockdefs.h:36
Oid get_range_subtype(Oid rangeOid)
Definition lsyscache.c:3629
Oid get_element_type(Oid typid)
Definition lsyscache.c:2981
Oid get_multirange_range(Oid multirangeOid)
Definition lsyscache.c:3705
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition lsyscache.c:2491
RegProcedure get_opcode(Oid opno)
Definition lsyscache.c:1505
Oid get_typcollation(Oid typid)
Definition lsyscache.c:3278
Oid get_range_multirange(Oid rangeOid)
Definition lsyscache.c:3680
char get_typtype(Oid typid)
Definition lsyscache.c:2851
Oid getBaseType(Oid typid)
Definition lsyscache.c:2743
Oid get_array_type(Oid typid)
Definition lsyscache.c:3009
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition mcxt.c:1266
void * palloc0(Size size)
Definition mcxt.c:1417
void * palloc(Size size)
Definition mcxt.c:1387
void MemoryContextDelete(MemoryContext context)
Definition mcxt.c:472
#define AllocSetContextCreate
Definition memutils.h:129
#define ALLOCSET_SMALL_SIZES
Definition memutils.h:170
void namestrcpy(Name name, const char *str)
Definition name.c:233
RangeVar * makeRangeVarFromNameList(const List *names)
Definition namespace.c:3626
Oid exprType(const Node *expr)
Definition nodeFuncs.c:42
Oid exprInputCollation(const Node *expr)
Definition nodeFuncs.c:1084
int32 exprTypmod(const Node *expr)
Definition nodeFuncs.c:304
Oid exprCollation(const Node *expr)
Definition nodeFuncs.c:826
#define IsA(nodeptr, _type_)
Definition nodes.h:164
static char * errmsg
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:124
NameData attname
FormData_pg_attribute * Form_pg_attribute
static char * label
NameData relname
Definition pg_class.h:40
#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
END_CATALOG_STRUCT typedef FormData_pg_proc * Form_pg_proc
Definition pg_proc.h:140
char typalign
Definition pg_type.h:178
static Datum PointerGetDatum(const void *X)
Definition postgres.h:342
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:252
uint64_t Datum
Definition postgres.h:70
static Pointer DatumGetPointer(Datum X)
Definition postgres.h:332
#define InvalidOid
unsigned int Oid
static int fb(int x)
char * psprintf(const char *fmt,...)
Definition psprintf.c:43
List * stringToQualifiedNameList(const char *string, Node *escontext)
Definition regproc.c:1922
#define RelationGetDescr(relation)
Definition rel.h:540
void relation_close(Relation relation, LOCKMODE lockmode)
Definition relation.c:205
Relation relation_openrv(const RangeVar *relation, LOCKMODE lockmode)
Definition relation.c:137
void * fn_extra
Definition fmgr.h:64
Node * 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
FmgrInfo * flinfo
Definition fmgr.h:87
Definition pg_list.h:54
Definition nodes.h:135
ExprContext * econtext
Definition execnodes.h:367
List * args
Definition primnodes.h:1449
int32 tdtypmod
Definition tupdesc.h:152
Definition c.h:817
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:264
Datum SysCacheGetAttrNotNull(SysCacheIdentifier cacheId, HeapTuple tup, AttrNumber attributeNumber)
Definition syscache.c:625
HeapTuple SearchSysCache1(SysCacheIdentifier cacheId, Datum key1)
Definition syscache.c:220
Datum SysCacheGetAttr(SysCacheIdentifier cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition syscache.c:595
TupleDesc CreateTemplateTupleDesc(int natts)
Definition tupdesc.c:165
void TupleDescFinalize(TupleDesc tupdesc)
Definition tupdesc.c:508
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition tupdesc.c:242
void TupleDescInitEntryCollation(TupleDesc desc, AttrNumber attributeNumber, Oid collationid)
Definition tupdesc.c:1081
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition tupdesc.c:897
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition tupdesc.h:178
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition tuplestore.c:331
void assign_record_type_typmod(TupleDesc tupDesc)
Definition typcache.c:2067
TupleDesc lookup_rowtype_tupdesc_copy(Oid type_id, int32 typmod)
Definition typcache.c:1981
#define strVal(v)
Definition value.h:82