LCOV - differential code coverage report
Current view: top level - src/backend/catalog - pg_aggregate.c (source / functions) Coverage Total Hit UBC GNC CBC DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 81.0 % 258 209 49 5 204 5
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 2 2 2
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

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

Generated by: LCOV version v1.16-55-g56c0a2a