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

Generated by: LCOV version 1.13