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

Generated by: LCOV version 1.13