Coverage Report

Created: 2025-06-15 06:31

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