LCOV - code coverage report
Current view: top level - src/backend/utils/fmgr - funcapi.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 81.9 % 1013 830
Test Date: 2026-01-26 10:56:24 Functions: 92.3 % 26 24
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 54.7 % 763 417

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * funcapi.c
       4                 :             :  *        Utility and convenience functions for fmgr functions that return
       5                 :             :  *        sets and/or composite types, or deal with VARIADIC inputs.
       6                 :             :  *
       7                 :             :  * Copyright (c) 2002-2026, PostgreSQL Global Development Group
       8                 :             :  *
       9                 :             :  * IDENTIFICATION
      10                 :             :  *        src/backend/utils/fmgr/funcapi.c
      11                 :             :  *
      12                 :             :  *-------------------------------------------------------------------------
      13                 :             :  */
      14                 :             : #include "postgres.h"
      15                 :             : 
      16                 :             : #include "access/htup_details.h"
      17                 :             : #include "access/relation.h"
      18                 :             : #include "catalog/namespace.h"
      19                 :             : #include "catalog/pg_proc.h"
      20                 :             : #include "catalog/pg_type.h"
      21                 :             : #include "funcapi.h"
      22                 :             : #include "miscadmin.h"
      23                 :             : #include "nodes/nodeFuncs.h"
      24                 :             : #include "utils/array.h"
      25                 :             : #include "utils/builtins.h"
      26                 :             : #include "utils/lsyscache.h"
      27                 :             : #include "utils/memutils.h"
      28                 :             : #include "utils/regproc.h"
      29                 :             : #include "utils/rel.h"
      30                 :             : #include "utils/syscache.h"
      31                 :             : #include "utils/tuplestore.h"
      32                 :             : #include "utils/typcache.h"
      33                 :             : 
      34                 :             : 
      35                 :             : typedef struct polymorphic_actuals
      36                 :             : {
      37                 :             :         Oid                     anyelement_type;        /* anyelement mapping, if known */
      38                 :             :         Oid                     anyarray_type;  /* anyarray mapping, if known */
      39                 :             :         Oid                     anyrange_type;  /* anyrange mapping, if known */
      40                 :             :         Oid                     anymultirange_type; /* anymultirange mapping, if known */
      41                 :             : } polymorphic_actuals;
      42                 :             : 
      43                 :             : static void shutdown_MultiFuncCall(Datum arg);
      44                 :             : static TypeFuncClass internal_get_result_type(Oid funcid,
      45                 :             :                                                                                           Node *call_expr,
      46                 :             :                                                                                           ReturnSetInfo *rsinfo,
      47                 :             :                                                                                           Oid *resultTypeId,
      48                 :             :                                                                                           TupleDesc *resultTupleDesc);
      49                 :             : static void resolve_anyelement_from_others(polymorphic_actuals *actuals);
      50                 :             : static void resolve_anyarray_from_others(polymorphic_actuals *actuals);
      51                 :             : static void resolve_anyrange_from_others(polymorphic_actuals *actuals);
      52                 :             : static void resolve_anymultirange_from_others(polymorphic_actuals *actuals);
      53                 :             : static bool resolve_polymorphic_tupdesc(TupleDesc tupdesc,
      54                 :             :                                                                                 oidvector *declared_args,
      55                 :             :                                                                                 Node *call_expr);
      56                 :             : static TypeFuncClass get_type_func_class(Oid typid, Oid *base_typeid);
      57                 :             : 
      58                 :             : 
      59                 :             : /*
      60                 :             :  * InitMaterializedSRF
      61                 :             :  *
      62                 :             :  * Helper function to build the state of a set-returning function used
      63                 :             :  * in the context of a single call with materialize mode.  This code
      64                 :             :  * includes sanity checks on ReturnSetInfo, creates the Tuplestore and
      65                 :             :  * the TupleDesc used with the function and stores them into the
      66                 :             :  * function's ReturnSetInfo.
      67                 :             :  *
      68                 :             :  * "flags" can be set to MAT_SRF_USE_EXPECTED_DESC, to use the tuple
      69                 :             :  * descriptor coming from expectedDesc, which is the tuple descriptor
      70                 :             :  * expected by the caller.  MAT_SRF_BLESS can be set to complete the
      71                 :             :  * information associated to the tuple descriptor, which is necessary
      72                 :             :  * in some cases where the tuple descriptor comes from a transient
      73                 :             :  * RECORD datatype.
      74                 :             :  */
      75                 :             : void
      76                 :        2437 : InitMaterializedSRF(FunctionCallInfo fcinfo, bits32 flags)
      77                 :             : {
      78                 :        2437 :         bool            random_access;
      79                 :        2437 :         ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
      80                 :        2437 :         Tuplestorestate *tupstore;
      81                 :        2437 :         MemoryContext old_context,
      82                 :             :                                 per_query_ctx;
      83                 :        2437 :         TupleDesc       stored_tupdesc;
      84                 :             : 
      85                 :             :         /* check to see if caller supports returning a tuplestore */
      86         [ +  - ]:        2437 :         if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
      87   [ #  #  #  # ]:           0 :                 ereport(ERROR,
      88                 :             :                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
      89                 :             :                                  errmsg("set-valued function called in context that cannot accept a set")));
      90         [ +  - ]:        2641 :         if (!(rsinfo->allowedModes & SFRM_Materialize) ||
      91         [ +  + ]:        2437 :                 ((flags & MAT_SRF_USE_EXPECTED_DESC) != 0 && rsinfo->expectedDesc == NULL))
      92   [ #  #  #  # ]:           0 :                 ereport(ERROR,
      93                 :             :                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
      94                 :             :                                  errmsg("materialize mode required, but it is not allowed in this context")));
      95                 :             : 
      96                 :             :         /*
      97                 :             :          * Store the tuplestore and the tuple descriptor in ReturnSetInfo.  This
      98                 :             :          * must be done in the per-query memory context.
      99                 :             :          */
     100                 :        2437 :         per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
     101                 :        2437 :         old_context = MemoryContextSwitchTo(per_query_ctx);
     102                 :             : 
     103                 :             :         /* build a tuple descriptor for our result type */
     104         [ +  + ]:        2437 :         if ((flags & MAT_SRF_USE_EXPECTED_DESC) != 0)
     105                 :         204 :                 stored_tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc);
     106                 :             :         else
     107                 :             :         {
     108         [ +  - ]:        2233 :                 if (get_call_result_type(fcinfo, NULL, &stored_tupdesc) != TYPEFUNC_COMPOSITE)
     109   [ #  #  #  # ]:           0 :                         elog(ERROR, "return type must be a row type");
     110                 :             :         }
     111                 :             : 
     112                 :             :         /* If requested, bless the tuple descriptor */
     113         [ +  + ]:        2437 :         if ((flags & MAT_SRF_BLESS) != 0)
     114                 :        2110 :                 BlessTupleDesc(stored_tupdesc);
     115                 :             : 
     116                 :        2437 :         random_access = (rsinfo->allowedModes & SFRM_Materialize_Random) != 0;
     117                 :             : 
     118                 :        2437 :         tupstore = tuplestore_begin_heap(random_access, false, work_mem);
     119                 :        2437 :         rsinfo->returnMode = SFRM_Materialize;
     120                 :        2437 :         rsinfo->setResult = tupstore;
     121                 :        2437 :         rsinfo->setDesc = stored_tupdesc;
     122                 :        2437 :         MemoryContextSwitchTo(old_context);
     123                 :        2437 : }
     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                 :       28398 : init_MultiFuncCall(PG_FUNCTION_ARGS)
     134                 :             : {
     135                 :       28398 :         FuncCallContext *retval;
     136                 :             : 
     137                 :             :         /*
     138                 :             :          * Bail if we're called in the wrong context
     139                 :             :          */
     140         [ +  - ]:       28398 :         if (fcinfo->resultinfo == NULL || !IsA(fcinfo->resultinfo, ReturnSetInfo))
     141   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     142                 :             :                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     143                 :             :                                  errmsg("set-valued function called in context that cannot accept a set")));
     144                 :             : 
     145         [ +  - ]:       28398 :         if (fcinfo->flinfo->fn_extra == NULL)
     146                 :             :         {
     147                 :             :                 /*
     148                 :             :                  * First call
     149                 :             :                  */
     150                 :       28398 :                 ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
     151                 :       28398 :                 MemoryContext multi_call_ctx;
     152                 :             : 
     153                 :             :                 /*
     154                 :             :                  * Create a suitably long-lived context to hold cross-call data
     155                 :             :                  */
     156                 :       28398 :                 multi_call_ctx = AllocSetContextCreate(fcinfo->flinfo->fn_mcxt,
     157                 :             :                                                                                            "SRF multi-call context",
     158                 :             :                                                                                            ALLOCSET_SMALL_SIZES);
     159                 :             : 
     160                 :             :                 /*
     161                 :             :                  * Allocate suitably long-lived space and zero it
     162                 :             :                  */
     163                 :       28398 :                 retval = (FuncCallContext *)
     164                 :       28398 :                         MemoryContextAllocZero(multi_call_ctx,
     165                 :             :                                                                    sizeof(FuncCallContext));
     166                 :             : 
     167                 :             :                 /*
     168                 :             :                  * initialize the elements
     169                 :             :                  */
     170                 :       28398 :                 retval->call_cntr = 0;
     171                 :       28398 :                 retval->max_calls = 0;
     172                 :       28398 :                 retval->user_fctx = NULL;
     173                 :       28398 :                 retval->attinmeta = NULL;
     174                 :       28398 :                 retval->tuple_desc = NULL;
     175                 :       28398 :                 retval->multi_call_memory_ctx = multi_call_ctx;
     176                 :             : 
     177                 :             :                 /*
     178                 :             :                  * save the pointer for cross-call use
     179                 :             :                  */
     180                 :       28398 :                 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                 :       56796 :                 RegisterExprContextCallback(rsi->econtext,
     187                 :             :                                                                         shutdown_MultiFuncCall,
     188                 :       28398 :                                                                         PointerGetDatum(fcinfo->flinfo));
     189                 :       28398 :         }
     190                 :             :         else
     191                 :             :         {
     192                 :             :                 /* second and subsequent calls */
     193   [ #  #  #  # ]:           0 :                 elog(ERROR, "init_MultiFuncCall cannot be called more than once");
     194                 :             : 
     195                 :             :                 /* never reached, but keep compiler happy */
     196                 :           0 :                 retval = NULL;
     197                 :             :         }
     198                 :             : 
     199                 :       56796 :         return retval;
     200                 :       28398 : }
     201                 :             : 
     202                 :             : /*
     203                 :             :  * per_MultiFuncCall
     204                 :             :  *
     205                 :             :  * Do Multi-function per-call setup
     206                 :             :  */
     207                 :             : FuncCallContext *
     208                 :     1825645 : per_MultiFuncCall(PG_FUNCTION_ARGS)
     209                 :             : {
     210                 :     1825645 :         FuncCallContext *retval = (FuncCallContext *) fcinfo->flinfo->fn_extra;
     211                 :             : 
     212                 :     3651290 :         return retval;
     213                 :     1825645 : }
     214                 :             : 
     215                 :             : /*
     216                 :             :  * end_MultiFuncCall
     217                 :             :  * Clean up after init_MultiFuncCall
     218                 :             :  */
     219                 :             : void
     220                 :       28150 : end_MultiFuncCall(PG_FUNCTION_ARGS, FuncCallContext *funcctx)
     221                 :             : {
     222                 :       28150 :         ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
     223                 :             : 
     224                 :             :         /* Deregister the shutdown callback */
     225                 :       56300 :         UnregisterExprContextCallback(rsi->econtext,
     226                 :             :                                                                   shutdown_MultiFuncCall,
     227                 :       28150 :                                                                   PointerGetDatum(fcinfo->flinfo));
     228                 :             : 
     229                 :             :         /* But use it to do the real work */
     230                 :       28150 :         shutdown_MultiFuncCall(PointerGetDatum(fcinfo->flinfo));
     231                 :       28150 : }
     232                 :             : 
     233                 :             : /*
     234                 :             :  * shutdown_MultiFuncCall
     235                 :             :  * Shutdown function to clean up after init_MultiFuncCall
     236                 :             :  */
     237                 :             : static void
     238                 :       28162 : shutdown_MultiFuncCall(Datum arg)
     239                 :             : {
     240                 :       28162 :         FmgrInfo   *flinfo = (FmgrInfo *) DatumGetPointer(arg);
     241                 :       28162 :         FuncCallContext *funcctx = (FuncCallContext *) flinfo->fn_extra;
     242                 :             : 
     243                 :             :         /* unbind from flinfo */
     244                 :       28162 :         flinfo->fn_extra = NULL;
     245                 :             : 
     246                 :             :         /*
     247                 :             :          * Delete context that holds all multi-call data, including the
     248                 :             :          * FuncCallContext itself
     249                 :             :          */
     250                 :       28162 :         MemoryContextDelete(funcctx->multi_call_memory_ctx);
     251                 :       28162 : }
     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                 :       10789 : get_call_result_type(FunctionCallInfo fcinfo,
     277                 :             :                                          Oid *resultTypeId,
     278                 :             :                                          TupleDesc *resultTupleDesc)
     279                 :             : {
     280                 :       21578 :         return internal_get_result_type(fcinfo->flinfo->fn_oid,
     281                 :       10789 :                                                                         fcinfo->flinfo->fn_expr,
     282                 :       10789 :                                                                         (ReturnSetInfo *) fcinfo->resultinfo,
     283                 :       10789 :                                                                         resultTypeId,
     284                 :       10789 :                                                                         resultTupleDesc);
     285                 :             : }
     286                 :             : 
     287                 :             : /*
     288                 :             :  * get_expr_result_type
     289                 :             :  *              As above, but work from a calling expression node tree
     290                 :             :  *
     291                 :             :  * Beware of using this on the funcexpr of a RTE that has a coldeflist.
     292                 :             :  * The correct conclusion in such cases is always that the function returns
     293                 :             :  * RECORD with the columns defined by the coldeflist fields (funccolnames etc).
     294                 :             :  * If it does not, it's the executor's responsibility to catch the discrepancy
     295                 :             :  * at runtime; but code processing the query in advance of that point might
     296                 :             :  * come to inconsistent conclusions if it checks the actual expression.
     297                 :             :  */
     298                 :             : TypeFuncClass
     299                 :       15361 : get_expr_result_type(Node *expr,
     300                 :             :                                          Oid *resultTypeId,
     301                 :             :                                          TupleDesc *resultTupleDesc)
     302                 :             : {
     303                 :       15361 :         TypeFuncClass result;
     304                 :             : 
     305   [ +  -  +  + ]:       15361 :         if (expr && IsA(expr, FuncExpr))
     306                 :       29696 :                 result = internal_get_result_type(((FuncExpr *) expr)->funcid,
     307                 :       14848 :                                                                                   expr,
     308                 :             :                                                                                   NULL,
     309                 :       14848 :                                                                                   resultTypeId,
     310                 :       14848 :                                                                                   resultTupleDesc);
     311   [ +  -  +  + ]:         513 :         else if (expr && IsA(expr, OpExpr))
     312                 :          10 :                 result = internal_get_result_type(get_opcode(((OpExpr *) expr)->opno),
     313                 :           5 :                                                                                   expr,
     314                 :             :                                                                                   NULL,
     315                 :           5 :                                                                                   resultTypeId,
     316                 :           5 :                                                                                   resultTupleDesc);
     317   [ +  -  +  +  :         508 :         else if (expr && IsA(expr, RowExpr) &&
                   -  + ]
     318                 :          16 :                          ((RowExpr *) expr)->row_typeid == RECORDOID)
     319                 :             :         {
     320                 :             :                 /* We can resolve the record type by generating the tupdesc directly */
     321                 :          16 :                 RowExpr    *rexpr = (RowExpr *) expr;
     322                 :          16 :                 TupleDesc       tupdesc;
     323                 :          16 :                 AttrNumber      i = 1;
     324                 :          16 :                 ListCell   *lcc,
     325                 :             :                                    *lcn;
     326                 :             : 
     327                 :          16 :                 tupdesc = CreateTemplateTupleDesc(list_length(rexpr->args));
     328         [ +  - ]:          16 :                 Assert(list_length(rexpr->args) == list_length(rexpr->colnames));
     329   [ +  -  +  +  :          47 :                 forboth(lcc, rexpr->args, lcn, rexpr->colnames)
          +  -  +  +  +  
                +  +  + ]
     330                 :             :                 {
     331                 :          31 :                         Node       *col = (Node *) lfirst(lcc);
     332                 :          31 :                         char       *colname = strVal(lfirst(lcn));
     333                 :             : 
     334                 :          62 :                         TupleDescInitEntry(tupdesc, i,
     335                 :          31 :                                                            colname,
     336                 :          31 :                                                            exprType(col),
     337                 :          31 :                                                            exprTypmod(col),
     338                 :             :                                                            0);
     339                 :          62 :                         TupleDescInitEntryCollation(tupdesc, i,
     340                 :          31 :                                                                                 exprCollation(col));
     341                 :          31 :                         i++;
     342                 :          31 :                 }
     343         [ -  + ]:          16 :                 if (resultTypeId)
     344                 :           0 :                         *resultTypeId = rexpr->row_typeid;
     345         [ +  - ]:          16 :                 if (resultTupleDesc)
     346                 :          16 :                         *resultTupleDesc = BlessTupleDesc(tupdesc);
     347                 :          16 :                 return TYPEFUNC_COMPOSITE;
     348                 :          16 :         }
     349   [ +  -  +  + ]:         492 :         else if (expr && IsA(expr, Const) &&
     350   [ +  +  -  + ]:          74 :                          ((Const *) expr)->consttype == RECORDOID &&
     351                 :           3 :                          !((Const *) expr)->constisnull)
     352                 :             :         {
     353                 :             :                 /*
     354                 :             :                  * When EXPLAIN'ing some queries with SEARCH/CYCLE clauses, we may
     355                 :             :                  * need to resolve field names of a RECORD-type Const.  The datum
     356                 :             :                  * should contain a typmod that will tell us that.
     357                 :             :                  */
     358                 :           3 :                 HeapTupleHeader rec;
     359                 :           3 :                 Oid                     tupType;
     360                 :           3 :                 int32           tupTypmod;
     361                 :             : 
     362                 :           3 :                 rec = DatumGetHeapTupleHeader(((Const *) expr)->constvalue);
     363                 :           3 :                 tupType = HeapTupleHeaderGetTypeId(rec);
     364                 :           3 :                 tupTypmod = HeapTupleHeaderGetTypMod(rec);
     365         [ +  - ]:           3 :                 if (resultTypeId)
     366                 :           0 :                         *resultTypeId = tupType;
     367   [ +  -  +  - ]:           3 :                 if (tupType != RECORDOID || tupTypmod >= 0)
     368                 :             :                 {
     369                 :             :                         /* Should be able to look it up */
     370         [ -  + ]:           3 :                         if (resultTupleDesc)
     371                 :           6 :                                 *resultTupleDesc = lookup_rowtype_tupdesc_copy(tupType,
     372                 :           3 :                                                                                                                            tupTypmod);
     373                 :           3 :                         return TYPEFUNC_COMPOSITE;
     374                 :             :                 }
     375                 :             :                 else
     376                 :             :                 {
     377                 :             :                         /* This shouldn't really happen ... */
     378         [ #  # ]:           0 :                         if (resultTupleDesc)
     379                 :           0 :                                 *resultTupleDesc = NULL;
     380                 :           0 :                         return TYPEFUNC_RECORD;
     381                 :             :                 }
     382                 :           3 :         }
     383                 :             :         else
     384                 :             :         {
     385                 :             :                 /* handle as a generic expression; no chance to resolve RECORD */
     386                 :         489 :                 Oid                     typid = exprType(expr);
     387                 :         489 :                 Oid                     base_typid;
     388                 :             : 
     389         [ +  + ]:         489 :                 if (resultTypeId)
     390                 :         114 :                         *resultTypeId = typid;
     391         [ +  - ]:         489 :                 if (resultTupleDesc)
     392                 :         489 :                         *resultTupleDesc = NULL;
     393                 :         489 :                 result = get_type_func_class(typid, &base_typid);
     394         [ +  + ]:         489 :                 if ((result == TYPEFUNC_COMPOSITE ||
     395         [ +  + ]:         489 :                          result == TYPEFUNC_COMPOSITE_DOMAIN) &&
     396                 :         489 :                         resultTupleDesc)
     397                 :         349 :                         *resultTupleDesc = lookup_rowtype_tupdesc_copy(base_typid, -1);
     398                 :         489 :         }
     399                 :             : 
     400                 :       15342 :         return result;
     401                 :       15361 : }
     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                 :         330 : get_func_result_type(Oid functionId,
     411                 :             :                                          Oid *resultTypeId,
     412                 :             :                                          TupleDesc *resultTupleDesc)
     413                 :             : {
     414                 :         660 :         return internal_get_result_type(functionId,
     415                 :             :                                                                         NULL,
     416                 :             :                                                                         NULL,
     417                 :         330 :                                                                         resultTypeId,
     418                 :         330 :                                                                         resultTupleDesc);
     419                 :             : }
     420                 :             : 
     421                 :             : /*
     422                 :             :  * internal_get_result_type -- workhorse code implementing all the above
     423                 :             :  *
     424                 :             :  * funcid must always be supplied.  call_expr and rsinfo can be NULL if not
     425                 :             :  * available.  We will return TYPEFUNC_RECORD, and store NULL into
     426                 :             :  * *resultTupleDesc, if we cannot deduce the complete result rowtype from
     427                 :             :  * the available information.
     428                 :             :  */
     429                 :             : static TypeFuncClass
     430                 :       35860 : internal_get_result_type(Oid funcid,
     431                 :             :                                                  Node *call_expr,
     432                 :             :                                                  ReturnSetInfo *rsinfo,
     433                 :             :                                                  Oid *resultTypeId,
     434                 :             :                                                  TupleDesc *resultTupleDesc)
     435                 :             : {
     436                 :       35860 :         TypeFuncClass result;
     437                 :       35860 :         HeapTuple       tp;
     438                 :       35860 :         Form_pg_proc procform;
     439                 :       35860 :         Oid                     rettype;
     440                 :       35860 :         Oid                     base_rettype;
     441                 :       35860 :         TupleDesc       tupdesc;
     442                 :             : 
     443                 :             :         /* First fetch the function's pg_proc row to inspect its rettype */
     444                 :       35860 :         tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
     445         [ +  - ]:       35860 :         if (!HeapTupleIsValid(tp))
     446   [ #  #  #  # ]:           0 :                 elog(ERROR, "cache lookup failed for function %u", funcid);
     447                 :       35860 :         procform = (Form_pg_proc) GETSTRUCT(tp);
     448                 :             : 
     449                 :       35860 :         rettype = procform->prorettype;
     450                 :             : 
     451                 :             :         /* Check for OUT parameters defining a RECORD result */
     452                 :       35860 :         tupdesc = build_function_result_tupdesc_t(tp);
     453         [ +  + ]:       35860 :         if (tupdesc)
     454                 :             :         {
     455                 :             :                 /*
     456                 :             :                  * It has OUT parameters, so it's basically like a regular composite
     457                 :             :                  * type, except we have to be able to resolve any polymorphic OUT
     458                 :             :                  * parameters.
     459                 :             :                  */
     460         [ +  + ]:       11714 :                 if (resultTypeId)
     461                 :        5236 :                         *resultTypeId = rettype;
     462                 :             : 
     463   [ +  -  +  - ]:       23428 :                 if (resolve_polymorphic_tupdesc(tupdesc,
     464                 :       11714 :                                                                                 &procform->proargtypes,
     465                 :       11714 :                                                                                 call_expr))
     466                 :             :                 {
     467   [ +  -  -  + ]:       11714 :                         if (tupdesc->tdtypeid == RECORDOID &&
     468                 :       11714 :                                 tupdesc->tdtypmod < 0)
     469                 :       11714 :                                 assign_record_type_typmod(tupdesc);
     470         [ -  + ]:       11714 :                         if (resultTupleDesc)
     471                 :       11714 :                                 *resultTupleDesc = tupdesc;
     472                 :       11714 :                         result = TYPEFUNC_COMPOSITE;
     473                 :       11714 :                 }
     474                 :             :                 else
     475                 :             :                 {
     476         [ #  # ]:           0 :                         if (resultTupleDesc)
     477                 :           0 :                                 *resultTupleDesc = NULL;
     478                 :           0 :                         result = TYPEFUNC_RECORD;
     479                 :             :                 }
     480                 :             : 
     481                 :       11714 :                 ReleaseSysCache(tp);
     482                 :             : 
     483                 :       11714 :                 return result;
     484                 :             :         }
     485                 :             : 
     486                 :             :         /*
     487                 :             :          * If scalar polymorphic result, try to resolve it.
     488                 :             :          */
     489   [ +  +  +  +  :       24146 :         if (IsPolymorphicType(rettype))
          +  -  +  -  +  
          +  +  +  +  +  
          +  +  +  -  +  
                      + ]
     490                 :             :         {
     491                 :       24146 :                 Oid                     newrettype = exprType(call_expr);
     492                 :             : 
     493         [ +  - ]:       24146 :                 if (newrettype == InvalidOid)   /* this probably should not happen */
     494   [ #  #  #  # ]:           0 :                         ereport(ERROR,
     495                 :             :                                         (errcode(ERRCODE_DATATYPE_MISMATCH),
     496                 :             :                                          errmsg("could not determine actual result type for function \"%s\" declared to return type %s",
     497                 :             :                                                         NameStr(procform->proname),
     498                 :             :                                                         format_type_be(rettype))));
     499                 :        1558 :                 rettype = newrettype;
     500                 :        1558 :         }
     501                 :             : 
     502         [ +  + ]:        1558 :         if (resultTypeId)
     503                 :       13514 :                 *resultTypeId = rettype;
     504         [ +  + ]:       25470 :         if (resultTupleDesc)
     505                 :       14258 :                 *resultTupleDesc = NULL;        /* default result */
     506                 :             : 
     507                 :             :         /* Classify the result type */
     508                 :       25470 :         result = get_type_func_class(rettype, &base_rettype);
     509   [ +  +  +  + ]:       25470 :         switch (result)
     510                 :             :         {
     511                 :             :                 case TYPEFUNC_COMPOSITE:
     512                 :             :                 case TYPEFUNC_COMPOSITE_DOMAIN:
     513         [ +  - ]:         980 :                         if (resultTupleDesc)
     514                 :         980 :                                 *resultTupleDesc = lookup_rowtype_tupdesc_copy(base_rettype, -1);
     515                 :             :                         /* Named composite types can't have any polymorphic columns */
     516                 :         980 :                         break;
     517                 :             :                 case TYPEFUNC_SCALAR:
     518                 :             :                         break;
     519                 :             :                 case TYPEFUNC_RECORD:
     520                 :             :                         /* We must get the tupledesc from call context */
     521   [ +  +  +  -  :         198 :                         if (rsinfo && IsA(rsinfo, ReturnSetInfo) &&
                   +  + ]
     522                 :          83 :                                 rsinfo->expectedDesc != NULL)
     523                 :             :                         {
     524                 :          73 :                                 result = TYPEFUNC_COMPOSITE;
     525         [ -  + ]:          73 :                                 if (resultTupleDesc)
     526                 :          73 :                                         *resultTupleDesc = rsinfo->expectedDesc;
     527                 :             :                                 /* Assume no polymorphic columns here, either */
     528                 :          73 :                         }
     529                 :         198 :                         break;
     530                 :             :                 default:
     531                 :           2 :                         break;
     532                 :             :         }
     533                 :             : 
     534                 :       25470 :         ReleaseSysCache(tp);
     535                 :             : 
     536                 :       25470 :         return result;
     537                 :       37184 : }
     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                 :        2330 : get_expr_result_tupdesc(Node *expr, bool noError)
     552                 :             : {
     553                 :        2330 :         TupleDesc       tupleDesc;
     554                 :        2330 :         TypeFuncClass functypclass;
     555                 :             : 
     556                 :        2330 :         functypclass = get_expr_result_type(expr, NULL, &tupleDesc);
     557                 :             : 
     558   [ +  +  +  + ]:        2330 :         if (functypclass == TYPEFUNC_COMPOSITE ||
     559                 :         155 :                 functypclass == TYPEFUNC_COMPOSITE_DOMAIN)
     560                 :        2197 :                 return tupleDesc;
     561                 :             : 
     562         [ +  - ]:         133 :         if (!noError)
     563                 :             :         {
     564                 :           0 :                 Oid                     exprTypeId = exprType(expr);
     565                 :             : 
     566         [ #  # ]:           0 :                 if (exprTypeId != RECORDOID)
     567   [ #  #  #  # ]:           0 :                         ereport(ERROR,
     568                 :             :                                         (errcode(ERRCODE_WRONG_OBJECT_TYPE),
     569                 :             :                                          errmsg("type %s is not composite",
     570                 :             :                                                         format_type_be(exprTypeId))));
     571                 :             :                 else
     572   [ #  #  #  # ]:           0 :                         ereport(ERROR,
     573                 :             :                                         (errcode(ERRCODE_WRONG_OBJECT_TYPE),
     574                 :             :                                          errmsg("record type has not been registered")));
     575                 :           0 :         }
     576                 :             : 
     577                 :         133 :         return NULL;
     578                 :        2330 : }
     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                 :          70 : resolve_anyelement_from_others(polymorphic_actuals *actuals)
     590                 :             : {
     591         [ +  + ]:          70 :         if (OidIsValid(actuals->anyarray_type))
     592                 :             :         {
     593                 :             :                 /* Use the element type corresponding to actual type */
     594                 :          33 :                 Oid                     array_base_type = getBaseType(actuals->anyarray_type);
     595                 :          33 :                 Oid                     array_typelem = get_element_type(array_base_type);
     596                 :             : 
     597         [ +  - ]:          33 :                 if (!OidIsValid(array_typelem))
     598   [ #  #  #  # ]:           0 :                         ereport(ERROR,
     599                 :             :                                         (errcode(ERRCODE_DATATYPE_MISMATCH),
     600                 :             :                                          errmsg("argument declared %s is not an array but type %s",
     601                 :             :                                                         "anyarray",
     602                 :             :                                                         format_type_be(array_base_type))));
     603                 :          33 :                 actuals->anyelement_type = array_typelem;
     604                 :          33 :         }
     605         [ +  + ]:          37 :         else if (OidIsValid(actuals->anyrange_type))
     606                 :             :         {
     607                 :             :                 /* Use the element type corresponding to actual type */
     608                 :          29 :                 Oid                     range_base_type = getBaseType(actuals->anyrange_type);
     609                 :          29 :                 Oid                     range_typelem = get_range_subtype(range_base_type);
     610                 :             : 
     611         [ +  - ]:          29 :                 if (!OidIsValid(range_typelem))
     612   [ #  #  #  # ]:           0 :                         ereport(ERROR,
     613                 :             :                                         (errcode(ERRCODE_DATATYPE_MISMATCH),
     614                 :             :                                          errmsg("argument declared %s is not a range type but type %s",
     615                 :             :                                                         "anyrange",
     616                 :             :                                                         format_type_be(range_base_type))));
     617                 :          29 :                 actuals->anyelement_type = range_typelem;
     618                 :          29 :         }
     619         [ +  - ]:           8 :         else if (OidIsValid(actuals->anymultirange_type))
     620                 :             :         {
     621                 :             :                 /* Use the element type based on the multirange type */
     622                 :           8 :                 Oid                     multirange_base_type;
     623                 :           8 :                 Oid                     multirange_typelem;
     624                 :           8 :                 Oid                     range_base_type;
     625                 :           8 :                 Oid                     range_typelem;
     626                 :             : 
     627                 :           8 :                 multirange_base_type = getBaseType(actuals->anymultirange_type);
     628                 :           8 :                 multirange_typelem = get_multirange_range(multirange_base_type);
     629         [ +  - ]:           8 :                 if (!OidIsValid(multirange_typelem))
     630   [ #  #  #  # ]:           0 :                         ereport(ERROR,
     631                 :             :                                         (errcode(ERRCODE_DATATYPE_MISMATCH),
     632                 :             :                                          errmsg("argument declared %s is not a multirange type but type %s",
     633                 :             :                                                         "anymultirange",
     634                 :             :                                                         format_type_be(multirange_base_type))));
     635                 :             : 
     636                 :           8 :                 range_base_type = getBaseType(multirange_typelem);
     637                 :           8 :                 range_typelem = get_range_subtype(range_base_type);
     638                 :             : 
     639         [ +  - ]:           8 :                 if (!OidIsValid(range_typelem))
     640   [ #  #  #  # ]:           0 :                         ereport(ERROR,
     641                 :             :                                         (errcode(ERRCODE_DATATYPE_MISMATCH),
     642                 :             :                                          errmsg("argument declared %s does not contain a range type but type %s",
     643                 :             :                                                         "anymultirange",
     644                 :             :                                                         format_type_be(range_base_type))));
     645                 :           8 :                 actuals->anyelement_type = range_typelem;
     646                 :           8 :         }
     647                 :             :         else
     648   [ #  #  #  # ]:           0 :                 elog(ERROR, "could not determine polymorphic type");
     649                 :          70 : }
     650                 :             : 
     651                 :             : /*
     652                 :             :  * Resolve actual type of ANYARRAY from other polymorphic inputs
     653                 :             :  */
     654                 :             : static void
     655                 :          67 : resolve_anyarray_from_others(polymorphic_actuals *actuals)
     656                 :             : {
     657                 :             :         /* If we don't know ANYELEMENT, resolve that first */
     658         [ +  + ]:          67 :         if (!OidIsValid(actuals->anyelement_type))
     659                 :          12 :                 resolve_anyelement_from_others(actuals);
     660                 :             : 
     661         [ +  - ]:          67 :         if (OidIsValid(actuals->anyelement_type))
     662                 :             :         {
     663                 :             :                 /* Use the array type corresponding to actual type */
     664                 :          67 :                 Oid                     array_typeid = get_array_type(actuals->anyelement_type);
     665                 :             : 
     666         [ +  - ]:          67 :                 if (!OidIsValid(array_typeid))
     667   [ #  #  #  # ]:           0 :                         ereport(ERROR,
     668                 :             :                                         (errcode(ERRCODE_UNDEFINED_OBJECT),
     669                 :             :                                          errmsg("could not find array type for data type %s",
     670                 :             :                                                         format_type_be(actuals->anyelement_type))));
     671                 :          67 :                 actuals->anyarray_type = array_typeid;
     672                 :          67 :         }
     673                 :             :         else
     674   [ #  #  #  # ]:           0 :                 elog(ERROR, "could not determine polymorphic type");
     675                 :          67 : }
     676                 :             : 
     677                 :             : /*
     678                 :             :  * Resolve actual type of ANYRANGE from other polymorphic inputs
     679                 :             :  */
     680                 :             : static void
     681                 :           4 : resolve_anyrange_from_others(polymorphic_actuals *actuals)
     682                 :             : {
     683                 :             :         /*
     684                 :             :          * We can't deduce a range type from other polymorphic array or base
     685                 :             :          * types, because there may be multiple range types with the same subtype,
     686                 :             :          * but we can deduce it from a polymorphic multirange type.
     687                 :             :          */
     688         [ +  - ]:           4 :         if (OidIsValid(actuals->anymultirange_type))
     689                 :             :         {
     690                 :             :                 /* Use the element type based on the multirange type */
     691                 :           4 :                 Oid                     multirange_base_type = getBaseType(actuals->anymultirange_type);
     692                 :           4 :                 Oid                     multirange_typelem = get_multirange_range(multirange_base_type);
     693                 :             : 
     694         [ +  - ]:           4 :                 if (!OidIsValid(multirange_typelem))
     695   [ #  #  #  # ]:           0 :                         ereport(ERROR,
     696                 :             :                                         (errcode(ERRCODE_DATATYPE_MISMATCH),
     697                 :             :                                          errmsg("argument declared %s is not a multirange type but type %s",
     698                 :             :                                                         "anymultirange",
     699                 :             :                                                         format_type_be(multirange_base_type))));
     700                 :           4 :                 actuals->anyrange_type = multirange_typelem;
     701                 :           4 :         }
     702                 :             :         else
     703   [ #  #  #  # ]:           0 :                 elog(ERROR, "could not determine polymorphic type");
     704                 :           4 : }
     705                 :             : 
     706                 :             : /*
     707                 :             :  * Resolve actual type of ANYMULTIRANGE from other polymorphic inputs
     708                 :             :  */
     709                 :             : static void
     710                 :           4 : resolve_anymultirange_from_others(polymorphic_actuals *actuals)
     711                 :             : {
     712                 :             :         /*
     713                 :             :          * We can't deduce a multirange type from polymorphic array or base types,
     714                 :             :          * because there may be multiple range types with the same subtype, but we
     715                 :             :          * can deduce it from a polymorphic range type.
     716                 :             :          */
     717         [ +  - ]:           4 :         if (OidIsValid(actuals->anyrange_type))
     718                 :             :         {
     719                 :           4 :                 Oid                     range_base_type = getBaseType(actuals->anyrange_type);
     720                 :           4 :                 Oid                     multirange_typeid = get_range_multirange(range_base_type);
     721                 :             : 
     722         [ +  - ]:           4 :                 if (!OidIsValid(multirange_typeid))
     723   [ #  #  #  # ]:           0 :                         ereport(ERROR,
     724                 :             :                                         (errcode(ERRCODE_UNDEFINED_OBJECT),
     725                 :             :                                          errmsg("could not find multirange type for data type %s",
     726                 :             :                                                         format_type_be(actuals->anyrange_type))));
     727                 :           4 :                 actuals->anymultirange_type = multirange_typeid;
     728                 :           4 :         }
     729                 :             :         else
     730   [ #  #  #  # ]:           0 :                 elog(ERROR, "could not determine polymorphic type");
     731                 :           4 : }
     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                 :       11714 : resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
     745                 :             :                                                         Node *call_expr)
     746                 :             : {
     747                 :       11714 :         int                     natts = tupdesc->natts;
     748                 :       11714 :         int                     nargs = declared_args->dim1;
     749                 :       11714 :         bool            have_polymorphic_result = false;
     750                 :       11714 :         bool            have_anyelement_result = false;
     751                 :       11714 :         bool            have_anyarray_result = false;
     752                 :       11714 :         bool            have_anyrange_result = false;
     753                 :       11714 :         bool            have_anymultirange_result = false;
     754                 :       11714 :         bool            have_anycompatible_result = false;
     755                 :       11714 :         bool            have_anycompatible_array_result = false;
     756                 :       11714 :         bool            have_anycompatible_range_result = false;
     757                 :       11714 :         bool            have_anycompatible_multirange_result = false;
     758                 :       11714 :         polymorphic_actuals poly_actuals;
     759                 :       11714 :         polymorphic_actuals anyc_actuals;
     760                 :       11714 :         Oid                     anycollation = InvalidOid;
     761                 :       11714 :         Oid                     anycompatcollation = InvalidOid;
     762                 :       11714 :         int                     i;
     763                 :             : 
     764                 :             :         /* See if there are any polymorphic outputs; quick out if not */
     765         [ +  + ]:       75065 :         for (i = 0; i < natts; i++)
     766                 :             :         {
     767   [ +  +  +  +  :       63351 :                 switch (TupleDescAttr(tupdesc, i)->atttypid)
             +  +  +  +  
                      - ]
     768                 :             :                 {
     769                 :             :                         case ANYELEMENTOID:
     770                 :             :                         case ANYNONARRAYOID:
     771                 :             :                         case ANYENUMOID:
     772                 :          88 :                                 have_polymorphic_result = true;
     773                 :          88 :                                 have_anyelement_result = true;
     774                 :          88 :                                 break;
     775                 :             :                         case ANYARRAYOID:
     776                 :          55 :                                 have_polymorphic_result = true;
     777                 :          55 :                                 have_anyarray_result = true;
     778                 :          55 :                                 break;
     779                 :             :                         case ANYRANGEOID:
     780                 :          12 :                                 have_polymorphic_result = true;
     781                 :          12 :                                 have_anyrange_result = true;
     782                 :          12 :                                 break;
     783                 :             :                         case ANYMULTIRANGEOID:
     784                 :          16 :                                 have_polymorphic_result = true;
     785                 :          16 :                                 have_anymultirange_result = true;
     786                 :          16 :                                 break;
     787                 :             :                         case ANYCOMPATIBLEOID:
     788                 :             :                         case ANYCOMPATIBLENONARRAYOID:
     789                 :          21 :                                 have_polymorphic_result = true;
     790                 :          21 :                                 have_anycompatible_result = true;
     791                 :          21 :                                 break;
     792                 :             :                         case ANYCOMPATIBLEARRAYOID:
     793                 :          41 :                                 have_polymorphic_result = true;
     794                 :          41 :                                 have_anycompatible_array_result = true;
     795                 :          41 :                                 break;
     796                 :             :                         case ANYCOMPATIBLERANGEOID:
     797                 :           6 :                                 have_polymorphic_result = true;
     798                 :           6 :                                 have_anycompatible_range_result = true;
     799                 :           6 :                                 break;
     800                 :             :                         case ANYCOMPATIBLEMULTIRANGEOID:
     801                 :           0 :                                 have_polymorphic_result = true;
     802                 :           0 :                                 have_anycompatible_multirange_result = true;
     803                 :           0 :                                 break;
     804                 :             :                         default:
     805                 :       63112 :                                 break;
     806                 :             :                 }
     807                 :       63351 :         }
     808         [ +  + ]:       11714 :         if (!have_polymorphic_result)
     809                 :       11569 :                 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         [ +  - ]:         145 :         if (!call_expr)
     819                 :           0 :                 return false;                   /* no hope */
     820                 :             : 
     821                 :         145 :         memset(&poly_actuals, 0, sizeof(poly_actuals));
     822                 :         145 :         memset(&anyc_actuals, 0, sizeof(anyc_actuals));
     823                 :             : 
     824         [ +  + ]:         367 :         for (i = 0; i < nargs; i++)
     825                 :             :         {
     826   [ +  +  -  +  :         222 :                 switch (declared_args->values[i])
             +  +  +  +  
                      - ]
     827                 :             :                 {
     828                 :             :                         case ANYELEMENTOID:
     829                 :             :                         case ANYNONARRAYOID:
     830                 :             :                         case ANYENUMOID:
     831         [ +  + ]:          55 :                                 if (!OidIsValid(poly_actuals.anyelement_type))
     832                 :             :                                 {
     833                 :          51 :                                         poly_actuals.anyelement_type =
     834                 :          51 :                                                 get_call_expr_argtype(call_expr, i);
     835         [ +  - ]:          51 :                                         if (!OidIsValid(poly_actuals.anyelement_type))
     836                 :           0 :                                                 return false;
     837                 :          51 :                                 }
     838                 :          55 :                                 break;
     839                 :             :                         case ANYARRAYOID:
     840         [ -  + ]:          53 :                                 if (!OidIsValid(poly_actuals.anyarray_type))
     841                 :             :                                 {
     842                 :          53 :                                         poly_actuals.anyarray_type =
     843                 :          53 :                                                 get_call_expr_argtype(call_expr, i);
     844         [ +  - ]:          53 :                                         if (!OidIsValid(poly_actuals.anyarray_type))
     845                 :           0 :                                                 return false;
     846                 :          53 :                                 }
     847                 :          53 :                                 break;
     848                 :             :                         case ANYRANGEOID:
     849         [ -  + ]:          24 :                                 if (!OidIsValid(poly_actuals.anyrange_type))
     850                 :             :                                 {
     851                 :          24 :                                         poly_actuals.anyrange_type =
     852                 :          24 :                                                 get_call_expr_argtype(call_expr, i);
     853         [ -  + ]:          24 :                                         if (!OidIsValid(poly_actuals.anyrange_type))
     854                 :           0 :                                                 return false;
     855                 :          24 :                                 }
     856                 :          24 :                                 break;
     857                 :             :                         case ANYMULTIRANGEOID:
     858         [ -  + ]:          20 :                                 if (!OidIsValid(poly_actuals.anymultirange_type))
     859                 :             :                                 {
     860                 :          20 :                                         poly_actuals.anymultirange_type =
     861                 :          20 :                                                 get_call_expr_argtype(call_expr, i);
     862         [ -  + ]:          20 :                                         if (!OidIsValid(poly_actuals.anymultirange_type))
     863                 :           0 :                                                 return false;
     864                 :          20 :                                 }
     865                 :          20 :                                 break;
     866                 :             :                         case ANYCOMPATIBLEOID:
     867                 :             :                         case ANYCOMPATIBLENONARRAYOID:
     868         [ +  + ]:          49 :                                 if (!OidIsValid(anyc_actuals.anyelement_type))
     869                 :             :                                 {
     870                 :          29 :                                         anyc_actuals.anyelement_type =
     871                 :          29 :                                                 get_call_expr_argtype(call_expr, i);
     872         [ -  + ]:          29 :                                         if (!OidIsValid(anyc_actuals.anyelement_type))
     873                 :           0 :                                                 return false;
     874                 :          29 :                                 }
     875                 :          49 :                                 break;
     876                 :             :                         case ANYCOMPATIBLEARRAYOID:
     877         [ -  + ]:           9 :                                 if (!OidIsValid(anyc_actuals.anyarray_type))
     878                 :             :                                 {
     879                 :           9 :                                         anyc_actuals.anyarray_type =
     880                 :           9 :                                                 get_call_expr_argtype(call_expr, i);
     881         [ +  - ]:           9 :                                         if (!OidIsValid(anyc_actuals.anyarray_type))
     882                 :           0 :                                                 return false;
     883                 :           9 :                                 }
     884                 :           9 :                                 break;
     885                 :             :                         case ANYCOMPATIBLERANGEOID:
     886         [ -  + ]:          12 :                                 if (!OidIsValid(anyc_actuals.anyrange_type))
     887                 :             :                                 {
     888                 :          12 :                                         anyc_actuals.anyrange_type =
     889                 :          12 :                                                 get_call_expr_argtype(call_expr, i);
     890         [ -  + ]:          12 :                                         if (!OidIsValid(anyc_actuals.anyrange_type))
     891                 :           0 :                                                 return false;
     892                 :          12 :                                 }
     893                 :          12 :                                 break;
     894                 :             :                         case ANYCOMPATIBLEMULTIRANGEOID:
     895         [ #  # ]:           0 :                                 if (!OidIsValid(anyc_actuals.anymultirange_type))
     896                 :             :                                 {
     897                 :           0 :                                         anyc_actuals.anymultirange_type =
     898                 :           0 :                                                 get_call_expr_argtype(call_expr, i);
     899         [ #  # ]:           0 :                                         if (!OidIsValid(anyc_actuals.anymultirange_type))
     900                 :           0 :                                                 return false;
     901                 :           0 :                                 }
     902                 :           0 :                                 break;
     903                 :             :                         default:
     904                 :           0 :                                 break;
     905                 :             :                 }
     906                 :         222 :         }
     907                 :             : 
     908                 :             :         /* If needed, deduce one polymorphic type from others */
     909   [ +  +  +  + ]:         145 :         if (have_anyelement_result && !OidIsValid(poly_actuals.anyelement_type))
     910                 :          45 :                 resolve_anyelement_from_others(&poly_actuals);
     911                 :             : 
     912   [ +  +  +  + ]:         145 :         if (have_anyarray_result && !OidIsValid(poly_actuals.anyarray_type))
     913                 :          31 :                 resolve_anyarray_from_others(&poly_actuals);
     914                 :             : 
     915   [ +  +  +  + ]:         145 :         if (have_anyrange_result && !OidIsValid(poly_actuals.anyrange_type))
     916                 :           4 :                 resolve_anyrange_from_others(&poly_actuals);
     917                 :             : 
     918   [ +  +  +  + ]:         145 :         if (have_anymultirange_result && !OidIsValid(poly_actuals.anymultirange_type))
     919                 :           4 :                 resolve_anymultirange_from_others(&poly_actuals);
     920                 :             : 
     921   [ +  +  +  + ]:         145 :         if (have_anycompatible_result && !OidIsValid(anyc_actuals.anyelement_type))
     922                 :          12 :                 resolve_anyelement_from_others(&anyc_actuals);
     923                 :             : 
     924   [ +  +  +  + ]:         145 :         if (have_anycompatible_array_result && !OidIsValid(anyc_actuals.anyarray_type))
     925                 :          32 :                 resolve_anyarray_from_others(&anyc_actuals);
     926                 :             : 
     927   [ +  +  +  - ]:         145 :         if (have_anycompatible_range_result && !OidIsValid(anyc_actuals.anyrange_type))
     928                 :           0 :                 resolve_anyrange_from_others(&anyc_actuals);
     929                 :             : 
     930   [ -  +  #  # ]:         145 :         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         [ +  + ]:         145 :         if (OidIsValid(poly_actuals.anyelement_type))
     941                 :         108 :                 anycollation = get_typcollation(poly_actuals.anyelement_type);
     942         [ +  - ]:          37 :         else if (OidIsValid(poly_actuals.anyarray_type))
     943                 :           0 :                 anycollation = get_typcollation(poly_actuals.anyarray_type);
     944                 :             : 
     945         [ +  + ]:         145 :         if (OidIsValid(anyc_actuals.anyelement_type))
     946                 :          41 :                 anycompatcollation = get_typcollation(anyc_actuals.anyelement_type);
     947         [ +  - ]:         104 :         else if (OidIsValid(anyc_actuals.anyarray_type))
     948                 :           0 :                 anycompatcollation = get_typcollation(anyc_actuals.anyarray_type);
     949                 :             : 
     950   [ +  +  +  + ]:         145 :         if (OidIsValid(anycollation) || OidIsValid(anycompatcollation))
     951                 :             :         {
     952                 :             :                 /*
     953                 :             :                  * The types are collatable, so consider whether to use a nondefault
     954                 :             :                  * collation.  We do so if we can identify the input collation used
     955                 :             :                  * for the function.
     956                 :             :                  */
     957                 :          13 :                 Oid                     inputcollation = exprInputCollation(call_expr);
     958                 :             : 
     959         [ +  + ]:          13 :                 if (OidIsValid(inputcollation))
     960                 :             :                 {
     961         [ -  + ]:           8 :                         if (OidIsValid(anycollation))
     962                 :           8 :                                 anycollation = inputcollation;
     963         [ +  - ]:           8 :                         if (OidIsValid(anycompatcollation))
     964                 :           0 :                                 anycompatcollation = inputcollation;
     965                 :           8 :                 }
     966                 :          13 :         }
     967                 :             : 
     968                 :             :         /* And finally replace the tuple column types as needed */
     969         [ +  + ]:         441 :         for (i = 0; i < natts; i++)
     970                 :             :         {
     971                 :         296 :                 Form_pg_attribute att = TupleDescAttr(tupdesc, i);
     972                 :             : 
     973   [ +  +  +  +  :         296 :                 switch (att->atttypid)
             +  +  +  +  
                      - ]
     974                 :             :                 {
     975                 :             :                         case ANYELEMENTOID:
     976                 :             :                         case ANYNONARRAYOID:
     977                 :             :                         case ANYENUMOID:
     978                 :         176 :                                 TupleDescInitEntry(tupdesc, i + 1,
     979                 :          88 :                                                                    NameStr(att->attname),
     980                 :          88 :                                                                    poly_actuals.anyelement_type,
     981                 :             :                                                                    -1,
     982                 :             :                                                                    0);
     983                 :          88 :                                 TupleDescInitEntryCollation(tupdesc, i + 1, anycollation);
     984                 :          88 :                                 break;
     985                 :             :                         case ANYARRAYOID:
     986                 :         110 :                                 TupleDescInitEntry(tupdesc, i + 1,
     987                 :          55 :                                                                    NameStr(att->attname),
     988                 :          55 :                                                                    poly_actuals.anyarray_type,
     989                 :             :                                                                    -1,
     990                 :             :                                                                    0);
     991                 :          55 :                                 TupleDescInitEntryCollation(tupdesc, i + 1, anycollation);
     992                 :          55 :                                 break;
     993                 :             :                         case ANYRANGEOID:
     994                 :          24 :                                 TupleDescInitEntry(tupdesc, i + 1,
     995                 :          12 :                                                                    NameStr(att->attname),
     996                 :          12 :                                                                    poly_actuals.anyrange_type,
     997                 :             :                                                                    -1,
     998                 :             :                                                                    0);
     999                 :             :                                 /* no collation should be attached to a range type */
    1000                 :          12 :                                 break;
    1001                 :             :                         case ANYMULTIRANGEOID:
    1002                 :          32 :                                 TupleDescInitEntry(tupdesc, i + 1,
    1003                 :          16 :                                                                    NameStr(att->attname),
    1004                 :          16 :                                                                    poly_actuals.anymultirange_type,
    1005                 :             :                                                                    -1,
    1006                 :             :                                                                    0);
    1007                 :             :                                 /* no collation should be attached to a multirange type */
    1008                 :          16 :                                 break;
    1009                 :             :                         case ANYCOMPATIBLEOID:
    1010                 :             :                         case ANYCOMPATIBLENONARRAYOID:
    1011                 :          42 :                                 TupleDescInitEntry(tupdesc, i + 1,
    1012                 :          21 :                                                                    NameStr(att->attname),
    1013                 :          21 :                                                                    anyc_actuals.anyelement_type,
    1014                 :             :                                                                    -1,
    1015                 :             :                                                                    0);
    1016                 :          21 :                                 TupleDescInitEntryCollation(tupdesc, i + 1, anycompatcollation);
    1017                 :          21 :                                 break;
    1018                 :             :                         case ANYCOMPATIBLEARRAYOID:
    1019                 :          82 :                                 TupleDescInitEntry(tupdesc, i + 1,
    1020                 :          41 :                                                                    NameStr(att->attname),
    1021                 :          41 :                                                                    anyc_actuals.anyarray_type,
    1022                 :             :                                                                    -1,
    1023                 :             :                                                                    0);
    1024                 :          41 :                                 TupleDescInitEntryCollation(tupdesc, i + 1, anycompatcollation);
    1025                 :          41 :                                 break;
    1026                 :             :                         case ANYCOMPATIBLERANGEOID:
    1027                 :          12 :                                 TupleDescInitEntry(tupdesc, i + 1,
    1028                 :           6 :                                                                    NameStr(att->attname),
    1029                 :           6 :                                                                    anyc_actuals.anyrange_type,
    1030                 :             :                                                                    -1,
    1031                 :             :                                                                    0);
    1032                 :             :                                 /* no collation should be attached to a range type */
    1033                 :           6 :                                 break;
    1034                 :             :                         case ANYCOMPATIBLEMULTIRANGEOID:
    1035                 :           0 :                                 TupleDescInitEntry(tupdesc, i + 1,
    1036                 :           0 :                                                                    NameStr(att->attname),
    1037                 :           0 :                                                                    anyc_actuals.anymultirange_type,
    1038                 :             :                                                                    -1,
    1039                 :             :                                                                    0);
    1040                 :             :                                 /* no collation should be attached to a multirange type */
    1041                 :           0 :                                 break;
    1042                 :             :                         default:
    1043                 :          57 :                                 break;
    1044                 :             :                 }
    1045                 :         296 :         }
    1046                 :             : 
    1047                 :         145 :         return true;
    1048                 :       11714 : }
    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                 :        2560 : resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes,
    1065                 :             :                                                          Node *call_expr)
    1066                 :             : {
    1067                 :        2560 :         bool            have_polymorphic_result = false;
    1068                 :        2560 :         bool            have_anyelement_result = false;
    1069                 :        2560 :         bool            have_anyarray_result = false;
    1070                 :        2560 :         bool            have_anyrange_result = false;
    1071                 :        2560 :         bool            have_anymultirange_result = false;
    1072                 :        2560 :         bool            have_anycompatible_result = false;
    1073                 :        2560 :         bool            have_anycompatible_array_result = false;
    1074                 :        2560 :         bool            have_anycompatible_range_result = false;
    1075                 :        2560 :         bool            have_anycompatible_multirange_result = false;
    1076                 :        2560 :         polymorphic_actuals poly_actuals;
    1077                 :        2560 :         polymorphic_actuals anyc_actuals;
    1078                 :        2560 :         int                     inargno;
    1079                 :        2560 :         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                 :        2560 :         memset(&poly_actuals, 0, sizeof(poly_actuals));
    1087                 :        2560 :         memset(&anyc_actuals, 0, sizeof(anyc_actuals));
    1088                 :        2560 :         inargno = 0;
    1089         [ +  + ]:        6545 :         for (i = 0; i < numargs; i++)
    1090                 :             :         {
    1091         [ +  + ]:        3985 :                 char            argmode = argmodes ? argmodes[i] : PROARGMODE_IN;
    1092                 :             : 
    1093   [ +  +  +  +  :        3985 :                 switch (argtypes[i])
             +  +  +  +  
                      - ]
    1094                 :             :                 {
    1095                 :             :                         case ANYELEMENTOID:
    1096                 :             :                         case ANYNONARRAYOID:
    1097                 :             :                         case ANYENUMOID:
    1098   [ +  +  -  + ]:         122 :                                 if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
    1099                 :             :                                 {
    1100                 :           1 :                                         have_polymorphic_result = true;
    1101                 :           1 :                                         have_anyelement_result = true;
    1102                 :           1 :                                 }
    1103                 :             :                                 else
    1104                 :             :                                 {
    1105         [ +  + ]:         121 :                                         if (!OidIsValid(poly_actuals.anyelement_type))
    1106                 :             :                                         {
    1107                 :         112 :                                                 poly_actuals.anyelement_type =
    1108                 :         112 :                                                         get_call_expr_argtype(call_expr, inargno);
    1109         [ +  - ]:         112 :                                                 if (!OidIsValid(poly_actuals.anyelement_type))
    1110                 :           0 :                                                         return false;
    1111                 :         112 :                                         }
    1112                 :         121 :                                         argtypes[i] = poly_actuals.anyelement_type;
    1113                 :             :                                 }
    1114                 :         122 :                                 break;
    1115                 :             :                         case ANYARRAYOID:
    1116   [ +  +  -  + ]:          92 :                                 if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
    1117                 :             :                                 {
    1118                 :           3 :                                         have_polymorphic_result = true;
    1119                 :           3 :                                         have_anyarray_result = true;
    1120                 :           3 :                                 }
    1121                 :             :                                 else
    1122                 :             :                                 {
    1123         [ +  + ]:          89 :                                         if (!OidIsValid(poly_actuals.anyarray_type))
    1124                 :             :                                         {
    1125                 :          87 :                                                 poly_actuals.anyarray_type =
    1126                 :          87 :                                                         get_call_expr_argtype(call_expr, inargno);
    1127         [ +  - ]:          87 :                                                 if (!OidIsValid(poly_actuals.anyarray_type))
    1128                 :           0 :                                                         return false;
    1129                 :          87 :                                         }
    1130                 :          89 :                                         argtypes[i] = poly_actuals.anyarray_type;
    1131                 :             :                                 }
    1132                 :          92 :                                 break;
    1133                 :             :                         case ANYRANGEOID:
    1134   [ +  -  -  + ]:          10 :                                 if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
    1135                 :             :                                 {
    1136                 :           0 :                                         have_polymorphic_result = true;
    1137                 :           0 :                                         have_anyrange_result = true;
    1138                 :           0 :                                 }
    1139                 :             :                                 else
    1140                 :             :                                 {
    1141         [ -  + ]:          10 :                                         if (!OidIsValid(poly_actuals.anyrange_type))
    1142                 :             :                                         {
    1143                 :          10 :                                                 poly_actuals.anyrange_type =
    1144                 :          10 :                                                         get_call_expr_argtype(call_expr, inargno);
    1145         [ +  - ]:          10 :                                                 if (!OidIsValid(poly_actuals.anyrange_type))
    1146                 :           0 :                                                         return false;
    1147                 :          10 :                                         }
    1148                 :          10 :                                         argtypes[i] = poly_actuals.anyrange_type;
    1149                 :             :                                 }
    1150                 :          10 :                                 break;
    1151                 :             :                         case ANYMULTIRANGEOID:
    1152   [ +  -  -  + ]:           5 :                                 if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
    1153                 :             :                                 {
    1154                 :           0 :                                         have_polymorphic_result = true;
    1155                 :           0 :                                         have_anymultirange_result = true;
    1156                 :           0 :                                 }
    1157                 :             :                                 else
    1158                 :             :                                 {
    1159         [ -  + ]:           5 :                                         if (!OidIsValid(poly_actuals.anymultirange_type))
    1160                 :             :                                         {
    1161                 :           5 :                                                 poly_actuals.anymultirange_type =
    1162                 :           5 :                                                         get_call_expr_argtype(call_expr, inargno);
    1163         [ -  + ]:           5 :                                                 if (!OidIsValid(poly_actuals.anymultirange_type))
    1164                 :           0 :                                                         return false;
    1165                 :           5 :                                         }
    1166                 :           5 :                                         argtypes[i] = poly_actuals.anymultirange_type;
    1167                 :             :                                 }
    1168                 :           5 :                                 break;
    1169                 :             :                         case ANYCOMPATIBLEOID:
    1170                 :             :                         case ANYCOMPATIBLENONARRAYOID:
    1171   [ +  +  -  + ]:          37 :                                 if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
    1172                 :             :                                 {
    1173                 :           1 :                                         have_polymorphic_result = true;
    1174                 :           1 :                                         have_anycompatible_result = true;
    1175                 :           1 :                                 }
    1176                 :             :                                 else
    1177                 :             :                                 {
    1178         [ +  + ]:          36 :                                         if (!OidIsValid(anyc_actuals.anyelement_type))
    1179                 :             :                                         {
    1180                 :          22 :                                                 anyc_actuals.anyelement_type =
    1181                 :          22 :                                                         get_call_expr_argtype(call_expr, inargno);
    1182         [ +  - ]:          22 :                                                 if (!OidIsValid(anyc_actuals.anyelement_type))
    1183                 :           0 :                                                         return false;
    1184                 :          22 :                                         }
    1185                 :          36 :                                         argtypes[i] = anyc_actuals.anyelement_type;
    1186                 :             :                                 }
    1187                 :          37 :                                 break;
    1188                 :             :                         case ANYCOMPATIBLEARRAYOID:
    1189   [ +  +  -  + ]:          14 :                                 if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
    1190                 :             :                                 {
    1191                 :           3 :                                         have_polymorphic_result = true;
    1192                 :           3 :                                         have_anycompatible_array_result = true;
    1193                 :           3 :                                 }
    1194                 :             :                                 else
    1195                 :             :                                 {
    1196         [ -  + ]:          11 :                                         if (!OidIsValid(anyc_actuals.anyarray_type))
    1197                 :             :                                         {
    1198                 :          11 :                                                 anyc_actuals.anyarray_type =
    1199                 :          11 :                                                         get_call_expr_argtype(call_expr, inargno);
    1200         [ +  - ]:          11 :                                                 if (!OidIsValid(anyc_actuals.anyarray_type))
    1201                 :           0 :                                                         return false;
    1202                 :          11 :                                         }
    1203                 :          11 :                                         argtypes[i] = anyc_actuals.anyarray_type;
    1204                 :             :                                 }
    1205                 :          14 :                                 break;
    1206                 :             :                         case ANYCOMPATIBLERANGEOID:
    1207   [ +  -  -  + ]:          12 :                                 if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
    1208                 :             :                                 {
    1209                 :           0 :                                         have_polymorphic_result = true;
    1210                 :           0 :                                         have_anycompatible_range_result = true;
    1211                 :           0 :                                 }
    1212                 :             :                                 else
    1213                 :             :                                 {
    1214         [ -  + ]:          12 :                                         if (!OidIsValid(anyc_actuals.anyrange_type))
    1215                 :             :                                         {
    1216                 :          12 :                                                 anyc_actuals.anyrange_type =
    1217                 :          12 :                                                         get_call_expr_argtype(call_expr, inargno);
    1218         [ +  - ]:          12 :                                                 if (!OidIsValid(anyc_actuals.anyrange_type))
    1219                 :           0 :                                                         return false;
    1220                 :          12 :                                         }
    1221                 :          12 :                                         argtypes[i] = anyc_actuals.anyrange_type;
    1222                 :             :                                 }
    1223                 :          12 :                                 break;
    1224                 :             :                         case ANYCOMPATIBLEMULTIRANGEOID:
    1225   [ #  #  #  # ]:           0 :                                 if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
    1226                 :             :                                 {
    1227                 :           0 :                                         have_polymorphic_result = true;
    1228                 :           0 :                                         have_anycompatible_multirange_result = true;
    1229                 :           0 :                                 }
    1230                 :             :                                 else
    1231                 :             :                                 {
    1232         [ #  # ]:           0 :                                         if (!OidIsValid(anyc_actuals.anymultirange_type))
    1233                 :             :                                         {
    1234                 :           0 :                                                 anyc_actuals.anymultirange_type =
    1235                 :           0 :                                                         get_call_expr_argtype(call_expr, inargno);
    1236         [ #  # ]:           0 :                                                 if (!OidIsValid(anyc_actuals.anymultirange_type))
    1237                 :           0 :                                                         return false;
    1238                 :           0 :                                         }
    1239                 :           0 :                                         argtypes[i] = anyc_actuals.anymultirange_type;
    1240                 :             :                                 }
    1241                 :           0 :                                 break;
    1242                 :             :                         default:
    1243                 :        3693 :                                 break;
    1244                 :             :                 }
    1245   [ +  +  +  + ]:        3985 :                 if (argmode != PROARGMODE_OUT && argmode != PROARGMODE_TABLE)
    1246                 :        3963 :                         inargno++;
    1247         [ -  + ]:        3985 :         }
    1248                 :             : 
    1249                 :             :         /* Done? */
    1250         [ +  + ]:        2560 :         if (!have_polymorphic_result)
    1251                 :        2556 :                 return true;
    1252                 :             : 
    1253                 :             :         /* If needed, deduce one polymorphic type from others */
    1254   [ +  +  +  - ]:           4 :         if (have_anyelement_result && !OidIsValid(poly_actuals.anyelement_type))
    1255                 :           0 :                 resolve_anyelement_from_others(&poly_actuals);
    1256                 :             : 
    1257   [ +  +  +  + ]:           4 :         if (have_anyarray_result && !OidIsValid(poly_actuals.anyarray_type))
    1258                 :           1 :                 resolve_anyarray_from_others(&poly_actuals);
    1259                 :             : 
    1260   [ -  +  #  # ]:           4 :         if (have_anyrange_result && !OidIsValid(poly_actuals.anyrange_type))
    1261                 :           0 :                 resolve_anyrange_from_others(&poly_actuals);
    1262                 :             : 
    1263   [ -  +  #  # ]:           4 :         if (have_anymultirange_result && !OidIsValid(poly_actuals.anymultirange_type))
    1264                 :           0 :                 resolve_anymultirange_from_others(&poly_actuals);
    1265                 :             : 
    1266   [ +  +  -  + ]:           4 :         if (have_anycompatible_result && !OidIsValid(anyc_actuals.anyelement_type))
    1267                 :           1 :                 resolve_anyelement_from_others(&anyc_actuals);
    1268                 :             : 
    1269   [ +  +  -  + ]:           4 :         if (have_anycompatible_array_result && !OidIsValid(anyc_actuals.anyarray_type))
    1270                 :           3 :                 resolve_anyarray_from_others(&anyc_actuals);
    1271                 :             : 
    1272   [ -  +  #  # ]:           4 :         if (have_anycompatible_range_result && !OidIsValid(anyc_actuals.anyrange_type))
    1273                 :           0 :                 resolve_anyrange_from_others(&anyc_actuals);
    1274                 :             : 
    1275   [ -  +  #  # ]:           4 :         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         [ +  + ]:          22 :         for (i = 0; i < numargs; i++)
    1280                 :             :         {
    1281   [ +  +  +  +  :          18 :                 switch (argtypes[i])
             -  -  +  -  
                      - ]
    1282                 :             :                 {
    1283                 :             :                         case ANYELEMENTOID:
    1284                 :             :                         case ANYNONARRAYOID:
    1285                 :             :                         case ANYENUMOID:
    1286                 :           1 :                                 argtypes[i] = poly_actuals.anyelement_type;
    1287                 :           1 :                                 break;
    1288                 :             :                         case ANYARRAYOID:
    1289                 :           3 :                                 argtypes[i] = poly_actuals.anyarray_type;
    1290                 :           3 :                                 break;
    1291                 :             :                         case ANYRANGEOID:
    1292                 :           0 :                                 argtypes[i] = poly_actuals.anyrange_type;
    1293                 :           0 :                                 break;
    1294                 :             :                         case ANYMULTIRANGEOID:
    1295                 :           0 :                                 argtypes[i] = poly_actuals.anymultirange_type;
    1296                 :           0 :                                 break;
    1297                 :             :                         case ANYCOMPATIBLEOID:
    1298                 :             :                         case ANYCOMPATIBLENONARRAYOID:
    1299                 :           1 :                                 argtypes[i] = anyc_actuals.anyelement_type;
    1300                 :           1 :                                 break;
    1301                 :             :                         case ANYCOMPATIBLEARRAYOID:
    1302                 :           3 :                                 argtypes[i] = anyc_actuals.anyarray_type;
    1303                 :           3 :                                 break;
    1304                 :             :                         case ANYCOMPATIBLERANGEOID:
    1305                 :           0 :                                 argtypes[i] = anyc_actuals.anyrange_type;
    1306                 :           0 :                                 break;
    1307                 :             :                         case ANYCOMPATIBLEMULTIRANGEOID:
    1308                 :           0 :                                 argtypes[i] = anyc_actuals.anymultirange_type;
    1309                 :           0 :                                 break;
    1310                 :             :                         default:
    1311                 :          10 :                                 break;
    1312                 :             :                 }
    1313                 :          18 :         }
    1314                 :             : 
    1315                 :           4 :         return true;
    1316                 :        2560 : }
    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                 :       14747 : get_type_func_class(Oid typid, Oid *base_typeid)
    1329                 :             : {
    1330                 :       14747 :         *base_typeid = typid;
    1331                 :             : 
    1332   [ +  -  +  +  :       14747 :         switch (get_typtype(typid))
                      + ]
    1333                 :             :         {
    1334                 :             :                 case TYPTYPE_COMPOSITE:
    1335                 :        1292 :                         return TYPEFUNC_COMPOSITE;
    1336                 :             :                 case TYPTYPE_BASE:
    1337                 :             :                 case TYPTYPE_ENUM:
    1338                 :             :                 case TYPTYPE_RANGE:
    1339                 :             :                 case TYPTYPE_MULTIRANGE:
    1340                 :       13081 :                         return TYPEFUNC_SCALAR;
    1341                 :             :                 case TYPTYPE_DOMAIN:
    1342                 :          40 :                         *base_typeid = typid = getBaseType(typid);
    1343         [ +  + ]:          40 :                         if (get_typtype(typid) == TYPTYPE_COMPOSITE)
    1344                 :          37 :                                 return TYPEFUNC_COMPOSITE_DOMAIN;
    1345                 :             :                         else                            /* domain base type can't be a pseudotype */
    1346                 :           3 :                                 return TYPEFUNC_SCALAR;
    1347                 :             :                 case TYPTYPE_PSEUDO:
    1348         [ +  + ]:         334 :                         if (typid == RECORDOID)
    1349                 :         202 :                                 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   [ +  +  -  + ]:         132 :                         if (typid == VOIDOID || typid == CSTRINGOID)
    1358                 :         130 :                                 return TYPEFUNC_SCALAR;
    1359                 :           2 :                         return TYPEFUNC_OTHER;
    1360                 :             :         }
    1361                 :             :         /* shouldn't get here, probably */
    1362                 :           0 :         return TYPEFUNC_OTHER;
    1363                 :       14747 : }
    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                 :        1270 : get_func_arg_info(HeapTuple procTup,
    1380                 :             :                                   Oid **p_argtypes, char ***p_argnames, char **p_argmodes)
    1381                 :             : {
    1382                 :        1270 :         Form_pg_proc procStruct = (Form_pg_proc) GETSTRUCT(procTup);
    1383                 :        1270 :         Datum           proallargtypes;
    1384                 :        1270 :         Datum           proargmodes;
    1385                 :        1270 :         Datum           proargnames;
    1386                 :        1270 :         bool            isNull;
    1387                 :        1270 :         ArrayType  *arr;
    1388                 :        1270 :         int                     numargs;
    1389                 :        1270 :         Datum      *elems;
    1390                 :        1270 :         int                     nelems;
    1391                 :        1270 :         int                     i;
    1392                 :             : 
    1393                 :             :         /* First discover the total number of parameters and get their types */
    1394                 :        1270 :         proallargtypes = SysCacheGetAttr(PROCOID, procTup,
    1395                 :             :                                                                          Anum_pg_proc_proallargtypes,
    1396                 :             :                                                                          &isNull);
    1397         [ +  + ]:        1270 :         if (!isNull)
    1398                 :             :         {
    1399                 :             :                 /*
    1400                 :             :                  * We expect the arrays to be 1-D arrays of the right types; verify
    1401                 :             :                  * that.  For the OID and char arrays, we don't need to use
    1402                 :             :                  * deconstruct_array() since the array data is just going to look like
    1403                 :             :                  * a C array of values.
    1404                 :             :                  */
    1405                 :         112 :                 arr = DatumGetArrayTypeP(proallargtypes);       /* ensure not toasted */
    1406                 :         112 :                 numargs = ARR_DIMS(arr)[0];
    1407         [ +  - ]:         112 :                 if (ARR_NDIM(arr) != 1 ||
    1408                 :         112 :                         numargs < 0 ||
    1409                 :         112 :                         ARR_HASNULL(arr) ||
    1410                 :         112 :                         ARR_ELEMTYPE(arr) != OIDOID)
    1411   [ #  #  #  # ]:           0 :                         elog(ERROR, "proallargtypes is not a 1-D Oid array or it contains nulls");
    1412         [ +  - ]:         112 :                 Assert(numargs >= procStruct->pronargs);
    1413                 :         112 :                 *p_argtypes = (Oid *) palloc(numargs * sizeof(Oid));
    1414         [ -  + ]:         112 :                 memcpy(*p_argtypes, ARR_DATA_PTR(arr),
    1415                 :             :                            numargs * sizeof(Oid));
    1416                 :         112 :         }
    1417                 :             :         else
    1418                 :             :         {
    1419                 :             :                 /* If no proallargtypes, use proargtypes */
    1420                 :        1158 :                 numargs = procStruct->proargtypes.dim1;
    1421         [ +  - ]:        1158 :                 Assert(numargs == procStruct->pronargs);
    1422                 :        1158 :                 *p_argtypes = (Oid *) palloc(numargs * sizeof(Oid));
    1423                 :        1158 :                 memcpy(*p_argtypes, procStruct->proargtypes.values,
    1424                 :             :                            numargs * sizeof(Oid));
    1425                 :             :         }
    1426                 :             : 
    1427                 :             :         /* Get argument names, if available */
    1428                 :        1270 :         proargnames = SysCacheGetAttr(PROCOID, procTup,
    1429                 :             :                                                                   Anum_pg_proc_proargnames,
    1430                 :             :                                                                   &isNull);
    1431         [ +  + ]:        1270 :         if (isNull)
    1432                 :         770 :                 *p_argnames = NULL;
    1433                 :             :         else
    1434                 :             :         {
    1435                 :         500 :                 deconstruct_array_builtin(DatumGetArrayTypeP(proargnames), TEXTOID,
    1436                 :             :                                                                   &elems, NULL, &nelems);
    1437         [ +  - ]:         500 :                 if (nelems != numargs)  /* should not happen */
    1438   [ #  #  #  # ]:           0 :                         elog(ERROR, "proargnames must have the same number of elements as the function has arguments");
    1439                 :         500 :                 *p_argnames = palloc_array(char *, numargs);
    1440         [ +  + ]:        1984 :                 for (i = 0; i < numargs; i++)
    1441                 :        1484 :                         (*p_argnames)[i] = TextDatumGetCString(elems[i]);
    1442                 :             :         }
    1443                 :             : 
    1444                 :             :         /* Get argument modes, if available */
    1445                 :        1270 :         proargmodes = SysCacheGetAttr(PROCOID, procTup,
    1446                 :             :                                                                   Anum_pg_proc_proargmodes,
    1447                 :             :                                                                   &isNull);
    1448         [ +  + ]:        1270 :         if (isNull)
    1449                 :        1158 :                 *p_argmodes = NULL;
    1450                 :             :         else
    1451                 :             :         {
    1452                 :         112 :                 arr = DatumGetArrayTypeP(proargmodes);  /* ensure not toasted */
    1453         [ +  - ]:         112 :                 if (ARR_NDIM(arr) != 1 ||
    1454                 :         112 :                         ARR_DIMS(arr)[0] != numargs ||
    1455                 :         112 :                         ARR_HASNULL(arr) ||
    1456                 :         112 :                         ARR_ELEMTYPE(arr) != CHAROID)
    1457   [ #  #  #  # ]:           0 :                         elog(ERROR, "proargmodes is not a 1-D char array of length %d or it contains nulls",
    1458                 :             :                                  numargs);
    1459                 :         112 :                 *p_argmodes = (char *) palloc(numargs * sizeof(char));
    1460         [ -  + ]:         112 :                 memcpy(*p_argmodes, ARR_DATA_PTR(arr),
    1461                 :             :                            numargs * sizeof(char));
    1462                 :             :         }
    1463                 :             : 
    1464                 :        2540 :         return numargs;
    1465                 :        1270 : }
    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                 :          24 : get_func_trftypes(HeapTuple procTup,
    1476                 :             :                                   Oid **p_trftypes)
    1477                 :             : {
    1478                 :          24 :         Datum           protrftypes;
    1479                 :          24 :         ArrayType  *arr;
    1480                 :          24 :         int                     nelems;
    1481                 :          24 :         bool            isNull;
    1482                 :             : 
    1483                 :          24 :         protrftypes = SysCacheGetAttr(PROCOID, procTup,
    1484                 :             :                                                                   Anum_pg_proc_protrftypes,
    1485                 :             :                                                                   &isNull);
    1486         [ +  - ]:          24 :         if (!isNull)
    1487                 :             :         {
    1488                 :             :                 /*
    1489                 :             :                  * We expect the arrays to be 1-D arrays of the right types; verify
    1490                 :             :                  * that.  For the OID and char arrays, we don't need to use
    1491                 :             :                  * deconstruct_array() since the array data is just going to look like
    1492                 :             :                  * a C array of values.
    1493                 :             :                  */
    1494                 :           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                 :             :                            nelems * sizeof(Oid));
    1504                 :             : 
    1505                 :           0 :                 return nelems;
    1506                 :             :         }
    1507                 :             :         else
    1508                 :          24 :                 return 0;
    1509                 :          24 : }
    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                 :         865 : get_func_input_arg_names(Datum proargnames, Datum proargmodes,
    1523                 :             :                                                  char ***arg_names)
    1524                 :             : {
    1525                 :         865 :         ArrayType  *arr;
    1526                 :         865 :         int                     numargs;
    1527                 :         865 :         Datum      *argnames;
    1528                 :         865 :         char       *argmodes;
    1529                 :         865 :         char      **inargnames;
    1530                 :         865 :         int                     numinargs;
    1531                 :         865 :         int                     i;
    1532                 :             : 
    1533                 :             :         /* Do nothing if null proargnames */
    1534         [ +  + ]:         865 :         if (proargnames == PointerGetDatum(NULL))
    1535                 :             :         {
    1536                 :         502 :                 *arg_names = NULL;
    1537                 :         502 :                 return 0;
    1538                 :             :         }
    1539                 :             : 
    1540                 :             :         /*
    1541                 :             :          * We expect the arrays to be 1-D arrays of the right types; verify that.
    1542                 :             :          * For proargmodes, we don't need to use deconstruct_array() since the
    1543                 :             :          * array data is just going to look like a C array of values.
    1544                 :             :          */
    1545                 :         363 :         arr = DatumGetArrayTypeP(proargnames);  /* ensure not toasted */
    1546         [ +  - ]:         363 :         if (ARR_NDIM(arr) != 1 ||
    1547                 :         363 :                 ARR_HASNULL(arr) ||
    1548                 :         363 :                 ARR_ELEMTYPE(arr) != TEXTOID)
    1549   [ #  #  #  # ]:           0 :                 elog(ERROR, "proargnames is not a 1-D text array or it contains nulls");
    1550                 :         363 :         deconstruct_array_builtin(arr, TEXTOID, &argnames, NULL, &numargs);
    1551         [ +  + ]:         363 :         if (proargmodes != PointerGetDatum(NULL))
    1552                 :             :         {
    1553                 :         131 :                 arr = DatumGetArrayTypeP(proargmodes);  /* ensure not toasted */
    1554         [ +  - ]:         131 :                 if (ARR_NDIM(arr) != 1 ||
    1555                 :         131 :                         ARR_DIMS(arr)[0] != numargs ||
    1556                 :         131 :                         ARR_HASNULL(arr) ||
    1557                 :         131 :                         ARR_ELEMTYPE(arr) != CHAROID)
    1558   [ #  #  #  # ]:           0 :                         elog(ERROR, "proargmodes is not a 1-D char array of length %d or it contains nulls",
    1559                 :             :                                  numargs);
    1560         [ -  + ]:         131 :                 argmodes = (char *) ARR_DATA_PTR(arr);
    1561                 :         131 :         }
    1562                 :             :         else
    1563                 :         232 :                 argmodes = NULL;
    1564                 :             : 
    1565                 :             :         /* zero elements probably shouldn't happen, but handle it gracefully */
    1566         [ -  + ]:         363 :         if (numargs <= 0)
    1567                 :             :         {
    1568                 :           0 :                 *arg_names = NULL;
    1569                 :           0 :                 return 0;
    1570                 :             :         }
    1571                 :             : 
    1572                 :             :         /* extract input-argument names */
    1573                 :         363 :         inargnames = (char **) palloc(numargs * sizeof(char *));
    1574                 :         363 :         numinargs = 0;
    1575         [ +  + ]:        1223 :         for (i = 0; i < numargs; i++)
    1576                 :             :         {
    1577         [ +  + ]:         860 :                 if (argmodes == NULL ||
    1578         [ +  + ]:         443 :                         argmodes[i] == PROARGMODE_IN ||
    1579   [ +  +  +  + ]:         271 :                         argmodes[i] == PROARGMODE_INOUT ||
    1580                 :         250 :                         argmodes[i] == PROARGMODE_VARIADIC)
    1581                 :             :                 {
    1582                 :         635 :                         char       *pname = TextDatumGetCString(argnames[i]);
    1583                 :             : 
    1584         [ +  + ]:         635 :                         if (pname[0] != '\0')
    1585                 :         621 :                                 inargnames[numinargs] = pname;
    1586                 :             :                         else
    1587                 :          14 :                                 inargnames[numinargs] = NULL;
    1588                 :         635 :                         numinargs++;
    1589                 :         635 :                 }
    1590                 :         860 :         }
    1591                 :             : 
    1592                 :         363 :         *arg_names = inargnames;
    1593                 :         363 :         return numinargs;
    1594                 :         865 : }
    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                 :        2205 : get_func_result_name(Oid functionId)
    1608                 :             : {
    1609                 :        2205 :         char       *result;
    1610                 :        2205 :         HeapTuple       procTuple;
    1611                 :        2205 :         Datum           proargmodes;
    1612                 :        2205 :         Datum           proargnames;
    1613                 :        2205 :         ArrayType  *arr;
    1614                 :        2205 :         int                     numargs;
    1615                 :        2205 :         char       *argmodes;
    1616                 :        2205 :         Datum      *argnames;
    1617                 :        2205 :         int                     numoutargs;
    1618                 :        2205 :         int                     nargnames;
    1619                 :        2205 :         int                     i;
    1620                 :             : 
    1621                 :             :         /* First fetch the function's pg_proc row */
    1622                 :        2205 :         procTuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(functionId));
    1623         [ +  - ]:        2205 :         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   [ +  +  +  + ]:        2205 :         if (heap_attisnull(procTuple, Anum_pg_proc_proargmodes, NULL) ||
    1628                 :         230 :                 heap_attisnull(procTuple, Anum_pg_proc_proargnames, NULL))
    1629                 :        1980 :                 result = NULL;
    1630                 :             :         else
    1631                 :             :         {
    1632                 :             :                 /* Get the data out of the tuple */
    1633                 :         225 :                 proargmodes = SysCacheGetAttrNotNull(PROCOID, procTuple,
    1634                 :             :                                                                                          Anum_pg_proc_proargmodes);
    1635                 :         225 :                 proargnames = SysCacheGetAttrNotNull(PROCOID, procTuple,
    1636                 :             :                                                                                          Anum_pg_proc_proargnames);
    1637                 :             : 
    1638                 :             :                 /*
    1639                 :             :                  * We expect the arrays to be 1-D arrays of the right types; verify
    1640                 :             :                  * that.  For the char array, we don't need to use deconstruct_array()
    1641                 :             :                  * since the array data is just going to look like a C array of
    1642                 :             :                  * values.
    1643                 :             :                  */
    1644                 :         225 :                 arr = DatumGetArrayTypeP(proargmodes);  /* ensure not toasted */
    1645                 :         225 :                 numargs = ARR_DIMS(arr)[0];
    1646         [ +  - ]:         225 :                 if (ARR_NDIM(arr) != 1 ||
    1647                 :         225 :                         numargs < 0 ||
    1648                 :         225 :                         ARR_HASNULL(arr) ||
    1649                 :         225 :                         ARR_ELEMTYPE(arr) != CHAROID)
    1650   [ #  #  #  # ]:           0 :                         elog(ERROR, "proargmodes is not a 1-D char array or it contains nulls");
    1651         [ -  + ]:         225 :                 argmodes = (char *) ARR_DATA_PTR(arr);
    1652                 :         225 :                 arr = DatumGetArrayTypeP(proargnames);  /* ensure not toasted */
    1653         [ +  - ]:         225 :                 if (ARR_NDIM(arr) != 1 ||
    1654                 :         225 :                         ARR_DIMS(arr)[0] != numargs ||
    1655                 :         225 :                         ARR_HASNULL(arr) ||
    1656                 :         225 :                         ARR_ELEMTYPE(arr) != TEXTOID)
    1657   [ #  #  #  # ]:           0 :                         elog(ERROR, "proargnames is not a 1-D text array of length %d or it contains nulls",
    1658                 :             :                                  numargs);
    1659                 :         225 :                 deconstruct_array_builtin(arr, TEXTOID, &argnames, NULL, &nargnames);
    1660         [ +  - ]:         225 :                 Assert(nargnames == numargs);
    1661                 :             : 
    1662                 :             :                 /* scan for output argument(s) */
    1663                 :         225 :                 result = NULL;
    1664                 :         225 :                 numoutargs = 0;
    1665         [ +  + ]:         671 :                 for (i = 0; i < numargs; i++)
    1666                 :             :                 {
    1667   [ +  +  +  + ]:         446 :                         if (argmodes[i] == PROARGMODE_IN ||
    1668                 :         225 :                                 argmodes[i] == PROARGMODE_VARIADIC)
    1669                 :         222 :                                 continue;
    1670   [ +  +  +  +  :         224 :                         Assert(argmodes[i] == PROARGMODE_OUT ||
                   -  + ]
    1671                 :             :                                    argmodes[i] == PROARGMODE_INOUT ||
    1672                 :             :                                    argmodes[i] == PROARGMODE_TABLE);
    1673         [ +  - ]:         224 :                         if (++numoutargs > 1)
    1674                 :             :                         {
    1675                 :             :                                 /* multiple out args, so forget it */
    1676                 :           0 :                                 result = NULL;
    1677                 :           0 :                                 break;
    1678                 :             :                         }
    1679                 :         224 :                         result = TextDatumGetCString(argnames[i]);
    1680   [ +  -  -  + ]:         224 :                         if (result == NULL || result[0] == '\0')
    1681                 :             :                         {
    1682                 :             :                                 /* Parameter is not named, so forget it */
    1683                 :           0 :                                 result = NULL;
    1684                 :           0 :                                 break;
    1685                 :             :                         }
    1686                 :         224 :                 }
    1687                 :             :         }
    1688                 :             : 
    1689                 :        2205 :         ReleaseSysCache(procTuple);
    1690                 :             : 
    1691                 :        4410 :         return result;
    1692                 :        2205 : }
    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                 :       26005 : build_function_result_tupdesc_t(HeapTuple procTuple)
    1706                 :             : {
    1707                 :       26005 :         Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(procTuple);
    1708                 :       26005 :         Datum           proallargtypes;
    1709                 :       26005 :         Datum           proargmodes;
    1710                 :       26005 :         Datum           proargnames;
    1711                 :       26005 :         bool            isnull;
    1712                 :             : 
    1713                 :             :         /* Return NULL if the function isn't declared to return RECORD */
    1714         [ +  + ]:       26005 :         if (procform->prorettype != RECORDOID)
    1715                 :       14097 :                 return NULL;
    1716                 :             : 
    1717                 :             :         /* If there are no OUT parameters, return NULL */
    1718   [ +  +  -  + ]:       11908 :         if (heap_attisnull(procTuple, Anum_pg_proc_proallargtypes, NULL) ||
    1719                 :       11745 :                 heap_attisnull(procTuple, Anum_pg_proc_proargmodes, NULL))
    1720                 :         163 :                 return NULL;
    1721                 :             : 
    1722                 :             :         /* Get the data out of the tuple */
    1723                 :       11745 :         proallargtypes = SysCacheGetAttrNotNull(PROCOID, procTuple,
    1724                 :             :                                                                                         Anum_pg_proc_proallargtypes);
    1725                 :       11745 :         proargmodes = SysCacheGetAttrNotNull(PROCOID, procTuple,
    1726                 :             :                                                                                  Anum_pg_proc_proargmodes);
    1727                 :       11745 :         proargnames = SysCacheGetAttr(PROCOID, procTuple,
    1728                 :             :                                                                   Anum_pg_proc_proargnames,
    1729                 :             :                                                                   &isnull);
    1730         [ +  + ]:       11745 :         if (isnull)
    1731                 :          19 :                 proargnames = PointerGetDatum(NULL);    /* just to be sure */
    1732                 :             : 
    1733                 :       23490 :         return build_function_result_tupdesc_d(procform->prokind,
    1734                 :       11745 :                                                                                    proallargtypes,
    1735                 :       11745 :                                                                                    proargmodes,
    1736                 :       11745 :                                                                                    proargnames);
    1737                 :       26005 : }
    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                 :       11762 : build_function_result_tupdesc_d(char prokind,
    1752                 :             :                                                                 Datum proallargtypes,
    1753                 :             :                                                                 Datum proargmodes,
    1754                 :             :                                                                 Datum proargnames)
    1755                 :             : {
    1756                 :       11762 :         TupleDesc       desc;
    1757                 :       11762 :         ArrayType  *arr;
    1758                 :       11762 :         int                     numargs;
    1759                 :       11762 :         Oid                *argtypes;
    1760                 :       11762 :         char       *argmodes;
    1761                 :       11762 :         Datum      *argnames = NULL;
    1762                 :       11762 :         Oid                *outargtypes;
    1763                 :       11762 :         char      **outargnames;
    1764                 :       11762 :         int                     numoutargs;
    1765                 :       11762 :         int                     nargnames;
    1766                 :       11762 :         int                     i;
    1767                 :             : 
    1768                 :             :         /* Can't have output args if columns are null */
    1769   [ +  +  -  + ]:       11762 :         if (proallargtypes == PointerGetDatum(NULL) ||
    1770                 :       11760 :                 proargmodes == PointerGetDatum(NULL))
    1771                 :           2 :                 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                 :       11760 :         arr = DatumGetArrayTypeP(proallargtypes);       /* ensure not toasted */
    1779                 :       11760 :         numargs = ARR_DIMS(arr)[0];
    1780         [ +  - ]:       11760 :         if (ARR_NDIM(arr) != 1 ||
    1781                 :       11760 :                 numargs < 0 ||
    1782                 :       11760 :                 ARR_HASNULL(arr) ||
    1783                 :       11760 :                 ARR_ELEMTYPE(arr) != OIDOID)
    1784   [ #  #  #  # ]:           0 :                 elog(ERROR, "proallargtypes is not a 1-D Oid array or it contains nulls");
    1785         [ -  + ]:       11760 :         argtypes = (Oid *) ARR_DATA_PTR(arr);
    1786                 :       11760 :         arr = DatumGetArrayTypeP(proargmodes);  /* ensure not toasted */
    1787         [ +  - ]:       11760 :         if (ARR_NDIM(arr) != 1 ||
    1788                 :       11760 :                 ARR_DIMS(arr)[0] != numargs ||
    1789                 :       11760 :                 ARR_HASNULL(arr) ||
    1790                 :       11760 :                 ARR_ELEMTYPE(arr) != CHAROID)
    1791   [ #  #  #  # ]:           0 :                 elog(ERROR, "proargmodes is not a 1-D char array of length %d or it contains nulls",
    1792                 :             :                          numargs);
    1793         [ +  - ]:       11760 :         argmodes = (char *) ARR_DATA_PTR(arr);
    1794         [ +  + ]:       11760 :         if (proargnames != PointerGetDatum(NULL))
    1795                 :             :         {
    1796                 :       11739 :                 arr = DatumGetArrayTypeP(proargnames);  /* ensure not toasted */
    1797         [ +  - ]:       11739 :                 if (ARR_NDIM(arr) != 1 ||
    1798                 :       11739 :                         ARR_DIMS(arr)[0] != numargs ||
    1799                 :       11739 :                         ARR_HASNULL(arr) ||
    1800                 :       11739 :                         ARR_ELEMTYPE(arr) != TEXTOID)
    1801   [ #  #  #  # ]:           0 :                         elog(ERROR, "proargnames is not a 1-D text array of length %d or it contains nulls",
    1802                 :             :                                  numargs);
    1803                 :       11739 :                 deconstruct_array_builtin(arr, TEXTOID, &argnames, NULL, &nargnames);
    1804         [ +  - ]:       11739 :                 Assert(nargnames == numargs);
    1805                 :       11739 :         }
    1806                 :             : 
    1807                 :             :         /* zero elements probably shouldn't happen, but handle it gracefully */
    1808         [ -  + ]:       11760 :         if (numargs <= 0)
    1809                 :           0 :                 return NULL;
    1810                 :             : 
    1811                 :             :         /* extract output-argument types and names */
    1812                 :       11760 :         outargtypes = (Oid *) palloc(numargs * sizeof(Oid));
    1813                 :       11760 :         outargnames = (char **) palloc(numargs * sizeof(char *));
    1814                 :       11760 :         numoutargs = 0;
    1815         [ +  + ]:       99579 :         for (i = 0; i < numargs; i++)
    1816                 :             :         {
    1817                 :       87819 :                 char       *pname;
    1818                 :             : 
    1819   [ +  +  +  + ]:       87819 :                 if (argmodes[i] == PROARGMODE_IN ||
    1820                 :       63498 :                         argmodes[i] == PROARGMODE_VARIADIC)
    1821                 :       24359 :                         continue;
    1822   [ +  +  +  +  :       63460 :                 Assert(argmodes[i] == PROARGMODE_OUT ||
                   -  + ]
    1823                 :             :                            argmodes[i] == PROARGMODE_INOUT ||
    1824                 :             :                            argmodes[i] == PROARGMODE_TABLE);
    1825                 :       63460 :                 outargtypes[numoutargs] = argtypes[i];
    1826         [ +  + ]:       63460 :                 if (argnames)
    1827                 :       63418 :                         pname = TextDatumGetCString(argnames[i]);
    1828                 :             :                 else
    1829                 :          42 :                         pname = NULL;
    1830   [ +  +  +  + ]:       63460 :                 if (pname == NULL || pname[0] == '\0')
    1831                 :             :                 {
    1832                 :             :                         /* Parameter is not named, so gin up a column name */
    1833                 :          60 :                         pname = psprintf("column%d", numoutargs + 1);
    1834                 :          60 :                 }
    1835                 :       63460 :                 outargnames[numoutargs] = pname;
    1836                 :       63460 :                 numoutargs++;
    1837      [ -  +  + ]:       87819 :         }
    1838                 :             : 
    1839                 :             :         /*
    1840                 :             :          * If there is no output argument, or only one, the function does not
    1841                 :             :          * return tuples.
    1842                 :             :          */
    1843   [ +  +  +  - ]:       11760 :         if (numoutargs < 2 && prokind != PROKIND_PROCEDURE)
    1844                 :           0 :                 return NULL;
    1845                 :             : 
    1846                 :       11760 :         desc = CreateTemplateTupleDesc(numoutargs);
    1847         [ +  + ]:       75220 :         for (i = 0; i < numoutargs; i++)
    1848                 :             :         {
    1849                 :      126920 :                 TupleDescInitEntry(desc, i + 1,
    1850                 :       63460 :                                                    outargnames[i],
    1851                 :       63460 :                                                    outargtypes[i],
    1852                 :             :                                                    -1,
    1853                 :             :                                                    0);
    1854                 :       63460 :         }
    1855                 :             : 
    1856                 :       11760 :         return desc;
    1857                 :       11762 : }
    1858                 :             : 
    1859                 :             : 
    1860                 :             : /*
    1861                 :             :  * RelationNameGetTupleDesc
    1862                 :             :  *
    1863                 :             :  * Given a (possibly qualified) relation name, build a TupleDesc.
    1864                 :             :  *
    1865                 :             :  * Note: while this works as advertised, it's seldom the best way to
    1866                 :             :  * build a tupdesc for a function's result type.  It's kept around
    1867                 :             :  * only for backwards compatibility with existing user-written code.
    1868                 :             :  */
    1869                 :             : TupleDesc
    1870                 :           0 : RelationNameGetTupleDesc(const char *relname)
    1871                 :             : {
    1872                 :           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                 :           0 : TypeGetTupleDesc(Oid typeoid, List *colaliases)
    1904                 :             : {
    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                 :             :         {
    1917                 :             :                 /* Composite data type, e.g. a table's row type */
    1918                 :           0 :                 tupdesc = lookup_rowtype_tupdesc_copy(base_typeoid, -1);
    1919                 :             : 
    1920         [ #  # ]:           0 :                 if (colaliases != NIL)
    1921                 :             :                 {
    1922                 :           0 :                         int                     natts = tupdesc->natts;
    1923                 :           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                 :             :                                                 (errcode(ERRCODE_DATATYPE_MISMATCH),
    1929                 :             :                                                  errmsg("number of aliases does not match number of columns")));
    1930                 :             : 
    1931                 :             :                         /* OK, use the aliases instead */
    1932         [ #  # ]:           0 :                         for (varattno = 0; varattno < natts; varattno++)
    1933                 :             :                         {
    1934                 :           0 :                                 char       *label = strVal(list_nth(colaliases, varattno));
    1935                 :           0 :                                 Form_pg_attribute attr = TupleDescAttr(tupdesc, varattno);
    1936                 :             : 
    1937         [ #  # ]:           0 :                                 if (label != NULL)
    1938                 :           0 :                                         namestrcpy(&(attr->attname), label);
    1939                 :           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                 :             :         {
    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                 :             :                                         (errcode(ERRCODE_DATATYPE_MISMATCH),
    1955                 :             :                                          errmsg("no column alias was provided")));
    1956                 :             : 
    1957                 :             :                 /* the alias list length must be 1 */
    1958         [ #  # ]:           0 :                 if (list_length(colaliases) != 1)
    1959   [ #  #  #  # ]:           0 :                         ereport(ERROR,
    1960                 :             :                                         (errcode(ERRCODE_DATATYPE_MISMATCH),
    1961                 :             :                                          errmsg("number of aliases does not match number of columns")));
    1962                 :             : 
    1963                 :             :                 /* OK, get the column alias */
    1964                 :           0 :                 attname = strVal(linitial(colaliases));
    1965                 :             : 
    1966                 :           0 :                 tupdesc = CreateTemplateTupleDesc(1);
    1967                 :           0 :                 TupleDescInitEntry(tupdesc,
    1968                 :             :                                                    (AttrNumber) 1,
    1969                 :           0 :                                                    attname,
    1970                 :           0 :                                                    typeoid,
    1971                 :             :                                                    -1,
    1972                 :             :                                                    0);
    1973                 :           0 :         }
    1974         [ #  # ]:           0 :         else if (functypclass == TYPEFUNC_RECORD)
    1975                 :             :         {
    1976                 :             :                 /* XXX can't support this because typmod wasn't passed in ... */
    1977   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    1978                 :             :                                 (errcode(ERRCODE_DATATYPE_MISMATCH),
    1979                 :             :                                  errmsg("could not determine row description for function returning record")));
    1980                 :           0 :         }
    1981                 :             :         else
    1982                 :             :         {
    1983                 :             :                 /* crummy error message, but parser should have caught this */
    1984   [ #  #  #  # ]:           0 :                 elog(ERROR, "function in FROM has unsupported return type");
    1985                 :             :         }
    1986                 :             : 
    1987                 :           0 :         return tupdesc;
    1988                 :           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                 :         193 : extract_variadic_args(FunctionCallInfo fcinfo, int variadic_start,
    2006                 :             :                                           bool convert_unknown, Datum **args, Oid **types,
    2007                 :             :                                           bool **nulls)
    2008                 :             : {
    2009                 :         193 :         bool            variadic = get_fn_expr_variadic(fcinfo->flinfo);
    2010                 :         193 :         Datum      *args_res;
    2011                 :         193 :         bool       *nulls_res;
    2012                 :         193 :         Oid                *types_res;
    2013                 :         193 :         int                     nargs,
    2014                 :             :                                 i;
    2015                 :             : 
    2016                 :         193 :         *args = NULL;
    2017                 :         193 :         *types = NULL;
    2018                 :         193 :         *nulls = NULL;
    2019                 :             : 
    2020         [ +  + ]:         193 :         if (variadic)
    2021                 :             :         {
    2022                 :          30 :                 ArrayType  *array_in;
    2023                 :          30 :                 Oid                     element_type;
    2024                 :          30 :                 bool            typbyval;
    2025                 :          30 :                 char            typalign;
    2026                 :          30 :                 int16           typlen;
    2027                 :             : 
    2028         [ +  - ]:          30 :                 Assert(PG_NARGS() == variadic_start + 1);
    2029                 :             : 
    2030         [ +  + ]:          30 :                 if (PG_ARGISNULL(variadic_start))
    2031                 :           4 :                         return -1;
    2032                 :             : 
    2033                 :          26 :                 array_in = PG_GETARG_ARRAYTYPE_P(variadic_start);
    2034                 :          26 :                 element_type = ARR_ELEMTYPE(array_in);
    2035                 :             : 
    2036                 :          26 :                 get_typlenbyvalalign(element_type,
    2037                 :             :                                                          &typlen, &typbyval, &typalign);
    2038                 :          52 :                 deconstruct_array(array_in, element_type, typlen, typbyval,
    2039                 :          26 :                                                   typalign, &args_res, &nulls_res,
    2040                 :             :                                                   &nargs);
    2041                 :             : 
    2042                 :             :                 /* All the elements of the array have the same type */
    2043                 :          26 :                 types_res = (Oid *) palloc0(nargs * sizeof(Oid));
    2044         [ +  + ]:         106 :                 for (i = 0; i < nargs; i++)
    2045                 :          80 :                         types_res[i] = element_type;
    2046         [ +  + ]:          30 :         }
    2047                 :             :         else
    2048                 :             :         {
    2049                 :         163 :                 nargs = PG_NARGS() - variadic_start;
    2050         [ +  - ]:         163 :                 Assert(nargs > 0);
    2051                 :         163 :                 nulls_res = (bool *) palloc0(nargs * sizeof(bool));
    2052                 :         163 :                 args_res = (Datum *) palloc0(nargs * sizeof(Datum));
    2053                 :         163 :                 types_res = (Oid *) palloc0(nargs * sizeof(Oid));
    2054                 :             : 
    2055         [ +  + ]:        1352 :                 for (i = 0; i < nargs; i++)
    2056                 :             :                 {
    2057                 :        1189 :                         nulls_res[i] = PG_ARGISNULL(i + variadic_start);
    2058                 :        2378 :                         types_res[i] = get_fn_expr_argtype(fcinfo->flinfo,
    2059                 :        1189 :                                                                                            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         [ +  - ]:        1189 :                         if (convert_unknown &&
    2069   [ +  +  -  + ]:        1189 :                                 types_res[i] == UNKNOWNOID &&
    2070                 :         797 :                                 get_fn_expr_arg_stable(fcinfo->flinfo, i + variadic_start))
    2071                 :             :                         {
    2072                 :         797 :                                 types_res[i] = TEXTOID;
    2073                 :             : 
    2074         [ +  + ]:         797 :                                 if (PG_ARGISNULL(i + variadic_start))
    2075                 :          20 :                                         args_res[i] = (Datum) 0;
    2076                 :             :                                 else
    2077                 :         777 :                                         args_res[i] =
    2078                 :         777 :                                                 CStringGetTextDatum(PG_GETARG_POINTER(i + variadic_start));
    2079                 :         797 :                         }
    2080                 :             :                         else
    2081                 :             :                         {
    2082                 :             :                                 /* no conversion needed, just take the datum as given */
    2083                 :         392 :                                 args_res[i] = PG_GETARG_DATUM(i + variadic_start);
    2084                 :             :                         }
    2085                 :             : 
    2086         [ +  - ]:        2378 :                         if (!OidIsValid(types_res[i]) ||
    2087         [ +  - ]:        1189 :                                 (convert_unknown && types_res[i] == UNKNOWNOID))
    2088   [ #  #  #  # ]:           0 :                                 ereport(ERROR,
    2089                 :             :                                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    2090                 :             :                                                  errmsg("could not determine data type for argument %d",
    2091                 :             :                                                                 i + 1)));
    2092                 :        1189 :                 }
    2093                 :             :         }
    2094                 :             : 
    2095                 :             :         /* Fill in results */
    2096                 :         189 :         *args = args_res;
    2097                 :         189 :         *nulls = nulls_res;
    2098                 :         189 :         *types = types_res;
    2099                 :             : 
    2100                 :         189 :         return nargs;
    2101                 :         193 : }
        

Generated by: LCOV version 2.3.2-1