LCOV - code coverage report
Current view: top level - src/backend/catalog - pg_aggregate.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 204 253 80.6 %
Date: 2024-04-19 09:12:35 Functions: 2 2 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14