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