Fix a compiler warning in initStringInfo().
[pgsql.git] / src / backend / utils / fmgr / funcapi.c
blob5f2317211c9d4357b4e708bf604ebfade99ab682
1 /*-------------------------------------------------------------------------
3 * funcapi.c
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
9 * IDENTIFICATION
10 * src/backend/utils/fmgr/funcapi.c
12 *-------------------------------------------------------------------------
14 #include "postgres.h"
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"
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,
45 Node *call_expr,
46 ReturnSetInfo *rsinfo,
47 Oid *resultTypeId,
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,
55 Node *call_expr);
56 static TypeFuncClass get_type_func_class(Oid typid, Oid *base_typeid);
60 * InitMaterializedSRF
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
73 * RECORD datatype.
75 void
76 InitMaterializedSRF(FunctionCallInfo fcinfo, bits32 flags)
78 bool random_access;
79 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
80 Tuplestorestate *tupstore;
81 MemoryContext old_context,
82 per_query_ctx;
83 TupleDesc stored_tupdesc;
85 /* check to see if caller supports returning a tuplestore */
86 if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
87 ereport(ERROR,
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))
92 ereport(ERROR,
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);
106 else
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);
127 * init_MultiFuncCall
128 * Create an empty FuncCallContext data structure
129 * and do some other basic Multi-function call setup
130 * and error checking
132 FuncCallContext *
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))
141 ereport(ERROR,
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)
148 * First call
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
184 * to completion.
186 RegisterExprContextCallback(rsi->econtext,
187 shutdown_MultiFuncCall,
188 PointerGetDatum(fcinfo->flinfo));
190 else
192 /* second and subsequent calls */
193 elog(ERROR, "init_MultiFuncCall cannot be called more than once");
195 /* never reached, but keep compiler happy */
196 retval = NULL;
199 return retval;
203 * per_MultiFuncCall
205 * Do Multi-function per-call setup
207 FuncCallContext *
208 per_MultiFuncCall(PG_FUNCTION_ARGS)
210 FuncCallContext *retval = (FuncCallContext *) fcinfo->flinfo->fn_extra;
212 return retval;
216 * end_MultiFuncCall
217 * Clean up after init_MultiFuncCall
219 void
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
237 static void
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.
275 TypeFuncClass
276 get_call_result_type(FunctionCallInfo fcinfo,
277 Oid *resultTypeId,
278 TupleDesc *resultTupleDesc)
280 return internal_get_result_type(fcinfo->flinfo->fn_oid,
281 fcinfo->flinfo->fn_expr,
282 (ReturnSetInfo *) fcinfo->resultinfo,
283 resultTypeId,
284 resultTupleDesc);
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.
298 TypeFuncClass
299 get_expr_result_type(Node *expr,
300 Oid *resultTypeId,
301 TupleDesc *resultTupleDesc)
303 TypeFuncClass result;
305 if (expr && IsA(expr, FuncExpr))
306 result = internal_get_result_type(((FuncExpr *) expr)->funcid,
307 expr,
308 NULL,
309 resultTypeId,
310 resultTupleDesc);
311 else if (expr && IsA(expr, OpExpr))
312 result = internal_get_result_type(get_opcode(((OpExpr *) expr)->opno),
313 expr,
314 NULL,
315 resultTypeId,
316 resultTupleDesc);
317 else if (expr && IsA(expr, RowExpr) &&
318 ((RowExpr *) expr)->row_typeid == RECORDOID)
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;
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,
335 colname,
336 exprType(col),
337 exprTypmod(col),
339 TupleDescInitEntryCollation(tupdesc, i,
340 exprCollation(col));
341 i++;
343 if (resultTypeId)
344 *resultTypeId = rexpr->row_typeid;
345 if (resultTupleDesc)
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.
358 HeapTupleHeader rec;
359 Oid tupType;
360 int32 tupTypmod;
362 rec = DatumGetHeapTupleHeader(((Const *) expr)->constvalue);
363 tupType = HeapTupleHeaderGetTypeId(rec);
364 tupTypmod = HeapTupleHeaderGetTypMod(rec);
365 if (resultTypeId)
366 *resultTypeId = tupType;
367 if (tupType != RECORDOID || tupTypmod >= 0)
369 /* Should be able to look it up */
370 if (resultTupleDesc)
371 *resultTupleDesc = lookup_rowtype_tupdesc_copy(tupType,
372 tupTypmod);
373 return TYPEFUNC_COMPOSITE;
375 else
377 /* This shouldn't really happen ... */
378 if (resultTupleDesc)
379 *resultTupleDesc = NULL;
380 return TYPEFUNC_RECORD;
383 else
385 /* handle as a generic expression; no chance to resolve RECORD */
386 Oid typid = exprType(expr);
387 Oid base_typid;
389 if (resultTypeId)
390 *resultTypeId = typid;
391 if (resultTupleDesc)
392 *resultTupleDesc = NULL;
393 result = get_type_func_class(typid, &base_typid);
394 if ((result == TYPEFUNC_COMPOSITE ||
395 result == TYPEFUNC_COMPOSITE_DOMAIN) &&
396 resultTupleDesc)
397 *resultTupleDesc = lookup_rowtype_tupdesc_copy(base_typid, -1);
400 return result;
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.
409 TypeFuncClass
410 get_func_result_type(Oid functionId,
411 Oid *resultTypeId,
412 TupleDesc *resultTupleDesc)
414 return internal_get_result_type(functionId,
415 NULL,
416 NULL,
417 resultTypeId,
418 resultTupleDesc);
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.
429 static TypeFuncClass
430 internal_get_result_type(Oid funcid,
431 Node *call_expr,
432 ReturnSetInfo *rsinfo,
433 Oid *resultTypeId,
434 TupleDesc *resultTupleDesc)
436 TypeFuncClass result;
437 HeapTuple tp;
438 Form_pg_proc procform;
439 Oid rettype;
440 Oid base_rettype;
441 TupleDesc tupdesc;
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);
453 if (tupdesc)
456 * It has OUT parameters, so it's basically like a regular composite
457 * type, except we have to be able to resolve any polymorphic OUT
458 * parameters.
460 if (resultTypeId)
461 *resultTypeId = rettype;
463 if (resolve_polymorphic_tupdesc(tupdesc,
464 &procform->proargtypes,
465 call_expr))
467 if (tupdesc->tdtypeid == RECORDOID &&
468 tupdesc->tdtypmod < 0)
469 assign_record_type_typmod(tupdesc);
470 if (resultTupleDesc)
471 *resultTupleDesc = tupdesc;
472 result = TYPEFUNC_COMPOSITE;
474 else
476 if (resultTupleDesc)
477 *resultTupleDesc = NULL;
478 result = TYPEFUNC_RECORD;
481 ReleaseSysCache(tp);
483 return result;
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 */
494 ereport(ERROR,
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;
502 if (resultTypeId)
503 *resultTypeId = rettype;
504 if (resultTupleDesc)
505 *resultTupleDesc = NULL; /* default result */
507 /* Classify the result type */
508 result = get_type_func_class(rettype, &base_rettype);
509 switch (result)
511 case TYPEFUNC_COMPOSITE:
512 case TYPEFUNC_COMPOSITE_DOMAIN:
513 if (resultTupleDesc)
514 *resultTupleDesc = lookup_rowtype_tupdesc_copy(base_rettype, -1);
515 /* Named composite types can't have any polymorphic columns */
516 break;
517 case TYPEFUNC_SCALAR:
518 break;
519 case TYPEFUNC_RECORD:
520 /* We must get the tupledesc from call context */
521 if (rsinfo && IsA(rsinfo, ReturnSetInfo) &&
522 rsinfo->expectedDesc != NULL)
524 result = TYPEFUNC_COMPOSITE;
525 if (resultTupleDesc)
526 *resultTupleDesc = rsinfo->expectedDesc;
527 /* Assume no polymorphic columns here, either */
529 break;
530 default:
531 break;
534 ReleaseSysCache(tp);
536 return result;
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.
550 TupleDesc
551 get_expr_result_tupdesc(Node *expr, bool noError)
553 TupleDesc tupleDesc;
554 TypeFuncClass functypclass;
556 functypclass = get_expr_result_type(expr, NULL, &tupleDesc);
558 if (functypclass == TYPEFUNC_COMPOSITE ||
559 functypclass == TYPEFUNC_COMPOSITE_DOMAIN)
560 return tupleDesc;
562 if (!noError)
564 Oid exprTypeId = exprType(expr);
566 if (exprTypeId != RECORDOID)
567 ereport(ERROR,
568 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
569 errmsg("type %s is not composite",
570 format_type_be(exprTypeId))));
571 else
572 ereport(ERROR,
573 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
574 errmsg("record type has not been registered")));
577 return NULL;
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.
588 static void
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))
598 ereport(ERROR,
599 (errcode(ERRCODE_DATATYPE_MISMATCH),
600 errmsg("argument declared %s is not an array but type %s",
601 "anyarray",
602 format_type_be(array_base_type))));
603 actuals->anyelement_type = array_typelem;
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))
612 ereport(ERROR,
613 (errcode(ERRCODE_DATATYPE_MISMATCH),
614 errmsg("argument declared %s is not a range type but type %s",
615 "anyrange",
616 format_type_be(range_base_type))));
617 actuals->anyelement_type = range_typelem;
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;
624 Oid range_base_type;
625 Oid range_typelem;
627 multirange_base_type = getBaseType(actuals->anymultirange_type);
628 multirange_typelem = get_multirange_range(multirange_base_type);
629 if (!OidIsValid(multirange_typelem))
630 ereport(ERROR,
631 (errcode(ERRCODE_DATATYPE_MISMATCH),
632 errmsg("argument declared %s is not a multirange type but type %s",
633 "anymultirange",
634 format_type_be(multirange_base_type))));
636 range_base_type = getBaseType(multirange_typelem);
637 range_typelem = get_range_subtype(range_base_type);
639 if (!OidIsValid(range_typelem))
640 ereport(ERROR,
641 (errcode(ERRCODE_DATATYPE_MISMATCH),
642 errmsg("argument declared %s does not contain a range type but type %s",
643 "anymultirange",
644 format_type_be(range_base_type))));
645 actuals->anyelement_type = range_typelem;
647 else
648 elog(ERROR, "could not determine polymorphic type");
652 * Resolve actual type of ANYARRAY from other polymorphic inputs
654 static void
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))
667 ereport(ERROR,
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;
673 else
674 elog(ERROR, "could not determine polymorphic type");
678 * Resolve actual type of ANYRANGE from other polymorphic inputs
680 static void
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))
695 ereport(ERROR,
696 (errcode(ERRCODE_DATATYPE_MISMATCH),
697 errmsg("argument declared %s is not a multirange type but type %s",
698 "anymultirange",
699 format_type_be(multirange_base_type))));
700 actuals->anyrange_type = multirange_typelem;
702 else
703 elog(ERROR, "could not determine polymorphic type");
707 * Resolve actual type of ANYMULTIRANGE from other polymorphic inputs
709 static void
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))
723 ereport(ERROR,
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;
729 else
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).
743 static bool
744 resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
745 Node *call_expr)
747 int natts = tupdesc->natts;
748 int nargs = declared_args->dim1;
749 bool have_polymorphic_result = false;
750 bool have_anyelement_result = false;
751 bool have_anyarray_result = false;
752 bool have_anyrange_result = false;
753 bool have_anymultirange_result = false;
754 bool have_anycompatible_result = false;
755 bool have_anycompatible_array_result = false;
756 bool have_anycompatible_range_result = false;
757 bool have_anycompatible_multirange_result = false;
758 polymorphic_actuals poly_actuals;
759 polymorphic_actuals anyc_actuals;
760 Oid anycollation = InvalidOid;
761 Oid anycompatcollation = InvalidOid;
762 int i;
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)
769 case ANYELEMENTOID:
770 case ANYNONARRAYOID:
771 case ANYENUMOID:
772 have_polymorphic_result = true;
773 have_anyelement_result = true;
774 break;
775 case ANYARRAYOID:
776 have_polymorphic_result = true;
777 have_anyarray_result = true;
778 break;
779 case ANYRANGEOID:
780 have_polymorphic_result = true;
781 have_anyrange_result = true;
782 break;
783 case ANYMULTIRANGEOID:
784 have_polymorphic_result = true;
785 have_anymultirange_result = true;
786 break;
787 case ANYCOMPATIBLEOID:
788 case ANYCOMPATIBLENONARRAYOID:
789 have_polymorphic_result = true;
790 have_anycompatible_result = true;
791 break;
792 case ANYCOMPATIBLEARRAYOID:
793 have_polymorphic_result = true;
794 have_anycompatible_array_result = true;
795 break;
796 case ANYCOMPATIBLERANGEOID:
797 have_polymorphic_result = true;
798 have_anycompatible_range_result = true;
799 break;
800 case ANYCOMPATIBLEMULTIRANGEOID:
801 have_polymorphic_result = true;
802 have_anycompatible_multirange_result = true;
803 break;
804 default:
805 break;
808 if (!have_polymorphic_result)
809 return true;
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.)
818 if (!call_expr)
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])
828 case ANYELEMENTOID:
829 case ANYNONARRAYOID:
830 case ANYENUMOID:
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))
836 return false;
838 break;
839 case ANYARRAYOID:
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))
845 return false;
847 break;
848 case ANYRANGEOID:
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))
854 return false;
856 break;
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))
863 return false;
865 break;
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))
873 return false;
875 break;
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))
882 return false;
884 break;
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))
891 return false;
893 break;
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))
900 return false;
902 break;
903 default:
904 break;
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
938 * considered here.
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
955 * for the function.
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)
975 case ANYELEMENTOID:
976 case ANYNONARRAYOID:
977 case ANYENUMOID:
978 TupleDescInitEntry(tupdesc, i + 1,
979 NameStr(att->attname),
980 poly_actuals.anyelement_type,
983 TupleDescInitEntryCollation(tupdesc, i + 1, anycollation);
984 break;
985 case ANYARRAYOID:
986 TupleDescInitEntry(tupdesc, i + 1,
987 NameStr(att->attname),
988 poly_actuals.anyarray_type,
991 TupleDescInitEntryCollation(tupdesc, i + 1, anycollation);
992 break;
993 case ANYRANGEOID:
994 TupleDescInitEntry(tupdesc, i + 1,
995 NameStr(att->attname),
996 poly_actuals.anyrange_type,
999 /* no collation should be attached to a range type */
1000 break;
1001 case ANYMULTIRANGEOID:
1002 TupleDescInitEntry(tupdesc, i + 1,
1003 NameStr(att->attname),
1004 poly_actuals.anymultirange_type,
1007 /* no collation should be attached to a multirange type */
1008 break;
1009 case ANYCOMPATIBLEOID:
1010 case ANYCOMPATIBLENONARRAYOID:
1011 TupleDescInitEntry(tupdesc, i + 1,
1012 NameStr(att->attname),
1013 anyc_actuals.anyelement_type,
1016 TupleDescInitEntryCollation(tupdesc, i + 1, anycompatcollation);
1017 break;
1018 case ANYCOMPATIBLEARRAYOID:
1019 TupleDescInitEntry(tupdesc, i + 1,
1020 NameStr(att->attname),
1021 anyc_actuals.anyarray_type,
1024 TupleDescInitEntryCollation(tupdesc, i + 1, anycompatcollation);
1025 break;
1026 case ANYCOMPATIBLERANGEOID:
1027 TupleDescInitEntry(tupdesc, i + 1,
1028 NameStr(att->attname),
1029 anyc_actuals.anyrange_type,
1032 /* no collation should be attached to a range type */
1033 break;
1034 case ANYCOMPATIBLEMULTIRANGEOID:
1035 TupleDescInitEntry(tupdesc, i + 1,
1036 NameStr(att->attname),
1037 anyc_actuals.anymultirange_type,
1040 /* no collation should be attached to a multirange type */
1041 break;
1042 default:
1043 break;
1047 return true;
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.
1063 bool
1064 resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes,
1065 Node *call_expr)
1067 bool have_polymorphic_result = false;
1068 bool have_anyelement_result = false;
1069 bool have_anyarray_result = false;
1070 bool have_anyrange_result = false;
1071 bool have_anymultirange_result = false;
1072 bool have_anycompatible_result = false;
1073 bool have_anycompatible_array_result = false;
1074 bool have_anycompatible_range_result = false;
1075 bool have_anycompatible_multirange_result = false;
1076 polymorphic_actuals poly_actuals;
1077 polymorphic_actuals anyc_actuals;
1078 int inargno;
1079 int i;
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));
1088 inargno = 0;
1089 for (i = 0; i < numargs; i++)
1091 char argmode = argmodes ? argmodes[i] : PROARGMODE_IN;
1093 switch (argtypes[i])
1095 case ANYELEMENTOID:
1096 case ANYNONARRAYOID:
1097 case ANYENUMOID:
1098 if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
1100 have_polymorphic_result = true;
1101 have_anyelement_result = true;
1103 else
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))
1110 return false;
1112 argtypes[i] = poly_actuals.anyelement_type;
1114 break;
1115 case ANYARRAYOID:
1116 if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
1118 have_polymorphic_result = true;
1119 have_anyarray_result = true;
1121 else
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))
1128 return false;
1130 argtypes[i] = poly_actuals.anyarray_type;
1132 break;
1133 case ANYRANGEOID:
1134 if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
1136 have_polymorphic_result = true;
1137 have_anyrange_result = true;
1139 else
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))
1146 return false;
1148 argtypes[i] = poly_actuals.anyrange_type;
1150 break;
1151 case ANYMULTIRANGEOID:
1152 if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
1154 have_polymorphic_result = true;
1155 have_anymultirange_result = true;
1157 else
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))
1164 return false;
1166 argtypes[i] = poly_actuals.anymultirange_type;
1168 break;
1169 case ANYCOMPATIBLEOID:
1170 case ANYCOMPATIBLENONARRAYOID:
1171 if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
1173 have_polymorphic_result = true;
1174 have_anycompatible_result = true;
1176 else
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))
1183 return false;
1185 argtypes[i] = anyc_actuals.anyelement_type;
1187 break;
1188 case ANYCOMPATIBLEARRAYOID:
1189 if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
1191 have_polymorphic_result = true;
1192 have_anycompatible_array_result = true;
1194 else
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))
1201 return false;
1203 argtypes[i] = anyc_actuals.anyarray_type;
1205 break;
1206 case ANYCOMPATIBLERANGEOID:
1207 if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
1209 have_polymorphic_result = true;
1210 have_anycompatible_range_result = true;
1212 else
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))
1219 return false;
1221 argtypes[i] = anyc_actuals.anyrange_type;
1223 break;
1224 case ANYCOMPATIBLEMULTIRANGEOID:
1225 if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
1227 have_polymorphic_result = true;
1228 have_anycompatible_multirange_result = true;
1230 else
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))
1237 return false;
1239 argtypes[i] = anyc_actuals.anymultirange_type;
1241 break;
1242 default:
1243 break;
1245 if (argmode != PROARGMODE_OUT && argmode != PROARGMODE_TABLE)
1246 inargno++;
1249 /* Done? */
1250 if (!have_polymorphic_result)
1251 return true;
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])
1283 case ANYELEMENTOID:
1284 case ANYNONARRAYOID:
1285 case ANYENUMOID:
1286 argtypes[i] = poly_actuals.anyelement_type;
1287 break;
1288 case ANYARRAYOID:
1289 argtypes[i] = poly_actuals.anyarray_type;
1290 break;
1291 case ANYRANGEOID:
1292 argtypes[i] = poly_actuals.anyrange_type;
1293 break;
1294 case ANYMULTIRANGEOID:
1295 argtypes[i] = poly_actuals.anymultirange_type;
1296 break;
1297 case ANYCOMPATIBLEOID:
1298 case ANYCOMPATIBLENONARRAYOID:
1299 argtypes[i] = anyc_actuals.anyelement_type;
1300 break;
1301 case ANYCOMPATIBLEARRAYOID:
1302 argtypes[i] = anyc_actuals.anyarray_type;
1303 break;
1304 case ANYCOMPATIBLERANGEOID:
1305 argtypes[i] = anyc_actuals.anyrange_type;
1306 break;
1307 case ANYCOMPATIBLEMULTIRANGEOID:
1308 argtypes[i] = anyc_actuals.anymultirange_type;
1309 break;
1310 default:
1311 break;
1315 return true;
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;
1336 case TYPTYPE_BASE:
1337 case TYPTYPE_ENUM:
1338 case TYPTYPE_RANGE:
1339 case TYPTYPE_MULTIRANGE:
1340 return TYPEFUNC_SCALAR;
1341 case TYPTYPE_DOMAIN:
1342 *base_typeid = typid = getBaseType(typid);
1343 if (get_typtype(typid) == TYPTYPE_COMPOSITE)
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;
1367 * get_func_arg_info
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;
1384 Datum proargmodes;
1385 Datum proargnames;
1386 bool isNull;
1387 ArrayType *arr;
1388 int numargs;
1389 Datum *elems;
1390 int nelems;
1391 int i;
1393 /* First discover the total number of parameters and get their types */
1394 proallargtypes = SysCacheGetAttr(PROCOID, procTup,
1395 Anum_pg_proc_proallargtypes,
1396 &isNull);
1397 if (!isNull)
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 ||
1408 numargs < 0 ||
1409 ARR_HASNULL(arr) ||
1410 ARR_ELEMTYPE(arr) != OIDOID)
1411 elog(ERROR, "proallargtypes is not a 1-D Oid array or it contains nulls");
1412 Assert(numargs >= procStruct->pronargs);
1413 *p_argtypes = (Oid *) palloc(numargs * sizeof(Oid));
1414 memcpy(*p_argtypes, ARR_DATA_PTR(arr),
1415 numargs * sizeof(Oid));
1417 else
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,
1430 &isNull);
1431 if (isNull)
1432 *p_argnames = NULL;
1433 else
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,
1447 &isNull);
1448 if (isNull)
1449 *p_argmodes = NULL;
1450 else
1452 arr = DatumGetArrayTypeP(proargmodes); /* ensure not toasted */
1453 if (ARR_NDIM(arr) != 1 ||
1454 ARR_DIMS(arr)[0] != numargs ||
1455 ARR_HASNULL(arr) ||
1456 ARR_ELEMTYPE(arr) != CHAROID)
1457 elog(ERROR, "proargmodes is not a 1-D char array of length %d or it contains nulls",
1458 numargs);
1459 *p_argmodes = (char *) palloc(numargs * sizeof(char));
1460 memcpy(*p_argmodes, ARR_DATA_PTR(arr),
1461 numargs * sizeof(char));
1464 return numargs;
1468 * get_func_trftypes
1470 * Returns the number of transformed types used by the function.
1471 * If there are any, a palloc'd array of the type OIDs is returned
1472 * into *p_trftypes.
1475 get_func_trftypes(HeapTuple procTup,
1476 Oid **p_trftypes)
1478 Datum protrftypes;
1479 ArrayType *arr;
1480 int nelems;
1481 bool isNull;
1483 protrftypes = SysCacheGetAttr(PROCOID, procTup,
1484 Anum_pg_proc_protrftypes,
1485 &isNull);
1486 if (!isNull)
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 ||
1497 nelems < 0 ||
1498 ARR_HASNULL(arr) ||
1499 ARR_ELEMTYPE(arr) != OIDOID)
1500 elog(ERROR, "protrftypes is not a 1-D Oid array or it contains nulls");
1501 *p_trftypes = (Oid *) palloc(nelems * sizeof(Oid));
1502 memcpy(*p_trftypes, ARR_DATA_PTR(arr),
1503 nelems * sizeof(Oid));
1505 return nelems;
1507 else
1508 return 0;
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,
1523 char ***arg_names)
1525 ArrayType *arr;
1526 int numargs;
1527 Datum *argnames;
1528 char *argmodes;
1529 char **inargnames;
1530 int numinargs;
1531 int i;
1533 /* Do nothing if null proargnames */
1534 if (proargnames == PointerGetDatum(NULL))
1536 *arg_names = NULL;
1537 return 0;
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 ||
1547 ARR_HASNULL(arr) ||
1548 ARR_ELEMTYPE(arr) != TEXTOID)
1549 elog(ERROR, "proargnames is not a 1-D text array or it contains nulls");
1550 deconstruct_array_builtin(arr, TEXTOID, &argnames, NULL, &numargs);
1551 if (proargmodes != PointerGetDatum(NULL))
1553 arr = DatumGetArrayTypeP(proargmodes); /* ensure not toasted */
1554 if (ARR_NDIM(arr) != 1 ||
1555 ARR_DIMS(arr)[0] != numargs ||
1556 ARR_HASNULL(arr) ||
1557 ARR_ELEMTYPE(arr) != CHAROID)
1558 elog(ERROR, "proargmodes is not a 1-D char array of length %d or it contains nulls",
1559 numargs);
1560 argmodes = (char *) ARR_DATA_PTR(arr);
1562 else
1563 argmodes = NULL;
1565 /* zero elements probably shouldn't happen, but handle it gracefully */
1566 if (numargs <= 0)
1568 *arg_names = NULL;
1569 return 0;
1572 /* extract input-argument names */
1573 inargnames = (char **) palloc(numargs * sizeof(char *));
1574 numinargs = 0;
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;
1586 else
1587 inargnames[numinargs] = NULL;
1588 numinargs++;
1592 *arg_names = inargnames;
1593 return numinargs;
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.
1606 char *
1607 get_func_result_name(Oid functionId)
1609 char *result;
1610 HeapTuple procTuple;
1611 Datum proargmodes;
1612 Datum proargnames;
1613 ArrayType *arr;
1614 int numargs;
1615 char *argmodes;
1616 Datum *argnames;
1617 int numoutargs;
1618 int nargnames;
1619 int i;
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))
1629 result = NULL;
1630 else
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
1642 * values.
1644 arr = DatumGetArrayTypeP(proargmodes); /* ensure not toasted */
1645 numargs = ARR_DIMS(arr)[0];
1646 if (ARR_NDIM(arr) != 1 ||
1647 numargs < 0 ||
1648 ARR_HASNULL(arr) ||
1649 ARR_ELEMTYPE(arr) != CHAROID)
1650 elog(ERROR, "proargmodes is not a 1-D char array or it contains nulls");
1651 argmodes = (char *) ARR_DATA_PTR(arr);
1652 arr = DatumGetArrayTypeP(proargnames); /* ensure not toasted */
1653 if (ARR_NDIM(arr) != 1 ||
1654 ARR_DIMS(arr)[0] != numargs ||
1655 ARR_HASNULL(arr) ||
1656 ARR_ELEMTYPE(arr) != TEXTOID)
1657 elog(ERROR, "proargnames is not a 1-D text array of length %d or it contains nulls",
1658 numargs);
1659 deconstruct_array_builtin(arr, TEXTOID, &argnames, NULL, &nargnames);
1660 Assert(nargnames == numargs);
1662 /* scan for output argument(s) */
1663 result = NULL;
1664 numoutargs = 0;
1665 for (i = 0; i < numargs; i++)
1667 if (argmodes[i] == PROARGMODE_IN ||
1668 argmodes[i] == PROARGMODE_VARIADIC)
1669 continue;
1670 Assert(argmodes[i] == PROARGMODE_OUT ||
1671 argmodes[i] == PROARGMODE_INOUT ||
1672 argmodes[i] == PROARGMODE_TABLE);
1673 if (++numoutargs > 1)
1675 /* multiple out args, so forget it */
1676 result = NULL;
1677 break;
1679 result = TextDatumGetCString(argnames[i]);
1680 if (result == NULL || result[0] == '\0')
1682 /* Parameter is not named, so forget it */
1683 result = NULL;
1684 break;
1689 ReleaseSysCache(procTuple);
1691 return result;
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.
1704 TupleDesc
1705 build_function_result_tupdesc_t(HeapTuple procTuple)
1707 Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(procTuple);
1708 Datum proallargtypes;
1709 Datum proargmodes;
1710 Datum proargnames;
1711 bool isnull;
1713 /* Return NULL if the function isn't declared to return RECORD */
1714 if (procform->prorettype != RECORDOID)
1715 return NULL;
1717 /* If there are no OUT parameters, return NULL */
1718 if (heap_attisnull(procTuple, Anum_pg_proc_proallargtypes, NULL) ||
1719 heap_attisnull(procTuple, Anum_pg_proc_proargmodes, NULL))
1720 return NULL;
1722 /* Get the data out of the tuple */
1723 proallargtypes = SysCacheGetAttrNotNull(PROCOID, procTuple,
1724 Anum_pg_proc_proallargtypes);
1725 proargmodes = SysCacheGetAttrNotNull(PROCOID, procTuple,
1726 Anum_pg_proc_proargmodes);
1727 proargnames = SysCacheGetAttr(PROCOID, procTuple,
1728 Anum_pg_proc_proargnames,
1729 &isnull);
1730 if (isnull)
1731 proargnames = PointerGetDatum(NULL); /* just to be sure */
1733 return build_function_result_tupdesc_d(procform->prokind,
1734 proallargtypes,
1735 proargmodes,
1736 proargnames);
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.
1750 TupleDesc
1751 build_function_result_tupdesc_d(char prokind,
1752 Datum proallargtypes,
1753 Datum proargmodes,
1754 Datum proargnames)
1756 TupleDesc desc;
1757 ArrayType *arr;
1758 int numargs;
1759 Oid *argtypes;
1760 char *argmodes;
1761 Datum *argnames = NULL;
1762 Oid *outargtypes;
1763 char **outargnames;
1764 int numoutargs;
1765 int nargnames;
1766 int i;
1768 /* Can't have output args if columns are null */
1769 if (proallargtypes == PointerGetDatum(NULL) ||
1770 proargmodes == PointerGetDatum(NULL))
1771 return 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 ||
1781 numargs < 0 ||
1782 ARR_HASNULL(arr) ||
1783 ARR_ELEMTYPE(arr) != OIDOID)
1784 elog(ERROR, "proallargtypes is not a 1-D Oid array or it contains nulls");
1785 argtypes = (Oid *) ARR_DATA_PTR(arr);
1786 arr = DatumGetArrayTypeP(proargmodes); /* ensure not toasted */
1787 if (ARR_NDIM(arr) != 1 ||
1788 ARR_DIMS(arr)[0] != numargs ||
1789 ARR_HASNULL(arr) ||
1790 ARR_ELEMTYPE(arr) != CHAROID)
1791 elog(ERROR, "proargmodes is not a 1-D char array of length %d or it contains nulls",
1792 numargs);
1793 argmodes = (char *) ARR_DATA_PTR(arr);
1794 if (proargnames != PointerGetDatum(NULL))
1796 arr = DatumGetArrayTypeP(proargnames); /* ensure not toasted */
1797 if (ARR_NDIM(arr) != 1 ||
1798 ARR_DIMS(arr)[0] != numargs ||
1799 ARR_HASNULL(arr) ||
1800 ARR_ELEMTYPE(arr) != TEXTOID)
1801 elog(ERROR, "proargnames is not a 1-D text array of length %d or it contains nulls",
1802 numargs);
1803 deconstruct_array_builtin(arr, TEXTOID, &argnames, NULL, &nargnames);
1804 Assert(nargnames == numargs);
1807 /* zero elements probably shouldn't happen, but handle it gracefully */
1808 if (numargs <= 0)
1809 return NULL;
1811 /* extract output-argument types and names */
1812 outargtypes = (Oid *) palloc(numargs * sizeof(Oid));
1813 outargnames = (char **) palloc(numargs * sizeof(char *));
1814 numoutargs = 0;
1815 for (i = 0; i < numargs; i++)
1817 char *pname;
1819 if (argmodes[i] == PROARGMODE_IN ||
1820 argmodes[i] == PROARGMODE_VARIADIC)
1821 continue;
1822 Assert(argmodes[i] == PROARGMODE_OUT ||
1823 argmodes[i] == PROARGMODE_INOUT ||
1824 argmodes[i] == PROARGMODE_TABLE);
1825 outargtypes[numoutargs] = argtypes[i];
1826 if (argnames)
1827 pname = TextDatumGetCString(argnames[i]);
1828 else
1829 pname = NULL;
1830 if (pname == NULL || pname[0] == '\0')
1832 /* Parameter is not named, so gin up a column name */
1833 pname = psprintf("column%d", numoutargs + 1);
1835 outargnames[numoutargs] = pname;
1836 numoutargs++;
1840 * If there is no output argument, or only one, the function does not
1841 * return tuples.
1843 if (numoutargs < 2 && prokind != PROKIND_PROCEDURE)
1844 return NULL;
1846 desc = CreateTemplateTupleDesc(numoutargs);
1847 for (i = 0; i < numoutargs; i++)
1849 TupleDescInitEntry(desc, i + 1,
1850 outargnames[i],
1851 outargtypes[i],
1856 return desc;
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.
1869 TupleDesc
1870 RelationNameGetTupleDesc(const char *relname)
1872 RangeVar *relvar;
1873 Relation rel;
1874 TupleDesc tupdesc;
1875 List *relname_list;
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);
1884 return tupdesc;
1888 * TypeGetTupleDesc
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.
1902 TupleDesc
1903 TypeGetTupleDesc(Oid typeoid, List *colaliases)
1905 Oid base_typeoid;
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;
1923 int varattno;
1925 /* does the list length match the number of attributes? */
1926 if (list_length(colaliases) != natts)
1927 ereport(ERROR,
1928 (errcode(ERRCODE_DATATYPE_MISMATCH),
1929 errmsg("number of aliases does not match number of columns")));
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);
1937 if (label != NULL)
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 */
1949 char *attname;
1951 /* the alias list is required for base types */
1952 if (colaliases == NIL)
1953 ereport(ERROR,
1954 (errcode(ERRCODE_DATATYPE_MISMATCH),
1955 errmsg("no column alias was provided")));
1957 /* the alias list length must be 1 */
1958 if (list_length(colaliases) != 1)
1959 ereport(ERROR,
1960 (errcode(ERRCODE_DATATYPE_MISMATCH),
1961 errmsg("number of aliases does not match number of columns")));
1963 /* OK, get the column alias */
1964 attname = strVal(linitial(colaliases));
1966 tupdesc = CreateTemplateTupleDesc(1);
1967 TupleDescInitEntry(tupdesc,
1968 (AttrNumber) 1,
1969 attname,
1970 typeoid,
1974 else if (functypclass == TYPEFUNC_RECORD)
1976 /* XXX can't support this because typmod wasn't passed in ... */
1977 ereport(ERROR,
1978 (errcode(ERRCODE_DATATYPE_MISMATCH),
1979 errmsg("could not determine row description for function returning record")));
1981 else
1983 /* crummy error message, but parser should have caught this */
1984 elog(ERROR, "function in FROM has unsupported return type");
1987 return tupdesc;
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
1999 * by the caller.
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,
2007 bool **nulls)
2009 bool variadic = get_fn_expr_variadic(fcinfo->flinfo);
2010 Datum *args_res;
2011 bool *nulls_res;
2012 Oid *types_res;
2013 int nargs,
2016 *args = NULL;
2017 *types = NULL;
2018 *nulls = NULL;
2020 if (variadic)
2022 ArrayType *array_in;
2023 Oid element_type;
2024 bool typbyval;
2025 char typalign;
2026 int16 typlen;
2028 Assert(PG_NARGS() == variadic_start + 1);
2030 if (PG_ARGISNULL(variadic_start))
2031 return -1;
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,
2040 &nargs);
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;
2047 else
2049 nargs = PG_NARGS() - variadic_start;
2050 Assert(nargs > 0);
2051 nulls_res = (bool *) palloc0(nargs * sizeof(bool));
2052 args_res = (Datum *) palloc0(nargs * sizeof(Datum));
2053 types_res = (Oid *) palloc0(nargs * sizeof(Oid));
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;
2076 else
2077 args_res[i] =
2078 CStringGetTextDatum(PG_GETARG_POINTER(i + variadic_start));
2080 else
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))
2088 ereport(ERROR,
2089 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2090 errmsg("could not determine data type for argument %d",
2091 i + 1)));
2095 /* Fill in results */
2096 *args = args_res;
2097 *nulls = nulls_res;
2098 *types = types_res;
2100 return nargs;