Coverage Report

Created: 2026-11-12 07:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/postgres/src/backend/utils/fmgr/funcapi.c
Line
Count
Source
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
InitMaterializedSRF(FunctionCallInfo fcinfo, uint32 flags)
77
0
{
78
0
  bool    random_access;
79
0
  ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
80
0
  Tuplestorestate *tupstore;
81
0
  MemoryContext old_context,
82
0
        per_query_ctx;
83
0
  TupleDesc stored_tupdesc;
84
85
  /* check to see if caller supports returning a tuplestore */
86
0
  if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
87
0
    ereport(ERROR,
88
0
        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
89
0
         errmsg("set-valued function called in context that cannot accept a set")));
90
0
  if (!(rsinfo->allowedModes & SFRM_Materialize) ||
91
0
    ((flags & MAT_SRF_USE_EXPECTED_DESC) != 0 && rsinfo->expectedDesc == NULL))
92
0
    ereport(ERROR,
93
0
        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
94
0
         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
0
  per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
101
0
  old_context = MemoryContextSwitchTo(per_query_ctx);
102
103
  /* build a tuple descriptor for our result type */
104
0
  if ((flags & MAT_SRF_USE_EXPECTED_DESC) != 0)
105
0
    stored_tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc);
106
0
  else
107
0
  {
108
0
    if (get_call_result_type(fcinfo, NULL, &stored_tupdesc) != TYPEFUNC_COMPOSITE)
109
0
      elog(ERROR, "return type must be a row type");
110
0
  }
111
112
  /* If requested, bless the tuple descriptor */
113
0
  if ((flags & MAT_SRF_BLESS) != 0)
114
0
    BlessTupleDesc(stored_tupdesc);
115
116
0
  random_access = (rsinfo->allowedModes & SFRM_Materialize_Random) != 0;
117
118
0
  tupstore = tuplestore_begin_heap(random_access, false, work_mem);
119
0
  rsinfo->returnMode = SFRM_Materialize;
120
0
  rsinfo->setResult = tupstore;
121
0
  rsinfo->setDesc = stored_tupdesc;
122
0
  MemoryContextSwitchTo(old_context);
123
0
}
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
init_MultiFuncCall(PG_FUNCTION_ARGS)
134
0
{
135
0
  FuncCallContext *retval;
136
137
  /*
138
   * Bail if we're called in the wrong context
139
   */
140
0
  if (fcinfo->resultinfo == NULL || !IsA(fcinfo->resultinfo, ReturnSetInfo))
141
0
    ereport(ERROR,
142
0
        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
143
0
         errmsg("set-valued function called in context that cannot accept a set")));
144
145
0
  if (fcinfo->flinfo->fn_extra == NULL)
146
0
  {
147
    /*
148
     * First call
149
     */
150
0
    ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
151
0
    MemoryContext multi_call_ctx;
152
153
    /*
154
     * Create a suitably long-lived context to hold cross-call data
155
     */
156
0
    multi_call_ctx = AllocSetContextCreate(fcinfo->flinfo->fn_mcxt,
157
0
                         "SRF multi-call context",
158
0
                         ALLOCSET_SMALL_SIZES);
159
160
    /*
161
     * Allocate suitably long-lived space and zero it
162
     */
163
0
    retval = (FuncCallContext *)
164
0
      MemoryContextAllocZero(multi_call_ctx,
165
0
                   sizeof(FuncCallContext));
166
167
    /*
168
     * initialize the elements
169
     */
170
0
    retval->call_cntr = 0;
171
0
    retval->max_calls = 0;
172
0
    retval->user_fctx = NULL;
173
0
    retval->attinmeta = NULL;
174
0
    retval->tuple_desc = NULL;
175
0
    retval->multi_call_memory_ctx = multi_call_ctx;
176
177
    /*
178
     * save the pointer for cross-call use
179
     */
180
0
    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
0
    RegisterExprContextCallback(rsi->econtext,
187
0
                  shutdown_MultiFuncCall,
188
0
                  PointerGetDatum(fcinfo->flinfo));
189
0
  }
190
0
  else
191
0
  {
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
0
    retval = NULL;
197
0
  }
198
199
0
  return retval;
200
0
}
201
202
/*
203
 * per_MultiFuncCall
204
 *
205
 * Do Multi-function per-call setup
206
 */
207
FuncCallContext *
208
per_MultiFuncCall(PG_FUNCTION_ARGS)
209
0
{
210
0
  FuncCallContext *retval = (FuncCallContext *) fcinfo->flinfo->fn_extra;
211
212
0
  return retval;
213
0
}
214
215
/*
216
 * end_MultiFuncCall
217
 * Clean up after init_MultiFuncCall
218
 */
219
void
220
end_MultiFuncCall(PG_FUNCTION_ARGS, FuncCallContext *funcctx)
221
0
{
222
0
  ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
223
224
  /* Deregister the shutdown callback */
225
0
  UnregisterExprContextCallback(rsi->econtext,
226
0
                  shutdown_MultiFuncCall,
227
0
                  PointerGetDatum(fcinfo->flinfo));
228
229
  /* But use it to do the real work */
230
0
  shutdown_MultiFuncCall(PointerGetDatum(fcinfo->flinfo));
231
0
}
232
233
/*
234
 * shutdown_MultiFuncCall
235
 * Shutdown function to clean up after init_MultiFuncCall
236
 */
237
static void
238
shutdown_MultiFuncCall(Datum arg)
239
0
{
240
0
  FmgrInfo   *flinfo = (FmgrInfo *) DatumGetPointer(arg);
241
0
  FuncCallContext *funcctx = (FuncCallContext *) flinfo->fn_extra;
242
243
  /* unbind from flinfo */
244
0
  flinfo->fn_extra = NULL;
245
246
  /*
247
   * Delete context that holds all multi-call data, including the
248
   * FuncCallContext itself
249
   */
250
0
  MemoryContextDelete(funcctx->multi_call_memory_ctx);
251
0
}
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
get_call_result_type(FunctionCallInfo fcinfo,
277
           Oid *resultTypeId,
278
           TupleDesc *resultTupleDesc)
279
0
{
280
0
  return internal_get_result_type(fcinfo->flinfo->fn_oid,
281
0
                  fcinfo->flinfo->fn_expr,
282
0
                  (ReturnSetInfo *) fcinfo->resultinfo,
283
0
                  resultTypeId,
284
0
                  resultTupleDesc);
285
0
}
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
get_expr_result_type(Node *expr,
300
           Oid *resultTypeId,
301
           TupleDesc *resultTupleDesc)
302
0
{
303
0
  TypeFuncClass result;
304
305
0
  if (expr && IsA(expr, FuncExpr))
306
0
    result = internal_get_result_type(((FuncExpr *) expr)->funcid,
307
0
                      expr,
308
0
                      NULL,
309
0
                      resultTypeId,
310
0
                      resultTupleDesc);
311
0
  else if (expr && IsA(expr, OpExpr))
312
0
    result = internal_get_result_type(get_opcode(((OpExpr *) expr)->opno),
313
0
                      expr,
314
0
                      NULL,
315
0
                      resultTypeId,
316
0
                      resultTupleDesc);
317
0
  else if (expr && IsA(expr, RowExpr) &&
318
0
       ((RowExpr *) expr)->row_typeid == RECORDOID)
319
0
  {
320
    /* We can resolve the record type by generating the tupdesc directly */
321
0
    RowExpr    *rexpr = (RowExpr *) expr;
322
0
    TupleDesc tupdesc;
323
0
    AttrNumber  i = 1;
324
0
    ListCell   *lcc,
325
0
           *lcn;
326
327
0
    tupdesc = CreateTemplateTupleDesc(list_length(rexpr->args));
328
0
    Assert(list_length(rexpr->args) == list_length(rexpr->colnames));
329
0
    forboth(lcc, rexpr->args, lcn, rexpr->colnames)
330
0
    {
331
0
      Node     *col = (Node *) lfirst(lcc);
332
0
      char     *colname = strVal(lfirst(lcn));
333
334
0
      TupleDescInitEntry(tupdesc, i,
335
0
                 colname,
336
0
                 exprType(col),
337
0
                 exprTypmod(col),
338
0
                 0);
339
0
      TupleDescInitEntryCollation(tupdesc, i,
340
0
                    exprCollation(col));
341
0
      i++;
342
0
    }
343
0
    TupleDescFinalize(tupdesc);
344
345
0
    if (resultTypeId)
346
0
      *resultTypeId = rexpr->row_typeid;
347
0
    if (resultTupleDesc)
348
0
      *resultTupleDesc = BlessTupleDesc(tupdesc);
349
0
    return TYPEFUNC_COMPOSITE;
350
0
  }
351
0
  else if (expr && IsA(expr, Const) &&
352
0
       ((Const *) expr)->consttype == RECORDOID &&
353
0
       !((Const *) expr)->constisnull)
354
0
  {
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
0
    HeapTupleHeader rec;
361
0
    Oid     tupType;
362
0
    int32   tupTypmod;
363
364
0
    rec = DatumGetHeapTupleHeader(((Const *) expr)->constvalue);
365
0
    tupType = HeapTupleHeaderGetTypeId(rec);
366
0
    tupTypmod = HeapTupleHeaderGetTypMod(rec);
367
0
    if (resultTypeId)
368
0
      *resultTypeId = tupType;
369
0
    if (tupType != RECORDOID || tupTypmod >= 0)
370
0
    {
371
      /* Should be able to look it up */
372
0
      if (resultTupleDesc)
373
0
        *resultTupleDesc = lookup_rowtype_tupdesc_copy(tupType,
374
0
                                 tupTypmod);
375
0
      return TYPEFUNC_COMPOSITE;
376
0
    }
377
0
    else
378
0
    {
379
      /* This shouldn't really happen ... */
380
0
      if (resultTupleDesc)
381
0
        *resultTupleDesc = NULL;
382
0
      return TYPEFUNC_RECORD;
383
0
    }
384
0
  }
385
0
  else
386
0
  {
387
    /* handle as a generic expression; no chance to resolve RECORD */
388
0
    Oid     typid = exprType(expr);
389
0
    Oid     base_typid;
390
391
0
    if (resultTypeId)
392
0
      *resultTypeId = typid;
393
0
    if (resultTupleDesc)
394
0
      *resultTupleDesc = NULL;
395
0
    result = get_type_func_class(typid, &base_typid);
396
0
    if ((result == TYPEFUNC_COMPOSITE ||
397
0
       result == TYPEFUNC_COMPOSITE_DOMAIN) &&
398
0
      resultTupleDesc)
399
0
      *resultTupleDesc = lookup_rowtype_tupdesc_copy(base_typid, -1);
400
0
  }
401
402
0
  return result;
403
0
}
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
get_func_result_type(Oid functionId,
413
           Oid *resultTypeId,
414
           TupleDesc *resultTupleDesc)
415
0
{
416
0
  return internal_get_result_type(functionId,
417
0
                  NULL,
418
0
                  NULL,
419
0
                  resultTypeId,
420
0
                  resultTupleDesc);
421
0
}
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
internal_get_result_type(Oid funcid,
433
             Node *call_expr,
434
             ReturnSetInfo *rsinfo,
435
             Oid *resultTypeId,
436
             TupleDesc *resultTupleDesc)
437
0
{
438
0
  TypeFuncClass result;
439
0
  HeapTuple tp;
440
0
  Form_pg_proc procform;
441
0
  Oid     rettype;
442
0
  Oid     base_rettype;
443
0
  TupleDesc tupdesc;
444
445
  /* First fetch the function's pg_proc row to inspect its rettype */
446
0
  tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
447
0
  if (!HeapTupleIsValid(tp))
448
0
    elog(ERROR, "cache lookup failed for function %u", funcid);
449
0
  procform = (Form_pg_proc) GETSTRUCT(tp);
450
451
0
  rettype = procform->prorettype;
452
453
  /* Check for OUT parameters defining a RECORD result */
454
0
  tupdesc = build_function_result_tupdesc_t(tp);
455
0
  if (tupdesc)
456
0
  {
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
0
    if (resultTypeId)
463
0
      *resultTypeId = rettype;
464
465
0
    if (resolve_polymorphic_tupdesc(tupdesc,
466
0
                    &procform->proargtypes,
467
0
                    call_expr))
468
0
    {
469
0
      if (tupdesc->tdtypeid == RECORDOID &&
470
0
        tupdesc->tdtypmod < 0)
471
0
        assign_record_type_typmod(tupdesc);
472
0
      if (resultTupleDesc)
473
0
        *resultTupleDesc = tupdesc;
474
0
      result = TYPEFUNC_COMPOSITE;
475
0
    }
476
0
    else
477
0
    {
478
0
      if (resultTupleDesc)
479
0
        *resultTupleDesc = NULL;
480
0
      result = TYPEFUNC_RECORD;
481
0
    }
482
483
0
    ReleaseSysCache(tp);
484
485
0
    return result;
486
0
  }
487
488
  /*
489
   * If scalar polymorphic result, try to resolve it.
490
   */
491
0
  if (IsPolymorphicType(rettype))
492
0
  {
493
0
    Oid     newrettype = exprType(call_expr);
494
495
0
    if (newrettype == InvalidOid) /* this probably should not happen */
496
0
      ereport(ERROR,
497
0
          (errcode(ERRCODE_DATATYPE_MISMATCH),
498
0
           errmsg("could not determine actual result type for function \"%s\" declared to return type %s",
499
0
              NameStr(procform->proname),
500
0
              format_type_be(rettype))));
501
0
    rettype = newrettype;
502
0
  }
503
504
0
  if (resultTypeId)
505
0
    *resultTypeId = rettype;
506
0
  if (resultTupleDesc)
507
0
    *resultTupleDesc = NULL; /* default result */
508
509
  /* Classify the result type */
510
0
  result = get_type_func_class(rettype, &base_rettype);
511
0
  switch (result)
512
0
  {
513
0
    case TYPEFUNC_COMPOSITE:
514
0
    case TYPEFUNC_COMPOSITE_DOMAIN:
515
0
      if (resultTupleDesc)
516
0
        *resultTupleDesc = lookup_rowtype_tupdesc_copy(base_rettype, -1);
517
      /* Named composite types can't have any polymorphic columns */
518
0
      break;
519
0
    case TYPEFUNC_SCALAR:
520
0
      break;
521
0
    case TYPEFUNC_RECORD:
522
      /* We must get the tupledesc from call context */
523
0
      if (rsinfo && IsA(rsinfo, ReturnSetInfo) &&
524
0
        rsinfo->expectedDesc != NULL)
525
0
      {
526
0
        result = TYPEFUNC_COMPOSITE;
527
0
        if (resultTupleDesc)
528
0
          *resultTupleDesc = rsinfo->expectedDesc;
529
        /* Assume no polymorphic columns here, either */
530
0
      }
531
0
      break;
532
0
    default:
533
0
      break;
534
0
  }
535
536
0
  ReleaseSysCache(tp);
537
538
0
  return result;
539
0
}
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
get_expr_result_tupdesc(Node *expr, bool noError)
554
0
{
555
0
  TupleDesc tupleDesc;
556
0
  TypeFuncClass functypclass;
557
558
0
  functypclass = get_expr_result_type(expr, NULL, &tupleDesc);
559
560
0
  if (functypclass == TYPEFUNC_COMPOSITE ||
561
0
    functypclass == TYPEFUNC_COMPOSITE_DOMAIN)
562
0
    return tupleDesc;
563
564
0
  if (!noError)
565
0
  {
566
0
    Oid     exprTypeId = exprType(expr);
567
568
0
    if (exprTypeId != RECORDOID)
569
0
      ereport(ERROR,
570
0
          (errcode(ERRCODE_WRONG_OBJECT_TYPE),
571
0
           errmsg("type %s is not composite",
572
0
              format_type_be(exprTypeId))));
573
0
    else
574
0
      ereport(ERROR,
575
0
          (errcode(ERRCODE_WRONG_OBJECT_TYPE),
576
0
           errmsg("record type has not been registered")));
577
0
  }
578
579
0
  return NULL;
580
0
}
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
resolve_anyelement_from_others(polymorphic_actuals *actuals)
592
0
{
593
0
  if (OidIsValid(actuals->anyarray_type))
594
0
  {
595
    /* Use the element type corresponding to actual type */
596
0
    Oid     array_base_type = getBaseType(actuals->anyarray_type);
597
0
    Oid     array_typelem = get_element_type(array_base_type);
598
599
0
    if (!OidIsValid(array_typelem))
600
0
      ereport(ERROR,
601
0
          (errcode(ERRCODE_DATATYPE_MISMATCH),
602
0
           errmsg("argument declared %s is not an array but type %s",
603
0
              "anyarray",
604
0
              format_type_be(array_base_type))));
605
0
    actuals->anyelement_type = array_typelem;
606
0
  }
607
0
  else if (OidIsValid(actuals->anyrange_type))
608
0
  {
609
    /* Use the element type corresponding to actual type */
610
0
    Oid     range_base_type = getBaseType(actuals->anyrange_type);
611
0
    Oid     range_typelem = get_range_subtype(range_base_type);
612
613
0
    if (!OidIsValid(range_typelem))
614
0
      ereport(ERROR,
615
0
          (errcode(ERRCODE_DATATYPE_MISMATCH),
616
0
           errmsg("argument declared %s is not a range type but type %s",
617
0
              "anyrange",
618
0
              format_type_be(range_base_type))));
619
0
    actuals->anyelement_type = range_typelem;
620
0
  }
621
0
  else if (OidIsValid(actuals->anymultirange_type))
622
0
  {
623
    /* Use the element type based on the multirange type */
624
0
    Oid     multirange_base_type;
625
0
    Oid     multirange_typelem;
626
0
    Oid     range_base_type;
627
0
    Oid     range_typelem;
628
629
0
    multirange_base_type = getBaseType(actuals->anymultirange_type);
630
0
    multirange_typelem = get_multirange_range(multirange_base_type);
631
0
    if (!OidIsValid(multirange_typelem))
632
0
      ereport(ERROR,
633
0
          (errcode(ERRCODE_DATATYPE_MISMATCH),
634
0
           errmsg("argument declared %s is not a multirange type but type %s",
635
0
              "anymultirange",
636
0
              format_type_be(multirange_base_type))));
637
638
0
    range_base_type = getBaseType(multirange_typelem);
639
0
    range_typelem = get_range_subtype(range_base_type);
640
641
0
    if (!OidIsValid(range_typelem))
642
0
      ereport(ERROR,
643
0
          (errcode(ERRCODE_DATATYPE_MISMATCH),
644
0
           errmsg("argument declared %s does not contain a range type but type %s",
645
0
              "anymultirange",
646
0
              format_type_be(range_base_type))));
647
0
    actuals->anyelement_type = range_typelem;
648
0
  }
649
0
  else
650
0
    elog(ERROR, "could not determine polymorphic type");
651
0
}
652
653
/*
654
 * Resolve actual type of ANYARRAY from other polymorphic inputs
655
 */
656
static void
657
resolve_anyarray_from_others(polymorphic_actuals *actuals)
658
0
{
659
  /* If we don't know ANYELEMENT, resolve that first */
660
0
  if (!OidIsValid(actuals->anyelement_type))
661
0
    resolve_anyelement_from_others(actuals);
662
663
0
  if (OidIsValid(actuals->anyelement_type))
664
0
  {
665
    /* Use the array type corresponding to actual type */
666
0
    Oid     array_typeid = get_array_type(actuals->anyelement_type);
667
668
0
    if (!OidIsValid(array_typeid))
669
0
      ereport(ERROR,
670
0
          (errcode(ERRCODE_UNDEFINED_OBJECT),
671
0
           errmsg("could not find array type for data type %s",
672
0
              format_type_be(actuals->anyelement_type))));
673
0
    actuals->anyarray_type = array_typeid;
674
0
  }
675
0
  else
676
0
    elog(ERROR, "could not determine polymorphic type");
677
0
}
678
679
/*
680
 * Resolve actual type of ANYRANGE from other polymorphic inputs
681
 */
682
static void
683
resolve_anyrange_from_others(polymorphic_actuals *actuals)
684
0
{
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
0
  if (OidIsValid(actuals->anymultirange_type))
691
0
  {
692
    /* Use the element type based on the multirange type */
693
0
    Oid     multirange_base_type = getBaseType(actuals->anymultirange_type);
694
0
    Oid     multirange_typelem = get_multirange_range(multirange_base_type);
695
696
0
    if (!OidIsValid(multirange_typelem))
697
0
      ereport(ERROR,
698
0
          (errcode(ERRCODE_DATATYPE_MISMATCH),
699
0
           errmsg("argument declared %s is not a multirange type but type %s",
700
0
              "anymultirange",
701
0
              format_type_be(multirange_base_type))));
702
0
    actuals->anyrange_type = multirange_typelem;
703
0
  }
704
0
  else
705
0
    elog(ERROR, "could not determine polymorphic type");
706
0
}
707
708
/*
709
 * Resolve actual type of ANYMULTIRANGE from other polymorphic inputs
710
 */
711
static void
712
resolve_anymultirange_from_others(polymorphic_actuals *actuals)
713
0
{
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
0
  if (OidIsValid(actuals->anyrange_type))
720
0
  {
721
0
    Oid     range_base_type = getBaseType(actuals->anyrange_type);
722
0
    Oid     multirange_typeid = get_range_multirange(range_base_type);
723
724
0
    if (!OidIsValid(multirange_typeid))
725
0
      ereport(ERROR,
726
0
          (errcode(ERRCODE_UNDEFINED_OBJECT),
727
0
           errmsg("could not find multirange type for data type %s",
728
0
              format_type_be(actuals->anyrange_type))));
729
0
    actuals->anymultirange_type = multirange_typeid;
730
0
  }
731
0
  else
732
0
    elog(ERROR, "could not determine polymorphic type");
733
0
}
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
resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
747
              Node *call_expr)
748
0
{
749
0
  int     natts = tupdesc->natts;
750
0
  int     nargs = declared_args->dim1;
751
0
  bool    have_polymorphic_result = false;
752
0
  bool    have_anyelement_result = false;
753
0
  bool    have_anyarray_result = false;
754
0
  bool    have_anyrange_result = false;
755
0
  bool    have_anymultirange_result = false;
756
0
  bool    have_anycompatible_result = false;
757
0
  bool    have_anycompatible_array_result = false;
758
0
  bool    have_anycompatible_range_result = false;
759
0
  bool    have_anycompatible_multirange_result = false;
760
0
  polymorphic_actuals poly_actuals;
761
0
  polymorphic_actuals anyc_actuals;
762
0
  Oid     anycollation = InvalidOid;
763
0
  Oid     anycompatcollation = InvalidOid;
764
0
  int     i;
765
766
  /* See if there are any polymorphic outputs; quick out if not */
767
0
  for (i = 0; i < natts; i++)
768
0
  {
769
0
    switch (TupleDescAttr(tupdesc, i)->atttypid)
770
0
    {
771
0
      case ANYELEMENTOID:
772
0
      case ANYNONARRAYOID:
773
0
      case ANYENUMOID:
774
0
        have_polymorphic_result = true;
775
0
        have_anyelement_result = true;
776
0
        break;
777
0
      case ANYARRAYOID:
778
0
        have_polymorphic_result = true;
779
0
        have_anyarray_result = true;
780
0
        break;
781
0
      case ANYRANGEOID:
782
0
        have_polymorphic_result = true;
783
0
        have_anyrange_result = true;
784
0
        break;
785
0
      case ANYMULTIRANGEOID:
786
0
        have_polymorphic_result = true;
787
0
        have_anymultirange_result = true;
788
0
        break;
789
0
      case ANYCOMPATIBLEOID:
790
0
      case ANYCOMPATIBLENONARRAYOID:
791
0
        have_polymorphic_result = true;
792
0
        have_anycompatible_result = true;
793
0
        break;
794
0
      case ANYCOMPATIBLEARRAYOID:
795
0
        have_polymorphic_result = true;
796
0
        have_anycompatible_array_result = true;
797
0
        break;
798
0
      case ANYCOMPATIBLERANGEOID:
799
0
        have_polymorphic_result = true;
800
0
        have_anycompatible_range_result = true;
801
0
        break;
802
0
      case ANYCOMPATIBLEMULTIRANGEOID:
803
0
        have_polymorphic_result = true;
804
0
        have_anycompatible_multirange_result = true;
805
0
        break;
806
0
      default:
807
0
        break;
808
0
    }
809
0
  }
810
0
  if (!have_polymorphic_result)
811
0
    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
0
  if (!call_expr)
821
0
    return false;     /* no hope */
822
823
0
  memset(&poly_actuals, 0, sizeof(poly_actuals));
824
0
  memset(&anyc_actuals, 0, sizeof(anyc_actuals));
825
826
0
  for (i = 0; i < nargs; i++)
827
0
  {
828
0
    switch (declared_args->values[i])
829
0
    {
830
0
      case ANYELEMENTOID:
831
0
      case ANYNONARRAYOID:
832
0
      case ANYENUMOID:
833
0
        if (!OidIsValid(poly_actuals.anyelement_type))
834
0
        {
835
0
          poly_actuals.anyelement_type =
836
0
            get_call_expr_argtype(call_expr, i);
837
0
          if (!OidIsValid(poly_actuals.anyelement_type))
838
0
            return false;
839
0
        }
840
0
        break;
841
0
      case ANYARRAYOID:
842
0
        if (!OidIsValid(poly_actuals.anyarray_type))
843
0
        {
844
0
          poly_actuals.anyarray_type =
845
0
            get_call_expr_argtype(call_expr, i);
846
0
          if (!OidIsValid(poly_actuals.anyarray_type))
847
0
            return false;
848
0
        }
849
0
        break;
850
0
      case ANYRANGEOID:
851
0
        if (!OidIsValid(poly_actuals.anyrange_type))
852
0
        {
853
0
          poly_actuals.anyrange_type =
854
0
            get_call_expr_argtype(call_expr, i);
855
0
          if (!OidIsValid(poly_actuals.anyrange_type))
856
0
            return false;
857
0
        }
858
0
        break;
859
0
      case ANYMULTIRANGEOID:
860
0
        if (!OidIsValid(poly_actuals.anymultirange_type))
861
0
        {
862
0
          poly_actuals.anymultirange_type =
863
0
            get_call_expr_argtype(call_expr, i);
864
0
          if (!OidIsValid(poly_actuals.anymultirange_type))
865
0
            return false;
866
0
        }
867
0
        break;
868
0
      case ANYCOMPATIBLEOID:
869
0
      case ANYCOMPATIBLENONARRAYOID:
870
0
        if (!OidIsValid(anyc_actuals.anyelement_type))
871
0
        {
872
0
          anyc_actuals.anyelement_type =
873
0
            get_call_expr_argtype(call_expr, i);
874
0
          if (!OidIsValid(anyc_actuals.anyelement_type))
875
0
            return false;
876
0
        }
877
0
        break;
878
0
      case ANYCOMPATIBLEARRAYOID:
879
0
        if (!OidIsValid(anyc_actuals.anyarray_type))
880
0
        {
881
0
          anyc_actuals.anyarray_type =
882
0
            get_call_expr_argtype(call_expr, i);
883
0
          if (!OidIsValid(anyc_actuals.anyarray_type))
884
0
            return false;
885
0
        }
886
0
        break;
887
0
      case ANYCOMPATIBLERANGEOID:
888
0
        if (!OidIsValid(anyc_actuals.anyrange_type))
889
0
        {
890
0
          anyc_actuals.anyrange_type =
891
0
            get_call_expr_argtype(call_expr, i);
892
0
          if (!OidIsValid(anyc_actuals.anyrange_type))
893
0
            return false;
894
0
        }
895
0
        break;
896
0
      case ANYCOMPATIBLEMULTIRANGEOID:
897
0
        if (!OidIsValid(anyc_actuals.anymultirange_type))
898
0
        {
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
0
        }
904
0
        break;
905
0
      default:
906
0
        break;
907
0
    }
908
0
  }
909
910
  /* If needed, deduce one polymorphic type from others */
911
0
  if (have_anyelement_result && !OidIsValid(poly_actuals.anyelement_type))
912
0
    resolve_anyelement_from_others(&poly_actuals);
913
914
0
  if (have_anyarray_result && !OidIsValid(poly_actuals.anyarray_type))
915
0
    resolve_anyarray_from_others(&poly_actuals);
916
917
0
  if (have_anyrange_result && !OidIsValid(poly_actuals.anyrange_type))
918
0
    resolve_anyrange_from_others(&poly_actuals);
919
920
0
  if (have_anymultirange_result && !OidIsValid(poly_actuals.anymultirange_type))
921
0
    resolve_anymultirange_from_others(&poly_actuals);
922
923
0
  if (have_anycompatible_result && !OidIsValid(anyc_actuals.anyelement_type))
924
0
    resolve_anyelement_from_others(&anyc_actuals);
925
926
0
  if (have_anycompatible_array_result && !OidIsValid(anyc_actuals.anyarray_type))
927
0
    resolve_anyarray_from_others(&anyc_actuals);
928
929
0
  if (have_anycompatible_range_result && !OidIsValid(anyc_actuals.anyrange_type))
930
0
    resolve_anyrange_from_others(&anyc_actuals);
931
932
0
  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
0
  if (OidIsValid(poly_actuals.anyelement_type))
943
0
    anycollation = get_typcollation(poly_actuals.anyelement_type);
944
0
  else if (OidIsValid(poly_actuals.anyarray_type))
945
0
    anycollation = get_typcollation(poly_actuals.anyarray_type);
946
947
0
  if (OidIsValid(anyc_actuals.anyelement_type))
948
0
    anycompatcollation = get_typcollation(anyc_actuals.anyelement_type);
949
0
  else if (OidIsValid(anyc_actuals.anyarray_type))
950
0
    anycompatcollation = get_typcollation(anyc_actuals.anyarray_type);
951
952
0
  if (OidIsValid(anycollation) || OidIsValid(anycompatcollation))
953
0
  {
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
0
    Oid     inputcollation = exprInputCollation(call_expr);
960
961
0
    if (OidIsValid(inputcollation))
962
0
    {
963
0
      if (OidIsValid(anycollation))
964
0
        anycollation = inputcollation;
965
0
      if (OidIsValid(anycompatcollation))
966
0
        anycompatcollation = inputcollation;
967
0
    }
968
0
  }
969
970
  /* And finally replace the tuple column types as needed */
971
0
  for (i = 0; i < natts; i++)
972
0
  {
973
0
    Form_pg_attribute att = TupleDescAttr(tupdesc, i);
974
975
0
    switch (att->atttypid)
976
0
    {
977
0
      case ANYELEMENTOID:
978
0
      case ANYNONARRAYOID:
979
0
      case ANYENUMOID:
980
0
        TupleDescInitEntry(tupdesc, i + 1,
981
0
                   NameStr(att->attname),
982
0
                   poly_actuals.anyelement_type,
983
0
                   -1,
984
0
                   0);
985
0
        TupleDescInitEntryCollation(tupdesc, i + 1, anycollation);
986
0
        break;
987
0
      case ANYARRAYOID:
988
0
        TupleDescInitEntry(tupdesc, i + 1,
989
0
                   NameStr(att->attname),
990
0
                   poly_actuals.anyarray_type,
991
0
                   -1,
992
0
                   0);
993
0
        TupleDescInitEntryCollation(tupdesc, i + 1, anycollation);
994
0
        break;
995
0
      case ANYRANGEOID:
996
0
        TupleDescInitEntry(tupdesc, i + 1,
997
0
                   NameStr(att->attname),
998
0
                   poly_actuals.anyrange_type,
999
0
                   -1,
1000
0
                   0);
1001
        /* no collation should be attached to a range type */
1002
0
        break;
1003
0
      case ANYMULTIRANGEOID:
1004
0
        TupleDescInitEntry(tupdesc, i + 1,
1005
0
                   NameStr(att->attname),
1006
0
                   poly_actuals.anymultirange_type,
1007
0
                   -1,
1008
0
                   0);
1009
        /* no collation should be attached to a multirange type */
1010
0
        break;
1011
0
      case ANYCOMPATIBLEOID:
1012
0
      case ANYCOMPATIBLENONARRAYOID:
1013
0
        TupleDescInitEntry(tupdesc, i + 1,
1014
0
                   NameStr(att->attname),
1015
0
                   anyc_actuals.anyelement_type,
1016
0
                   -1,
1017
0
                   0);
1018
0
        TupleDescInitEntryCollation(tupdesc, i + 1, anycompatcollation);
1019
0
        break;
1020
0
      case ANYCOMPATIBLEARRAYOID:
1021
0
        TupleDescInitEntry(tupdesc, i + 1,
1022
0
                   NameStr(att->attname),
1023
0
                   anyc_actuals.anyarray_type,
1024
0
                   -1,
1025
0
                   0);
1026
0
        TupleDescInitEntryCollation(tupdesc, i + 1, anycompatcollation);
1027
0
        break;
1028
0
      case ANYCOMPATIBLERANGEOID:
1029
0
        TupleDescInitEntry(tupdesc, i + 1,
1030
0
                   NameStr(att->attname),
1031
0
                   anyc_actuals.anyrange_type,
1032
0
                   -1,
1033
0
                   0);
1034
        /* no collation should be attached to a range type */
1035
0
        break;
1036
0
      case ANYCOMPATIBLEMULTIRANGEOID:
1037
0
        TupleDescInitEntry(tupdesc, i + 1,
1038
0
                   NameStr(att->attname),
1039
0
                   anyc_actuals.anymultirange_type,
1040
0
                   -1,
1041
0
                   0);
1042
        /* no collation should be attached to a multirange type */
1043
0
        break;
1044
0
      default:
1045
0
        break;
1046
0
    }
1047
0
  }
1048
1049
0
  TupleDescFinalize(tupdesc);
1050
0
  return true;
1051
0
}
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
resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes,
1068
               Node *call_expr)
1069
0
{
1070
0
  bool    have_polymorphic_result = false;
1071
0
  bool    have_anyelement_result = false;
1072
0
  bool    have_anyarray_result = false;
1073
0
  bool    have_anyrange_result = false;
1074
0
  bool    have_anymultirange_result = false;
1075
0
  bool    have_anycompatible_result = false;
1076
0
  bool    have_anycompatible_array_result = false;
1077
0
  bool    have_anycompatible_range_result = false;
1078
0
  bool    have_anycompatible_multirange_result = false;
1079
0
  polymorphic_actuals poly_actuals;
1080
0
  polymorphic_actuals anyc_actuals;
1081
0
  int     inargno;
1082
0
  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
0
  memset(&poly_actuals, 0, sizeof(poly_actuals));
1090
0
  memset(&anyc_actuals, 0, sizeof(anyc_actuals));
1091
0
  inargno = 0;
1092
0
  for (i = 0; i < numargs; i++)
1093
0
  {
1094
0
    char    argmode = argmodes ? argmodes[i] : PROARGMODE_IN;
1095
1096
0
    switch (argtypes[i])
1097
0
    {
1098
0
      case ANYELEMENTOID:
1099
0
      case ANYNONARRAYOID:
1100
0
      case ANYENUMOID:
1101
0
        if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
1102
0
        {
1103
0
          have_polymorphic_result = true;
1104
0
          have_anyelement_result = true;
1105
0
        }
1106
0
        else
1107
0
        {
1108
0
          if (!OidIsValid(poly_actuals.anyelement_type))
1109
0
          {
1110
0
            poly_actuals.anyelement_type =
1111
0
              get_call_expr_argtype(call_expr, inargno);
1112
0
            if (!OidIsValid(poly_actuals.anyelement_type))
1113
0
              return false;
1114
0
          }
1115
0
          argtypes[i] = poly_actuals.anyelement_type;
1116
0
        }
1117
0
        break;
1118
0
      case ANYARRAYOID:
1119
0
        if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
1120
0
        {
1121
0
          have_polymorphic_result = true;
1122
0
          have_anyarray_result = true;
1123
0
        }
1124
0
        else
1125
0
        {
1126
0
          if (!OidIsValid(poly_actuals.anyarray_type))
1127
0
          {
1128
0
            poly_actuals.anyarray_type =
1129
0
              get_call_expr_argtype(call_expr, inargno);
1130
0
            if (!OidIsValid(poly_actuals.anyarray_type))
1131
0
              return false;
1132
0
          }
1133
0
          argtypes[i] = poly_actuals.anyarray_type;
1134
0
        }
1135
0
        break;
1136
0
      case ANYRANGEOID:
1137
0
        if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
1138
0
        {
1139
0
          have_polymorphic_result = true;
1140
0
          have_anyrange_result = true;
1141
0
        }
1142
0
        else
1143
0
        {
1144
0
          if (!OidIsValid(poly_actuals.anyrange_type))
1145
0
          {
1146
0
            poly_actuals.anyrange_type =
1147
0
              get_call_expr_argtype(call_expr, inargno);
1148
0
            if (!OidIsValid(poly_actuals.anyrange_type))
1149
0
              return false;
1150
0
          }
1151
0
          argtypes[i] = poly_actuals.anyrange_type;
1152
0
        }
1153
0
        break;
1154
0
      case ANYMULTIRANGEOID:
1155
0
        if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
1156
0
        {
1157
0
          have_polymorphic_result = true;
1158
0
          have_anymultirange_result = true;
1159
0
        }
1160
0
        else
1161
0
        {
1162
0
          if (!OidIsValid(poly_actuals.anymultirange_type))
1163
0
          {
1164
0
            poly_actuals.anymultirange_type =
1165
0
              get_call_expr_argtype(call_expr, inargno);
1166
0
            if (!OidIsValid(poly_actuals.anymultirange_type))
1167
0
              return false;
1168
0
          }
1169
0
          argtypes[i] = poly_actuals.anymultirange_type;
1170
0
        }
1171
0
        break;
1172
0
      case ANYCOMPATIBLEOID:
1173
0
      case ANYCOMPATIBLENONARRAYOID:
1174
0
        if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
1175
0
        {
1176
0
          have_polymorphic_result = true;
1177
0
          have_anycompatible_result = true;
1178
0
        }
1179
0
        else
1180
0
        {
1181
0
          if (!OidIsValid(anyc_actuals.anyelement_type))
1182
0
          {
1183
0
            anyc_actuals.anyelement_type =
1184
0
              get_call_expr_argtype(call_expr, inargno);
1185
0
            if (!OidIsValid(anyc_actuals.anyelement_type))
1186
0
              return false;
1187
0
          }
1188
0
          argtypes[i] = anyc_actuals.anyelement_type;
1189
0
        }
1190
0
        break;
1191
0
      case ANYCOMPATIBLEARRAYOID:
1192
0
        if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
1193
0
        {
1194
0
          have_polymorphic_result = true;
1195
0
          have_anycompatible_array_result = true;
1196
0
        }
1197
0
        else
1198
0
        {
1199
0
          if (!OidIsValid(anyc_actuals.anyarray_type))
1200
0
          {
1201
0
            anyc_actuals.anyarray_type =
1202
0
              get_call_expr_argtype(call_expr, inargno);
1203
0
            if (!OidIsValid(anyc_actuals.anyarray_type))
1204
0
              return false;
1205
0
          }
1206
0
          argtypes[i] = anyc_actuals.anyarray_type;
1207
0
        }
1208
0
        break;
1209
0
      case ANYCOMPATIBLERANGEOID:
1210
0
        if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
1211
0
        {
1212
0
          have_polymorphic_result = true;
1213
0
          have_anycompatible_range_result = true;
1214
0
        }
1215
0
        else
1216
0
        {
1217
0
          if (!OidIsValid(anyc_actuals.anyrange_type))
1218
0
          {
1219
0
            anyc_actuals.anyrange_type =
1220
0
              get_call_expr_argtype(call_expr, inargno);
1221
0
            if (!OidIsValid(anyc_actuals.anyrange_type))
1222
0
              return false;
1223
0
          }
1224
0
          argtypes[i] = anyc_actuals.anyrange_type;
1225
0
        }
1226
0
        break;
1227
0
      case ANYCOMPATIBLEMULTIRANGEOID:
1228
0
        if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
1229
0
        {
1230
0
          have_polymorphic_result = true;
1231
0
          have_anycompatible_multirange_result = true;
1232
0
        }
1233
0
        else
1234
0
        {
1235
0
          if (!OidIsValid(anyc_actuals.anymultirange_type))
1236
0
          {
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
0
          }
1242
0
          argtypes[i] = anyc_actuals.anymultirange_type;
1243
0
        }
1244
0
        break;
1245
0
      default:
1246
0
        break;
1247
0
    }
1248
0
    if (argmode != PROARGMODE_OUT && argmode != PROARGMODE_TABLE)
1249
0
      inargno++;
1250
0
  }
1251
1252
  /* Done? */
1253
0
  if (!have_polymorphic_result)
1254
0
    return true;
1255
1256
  /* If needed, deduce one polymorphic type from others */
1257
0
  if (have_anyelement_result && !OidIsValid(poly_actuals.anyelement_type))
1258
0
    resolve_anyelement_from_others(&poly_actuals);
1259
1260
0
  if (have_anyarray_result && !OidIsValid(poly_actuals.anyarray_type))
1261
0
    resolve_anyarray_from_others(&poly_actuals);
1262
1263
0
  if (have_anyrange_result && !OidIsValid(poly_actuals.anyrange_type))
1264
0
    resolve_anyrange_from_others(&poly_actuals);
1265
1266
0
  if (have_anymultirange_result && !OidIsValid(poly_actuals.anymultirange_type))
1267
0
    resolve_anymultirange_from_others(&poly_actuals);
1268
1269
0
  if (have_anycompatible_result && !OidIsValid(anyc_actuals.anyelement_type))
1270
0
    resolve_anyelement_from_others(&anyc_actuals);
1271
1272
0
  if (have_anycompatible_array_result && !OidIsValid(anyc_actuals.anyarray_type))
1273
0
    resolve_anyarray_from_others(&anyc_actuals);
1274
1275
0
  if (have_anycompatible_range_result && !OidIsValid(anyc_actuals.anyrange_type))
1276
0
    resolve_anyrange_from_others(&anyc_actuals);
1277
1278
0
  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
0
  for (i = 0; i < numargs; i++)
1283
0
  {
1284
0
    switch (argtypes[i])
1285
0
    {
1286
0
      case ANYELEMENTOID:
1287
0
      case ANYNONARRAYOID:
1288
0
      case ANYENUMOID:
1289
0
        argtypes[i] = poly_actuals.anyelement_type;
1290
0
        break;
1291
0
      case ANYARRAYOID:
1292
0
        argtypes[i] = poly_actuals.anyarray_type;
1293
0
        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
0
      case ANYCOMPATIBLEOID:
1301
0
      case ANYCOMPATIBLENONARRAYOID:
1302
0
        argtypes[i] = anyc_actuals.anyelement_type;
1303
0
        break;
1304
0
      case ANYCOMPATIBLEARRAYOID:
1305
0
        argtypes[i] = anyc_actuals.anyarray_type;
1306
0
        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
0
      default:
1314
0
        break;
1315
0
    }
1316
0
  }
1317
1318
0
  return true;
1319
0
}
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
get_type_func_class(Oid typid, Oid *base_typeid)
1332
0
{
1333
0
  *base_typeid = typid;
1334
1335
0
  switch (get_typtype(typid))
1336
0
  {
1337
0
    case TYPTYPE_COMPOSITE:
1338
0
      return TYPEFUNC_COMPOSITE;
1339
0
    case TYPTYPE_BASE:
1340
0
    case TYPTYPE_ENUM:
1341
0
    case TYPTYPE_RANGE:
1342
0
    case TYPTYPE_MULTIRANGE:
1343
0
      return TYPEFUNC_SCALAR;
1344
0
    case TYPTYPE_DOMAIN:
1345
0
      *base_typeid = typid = getBaseType(typid);
1346
0
      if (get_typtype(typid) == TYPTYPE_COMPOSITE)
1347
0
        return TYPEFUNC_COMPOSITE_DOMAIN;
1348
0
      else        /* domain base type can't be a pseudotype */
1349
0
        return TYPEFUNC_SCALAR;
1350
0
    case TYPTYPE_PSEUDO:
1351
0
      if (typid == RECORDOID)
1352
0
        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
0
      if (typid == VOIDOID || typid == CSTRINGOID)
1361
0
        return TYPEFUNC_SCALAR;
1362
0
      return TYPEFUNC_OTHER;
1363
0
  }
1364
  /* shouldn't get here, probably */
1365
0
  return TYPEFUNC_OTHER;
1366
0
}
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
get_func_arg_info(HeapTuple procTup,
1383
          Oid **p_argtypes, char ***p_argnames, char **p_argmodes)
1384
0
{
1385
0
  Form_pg_proc procStruct = (Form_pg_proc) GETSTRUCT(procTup);
1386
0
  Datum   proallargtypes;
1387
0
  Datum   proargmodes;
1388
0
  Datum   proargnames;
1389
0
  bool    isNull;
1390
0
  ArrayType  *arr;
1391
0
  int     numargs;
1392
0
  Datum    *elems;
1393
0
  int     nelems;
1394
0
  int     i;
1395
1396
  /* First discover the total number of parameters and get their types */
1397
0
  proallargtypes = SysCacheGetAttr(PROCOID, procTup,
1398
0
                   Anum_pg_proc_proallargtypes,
1399
0
                   &isNull);
1400
0
  if (!isNull)
1401
0
  {
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
0
    arr = DatumGetArrayTypeP(proallargtypes); /* ensure not toasted */
1409
0
    numargs = ARR_DIMS(arr)[0];
1410
0
    if (ARR_NDIM(arr) != 1 ||
1411
0
      numargs < 0 ||
1412
0
      ARR_HASNULL(arr) ||
1413
0
      ARR_ELEMTYPE(arr) != OIDOID)
1414
0
      elog(ERROR, "proallargtypes is not a 1-D Oid array or it contains nulls");
1415
0
    Assert(numargs >= procStruct->pronargs);
1416
0
    *p_argtypes = palloc_array(Oid, numargs);
1417
0
    memcpy(*p_argtypes, ARR_DATA_PTR(arr),
1418
0
         numargs * sizeof(Oid));
1419
0
  }
1420
0
  else
1421
0
  {
1422
    /* If no proallargtypes, use proargtypes */
1423
0
    numargs = procStruct->proargtypes.dim1;
1424
0
    Assert(numargs == procStruct->pronargs);
1425
0
    *p_argtypes = palloc_array(Oid, numargs);
1426
0
    memcpy(*p_argtypes, procStruct->proargtypes.values,
1427
0
         numargs * sizeof(Oid));
1428
0
  }
1429
1430
  /* Get argument names, if available */
1431
0
  proargnames = SysCacheGetAttr(PROCOID, procTup,
1432
0
                  Anum_pg_proc_proargnames,
1433
0
                  &isNull);
1434
0
  if (isNull)
1435
0
    *p_argnames = NULL;
1436
0
  else
1437
0
  {
1438
0
    deconstruct_array_builtin(DatumGetArrayTypeP(proargnames), TEXTOID,
1439
0
                  &elems, NULL, &nelems);
1440
0
    if (nelems != numargs) /* should not happen */
1441
0
      elog(ERROR, "proargnames must have the same number of elements as the function has arguments");
1442
0
    *p_argnames = palloc_array(char *, numargs);
1443
0
    for (i = 0; i < numargs; i++)
1444
0
      (*p_argnames)[i] = TextDatumGetCString(elems[i]);
1445
0
  }
1446
1447
  /* Get argument modes, if available */
1448
0
  proargmodes = SysCacheGetAttr(PROCOID, procTup,
1449
0
                  Anum_pg_proc_proargmodes,
1450
0
                  &isNull);
1451
0
  if (isNull)
1452
0
    *p_argmodes = NULL;
1453
0
  else
1454
0
  {
1455
0
    arr = DatumGetArrayTypeP(proargmodes);  /* ensure not toasted */
1456
0
    if (ARR_NDIM(arr) != 1 ||
1457
0
      ARR_DIMS(arr)[0] != numargs ||
1458
0
      ARR_HASNULL(arr) ||
1459
0
      ARR_ELEMTYPE(arr) != CHAROID)
1460
0
      elog(ERROR, "proargmodes is not a 1-D char array of length %d or it contains nulls",
1461
0
         numargs);
1462
0
    *p_argmodes = (char *) palloc(numargs * sizeof(char));
1463
0
    memcpy(*p_argmodes, ARR_DATA_PTR(arr),
1464
0
         numargs * sizeof(char));
1465
0
  }
1466
1467
0
  return numargs;
1468
0
}
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
get_func_trftypes(HeapTuple procTup,
1479
          Oid **p_trftypes)
1480
0
{
1481
0
  Datum   protrftypes;
1482
0
  ArrayType  *arr;
1483
0
  int     nelems;
1484
0
  bool    isNull;
1485
1486
0
  protrftypes = SysCacheGetAttr(PROCOID, procTup,
1487
0
                  Anum_pg_proc_protrftypes,
1488
0
                  &isNull);
1489
0
  if (!isNull)
1490
0
  {
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
0
    arr = DatumGetArrayTypeP(protrftypes);  /* ensure not toasted */
1498
0
    nelems = ARR_DIMS(arr)[0];
1499
0
    if (ARR_NDIM(arr) != 1 ||
1500
0
      nelems < 0 ||
1501
0
      ARR_HASNULL(arr) ||
1502
0
      ARR_ELEMTYPE(arr) != OIDOID)
1503
0
      elog(ERROR, "protrftypes is not a 1-D Oid array or it contains nulls");
1504
0
    *p_trftypes = palloc_array(Oid, nelems);
1505
0
    memcpy(*p_trftypes, ARR_DATA_PTR(arr),
1506
0
         nelems * sizeof(Oid));
1507
1508
0
    return nelems;
1509
0
  }
1510
0
  else
1511
0
    return 0;
1512
0
}
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
get_func_input_arg_names(Datum proargnames, Datum proargmodes,
1526
             char ***arg_names)
1527
0
{
1528
0
  ArrayType  *arr;
1529
0
  int     numargs;
1530
0
  Datum    *argnames;
1531
0
  char     *argmodes;
1532
0
  char    **inargnames;
1533
0
  int     numinargs;
1534
0
  int     i;
1535
1536
  /* Do nothing if null proargnames */
1537
0
  if (proargnames == PointerGetDatum(NULL))
1538
0
  {
1539
0
    *arg_names = NULL;
1540
0
    return 0;
1541
0
  }
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
0
  arr = DatumGetArrayTypeP(proargnames);  /* ensure not toasted */
1549
0
  if (ARR_NDIM(arr) != 1 ||
1550
0
    ARR_HASNULL(arr) ||
1551
0
    ARR_ELEMTYPE(arr) != TEXTOID)
1552
0
    elog(ERROR, "proargnames is not a 1-D text array or it contains nulls");
1553
0
  deconstruct_array_builtin(arr, TEXTOID, &argnames, NULL, &numargs);
1554
0
  if (proargmodes != PointerGetDatum(NULL))
1555
0
  {
1556
0
    arr = DatumGetArrayTypeP(proargmodes);  /* ensure not toasted */
1557
0
    if (ARR_NDIM(arr) != 1 ||
1558
0
      ARR_DIMS(arr)[0] != numargs ||
1559
0
      ARR_HASNULL(arr) ||
1560
0
      ARR_ELEMTYPE(arr) != CHAROID)
1561
0
      elog(ERROR, "proargmodes is not a 1-D char array of length %d or it contains nulls",
1562
0
         numargs);
1563
0
    argmodes = (char *) ARR_DATA_PTR(arr);
1564
0
  }
1565
0
  else
1566
0
    argmodes = NULL;
1567
1568
  /* zero elements probably shouldn't happen, but handle it gracefully */
1569
0
  if (numargs <= 0)
1570
0
  {
1571
0
    *arg_names = NULL;
1572
0
    return 0;
1573
0
  }
1574
1575
  /* extract input-argument names */
1576
0
  inargnames = (char **) palloc(numargs * sizeof(char *));
1577
0
  numinargs = 0;
1578
0
  for (i = 0; i < numargs; i++)
1579
0
  {
1580
0
    if (argmodes == NULL ||
1581
0
      argmodes[i] == PROARGMODE_IN ||
1582
0
      argmodes[i] == PROARGMODE_INOUT ||
1583
0
      argmodes[i] == PROARGMODE_VARIADIC)
1584
0
    {
1585
0
      char     *pname = TextDatumGetCString(argnames[i]);
1586
1587
0
      if (pname[0] != '\0')
1588
0
        inargnames[numinargs] = pname;
1589
0
      else
1590
0
        inargnames[numinargs] = NULL;
1591
0
      numinargs++;
1592
0
    }
1593
0
  }
1594
1595
0
  *arg_names = inargnames;
1596
0
  return numinargs;
1597
0
}
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
get_func_result_name(Oid functionId)
1611
0
{
1612
0
  char     *result;
1613
0
  HeapTuple procTuple;
1614
0
  Datum   proargmodes;
1615
0
  Datum   proargnames;
1616
0
  ArrayType  *arr;
1617
0
  int     numargs;
1618
0
  char     *argmodes;
1619
0
  Datum    *argnames;
1620
0
  int     numoutargs;
1621
0
  int     nargnames;
1622
0
  int     i;
1623
1624
  /* First fetch the function's pg_proc row */
1625
0
  procTuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(functionId));
1626
0
  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
0
  if (heap_attisnull(procTuple, Anum_pg_proc_proargmodes, NULL) ||
1631
0
    heap_attisnull(procTuple, Anum_pg_proc_proargnames, NULL))
1632
0
    result = NULL;
1633
0
  else
1634
0
  {
1635
    /* Get the data out of the tuple */
1636
0
    proargmodes = SysCacheGetAttrNotNull(PROCOID, procTuple,
1637
0
                       Anum_pg_proc_proargmodes);
1638
0
    proargnames = SysCacheGetAttrNotNull(PROCOID, procTuple,
1639
0
                       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
0
    arr = DatumGetArrayTypeP(proargmodes);  /* ensure not toasted */
1648
0
    numargs = ARR_DIMS(arr)[0];
1649
0
    if (ARR_NDIM(arr) != 1 ||
1650
0
      numargs < 0 ||
1651
0
      ARR_HASNULL(arr) ||
1652
0
      ARR_ELEMTYPE(arr) != CHAROID)
1653
0
      elog(ERROR, "proargmodes is not a 1-D char array or it contains nulls");
1654
0
    argmodes = (char *) ARR_DATA_PTR(arr);
1655
0
    arr = DatumGetArrayTypeP(proargnames);  /* ensure not toasted */
1656
0
    if (ARR_NDIM(arr) != 1 ||
1657
0
      ARR_DIMS(arr)[0] != numargs ||
1658
0
      ARR_HASNULL(arr) ||
1659
0
      ARR_ELEMTYPE(arr) != TEXTOID)
1660
0
      elog(ERROR, "proargnames is not a 1-D text array of length %d or it contains nulls",
1661
0
         numargs);
1662
0
    deconstruct_array_builtin(arr, TEXTOID, &argnames, NULL, &nargnames);
1663
0
    Assert(nargnames == numargs);
1664
1665
    /* scan for output argument(s) */
1666
0
    result = NULL;
1667
0
    numoutargs = 0;
1668
0
    for (i = 0; i < numargs; i++)
1669
0
    {
1670
0
      if (argmodes[i] == PROARGMODE_IN ||
1671
0
        argmodes[i] == PROARGMODE_VARIADIC)
1672
0
        continue;
1673
0
      Assert(argmodes[i] == PROARGMODE_OUT ||
1674
0
           argmodes[i] == PROARGMODE_INOUT ||
1675
0
           argmodes[i] == PROARGMODE_TABLE);
1676
0
      if (++numoutargs > 1)
1677
0
      {
1678
        /* multiple out args, so forget it */
1679
0
        result = NULL;
1680
0
        break;
1681
0
      }
1682
0
      result = TextDatumGetCString(argnames[i]);
1683
0
      if (result == NULL || result[0] == '\0')
1684
0
      {
1685
        /* Parameter is not named, so forget it */
1686
0
        result = NULL;
1687
0
        break;
1688
0
      }
1689
0
    }
1690
0
  }
1691
1692
0
  ReleaseSysCache(procTuple);
1693
1694
0
  return result;
1695
0
}
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
build_function_result_tupdesc_t(HeapTuple procTuple)
1709
0
{
1710
0
  Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(procTuple);
1711
0
  Datum   proallargtypes;
1712
0
  Datum   proargmodes;
1713
0
  Datum   proargnames;
1714
0
  bool    isnull;
1715
1716
  /* Return NULL if the function isn't declared to return RECORD */
1717
0
  if (procform->prorettype != RECORDOID)
1718
0
    return NULL;
1719
1720
  /* If there are no OUT parameters, return NULL */
1721
0
  if (heap_attisnull(procTuple, Anum_pg_proc_proallargtypes, NULL) ||
1722
0
    heap_attisnull(procTuple, Anum_pg_proc_proargmodes, NULL))
1723
0
    return NULL;
1724
1725
  /* Get the data out of the tuple */
1726
0
  proallargtypes = SysCacheGetAttrNotNull(PROCOID, procTuple,
1727
0
                      Anum_pg_proc_proallargtypes);
1728
0
  proargmodes = SysCacheGetAttrNotNull(PROCOID, procTuple,
1729
0
                     Anum_pg_proc_proargmodes);
1730
0
  proargnames = SysCacheGetAttr(PROCOID, procTuple,
1731
0
                  Anum_pg_proc_proargnames,
1732
0
                  &isnull);
1733
0
  if (isnull)
1734
0
    proargnames = PointerGetDatum(NULL); /* just to be sure */
1735
1736
0
  return build_function_result_tupdesc_d(procform->prokind,
1737
0
                       proallargtypes,
1738
0
                       proargmodes,
1739
0
                       proargnames);
1740
0
}
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
build_function_result_tupdesc_d(char prokind,
1755
                Datum proallargtypes,
1756
                Datum proargmodes,
1757
                Datum proargnames)
1758
0
{
1759
0
  TupleDesc desc;
1760
0
  ArrayType  *arr;
1761
0
  int     numargs;
1762
0
  Oid      *argtypes;
1763
0
  char     *argmodes;
1764
0
  Datum    *argnames = NULL;
1765
0
  Oid      *outargtypes;
1766
0
  char    **outargnames;
1767
0
  int     numoutargs;
1768
0
  int     nargnames;
1769
0
  int     i;
1770
1771
  /* Can't have output args if columns are null */
1772
0
  if (proallargtypes == PointerGetDatum(NULL) ||
1773
0
    proargmodes == PointerGetDatum(NULL))
1774
0
    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
0
  arr = DatumGetArrayTypeP(proallargtypes); /* ensure not toasted */
1782
0
  numargs = ARR_DIMS(arr)[0];
1783
0
  if (ARR_NDIM(arr) != 1 ||
1784
0
    numargs < 0 ||
1785
0
    ARR_HASNULL(arr) ||
1786
0
    ARR_ELEMTYPE(arr) != OIDOID)
1787
0
    elog(ERROR, "proallargtypes is not a 1-D Oid array or it contains nulls");
1788
0
  argtypes = (Oid *) ARR_DATA_PTR(arr);
1789
0
  arr = DatumGetArrayTypeP(proargmodes);  /* ensure not toasted */
1790
0
  if (ARR_NDIM(arr) != 1 ||
1791
0
    ARR_DIMS(arr)[0] != numargs ||
1792
0
    ARR_HASNULL(arr) ||
1793
0
    ARR_ELEMTYPE(arr) != CHAROID)
1794
0
    elog(ERROR, "proargmodes is not a 1-D char array of length %d or it contains nulls",
1795
0
       numargs);
1796
0
  argmodes = (char *) ARR_DATA_PTR(arr);
1797
0
  if (proargnames != PointerGetDatum(NULL))
1798
0
  {
1799
0
    arr = DatumGetArrayTypeP(proargnames);  /* ensure not toasted */
1800
0
    if (ARR_NDIM(arr) != 1 ||
1801
0
      ARR_DIMS(arr)[0] != numargs ||
1802
0
      ARR_HASNULL(arr) ||
1803
0
      ARR_ELEMTYPE(arr) != TEXTOID)
1804
0
      elog(ERROR, "proargnames is not a 1-D text array of length %d or it contains nulls",
1805
0
         numargs);
1806
0
    deconstruct_array_builtin(arr, TEXTOID, &argnames, NULL, &nargnames);
1807
0
    Assert(nargnames == numargs);
1808
0
  }
1809
1810
  /* zero elements probably shouldn't happen, but handle it gracefully */
1811
0
  if (numargs <= 0)
1812
0
    return NULL;
1813
1814
  /* extract output-argument types and names */
1815
0
  outargtypes = (Oid *) palloc(numargs * sizeof(Oid));
1816
0
  outargnames = (char **) palloc(numargs * sizeof(char *));
1817
0
  numoutargs = 0;
1818
0
  for (i = 0; i < numargs; i++)
1819
0
  {
1820
0
    char     *pname;
1821
1822
0
    if (argmodes[i] == PROARGMODE_IN ||
1823
0
      argmodes[i] == PROARGMODE_VARIADIC)
1824
0
      continue;
1825
0
    Assert(argmodes[i] == PROARGMODE_OUT ||
1826
0
         argmodes[i] == PROARGMODE_INOUT ||
1827
0
         argmodes[i] == PROARGMODE_TABLE);
1828
0
    outargtypes[numoutargs] = argtypes[i];
1829
0
    if (argnames)
1830
0
      pname = TextDatumGetCString(argnames[i]);
1831
0
    else
1832
0
      pname = NULL;
1833
0
    if (pname == NULL || pname[0] == '\0')
1834
0
    {
1835
      /* Parameter is not named, so gin up a column name */
1836
0
      pname = psprintf("column%d", numoutargs + 1);
1837
0
    }
1838
0
    outargnames[numoutargs] = pname;
1839
0
    numoutargs++;
1840
0
  }
1841
1842
  /*
1843
   * If there is no output argument, or only one, the function does not
1844
   * return tuples.
1845
   */
1846
0
  if (numoutargs < 2 && prokind != PROKIND_PROCEDURE)
1847
0
    return NULL;
1848
1849
0
  desc = CreateTemplateTupleDesc(numoutargs);
1850
0
  for (i = 0; i < numoutargs; i++)
1851
0
  {
1852
0
    TupleDescInitEntry(desc, i + 1,
1853
0
               outargnames[i],
1854
0
               outargtypes[i],
1855
0
               -1,
1856
0
               0);
1857
0
  }
1858
1859
0
  TupleDescFinalize(desc);
1860
1861
0
  return desc;
1862
0
}
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
RelationNameGetTupleDesc(const char *relname)
1876
0
{
1877
0
  RangeVar   *relvar;
1878
0
  Relation  rel;
1879
0
  TupleDesc tupdesc;
1880
0
  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
0
}
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
TypeGetTupleDesc(Oid typeoid, List *colaliases)
1909
0
{
1910
0
  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
0
  {
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
0
    {
1927
0
      int     natts = tupdesc->natts;
1928
0
      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
0
            (errcode(ERRCODE_DATATYPE_MISMATCH),
1934
0
             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
0
      {
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
0
      }
1945
1946
      /* The tuple type is now an anonymous record type */
1947
0
      tupdesc->tdtypeid = RECORDOID;
1948
0
      tupdesc->tdtypmod = -1;
1949
0
    }
1950
0
  }
1951
0
  else if (functypclass == TYPEFUNC_SCALAR)
1952
0
  {
1953
    /* Base data type, i.e. scalar */
1954
0
    char     *attname;
1955
1956
    /* the alias list is required for base types */
1957
0
    if (colaliases == NIL)
1958
0
      ereport(ERROR,
1959
0
          (errcode(ERRCODE_DATATYPE_MISMATCH),
1960
0
           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
0
          (errcode(ERRCODE_DATATYPE_MISMATCH),
1966
0
           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
0
               (AttrNumber) 1,
1974
0
               attname,
1975
0
               typeoid,
1976
0
               -1,
1977
0
               0);
1978
0
    TupleDescFinalize(tupdesc);
1979
0
  }
1980
0
  else if (functypclass == TYPEFUNC_RECORD)
1981
0
  {
1982
    /* XXX can't support this because typmod wasn't passed in ... */
1983
0
    ereport(ERROR,
1984
0
        (errcode(ERRCODE_DATATYPE_MISMATCH),
1985
0
         errmsg("could not determine row description for function returning record")));
1986
0
  }
1987
0
  else
1988
0
  {
1989
    /* crummy error message, but parser should have caught this */
1990
0
    elog(ERROR, "function in FROM has unsupported return type");
1991
0
  }
1992
1993
0
  return tupdesc;
1994
0
}
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
extract_variadic_args(FunctionCallInfo fcinfo, int variadic_start,
2012
            bool convert_unknown, Datum **args, Oid **types,
2013
            bool **nulls)
2014
0
{
2015
0
  bool    variadic = get_fn_expr_variadic(fcinfo->flinfo);
2016
0
  Datum    *args_res;
2017
0
  bool     *nulls_res;
2018
0
  Oid      *types_res;
2019
0
  int     nargs,
2020
0
        i;
2021
2022
0
  *args = NULL;
2023
0
  *types = NULL;
2024
0
  *nulls = NULL;
2025
2026
0
  if (variadic)
2027
0
  {
2028
0
    ArrayType  *array_in;
2029
0
    Oid     element_type;
2030
0
    bool    typbyval;
2031
0
    char    typalign;
2032
0
    int16   typlen;
2033
2034
0
    Assert(PG_NARGS() == variadic_start + 1);
2035
2036
0
    if (PG_ARGISNULL(variadic_start))
2037
0
      return -1;
2038
2039
0
    array_in = PG_GETARG_ARRAYTYPE_P(variadic_start);
2040
0
    element_type = ARR_ELEMTYPE(array_in);
2041
2042
0
    get_typlenbyvalalign(element_type,
2043
0
               &typlen, &typbyval, &typalign);
2044
0
    deconstruct_array(array_in, element_type, typlen, typbyval,
2045
0
              typalign, &args_res, &nulls_res,
2046
0
              &nargs);
2047
2048
    /* All the elements of the array have the same type */
2049
0
    types_res = (Oid *) palloc0(nargs * sizeof(Oid));
2050
0
    for (i = 0; i < nargs; i++)
2051
0
      types_res[i] = element_type;
2052
0
  }
2053
0
  else
2054
0
  {
2055
0
    nargs = PG_NARGS() - variadic_start;
2056
0
    Assert(nargs > 0);
2057
0
    nulls_res = (bool *) palloc0(nargs * sizeof(bool));
2058
0
    args_res = (Datum *) palloc0(nargs * sizeof(Datum));
2059
0
    types_res = (Oid *) palloc0(nargs * sizeof(Oid));
2060
2061
0
    for (i = 0; i < nargs; i++)
2062
0
    {
2063
0
      nulls_res[i] = PG_ARGISNULL(i + variadic_start);
2064
0
      types_res[i] = get_fn_expr_argtype(fcinfo->flinfo,
2065
0
                         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
0
      if (convert_unknown &&
2075
0
        types_res[i] == UNKNOWNOID &&
2076
0
        get_fn_expr_arg_stable(fcinfo->flinfo, i + variadic_start))
2077
0
      {
2078
0
        types_res[i] = TEXTOID;
2079
2080
0
        if (PG_ARGISNULL(i + variadic_start))
2081
0
          args_res[i] = (Datum) 0;
2082
0
        else
2083
0
          args_res[i] =
2084
0
            CStringGetTextDatum(PG_GETARG_POINTER(i + variadic_start));
2085
0
      }
2086
0
      else
2087
0
      {
2088
        /* no conversion needed, just take the datum as given */
2089
0
        args_res[i] = PG_GETARG_DATUM(i + variadic_start);
2090
0
      }
2091
2092
0
      if (!OidIsValid(types_res[i]) ||
2093
0
        (convert_unknown && types_res[i] == UNKNOWNOID))
2094
0
        ereport(ERROR,
2095
0
            (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2096
0
             errmsg("could not determine data type for argument %d",
2097
0
                i + 1)));
2098
0
    }
2099
0
  }
2100
2101
  /* Fill in results */
2102
0
  *args = args_res;
2103
0
  *nulls = nulls_res;
2104
0
  *types = types_res;
2105
2106
0
  return nargs;
2107
0
}