LCOV - differential code coverage report
Current view: top level - src/backend/catalog - pg_aggregate.c (source / functions) Coverage Total Hit UBC CBC
Current: ba12a202ce1b5581dc0ed149cf3f637d7897ad5d vs 2866d8c7dbfc9d882a7d80fef93fbbe763709932 Lines: 80.8 % 266 215 51 215
Current Date: 2026-08-27 14:31:44 +0300 Functions: 100.0 % 2 2 2
Baseline: lcov-20260827-baseline Branches: 52.6 % 270 142 128 142
Baseline Date: 2026-08-27 14:31:58 +0300 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(1,7] days: 75.0 % 8 6 2 6
(360..) days: 81.0 % 258 209 49 209
Function coverage date bins:
(360..) days: 100.0 % 2 2 2
Branch coverage date bins:
(1,7] days: 40.0 % 10 4 6 4
(360..) days: 53.1 % 260 138 122 138

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

Generated by: LCOV version 2.0-1