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