LCOV - code coverage report
Current view: top level - src/backend/catalog - pg_aggregate.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 82.5 % 354 292
Test Date: 2026-01-26 10:56:24 Functions: 100.0 % 2 2
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 43.6 % 312 136

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * pg_aggregate.c
       4                 :             :  *        routines to support manipulation of the pg_aggregate relation
       5                 :             :  *
       6                 :             :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       7                 :             :  * Portions Copyright (c) 1994, Regents of the University of California
       8                 :             :  *
       9                 :             :  *
      10                 :             :  * IDENTIFICATION
      11                 :             :  *        src/backend/catalog/pg_aggregate.c
      12                 :             :  *
      13                 :             :  *-------------------------------------------------------------------------
      14                 :             :  */
      15                 :             : #include "postgres.h"
      16                 :             : 
      17                 :             : #include "access/htup_details.h"
      18                 :             : #include "access/table.h"
      19                 :             : #include "catalog/dependency.h"
      20                 :             : #include "catalog/indexing.h"
      21                 :             : #include "catalog/pg_aggregate.h"
      22                 :             : #include "catalog/pg_language.h"
      23                 :             : #include "catalog/pg_operator.h"
      24                 :             : #include "catalog/pg_proc.h"
      25                 :             : #include "catalog/pg_type.h"
      26                 :             : #include "miscadmin.h"
      27                 :             : #include "parser/parse_coerce.h"
      28                 :             : #include "parser/parse_func.h"
      29                 :             : #include "parser/parse_oper.h"
      30                 :             : #include "utils/acl.h"
      31                 :             : #include "utils/builtins.h"
      32                 :             : #include "utils/lsyscache.h"
      33                 :             : #include "utils/rel.h"
      34                 :             : #include "utils/syscache.h"
      35                 :             : 
      36                 :             : 
      37                 :             : static Oid      lookup_agg_function(List *fnName, int nargs, Oid *input_types,
      38                 :             :                                                                 Oid variadicArgType,
      39                 :             :                                                                 Oid *rettype);
      40                 :             : 
      41                 :             : 
      42                 :             : /*
      43                 :             :  * AggregateCreate
      44                 :             :  */
      45                 :             : ObjectAddress
      46                 :         101 : AggregateCreate(const char *aggName,
      47                 :             :                                 Oid aggNamespace,
      48                 :             :                                 bool replace,
      49                 :             :                                 char aggKind,
      50                 :             :                                 int numArgs,
      51                 :             :                                 int numDirectArgs,
      52                 :             :                                 oidvector *parameterTypes,
      53                 :             :                                 Datum allParameterTypes,
      54                 :             :                                 Datum parameterModes,
      55                 :             :                                 Datum parameterNames,
      56                 :             :                                 List *parameterDefaults,
      57                 :             :                                 Oid variadicArgType,
      58                 :             :                                 List *aggtransfnName,
      59                 :             :                                 List *aggfinalfnName,
      60                 :             :                                 List *aggcombinefnName,
      61                 :             :                                 List *aggserialfnName,
      62                 :             :                                 List *aggdeserialfnName,
      63                 :             :                                 List *aggmtransfnName,
      64                 :             :                                 List *aggminvtransfnName,
      65                 :             :                                 List *aggmfinalfnName,
      66                 :             :                                 bool finalfnExtraArgs,
      67                 :             :                                 bool mfinalfnExtraArgs,
      68                 :             :                                 char finalfnModify,
      69                 :             :                                 char mfinalfnModify,
      70                 :             :                                 List *aggsortopName,
      71                 :             :                                 Oid aggTransType,
      72                 :             :                                 int32 aggTransSpace,
      73                 :             :                                 Oid aggmTransType,
      74                 :             :                                 int32 aggmTransSpace,
      75                 :             :                                 const char *agginitval,
      76                 :             :                                 const char *aggminitval,
      77                 :             :                                 char proparallel)
      78                 :             : {
      79                 :         101 :         Relation        aggdesc;
      80                 :         101 :         HeapTuple       tup;
      81                 :         101 :         HeapTuple       oldtup;
      82                 :         101 :         bool            nulls[Natts_pg_aggregate];
      83                 :         101 :         Datum           values[Natts_pg_aggregate];
      84                 :         101 :         bool            replaces[Natts_pg_aggregate];
      85                 :         101 :         Form_pg_proc proc;
      86                 :         101 :         Oid                     transfn;
      87                 :         101 :         Oid                     finalfn = InvalidOid;   /* can be omitted */
      88                 :         101 :         Oid                     combinefn = InvalidOid; /* can be omitted */
      89                 :         101 :         Oid                     serialfn = InvalidOid;  /* can be omitted */
      90                 :         101 :         Oid                     deserialfn = InvalidOid;        /* can be omitted */
      91                 :         101 :         Oid                     mtransfn = InvalidOid;  /* can be omitted */
      92                 :         101 :         Oid                     minvtransfn = InvalidOid;       /* can be omitted */
      93                 :         101 :         Oid                     mfinalfn = InvalidOid;  /* can be omitted */
      94                 :         101 :         Oid                     sortop = InvalidOid;    /* can be omitted */
      95                 :         101 :         Oid                *aggArgTypes = parameterTypes->values;
      96                 :         101 :         bool            mtransIsStrict = false;
      97                 :         101 :         Oid                     rettype;
      98                 :         101 :         Oid                     finaltype;
      99                 :         101 :         Oid                     fnArgs[FUNC_MAX_ARGS];
     100                 :         101 :         int                     nargs_transfn;
     101                 :         101 :         int                     nargs_finalfn;
     102                 :         101 :         Oid                     procOid;
     103                 :         101 :         TupleDesc       tupDesc;
     104                 :         101 :         char       *detailmsg;
     105                 :         101 :         int                     i;
     106                 :         101 :         ObjectAddress myself,
     107                 :             :                                 referenced;
     108                 :         101 :         ObjectAddresses *addrs;
     109                 :         101 :         AclResult       aclresult;
     110                 :             : 
     111                 :             :         /* sanity checks (caller should have caught these) */
     112         [ +  - ]:         101 :         if (!aggName)
     113   [ #  #  #  # ]:           0 :                 elog(ERROR, "no aggregate name supplied");
     114                 :             : 
     115         [ +  - ]:         101 :         if (!aggtransfnName)
     116   [ #  #  #  # ]:           0 :                 elog(ERROR, "aggregate must have a transition function");
     117                 :             : 
     118         [ +  - ]:         101 :         if (numDirectArgs < 0 || numDirectArgs > numArgs)
     119   [ #  #  #  # ]:           0 :                 elog(ERROR, "incorrect number of direct arguments for aggregate");
     120                 :             : 
     121                 :             :         /*
     122                 :             :          * Aggregates can have at most FUNC_MAX_ARGS-1 args, else the transfn
     123                 :             :          * and/or finalfn will be unrepresentable in pg_proc.  We must check now
     124                 :             :          * to protect fixed-size arrays here and possibly in called functions.
     125                 :             :          */
     126         [ +  - ]:         101 :         if (numArgs < 0 || numArgs > FUNC_MAX_ARGS - 1)
     127   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     128                 :             :                                 (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
     129                 :             :                                  errmsg_plural("aggregates cannot have more than %d argument",
     130                 :             :                                                            "aggregates cannot have more than %d arguments",
     131                 :             :                                                            FUNC_MAX_ARGS - 1,
     132                 :             :                                                            FUNC_MAX_ARGS - 1)));
     133                 :             : 
     134                 :             :         /*
     135                 :             :          * If transtype is polymorphic, must have polymorphic argument also; else
     136                 :             :          * we will have no way to deduce the actual transtype.
     137                 :             :          */
     138                 :         202 :         detailmsg = check_valid_polymorphic_signature(aggTransType,
     139                 :         101 :                                                                                                   aggArgTypes,
     140                 :         101 :                                                                                                   numArgs);
     141         [ +  + ]:         101 :         if (detailmsg)
     142   [ +  -  +  - ]:          18 :                 ereport(ERROR,
     143                 :             :                                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     144                 :             :                                  errmsg("cannot determine transition data type"),
     145                 :             :                                  errdetail_internal("%s", detailmsg)));
     146                 :             : 
     147                 :             :         /*
     148                 :             :          * Likewise for moving-aggregate transtype, if any
     149                 :             :          */
     150         [ +  + ]:          83 :         if (OidIsValid(aggmTransType))
     151                 :             :         {
     152                 :          16 :                 detailmsg = check_valid_polymorphic_signature(aggmTransType,
     153                 :           8 :                                                                                                           aggArgTypes,
     154                 :           8 :                                                                                                           numArgs);
     155         [ +  - ]:           8 :                 if (detailmsg)
     156   [ #  #  #  # ]:           0 :                         ereport(ERROR,
     157                 :             :                                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     158                 :             :                                          errmsg("cannot determine transition data type"),
     159                 :             :                                          errdetail_internal("%s", detailmsg)));
     160                 :           8 :         }
     161                 :             : 
     162                 :             :         /*
     163                 :             :          * An ordered-set aggregate that is VARIADIC must be VARIADIC ANY.  In
     164                 :             :          * principle we could support regular variadic types, but it would make
     165                 :             :          * things much more complicated because we'd have to assemble the correct
     166                 :             :          * subsets of arguments into array values.  Since no standard aggregates
     167                 :             :          * have use for such a case, we aren't bothering for now.
     168                 :             :          */
     169   [ +  +  +  +  :          83 :         if (AGGKIND_IS_ORDERED_SET(aggKind) && OidIsValid(variadicArgType) &&
                   +  - ]
     170                 :           1 :                 variadicArgType != ANYOID)
     171   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     172                 :             :                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     173                 :             :                                  errmsg("a variadic ordered-set aggregate must use VARIADIC type ANY")));
     174                 :             : 
     175                 :             :         /*
     176                 :             :          * If it's a hypothetical-set aggregate, there must be at least as many
     177                 :             :          * direct arguments as aggregated ones, and the last N direct arguments
     178                 :             :          * must match the aggregated ones in type.  (We have to check this again
     179                 :             :          * when the aggregate is called, in case ANY is involved, but it makes
     180                 :             :          * sense to reject the aggregate definition now if the declared arg types
     181                 :             :          * don't match up.)  It's unconditionally OK if numDirectArgs == numArgs,
     182                 :             :          * indicating that the grammar merged identical VARIADIC entries from both
     183                 :             :          * lists.  Otherwise, if the agg is VARIADIC, then we had VARIADIC only on
     184                 :             :          * the aggregated side, which is not OK.  Otherwise, insist on the last N
     185                 :             :          * parameter types on each side matching exactly.
     186                 :             :          */
     187   [ +  +  +  - ]:          83 :         if (aggKind == AGGKIND_HYPOTHETICAL &&
     188                 :           1 :                 numDirectArgs < numArgs)
     189                 :             :         {
     190                 :           0 :                 int                     numAggregatedArgs = numArgs - numDirectArgs;
     191                 :             : 
     192         [ #  # ]:           0 :                 if (OidIsValid(variadicArgType) ||
     193                 :           0 :                         numDirectArgs < numAggregatedArgs ||
     194                 :           0 :                         memcmp(aggArgTypes + (numDirectArgs - numAggregatedArgs),
     195                 :           0 :                                    aggArgTypes + numDirectArgs,
     196                 :           0 :                                    numAggregatedArgs * sizeof(Oid)) != 0)
     197   [ #  #  #  # ]:           0 :                         ereport(ERROR,
     198                 :             :                                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     199                 :             :                                          errmsg("a hypothetical-set aggregate must have direct arguments matching its aggregated arguments")));
     200                 :           0 :         }
     201                 :             : 
     202                 :             :         /*
     203                 :             :          * Find the transfn.  For ordinary aggs, it takes the transtype plus all
     204                 :             :          * aggregate arguments.  For ordered-set aggs, it takes the transtype plus
     205                 :             :          * all aggregated args, but not direct args.  However, we have to treat
     206                 :             :          * specially the case where a trailing VARIADIC item is considered to
     207                 :             :          * cover both direct and aggregated args.
     208                 :             :          */
     209         [ +  + ]:          83 :         if (AGGKIND_IS_ORDERED_SET(aggKind))
     210                 :             :         {
     211         [ +  + ]:           3 :                 if (numDirectArgs < numArgs)
     212                 :           2 :                         nargs_transfn = numArgs - numDirectArgs + 1;
     213                 :             :                 else
     214                 :             :                 {
     215                 :             :                         /* special case with VARIADIC last arg */
     216         [ +  - ]:           1 :                         Assert(variadicArgType != InvalidOid);
     217                 :           1 :                         nargs_transfn = 2;
     218                 :             :                 }
     219                 :           3 :                 fnArgs[0] = aggTransType;
     220                 :           3 :                 memcpy(fnArgs + 1, aggArgTypes + (numArgs - (nargs_transfn - 1)),
     221                 :             :                            (nargs_transfn - 1) * sizeof(Oid));
     222                 :           3 :         }
     223                 :             :         else
     224                 :             :         {
     225                 :          80 :                 nargs_transfn = numArgs + 1;
     226                 :          80 :                 fnArgs[0] = aggTransType;
     227                 :          80 :                 memcpy(fnArgs + 1, aggArgTypes, numArgs * sizeof(Oid));
     228                 :             :         }
     229                 :         166 :         transfn = lookup_agg_function(aggtransfnName, nargs_transfn,
     230                 :          83 :                                                                   fnArgs, variadicArgType,
     231                 :             :                                                                   &rettype);
     232                 :             : 
     233                 :             :         /*
     234                 :             :          * Return type of transfn (possibly after refinement by
     235                 :             :          * enforce_generic_type_consistency, if transtype isn't polymorphic) must
     236                 :             :          * exactly match declared transtype.
     237                 :             :          *
     238                 :             :          * In the non-polymorphic-transtype case, it might be okay to allow a
     239                 :             :          * rettype that's binary-coercible to transtype, but I'm not quite
     240                 :             :          * convinced that it's either safe or useful.  When transtype is
     241                 :             :          * polymorphic we *must* demand exact equality.
     242                 :             :          */
     243         [ +  - ]:          83 :         if (rettype != aggTransType)
     244   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     245                 :             :                                 (errcode(ERRCODE_DATATYPE_MISMATCH),
     246                 :             :                                  errmsg("return type of transition function %s is not %s",
     247                 :             :                                                 NameListToString(aggtransfnName),
     248                 :             :                                                 format_type_be(aggTransType))));
     249                 :             : 
     250                 :          83 :         tup = SearchSysCache1(PROCOID, ObjectIdGetDatum(transfn));
     251         [ +  - ]:          83 :         if (!HeapTupleIsValid(tup))
     252   [ #  #  #  # ]:           0 :                 elog(ERROR, "cache lookup failed for function %u", transfn);
     253                 :          83 :         proc = (Form_pg_proc) GETSTRUCT(tup);
     254                 :             : 
     255                 :             :         /*
     256                 :             :          * If the transfn is strict and the initval is NULL, make sure first input
     257                 :             :          * type and transtype are the same (or at least binary-compatible), so
     258                 :             :          * that it's OK to use the first input value as the initial transValue.
     259                 :             :          */
     260   [ +  +  +  + ]:          83 :         if (proc->proisstrict && agginitval == NULL)
     261                 :             :         {
     262         [ +  - ]:          14 :                 if (numArgs < 1 ||
     263                 :          14 :                         !IsBinaryCoercible(aggArgTypes[0], aggTransType))
     264   [ #  #  #  # ]:           0 :                         ereport(ERROR,
     265                 :             :                                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     266                 :             :                                          errmsg("must not omit initial value when transition function is strict and transition type is not compatible with input type")));
     267                 :          14 :         }
     268                 :             : 
     269                 :          83 :         ReleaseSysCache(tup);
     270                 :             : 
     271                 :             :         /* handle moving-aggregate transfn, if supplied */
     272         [ +  + ]:          83 :         if (aggmtransfnName)
     273                 :             :         {
     274                 :             :                 /*
     275                 :             :                  * The arguments are the same as for the regular transfn, except that
     276                 :             :                  * the transition data type might be different.  So re-use the fnArgs
     277                 :             :                  * values set up above, except for that one.
     278                 :             :                  */
     279         [ +  - ]:           8 :                 Assert(OidIsValid(aggmTransType));
     280                 :           8 :                 fnArgs[0] = aggmTransType;
     281                 :             : 
     282                 :          16 :                 mtransfn = lookup_agg_function(aggmtransfnName, nargs_transfn,
     283                 :           8 :                                                                            fnArgs, variadicArgType,
     284                 :             :                                                                            &rettype);
     285                 :             : 
     286                 :             :                 /* As above, return type must exactly match declared mtranstype. */
     287         [ +  - ]:           8 :                 if (rettype != aggmTransType)
     288   [ #  #  #  # ]:           0 :                         ereport(ERROR,
     289                 :             :                                         (errcode(ERRCODE_DATATYPE_MISMATCH),
     290                 :             :                                          errmsg("return type of transition function %s is not %s",
     291                 :             :                                                         NameListToString(aggmtransfnName),
     292                 :             :                                                         format_type_be(aggmTransType))));
     293                 :             : 
     294                 :           8 :                 tup = SearchSysCache1(PROCOID, ObjectIdGetDatum(mtransfn));
     295         [ +  - ]:           8 :                 if (!HeapTupleIsValid(tup))
     296   [ #  #  #  # ]:           0 :                         elog(ERROR, "cache lookup failed for function %u", mtransfn);
     297                 :           8 :                 proc = (Form_pg_proc) GETSTRUCT(tup);
     298                 :             : 
     299                 :             :                 /*
     300                 :             :                  * If the mtransfn is strict and the minitval is NULL, check first
     301                 :             :                  * input type and mtranstype are binary-compatible.
     302                 :             :                  */
     303   [ +  +  +  + ]:           8 :                 if (proc->proisstrict && aggminitval == NULL)
     304                 :             :                 {
     305         [ +  - ]:           5 :                         if (numArgs < 1 ||
     306                 :           5 :                                 !IsBinaryCoercible(aggArgTypes[0], aggmTransType))
     307   [ #  #  #  # ]:           0 :                                 ereport(ERROR,
     308                 :             :                                                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     309                 :             :                                                  errmsg("must not omit initial value when transition function is strict and transition type is not compatible with input type")));
     310                 :           5 :                 }
     311                 :             : 
     312                 :             :                 /* Remember if mtransfn is strict; we may need this below */
     313                 :           8 :                 mtransIsStrict = proc->proisstrict;
     314                 :             : 
     315                 :           8 :                 ReleaseSysCache(tup);
     316                 :           8 :         }
     317                 :             : 
     318                 :             :         /* handle minvtransfn, if supplied */
     319         [ +  + ]:          83 :         if (aggminvtransfnName)
     320                 :             :         {
     321                 :             :                 /*
     322                 :             :                  * This must have the same number of arguments with the same types as
     323                 :             :                  * the forward transition function, so just re-use the fnArgs data.
     324                 :             :                  */
     325         [ +  - ]:           8 :                 Assert(aggmtransfnName);
     326                 :             : 
     327                 :          16 :                 minvtransfn = lookup_agg_function(aggminvtransfnName, nargs_transfn,
     328                 :           8 :                                                                                   fnArgs, variadicArgType,
     329                 :             :                                                                                   &rettype);
     330                 :             : 
     331                 :             :                 /* As above, return type must exactly match declared mtranstype. */
     332         [ +  + ]:           8 :                 if (rettype != aggmTransType)
     333   [ +  -  +  - ]:           1 :                         ereport(ERROR,
     334                 :             :                                         (errcode(ERRCODE_DATATYPE_MISMATCH),
     335                 :             :                                          errmsg("return type of inverse transition function %s is not %s",
     336                 :             :                                                         NameListToString(aggminvtransfnName),
     337                 :             :                                                         format_type_be(aggmTransType))));
     338                 :             : 
     339                 :           7 :                 tup = SearchSysCache1(PROCOID, ObjectIdGetDatum(minvtransfn));
     340         [ +  - ]:           7 :                 if (!HeapTupleIsValid(tup))
     341   [ #  #  #  # ]:           0 :                         elog(ERROR, "cache lookup failed for function %u", minvtransfn);
     342                 :           7 :                 proc = (Form_pg_proc) GETSTRUCT(tup);
     343                 :             : 
     344                 :             :                 /*
     345                 :             :                  * We require the strictness settings of the forward and inverse
     346                 :             :                  * transition functions to agree.  This saves having to handle
     347                 :             :                  * assorted special cases at execution time.
     348                 :             :                  */
     349         [ +  + ]:           7 :                 if (proc->proisstrict != mtransIsStrict)
     350   [ +  -  +  - ]:           1 :                         ereport(ERROR,
     351                 :             :                                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     352                 :             :                                          errmsg("strictness of aggregate's forward and inverse transition functions must match")));
     353                 :             : 
     354                 :           6 :                 ReleaseSysCache(tup);
     355                 :           6 :         }
     356                 :             : 
     357                 :             :         /* handle finalfn, if supplied */
     358         [ +  + ]:          81 :         if (aggfinalfnName)
     359                 :             :         {
     360                 :             :                 /*
     361                 :             :                  * If finalfnExtraArgs is specified, the transfn takes the transtype
     362                 :             :                  * plus all args; otherwise, it just takes the transtype plus any
     363                 :             :                  * direct args.  (Non-direct args are useless at runtime, and are
     364                 :             :                  * actually passed as NULLs, but we may need them in the function
     365                 :             :                  * signature to allow resolution of a polymorphic agg's result type.)
     366                 :             :                  */
     367                 :          33 :                 Oid                     ffnVariadicArgType = variadicArgType;
     368                 :             : 
     369                 :          33 :                 fnArgs[0] = aggTransType;
     370                 :          33 :                 memcpy(fnArgs + 1, aggArgTypes, numArgs * sizeof(Oid));
     371         [ +  + ]:          33 :                 if (finalfnExtraArgs)
     372                 :           2 :                         nargs_finalfn = numArgs + 1;
     373                 :             :                 else
     374                 :             :                 {
     375                 :          31 :                         nargs_finalfn = numDirectArgs + 1;
     376         [ +  + ]:          31 :                         if (numDirectArgs < numArgs)
     377                 :             :                         {
     378                 :             :                                 /* variadic argument doesn't affect finalfn */
     379                 :          27 :                                 ffnVariadicArgType = InvalidOid;
     380                 :          27 :                         }
     381                 :             :                 }
     382                 :             : 
     383                 :          66 :                 finalfn = lookup_agg_function(aggfinalfnName, nargs_finalfn,
     384                 :          33 :                                                                           fnArgs, ffnVariadicArgType,
     385                 :             :                                                                           &finaltype);
     386                 :             : 
     387                 :             :                 /*
     388                 :             :                  * When finalfnExtraArgs is specified, the finalfn will certainly be
     389                 :             :                  * passed at least one null argument, so complain if it's strict.
     390                 :             :                  * Nothing bad would happen at runtime (you'd just get a null result),
     391                 :             :                  * but it's surely not what the user wants, so let's complain now.
     392                 :             :                  */
     393   [ +  +  +  - ]:          33 :                 if (finalfnExtraArgs && func_strict(finalfn))
     394   [ #  #  #  # ]:           0 :                         ereport(ERROR,
     395                 :             :                                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     396                 :             :                                          errmsg("final function with extra arguments must not be declared STRICT")));
     397                 :          33 :         }
     398                 :             :         else
     399                 :             :         {
     400                 :             :                 /*
     401                 :             :                  * If no finalfn, aggregate result type is type of the state value
     402                 :             :                  */
     403                 :          48 :                 finaltype = aggTransType;
     404                 :             :         }
     405         [ +  - ]:          81 :         Assert(OidIsValid(finaltype));
     406                 :             : 
     407                 :             :         /* handle the combinefn, if supplied */
     408         [ +  + ]:          81 :         if (aggcombinefnName)
     409                 :             :         {
     410                 :           3 :                 Oid                     combineType;
     411                 :             : 
     412                 :             :                 /*
     413                 :             :                  * Combine function must have 2 arguments, each of which is the trans
     414                 :             :                  * type.  VARIADIC doesn't affect it.
     415                 :             :                  */
     416                 :           3 :                 fnArgs[0] = aggTransType;
     417                 :           3 :                 fnArgs[1] = aggTransType;
     418                 :             : 
     419                 :           6 :                 combinefn = lookup_agg_function(aggcombinefnName, 2,
     420                 :           3 :                                                                                 fnArgs, InvalidOid,
     421                 :             :                                                                                 &combineType);
     422                 :             : 
     423                 :             :                 /* Ensure the return type matches the aggregate's trans type */
     424         [ +  - ]:           3 :                 if (combineType != aggTransType)
     425   [ #  #  #  # ]:           0 :                         ereport(ERROR,
     426                 :             :                                         (errcode(ERRCODE_DATATYPE_MISMATCH),
     427                 :             :                                          errmsg("return type of combine function %s is not %s",
     428                 :             :                                                         NameListToString(aggcombinefnName),
     429                 :             :                                                         format_type_be(aggTransType))));
     430                 :             : 
     431                 :             :                 /*
     432                 :             :                  * A combine function to combine INTERNAL states must accept nulls and
     433                 :             :                  * ensure that the returned state is in the correct memory context. We
     434                 :             :                  * cannot directly check the latter, but we can check the former.
     435                 :             :                  */
     436   [ +  +  +  - ]:           3 :                 if (aggTransType == INTERNALOID && func_strict(combinefn))
     437   [ #  #  #  # ]:           0 :                         ereport(ERROR,
     438                 :             :                                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     439                 :             :                                          errmsg("combine function with transition type %s must not be declared STRICT",
     440                 :             :                                                         format_type_be(aggTransType))));
     441                 :           3 :         }
     442                 :             : 
     443                 :             :         /*
     444                 :             :          * Validate the serialization function, if present.
     445                 :             :          */
     446         [ +  + ]:          81 :         if (aggserialfnName)
     447                 :             :         {
     448                 :             :                 /* signature is always serialize(internal) returns bytea */
     449                 :           3 :                 fnArgs[0] = INTERNALOID;
     450                 :             : 
     451                 :           6 :                 serialfn = lookup_agg_function(aggserialfnName, 1,
     452                 :           3 :                                                                            fnArgs, InvalidOid,
     453                 :             :                                                                            &rettype);
     454                 :             : 
     455         [ +  - ]:           3 :                 if (rettype != BYTEAOID)
     456   [ #  #  #  # ]:           0 :                         ereport(ERROR,
     457                 :             :                                         (errcode(ERRCODE_DATATYPE_MISMATCH),
     458                 :             :                                          errmsg("return type of serialization function %s is not %s",
     459                 :             :                                                         NameListToString(aggserialfnName),
     460                 :             :                                                         format_type_be(BYTEAOID))));
     461                 :           3 :         }
     462                 :             : 
     463                 :             :         /*
     464                 :             :          * Validate the deserialization function, if present.
     465                 :             :          */
     466         [ +  + ]:          81 :         if (aggdeserialfnName)
     467                 :             :         {
     468                 :             :                 /* signature is always deserialize(bytea, internal) returns internal */
     469                 :           2 :                 fnArgs[0] = BYTEAOID;
     470                 :           2 :                 fnArgs[1] = INTERNALOID;        /* dummy argument for type safety */
     471                 :             : 
     472                 :           4 :                 deserialfn = lookup_agg_function(aggdeserialfnName, 2,
     473                 :           2 :                                                                                  fnArgs, InvalidOid,
     474                 :             :                                                                                  &rettype);
     475                 :             : 
     476         [ +  - ]:           2 :                 if (rettype != INTERNALOID)
     477   [ #  #  #  # ]:           0 :                         ereport(ERROR,
     478                 :             :                                         (errcode(ERRCODE_DATATYPE_MISMATCH),
     479                 :             :                                          errmsg("return type of deserialization function %s is not %s",
     480                 :             :                                                         NameListToString(aggdeserialfnName),
     481                 :             :                                                         format_type_be(INTERNALOID))));
     482                 :           2 :         }
     483                 :             : 
     484                 :             :         /*
     485                 :             :          * If finaltype (i.e. aggregate return type) is polymorphic, inputs must
     486                 :             :          * be polymorphic also, else parser will fail to deduce result type.
     487                 :             :          * (Note: given the previous test on transtype and inputs, this cannot
     488                 :             :          * happen, unless someone has snuck a finalfn definition into the catalogs
     489                 :             :          * that itself violates the rule against polymorphic result with no
     490                 :             :          * polymorphic input.)
     491                 :             :          */
     492                 :         162 :         detailmsg = check_valid_polymorphic_signature(finaltype,
     493                 :          81 :                                                                                                   aggArgTypes,
     494                 :          81 :                                                                                                   numArgs);
     495         [ +  - ]:          81 :         if (detailmsg)
     496   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     497                 :             :                                 (errcode(ERRCODE_DATATYPE_MISMATCH),
     498                 :             :                                  errmsg("cannot determine result data type"),
     499                 :             :                                  errdetail_internal("%s", detailmsg)));
     500                 :             : 
     501                 :             :         /*
     502                 :             :          * Also, the return type can't be INTERNAL unless there's at least one
     503                 :             :          * INTERNAL argument.  This is the same type-safety restriction we enforce
     504                 :             :          * for regular functions, but at the level of aggregates.  We must test
     505                 :             :          * this explicitly because we allow INTERNAL as the transtype.
     506                 :             :          */
     507                 :         162 :         detailmsg = check_valid_internal_signature(finaltype,
     508                 :          81 :                                                                                            aggArgTypes,
     509                 :          81 :                                                                                            numArgs);
     510         [ +  - ]:          81 :         if (detailmsg)
     511   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     512                 :             :                                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     513                 :             :                                  errmsg("unsafe use of pseudo-type \"internal\""),
     514                 :             :                                  errdetail_internal("%s", detailmsg)));
     515                 :             : 
     516                 :             :         /*
     517                 :             :          * If a moving-aggregate implementation is supplied, look up its finalfn
     518                 :             :          * if any, and check that the implied aggregate result type matches the
     519                 :             :          * plain implementation.
     520                 :             :          */
     521         [ +  + ]:          81 :         if (OidIsValid(aggmTransType))
     522                 :             :         {
     523                 :             :                 /* handle finalfn, if supplied */
     524         [ +  - ]:           6 :                 if (aggmfinalfnName)
     525                 :             :                 {
     526                 :             :                         /*
     527                 :             :                          * The arguments are figured the same way as for the regular
     528                 :             :                          * finalfn, but using aggmTransType and mfinalfnExtraArgs.
     529                 :             :                          */
     530                 :           0 :                         Oid                     ffnVariadicArgType = variadicArgType;
     531                 :             : 
     532                 :           0 :                         fnArgs[0] = aggmTransType;
     533                 :           0 :                         memcpy(fnArgs + 1, aggArgTypes, numArgs * sizeof(Oid));
     534         [ #  # ]:           0 :                         if (mfinalfnExtraArgs)
     535                 :           0 :                                 nargs_finalfn = numArgs + 1;
     536                 :             :                         else
     537                 :             :                         {
     538                 :           0 :                                 nargs_finalfn = numDirectArgs + 1;
     539         [ #  # ]:           0 :                                 if (numDirectArgs < numArgs)
     540                 :             :                                 {
     541                 :             :                                         /* variadic argument doesn't affect finalfn */
     542                 :           0 :                                         ffnVariadicArgType = InvalidOid;
     543                 :           0 :                                 }
     544                 :             :                         }
     545                 :             : 
     546                 :           0 :                         mfinalfn = lookup_agg_function(aggmfinalfnName, nargs_finalfn,
     547                 :           0 :                                                                                    fnArgs, ffnVariadicArgType,
     548                 :             :                                                                                    &rettype);
     549                 :             : 
     550                 :             :                         /* As above, check strictness if mfinalfnExtraArgs is given */
     551   [ #  #  #  # ]:           0 :                         if (mfinalfnExtraArgs && func_strict(mfinalfn))
     552   [ #  #  #  # ]:           0 :                                 ereport(ERROR,
     553                 :             :                                                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     554                 :             :                                                  errmsg("final function with extra arguments must not be declared STRICT")));
     555                 :           0 :                 }
     556                 :             :                 else
     557                 :             :                 {
     558                 :             :                         /*
     559                 :             :                          * If no finalfn, aggregate result type is type of the state value
     560                 :             :                          */
     561                 :           6 :                         rettype = aggmTransType;
     562                 :             :                 }
     563         [ +  - ]:           6 :                 Assert(OidIsValid(rettype));
     564         [ +  - ]:           6 :                 if (rettype != finaltype)
     565   [ #  #  #  # ]:           0 :                         ereport(ERROR,
     566                 :             :                                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     567                 :             :                                          errmsg("moving-aggregate implementation returns type %s, but plain implementation returns type %s",
     568                 :             :                                                         format_type_be(rettype),
     569                 :             :                                                         format_type_be(finaltype))));
     570                 :           6 :         }
     571                 :             : 
     572                 :             :         /* handle sortop, if supplied */
     573         [ +  - ]:          81 :         if (aggsortopName)
     574                 :             :         {
     575         [ #  # ]:           0 :                 if (numArgs != 1)
     576   [ #  #  #  # ]:           0 :                         ereport(ERROR,
     577                 :             :                                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     578                 :             :                                          errmsg("sort operator can only be specified for single-argument aggregates")));
     579                 :           0 :                 sortop = LookupOperName(NULL, aggsortopName,
     580                 :           0 :                                                                 aggArgTypes[0], aggArgTypes[0],
     581                 :             :                                                                 false, -1);
     582                 :           0 :         }
     583                 :             : 
     584                 :             :         /*
     585                 :             :          * permission checks on used types
     586                 :             :          */
     587         [ +  + ]:         160 :         for (i = 0; i < numArgs; i++)
     588                 :             :         {
     589                 :          79 :                 aclresult = object_aclcheck(TypeRelationId, aggArgTypes[i], GetUserId(), ACL_USAGE);
     590         [ +  - ]:          79 :                 if (aclresult != ACLCHECK_OK)
     591                 :           0 :                         aclcheck_error_type(aclresult, aggArgTypes[i]);
     592                 :          79 :         }
     593                 :             : 
     594                 :          81 :         aclresult = object_aclcheck(TypeRelationId, aggTransType, GetUserId(), ACL_USAGE);
     595         [ +  - ]:          81 :         if (aclresult != ACLCHECK_OK)
     596                 :           0 :                 aclcheck_error_type(aclresult, aggTransType);
     597                 :             : 
     598         [ +  + ]:          81 :         if (OidIsValid(aggmTransType))
     599                 :             :         {
     600                 :           6 :                 aclresult = object_aclcheck(TypeRelationId, aggmTransType, GetUserId(), ACL_USAGE);
     601         [ +  - ]:           6 :                 if (aclresult != ACLCHECK_OK)
     602                 :           0 :                         aclcheck_error_type(aclresult, aggmTransType);
     603                 :           6 :         }
     604                 :             : 
     605                 :          81 :         aclresult = object_aclcheck(TypeRelationId, finaltype, GetUserId(), ACL_USAGE);
     606         [ +  - ]:          81 :         if (aclresult != ACLCHECK_OK)
     607                 :           0 :                 aclcheck_error_type(aclresult, finaltype);
     608                 :             : 
     609                 :             : 
     610                 :             :         /*
     611                 :             :          * Everything looks okay.  Try to create the pg_proc entry for the
     612                 :             :          * aggregate.  (This could fail if there's already a conflicting entry.)
     613                 :             :          */
     614                 :             : 
     615                 :         162 :         myself = ProcedureCreate(aggName,
     616                 :          81 :                                                          aggNamespace,
     617                 :          81 :                                                          replace,       /* maybe replacement */
     618                 :             :                                                          false, /* doesn't return a set */
     619                 :          81 :                                                          finaltype, /* returnType */
     620                 :          81 :                                                          GetUserId(),   /* proowner */
     621                 :             :                                                          INTERNALlanguageId,    /* languageObjectId */
     622                 :             :                                                          InvalidOid,    /* no validator */
     623                 :             :                                                          "aggregate_dummy", /* placeholder (no such proc) */
     624                 :             :                                                          NULL,  /* probin */
     625                 :             :                                                          NULL,  /* prosqlbody */
     626                 :             :                                                          PROKIND_AGGREGATE,
     627                 :             :                                                          false, /* security invoker (currently not
     628                 :             :                                                                          * definable for agg) */
     629                 :             :                                                          false, /* isLeakProof */
     630                 :             :                                                          false, /* isStrict (not needed for agg) */
     631                 :             :                                                          PROVOLATILE_IMMUTABLE, /* volatility (not needed
     632                 :             :                                                                                                          * for agg) */
     633                 :          81 :                                                          proparallel,
     634                 :          81 :                                                          parameterTypes,        /* paramTypes */
     635                 :          81 :                                                          allParameterTypes, /* allParamTypes */
     636                 :          81 :                                                          parameterModes,        /* parameterModes */
     637                 :          81 :                                                          parameterNames,        /* parameterNames */
     638                 :          81 :                                                          parameterDefaults, /* parameterDefaults */
     639                 :          81 :                                                          PointerGetDatum(NULL), /* trftypes */
     640                 :             :                                                          NIL,   /* trfoids */
     641                 :          81 :                                                          PointerGetDatum(NULL), /* proconfig */
     642                 :             :                                                          InvalidOid,    /* no prosupport */
     643                 :             :                                                          1, /* procost */
     644                 :             :                                                          0);    /* prorows */
     645                 :          81 :         procOid = myself.objectId;
     646                 :             : 
     647                 :             :         /*
     648                 :             :          * Okay to create the pg_aggregate entry.
     649                 :             :          */
     650                 :          81 :         aggdesc = table_open(AggregateRelationId, RowExclusiveLock);
     651                 :          81 :         tupDesc = aggdesc->rd_att;
     652                 :             : 
     653                 :             :         /* initialize nulls and values */
     654         [ +  + ]:        1709 :         for (i = 0; i < Natts_pg_aggregate; i++)
     655                 :             :         {
     656                 :        1628 :                 nulls[i] = false;
     657                 :        1628 :                 values[i] = (Datum) 0;
     658                 :        1628 :                 replaces[i] = true;
     659                 :        1628 :         }
     660                 :          81 :         values[Anum_pg_aggregate_aggfnoid - 1] = ObjectIdGetDatum(procOid);
     661                 :          81 :         values[Anum_pg_aggregate_aggkind - 1] = CharGetDatum(aggKind);
     662                 :          81 :         values[Anum_pg_aggregate_aggnumdirectargs - 1] = Int16GetDatum(numDirectArgs);
     663                 :          81 :         values[Anum_pg_aggregate_aggtransfn - 1] = ObjectIdGetDatum(transfn);
     664                 :          81 :         values[Anum_pg_aggregate_aggfinalfn - 1] = ObjectIdGetDatum(finalfn);
     665                 :          81 :         values[Anum_pg_aggregate_aggcombinefn - 1] = ObjectIdGetDatum(combinefn);
     666                 :          81 :         values[Anum_pg_aggregate_aggserialfn - 1] = ObjectIdGetDatum(serialfn);
     667                 :          81 :         values[Anum_pg_aggregate_aggdeserialfn - 1] = ObjectIdGetDatum(deserialfn);
     668                 :          81 :         values[Anum_pg_aggregate_aggmtransfn - 1] = ObjectIdGetDatum(mtransfn);
     669                 :          81 :         values[Anum_pg_aggregate_aggminvtransfn - 1] = ObjectIdGetDatum(minvtransfn);
     670                 :          81 :         values[Anum_pg_aggregate_aggmfinalfn - 1] = ObjectIdGetDatum(mfinalfn);
     671                 :          81 :         values[Anum_pg_aggregate_aggfinalextra - 1] = BoolGetDatum(finalfnExtraArgs);
     672                 :          81 :         values[Anum_pg_aggregate_aggmfinalextra - 1] = BoolGetDatum(mfinalfnExtraArgs);
     673                 :          81 :         values[Anum_pg_aggregate_aggfinalmodify - 1] = CharGetDatum(finalfnModify);
     674                 :          81 :         values[Anum_pg_aggregate_aggmfinalmodify - 1] = CharGetDatum(mfinalfnModify);
     675                 :          81 :         values[Anum_pg_aggregate_aggsortop - 1] = ObjectIdGetDatum(sortop);
     676                 :          81 :         values[Anum_pg_aggregate_aggtranstype - 1] = ObjectIdGetDatum(aggTransType);
     677                 :          81 :         values[Anum_pg_aggregate_aggtransspace - 1] = Int32GetDatum(aggTransSpace);
     678                 :          81 :         values[Anum_pg_aggregate_aggmtranstype - 1] = ObjectIdGetDatum(aggmTransType);
     679                 :          81 :         values[Anum_pg_aggregate_aggmtransspace - 1] = Int32GetDatum(aggmTransSpace);
     680         [ +  + ]:          81 :         if (agginitval)
     681                 :          51 :                 values[Anum_pg_aggregate_agginitval - 1] = CStringGetTextDatum(agginitval);
     682                 :             :         else
     683                 :          30 :                 nulls[Anum_pg_aggregate_agginitval - 1] = true;
     684         [ +  + ]:          81 :         if (aggminitval)
     685                 :           9 :                 values[Anum_pg_aggregate_aggminitval - 1] = CStringGetTextDatum(aggminitval);
     686                 :             :         else
     687                 :          72 :                 nulls[Anum_pg_aggregate_aggminitval - 1] = true;
     688                 :             : 
     689         [ +  + ]:          81 :         if (replace)
     690                 :          10 :                 oldtup = SearchSysCache1(AGGFNOID, ObjectIdGetDatum(procOid));
     691                 :             :         else
     692                 :          71 :                 oldtup = NULL;
     693                 :             : 
     694         [ +  + ]:          81 :         if (HeapTupleIsValid(oldtup))
     695                 :             :         {
     696                 :          10 :                 Form_pg_aggregate oldagg = (Form_pg_aggregate) GETSTRUCT(oldtup);
     697                 :             : 
     698                 :             :                 /*
     699                 :             :                  * If we're replacing an existing entry, we need to validate that
     700                 :             :                  * we're not changing anything that would break callers. Specifically
     701                 :             :                  * we must not change aggkind or aggnumdirectargs, which affect how an
     702                 :             :                  * aggregate call is treated in parse analysis.
     703                 :             :                  */
     704         [ +  + ]:          10 :                 if (aggKind != oldagg->aggkind)
     705   [ +  -  +  -  :           1 :                         ereport(ERROR,
          +  -  #  #  #  
                      # ]
     706                 :             :                                         (errcode(ERRCODE_WRONG_OBJECT_TYPE),
     707                 :             :                                          errmsg("cannot change routine kind"),
     708                 :             :                                          (oldagg->aggkind == AGGKIND_NORMAL ?
     709                 :             :                                           errdetail("\"%s\" is an ordinary aggregate function.", aggName) :
     710                 :             :                                           oldagg->aggkind == AGGKIND_ORDERED_SET ?
     711                 :             :                                           errdetail("\"%s\" is an ordered-set aggregate.", aggName) :
     712                 :             :                                           oldagg->aggkind == AGGKIND_HYPOTHETICAL ?
     713                 :             :                                           errdetail("\"%s\" is a hypothetical-set aggregate.", aggName) :
     714                 :             :                                           0)));
     715         [ +  - ]:           9 :                 if (numDirectArgs != oldagg->aggnumdirectargs)
     716   [ #  #  #  # ]:           0 :                         ereport(ERROR,
     717                 :             :                                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     718                 :             :                                          errmsg("cannot change number of direct arguments of an aggregate function")));
     719                 :             : 
     720                 :           9 :                 replaces[Anum_pg_aggregate_aggfnoid - 1] = false;
     721                 :           9 :                 replaces[Anum_pg_aggregate_aggkind - 1] = false;
     722                 :           9 :                 replaces[Anum_pg_aggregate_aggnumdirectargs - 1] = false;
     723                 :             : 
     724                 :           9 :                 tup = heap_modify_tuple(oldtup, tupDesc, values, nulls, replaces);
     725                 :           9 :                 CatalogTupleUpdate(aggdesc, &tup->t_self, tup);
     726                 :           9 :                 ReleaseSysCache(oldtup);
     727                 :           9 :         }
     728                 :             :         else
     729                 :             :         {
     730                 :          71 :                 tup = heap_form_tuple(tupDesc, values, nulls);
     731                 :          71 :                 CatalogTupleInsert(aggdesc, tup);
     732                 :             :         }
     733                 :             : 
     734                 :          80 :         table_close(aggdesc, RowExclusiveLock);
     735                 :             : 
     736                 :             :         /*
     737                 :             :          * Create dependencies for the aggregate (above and beyond those already
     738                 :             :          * made by ProcedureCreate).  Note: we don't need an explicit dependency
     739                 :             :          * on aggTransType since we depend on it indirectly through transfn.
     740                 :             :          * Likewise for aggmTransType using the mtransfn, if it exists.
     741                 :             :          *
     742                 :             :          * If we're replacing an existing definition, ProcedureCreate deleted all
     743                 :             :          * our existing dependencies, so we have to do the same things here either
     744                 :             :          * way.
     745                 :             :          */
     746                 :             : 
     747                 :          80 :         addrs = new_object_addresses();
     748                 :             : 
     749                 :             :         /* Depends on transition function */
     750                 :          80 :         ObjectAddressSet(referenced, ProcedureRelationId, transfn);
     751                 :          80 :         add_exact_object_address(&referenced, addrs);
     752                 :             : 
     753                 :             :         /* Depends on final function, if any */
     754         [ +  + ]:          80 :         if (OidIsValid(finalfn))
     755                 :             :         {
     756                 :          30 :                 ObjectAddressSet(referenced, ProcedureRelationId, finalfn);
     757                 :          30 :                 add_exact_object_address(&referenced, addrs);
     758                 :          30 :         }
     759                 :             : 
     760                 :             :         /* Depends on combine function, if any */
     761         [ +  + ]:          80 :         if (OidIsValid(combinefn))
     762                 :             :         {
     763                 :           3 :                 ObjectAddressSet(referenced, ProcedureRelationId, combinefn);
     764                 :           3 :                 add_exact_object_address(&referenced, addrs);
     765                 :           3 :         }
     766                 :             : 
     767                 :             :         /* Depends on serialization function, if any */
     768         [ +  + ]:          80 :         if (OidIsValid(serialfn))
     769                 :             :         {
     770                 :           2 :                 ObjectAddressSet(referenced, ProcedureRelationId, serialfn);
     771                 :           2 :                 add_exact_object_address(&referenced, addrs);
     772                 :           2 :         }
     773                 :             : 
     774                 :             :         /* Depends on deserialization function, if any */
     775         [ +  + ]:          80 :         if (OidIsValid(deserialfn))
     776                 :             :         {
     777                 :           2 :                 ObjectAddressSet(referenced, ProcedureRelationId, deserialfn);
     778                 :           2 :                 add_exact_object_address(&referenced, addrs);
     779                 :           2 :         }
     780                 :             : 
     781                 :             :         /* Depends on forward transition function, if any */
     782         [ +  + ]:          80 :         if (OidIsValid(mtransfn))
     783                 :             :         {
     784                 :           6 :                 ObjectAddressSet(referenced, ProcedureRelationId, mtransfn);
     785                 :           6 :                 add_exact_object_address(&referenced, addrs);
     786                 :           6 :         }
     787                 :             : 
     788                 :             :         /* Depends on inverse transition function, if any */
     789         [ +  + ]:          80 :         if (OidIsValid(minvtransfn))
     790                 :             :         {
     791                 :           6 :                 ObjectAddressSet(referenced, ProcedureRelationId, minvtransfn);
     792                 :           6 :                 add_exact_object_address(&referenced, addrs);
     793                 :           6 :         }
     794                 :             : 
     795                 :             :         /* Depends on final function, if any */
     796         [ -  + ]:          80 :         if (OidIsValid(mfinalfn))
     797                 :             :         {
     798                 :           0 :                 ObjectAddressSet(referenced, ProcedureRelationId, mfinalfn);
     799                 :           0 :                 add_exact_object_address(&referenced, addrs);
     800                 :           0 :         }
     801                 :             : 
     802                 :             :         /* Depends on sort operator, if any */
     803         [ -  + ]:          80 :         if (OidIsValid(sortop))
     804                 :             :         {
     805                 :           0 :                 ObjectAddressSet(referenced, OperatorRelationId, sortop);
     806                 :           0 :                 add_exact_object_address(&referenced, addrs);
     807                 :           0 :         }
     808                 :             : 
     809                 :          80 :         record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
     810                 :          80 :         free_object_addresses(addrs);
     811                 :             :         return myself;
     812                 :          80 : }
     813                 :             : 
     814                 :             : /*
     815                 :             :  * lookup_agg_function
     816                 :             :  * common code for finding aggregate support functions
     817                 :             :  *
     818                 :             :  * fnName: possibly-schema-qualified function name
     819                 :             :  * nargs, input_types: expected function argument types
     820                 :             :  * variadicArgType: type of variadic argument if any, else InvalidOid
     821                 :             :  *
     822                 :             :  * Returns OID of function, and stores its return type into *rettype
     823                 :             :  *
     824                 :             :  * NB: must not scribble on input_types[], as we may re-use those
     825                 :             :  */
     826                 :             : static Oid
     827                 :         164 : lookup_agg_function(List *fnName,
     828                 :             :                                         int nargs,
     829                 :             :                                         Oid *input_types,
     830                 :             :                                         Oid variadicArgType,
     831                 :             :                                         Oid *rettype)
     832                 :             : {
     833                 :         164 :         Oid                     fnOid;
     834                 :         164 :         bool            retset;
     835                 :         164 :         int                     nvargs;
     836                 :         164 :         Oid                     vatype;
     837                 :         164 :         Oid                *true_oid_array;
     838                 :         164 :         FuncDetailCode fdresult;
     839                 :         164 :         int                     fgc_flags;
     840                 :         164 :         AclResult       aclresult;
     841                 :         164 :         int                     i;
     842                 :             : 
     843                 :             :         /*
     844                 :             :          * func_get_detail looks up the function in the catalogs, does
     845                 :             :          * disambiguation for polymorphic functions, handles inheritance, and
     846                 :             :          * returns the funcid and type and set or singleton status of the
     847                 :             :          * function's return value.  it also returns the true argument types to
     848                 :             :          * the function.
     849                 :             :          */
     850                 :         328 :         fdresult = func_get_detail(fnName, NIL, NIL,
     851                 :         164 :                                                            nargs, input_types, false, false, false,
     852                 :             :                                                            &fgc_flags,
     853                 :         164 :                                                            &fnOid, rettype, &retset,
     854                 :             :                                                            &nvargs, &vatype,
     855                 :             :                                                            &true_oid_array, NULL);
     856                 :             : 
     857                 :             :         /* only valid case is a normal function not returning a set */
     858         [ +  + ]:         164 :         if (fdresult != FUNCDETAIL_NORMAL || !OidIsValid(fnOid))
     859   [ +  -  +  - ]:          24 :                 ereport(ERROR,
     860                 :             :                                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
     861                 :             :                                  errmsg("function %s does not exist",
     862                 :             :                                                 func_signature_string(fnName, nargs,
     863                 :             :                                                                                           NIL, input_types))));
     864         [ +  - ]:         140 :         if (retset)
     865   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     866                 :             :                                 (errcode(ERRCODE_DATATYPE_MISMATCH),
     867                 :             :                                  errmsg("function %s returns a set",
     868                 :             :                                                 func_signature_string(fnName, nargs,
     869                 :             :                                                                                           NIL, input_types))));
     870                 :             : 
     871                 :             :         /*
     872                 :             :          * If the agg is declared to take VARIADIC ANY, the underlying functions
     873                 :             :          * had better be declared that way too, else they may receive too many
     874                 :             :          * parameters; but func_get_detail would have been happy with plain ANY.
     875                 :             :          * (Probably nothing very bad would happen, but it wouldn't work as the
     876                 :             :          * user expects.)  Other combinations should work without any special
     877                 :             :          * pushups, given that we told func_get_detail not to expand VARIADIC.
     878                 :             :          */
     879   [ +  +  +  - ]:         140 :         if (variadicArgType == ANYOID && vatype != ANYOID)
     880   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     881                 :             :                                 (errcode(ERRCODE_DATATYPE_MISMATCH),
     882                 :             :                                  errmsg("function %s must accept VARIADIC ANY to be used in this aggregate",
     883                 :             :                                                 func_signature_string(fnName, nargs,
     884                 :             :                                                                                           NIL, input_types))));
     885                 :             : 
     886                 :             :         /*
     887                 :             :          * If there are any polymorphic types involved, enforce consistency, and
     888                 :             :          * possibly refine the result type.  It's OK if the result is still
     889                 :             :          * polymorphic at this point, though.
     890                 :             :          */
     891                 :         280 :         *rettype = enforce_generic_type_consistency(input_types,
     892                 :         140 :                                                                                                 true_oid_array,
     893                 :         140 :                                                                                                 nargs,
     894                 :         140 :                                                                                                 *rettype,
     895                 :             :                                                                                                 true);
     896                 :             : 
     897                 :             :         /*
     898                 :             :          * func_get_detail will find functions requiring run-time argument type
     899                 :             :          * coercion, but nodeAgg.c isn't prepared to deal with that
     900                 :             :          */
     901         [ +  + ]:         389 :         for (i = 0; i < nargs; i++)
     902                 :             :         {
     903         [ +  + ]:         251 :                 if (!IsBinaryCoercible(input_types[i], true_oid_array[i]))
     904   [ +  -  +  - ]:           2 :                         ereport(ERROR,
     905                 :             :                                         (errcode(ERRCODE_DATATYPE_MISMATCH),
     906                 :             :                                          errmsg("function %s requires run-time type coercion",
     907                 :             :                                                         func_signature_string(fnName, nargs,
     908                 :             :                                                                                                   NIL, true_oid_array))));
     909                 :         249 :         }
     910                 :             : 
     911                 :             :         /* Check aggregate creator has permission to call the function */
     912                 :         138 :         aclresult = object_aclcheck(ProcedureRelationId, fnOid, GetUserId(), ACL_EXECUTE);
     913         [ +  - ]:         138 :         if (aclresult != ACLCHECK_OK)
     914                 :           0 :                 aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(fnOid));
     915                 :             : 
     916                 :         276 :         return fnOid;
     917                 :         138 : }
        

Generated by: LCOV version 2.3.2-1