LCOV - differential code coverage report
Current view: top level - src/backend/optimizer/prep - prepagg.c (source / functions) Coverage Total Hit UNC UIC UBC GBC GIC GNC CBC EUB ECB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 97.8 % 186 182 1 2 1 1 91 18 72 2 105 5
Current Date: 2023-04-08 17:13:01 Functions: 100.0 % 7 7 5 1 1 5
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (60,120] days: 87.5 % 8 7 1 7
Legend: Lines: hit not hit (240..) days: 98.3 % 178 175 2 1 1 91 11 72 2 97
Function coverage date bins:
(240..) days: 58.3 % 12 7 5 1 1 5

 Age         Owner                  TLA  Line data    Source code
                                  1                 : /*-------------------------------------------------------------------------
                                  2                 :  *
                                  3                 :  * prepagg.c
                                  4                 :  *    Routines to preprocess aggregate function calls
                                  5                 :  *
                                  6                 :  * If there are identical aggregate calls in the query, they only need to
                                  7                 :  * be computed once.  Also, some aggregate functions can share the same
                                  8                 :  * transition state, so that we only need to call the final function for
                                  9                 :  * them separately.  These optimizations are independent of how the
                                 10                 :  * aggregates are executed.
                                 11                 :  *
                                 12                 :  * preprocess_aggrefs() detects those cases, creates AggInfo and
                                 13                 :  * AggTransInfo structs for each aggregate and transition state that needs
                                 14                 :  * to be computed, and sets the 'aggno' and 'transno' fields in the Aggrefs
                                 15                 :  * accordingly.  It also resolves polymorphic transition types, and sets
                                 16                 :  * the 'aggtranstype' fields accordingly.
                                 17                 :  *
                                 18                 :  * XXX: The AggInfo and AggTransInfo structs are thrown away after
                                 19                 :  * planning, so executor startup has to perform some of the same lookups
                                 20                 :  * of transition functions and initial values that we do here.  One day, we
                                 21                 :  * might want to carry that information to the Agg nodes to save the effort
                                 22                 :  * at executor startup.  The Agg nodes are constructed much later in the
                                 23                 :  * planning, however, so it's not trivial.
                                 24                 :  *
                                 25                 :  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
                                 26                 :  * Portions Copyright (c) 1994, Regents of the University of California
                                 27                 :  *
                                 28                 :  *
                                 29                 :  * IDENTIFICATION
                                 30                 :  *    src/backend/optimizer/prep/prepagg.c
                                 31                 :  *
                                 32                 :  *-------------------------------------------------------------------------
                                 33                 :  */
                                 34                 : 
                                 35                 : #include "postgres.h"
                                 36                 : 
                                 37                 : #include "access/htup_details.h"
                                 38                 : #include "catalog/pg_aggregate.h"
                                 39                 : #include "catalog/pg_type.h"
                                 40                 : #include "nodes/nodeFuncs.h"
                                 41                 : #include "nodes/pathnodes.h"
                                 42                 : #include "optimizer/clauses.h"
                                 43                 : #include "optimizer/cost.h"
                                 44                 : #include "optimizer/optimizer.h"
                                 45                 : #include "optimizer/plancat.h"
                                 46                 : #include "optimizer/prep.h"
                                 47                 : #include "parser/parse_agg.h"
                                 48                 : #include "utils/builtins.h"
                                 49                 : #include "utils/datum.h"
                                 50                 : #include "utils/fmgroids.h"
                                 51                 : #include "utils/lsyscache.h"
                                 52                 : #include "utils/memutils.h"
                                 53                 : #include "utils/syscache.h"
                                 54                 : 
                                 55                 : static bool preprocess_aggrefs_walker(Node *node, PlannerInfo *root);
                                 56                 : static int  find_compatible_agg(PlannerInfo *root, Aggref *newagg,
                                 57                 :                                 List **same_input_transnos);
                                 58                 : static int  find_compatible_trans(PlannerInfo *root, Aggref *newagg,
                                 59                 :                                   bool shareable,
                                 60                 :                                   Oid aggtransfn, Oid aggtranstype,
                                 61                 :                                   int transtypeLen, bool transtypeByVal,
                                 62                 :                                   Oid aggcombinefn,
                                 63                 :                                   Oid aggserialfn, Oid aggdeserialfn,
                                 64                 :                                   Datum initValue, bool initValueIsNull,
                                 65                 :                                   List *transnos);
                                 66                 : static Datum GetAggInitVal(Datum textInitVal, Oid transtype);
                                 67                 : 
                                 68                 : /* -----------------
                                 69                 :  * Resolve the transition type of all Aggrefs, and determine which Aggrefs
                                 70                 :  * can share aggregate or transition state.
                                 71                 :  *
                                 72                 :  * Information about the aggregates and transition functions are collected
                                 73                 :  * in the root->agginfos and root->aggtransinfos lists.  The 'aggtranstype',
                                 74                 :  * 'aggno', and 'aggtransno' fields of each Aggref are filled in.
                                 75                 :  *
                                 76                 :  * NOTE: This modifies the Aggrefs in the input expression in-place!
                                 77                 :  *
                                 78                 :  * We try to optimize by detecting duplicate aggregate functions so that
                                 79                 :  * their state and final values are re-used, rather than needlessly being
                                 80                 :  * re-calculated independently.  We also detect aggregates that are not
                                 81                 :  * the same, but which can share the same transition state.
                                 82                 :  *
                                 83                 :  * Scenarios:
                                 84                 :  *
                                 85                 :  * 1. Identical aggregate function calls appear in the query:
                                 86                 :  *
                                 87                 :  *    SELECT SUM(x) FROM ... HAVING SUM(x) > 0
                                 88                 :  *
                                 89                 :  *    Since these aggregates are identical, we only need to calculate
                                 90                 :  *    the value once.  Both aggregates will share the same 'aggno' value.
                                 91                 :  *
                                 92                 :  * 2. Two different aggregate functions appear in the query, but the
                                 93                 :  *    aggregates have the same arguments, transition functions and
                                 94                 :  *    initial values (and, presumably, different final functions):
                                 95                 :  *
                                 96                 :  *    SELECT AVG(x), STDDEV(x) FROM ...
                                 97                 :  *
                                 98                 :  *    In this case we must create a new AggInfo for the varying aggregate,
                                 99                 :  *    and we need to call the final functions separately, but we need
                                100                 :  *    only run the transition function once.  (This requires that the
                                101                 :  *    final functions be nondestructive of the transition state, but
                                102                 :  *    that's required anyway for other reasons.)
                                103                 :  *
                                104                 :  * For either of these optimizations to be valid, all aggregate properties
                                105                 :  * used in the transition phase must be the same, including any modifiers
                                106                 :  * such as ORDER BY, DISTINCT and FILTER, and the arguments mustn't
                                107                 :  * contain any volatile functions.
                                108                 :  * -----------------
                                109                 :  */
                                110                 : void
  866 heikki.linnakangas        111 CBC       32004 : preprocess_aggrefs(PlannerInfo *root, Node *clause)
                                112                 : {
                                113           32004 :     (void) preprocess_aggrefs_walker(clause, root);
                                114           32004 : }
                                115                 : 
                                116                 : static void
                                117           18526 : preprocess_aggref(Aggref *aggref, PlannerInfo *root)
                                118                 : {
                                119                 :     HeapTuple   aggTuple;
                                120                 :     Form_pg_aggregate aggform;
                                121                 :     Oid         aggtransfn;
                                122                 :     Oid         aggfinalfn;
                                123                 :     Oid         aggcombinefn;
                                124                 :     Oid         aggserialfn;
                                125                 :     Oid         aggdeserialfn;
                                126                 :     Oid         aggtranstype;
                                127                 :     int32       aggtranstypmod;
                                128                 :     int32       aggtransspace;
                                129                 :     bool        shareable;
                                130                 :     int         aggno;
                                131                 :     int         transno;
                                132                 :     List       *same_input_transnos;
                                133                 :     int16       resulttypeLen;
                                134                 :     bool        resulttypeByVal;
                                135                 :     Datum       textInitVal;
                                136                 :     Datum       initValue;
                                137                 :     bool        initValueIsNull;
                                138                 :     bool        transtypeByVal;
                                139                 :     int16       transtypeLen;
                                140                 :     Oid         inputTypes[FUNC_MAX_ARGS];
                                141                 :     int         numArguments;
                                142                 : 
                                143           18526 :     Assert(aggref->agglevelsup == 0);
                                144                 : 
                                145                 :     /*
                                146                 :      * Fetch info about the aggregate from pg_aggregate.  Note it's correct to
                                147                 :      * ignore the moving-aggregate variant, since what we're concerned with
                                148                 :      * here is aggregates not window functions.
                                149                 :      */
                                150           18526 :     aggTuple = SearchSysCache1(AGGFNOID,
                                151                 :                                ObjectIdGetDatum(aggref->aggfnoid));
                                152           18526 :     if (!HeapTupleIsValid(aggTuple))
  866 heikki.linnakangas        153 UBC           0 :         elog(ERROR, "cache lookup failed for aggregate %u",
                                154                 :              aggref->aggfnoid);
  866 heikki.linnakangas        155 CBC       18526 :     aggform = (Form_pg_aggregate) GETSTRUCT(aggTuple);
                                156           18526 :     aggtransfn = aggform->aggtransfn;
                                157           18526 :     aggfinalfn = aggform->aggfinalfn;
                                158           18526 :     aggcombinefn = aggform->aggcombinefn;
                                159           18526 :     aggserialfn = aggform->aggserialfn;
                                160           18526 :     aggdeserialfn = aggform->aggdeserialfn;
                                161           18526 :     aggtranstype = aggform->aggtranstype;
                                162           18526 :     aggtransspace = aggform->aggtransspace;
                                163                 : 
                                164                 :     /*
                                165                 :      * Resolve the possibly-polymorphic aggregate transition type.
                                166                 :      */
                                167                 : 
                                168                 :     /* extract argument types (ignoring any ORDER BY expressions) */
                                169           18526 :     numArguments = get_aggregate_argtypes(aggref, inputTypes);
                                170                 : 
                                171                 :     /* resolve actual type of transition state, if polymorphic */
                                172           18526 :     aggtranstype = resolve_aggregate_transtype(aggref->aggfnoid,
                                173                 :                                                aggtranstype,
                                174                 :                                                inputTypes,
                                175                 :                                                numArguments);
                                176           18526 :     aggref->aggtranstype = aggtranstype;
                                177                 : 
                                178                 :     /*
                                179                 :      * If transition state is of same type as first aggregated input, assume
                                180                 :      * it's the same typmod (same width) as well.  This works for cases like
                                181                 :      * MAX/MIN and is probably somewhat reasonable otherwise.
                                182                 :      */
                                183           18526 :     aggtranstypmod = -1;
                                184           18526 :     if (aggref->args)
                                185                 :     {
                                186           13143 :         TargetEntry *tle = (TargetEntry *) linitial(aggref->args);
                                187                 : 
                                188           13143 :         if (aggtranstype == exprType((Node *) tle->expr))
                                189            1475 :             aggtranstypmod = exprTypmod((Node *) tle->expr);
                                190                 :     }
                                191                 : 
                                192                 :     /*
                                193                 :      * If finalfn is marked read-write, we can't share transition states; but
                                194                 :      * it is okay to share states for AGGMODIFY_SHAREABLE aggs.
                                195                 :      *
                                196                 :      * In principle, in a partial aggregate, we could share the transition
                                197                 :      * state even if the final function is marked as read-write, because the
                                198                 :      * partial aggregate doesn't execute the final function.  But it's too
                                199                 :      * early to know whether we're going perform a partial aggregate.
                                200                 :      */
                                201           18526 :     shareable = (aggform->aggfinalmodify != AGGMODIFY_READ_WRITE);
                                202                 : 
                                203                 :     /* get info about the output value's datatype */
                                204           18526 :     get_typlenbyval(aggref->aggtype,
                                205                 :                     &resulttypeLen,
                                206                 :                     &resulttypeByVal);
                                207                 : 
                                208                 :     /* get initial value */
                                209           18526 :     textInitVal = SysCacheGetAttr(AGGFNOID, aggTuple,
                                210                 :                                   Anum_pg_aggregate_agginitval,
                                211                 :                                   &initValueIsNull);
                                212           18526 :     if (initValueIsNull)
                                213           11460 :         initValue = (Datum) 0;
                                214                 :     else
                                215            7066 :         initValue = GetAggInitVal(textInitVal, aggtranstype);
                                216                 : 
                                217           18526 :     ReleaseSysCache(aggTuple);
                                218                 : 
                                219                 :     /*
                                220                 :      * 1. See if this is identical to another aggregate function call that
                                221                 :      * we've seen already.
                                222                 :      */
                                223           18526 :     aggno = find_compatible_agg(root, aggref, &same_input_transnos);
                                224           18526 :     if (aggno != -1)
                                225                 :     {
  264 tgl                       226 GNC         545 :         AggInfo    *agginfo = list_nth_node(AggInfo, root->agginfos, aggno);
                                227                 : 
  250 drowley                   228             545 :         agginfo->aggrefs = lappend(agginfo->aggrefs, aggref);
  866 heikki.linnakangas        229 CBC         545 :         transno = agginfo->transno;
  866 heikki.linnakangas        230 ECB             :     }
                                231                 :     else
                                232                 :     {
  264 tgl                       233 GNC       17981 :         AggInfo    *agginfo = makeNode(AggInfo);
  866 heikki.linnakangas        234 ECB             : 
  866 heikki.linnakangas        235 GIC       17981 :         agginfo->finalfn_oid = aggfinalfn;
  250 drowley                   236 GNC       17981 :         agginfo->aggrefs = list_make1(aggref);
  866 heikki.linnakangas        237 CBC       17981 :         agginfo->shareable = shareable;
  866 heikki.linnakangas        238 ECB             : 
  866 heikki.linnakangas        239 GIC       17981 :         aggno = list_length(root->agginfos);
  866 heikki.linnakangas        240 CBC       17981 :         root->agginfos = lappend(root->agginfos, agginfo);
  866 heikki.linnakangas        241 ECB             : 
                                242                 :         /*
                                243                 :          * Count it, and check for cases requiring ordered input.  Note that
                                244                 :          * ordered-set aggs always have nonempty aggorder.  Any ordered-input
                                245                 :          * case also defeats partial aggregation.
                                246                 :          */
  866 heikki.linnakangas        247 GIC       17981 :         if (aggref->aggorder != NIL || aggref->aggdistinct != NIL)
  866 heikki.linnakangas        248 ECB             :         {
  866 heikki.linnakangas        249 GIC        1033 :             root->numOrderedAggs++;
  866 heikki.linnakangas        250 CBC        1033 :             root->hasNonPartialAggs = true;
  866 heikki.linnakangas        251 ECB             :         }
                                252                 : 
  866 heikki.linnakangas        253 GIC       17981 :         get_typlenbyval(aggtranstype,
  866 heikki.linnakangas        254 ECB             :                         &transtypeLen,
                                255                 :                         &transtypeByVal);
                                256                 : 
                                257                 :         /*
                                258                 :          * 2. See if this aggregate can share transition state with another
                                259                 :          * aggregate that we've initialized already.
                                260                 :          */
  866 heikki.linnakangas        261 GIC       17981 :         transno = find_compatible_trans(root, aggref, shareable,
  866 heikki.linnakangas        262 ECB             :                                         aggtransfn, aggtranstype,
                                263                 :                                         transtypeLen, transtypeByVal,
                                264                 :                                         aggcombinefn,
                                265                 :                                         aggserialfn, aggdeserialfn,
                                266                 :                                         initValue, initValueIsNull,
                                267                 :                                         same_input_transnos);
  866 heikki.linnakangas        268 GIC       17981 :         if (transno == -1)
  866 heikki.linnakangas        269 ECB             :         {
  264 tgl                       270 GNC       17852 :             AggTransInfo *transinfo = makeNode(AggTransInfo);
  866 heikki.linnakangas        271 ECB             : 
  866 heikki.linnakangas        272 GIC       17852 :             transinfo->args = aggref->args;
  866 heikki.linnakangas        273 CBC       17852 :             transinfo->aggfilter = aggref->aggfilter;
                                274           17852 :             transinfo->transfn_oid = aggtransfn;
                                275           17852 :             transinfo->combinefn_oid = aggcombinefn;
                                276           17852 :             transinfo->serialfn_oid = aggserialfn;
                                277           17852 :             transinfo->deserialfn_oid = aggdeserialfn;
                                278           17852 :             transinfo->aggtranstype = aggtranstype;
                                279           17852 :             transinfo->aggtranstypmod = aggtranstypmod;
                                280           17852 :             transinfo->transtypeLen = transtypeLen;
                                281           17852 :             transinfo->transtypeByVal = transtypeByVal;
                                282           17852 :             transinfo->aggtransspace = aggtransspace;
                                283           17852 :             transinfo->initValue = initValue;
                                284           17852 :             transinfo->initValueIsNull = initValueIsNull;
  866 heikki.linnakangas        285 ECB             : 
  866 heikki.linnakangas        286 GIC       17852 :             transno = list_length(root->aggtransinfos);
  866 heikki.linnakangas        287 CBC       17852 :             root->aggtransinfos = lappend(root->aggtransinfos, transinfo);
  866 heikki.linnakangas        288 ECB             : 
                                289                 :             /*
                                290                 :              * Check whether partial aggregation is feasible, unless we
                                291                 :              * already found out that we can't do it.
                                292                 :              */
  866 heikki.linnakangas        293 GIC       17852 :             if (!root->hasNonPartialAggs)
  866 heikki.linnakangas        294 ECB             :             {
                                295                 :                 /*
                                296                 :                  * If there is no combine function, then partial aggregation
                                297                 :                  * is not possible.
                                298                 :                  */
  866 heikki.linnakangas        299 GIC       16693 :                 if (!OidIsValid(transinfo->combinefn_oid))
  866 heikki.linnakangas        300 CBC         328 :                     root->hasNonPartialAggs = true;
  866 heikki.linnakangas        301 ECB             : 
                                302                 :                 /*
                                303                 :                  * If we have any aggs with transtype INTERNAL then we must
                                304                 :                  * check whether they have serialization/deserialization
                                305                 :                  * functions; if not, we can't serialize partial-aggregation
                                306                 :                  * results.
                                307                 :                  */
   76 drowley                   308 GNC       16365 :                 else if (transinfo->aggtranstype == INTERNALOID)
                                309                 :                 {
                                310                 : 
                                311            7695 :                     if (!OidIsValid(transinfo->serialfn_oid) ||
                                312            7695 :                         !OidIsValid(transinfo->deserialfn_oid))
   76 drowley                   313 UNC           0 :                         root->hasNonSerialAggs = true;
                                314                 : 
                                315                 :                     /*
                                316                 :                      * array_agg_serialize and array_agg_deserialize make use
                                317                 :                      * of the aggregate non-byval input type's send and
                                318                 :                      * receive functions.  There's a chance that the type
                                319                 :                      * being aggregated has one or both of these functions
                                320                 :                      * missing.  In this case we must not allow the
                                321                 :                      * aggregate's serial and deserial functions to be used.
                                322                 :                      * It would be nice not to have special case this and
                                323                 :                      * instead provide some sort of supporting function within
                                324                 :                      * the aggregate to do this, but for now, that seems like
                                325                 :                      * overkill for this one case.
                                326                 :                      */
   76 drowley                   327 GNC        7695 :                     if ((transinfo->serialfn_oid == F_ARRAY_AGG_SERIALIZE ||
                                328            1937 :                          transinfo->deserialfn_oid == F_ARRAY_AGG_DESERIALIZE) &&
                                329            5758 :                         !agg_args_support_sendreceive(aggref))
                                330             303 :                         root->hasNonSerialAggs = true;
                                331                 :                 }
  866 heikki.linnakangas        332 ECB             :             }
                                333                 :         }
  866 heikki.linnakangas        334 GBC       17981 :         agginfo->transno = transno;
                                335                 :     }
                                336                 : 
                                337                 :     /*
                                338                 :      * Fill in the fields in the Aggref (aggtranstype was set above already)
                                339                 :      */
  866 heikki.linnakangas        340 GIC       18526 :     aggref->aggno = aggno;
                                341           18526 :     aggref->aggtransno = transno;
                                342           18526 : }
                                343                 : 
                                344                 : static bool
                                345           83692 : preprocess_aggrefs_walker(Node *node, PlannerInfo *root)
                                346                 : {
                                347           83692 :     if (node == NULL)
  866 heikki.linnakangas        348 CBC       16279 :         return false;
                                349           67413 :     if (IsA(node, Aggref))
  866 heikki.linnakangas        350 ECB             :     {
  866 heikki.linnakangas        351 CBC       18526 :         Aggref     *aggref = (Aggref *) node;
                                352                 : 
  866 heikki.linnakangas        353 GIC       18526 :         preprocess_aggref(aggref, root);
                                354                 : 
  866 heikki.linnakangas        355 ECB             :         /*
                                356                 :          * We assume that the parser checked that there are no aggregates (of
                                357                 :          * this level anyway) in the aggregated arguments, direct arguments,
                                358                 :          * or filter clause.  Hence, we need not recurse into any of them.
                                359                 :          */
  866 heikki.linnakangas        360 GIC       18526 :         return false;
  866 heikki.linnakangas        361 ECB             :     }
  866 heikki.linnakangas        362 CBC       48887 :     Assert(!IsA(node, SubLink));
                                363           48887 :     return expression_tree_walker(node, preprocess_aggrefs_walker,
                                364                 :                                   (void *) root);
                                365                 : }
  866 heikki.linnakangas        366 ECB             : 
                                367                 : 
                                368                 : /*
                                369                 :  * find_compatible_agg - search for a previously initialized per-Agg struct
                                370                 :  *
                                371                 :  * Searches the previously looked at aggregates to find one which is compatible
                                372                 :  * with this one, with the same input parameters.  If no compatible aggregate
                                373                 :  * can be found, returns -1.
                                374                 :  *
                                375                 :  * As a side-effect, this also collects a list of existing, shareable per-Trans
                                376                 :  * structs with matching inputs.  If no identical Aggref is found, the list is
                                377                 :  * passed later to find_compatible_trans, to see if we can at least reuse
                                378                 :  * the state value of another aggregate.
                                379                 :  */
                                380                 : static int
  866 heikki.linnakangas        381 CBC       18526 : find_compatible_agg(PlannerInfo *root, Aggref *newagg,
                                382                 :                     List **same_input_transnos)
  866 heikki.linnakangas        383 ECB             : {
                                384                 :     ListCell   *lc;
                                385                 :     int         aggno;
                                386                 : 
  866 heikki.linnakangas        387 GIC       18526 :     *same_input_transnos = NIL;
                                388                 : 
                                389                 :     /* we mustn't reuse the aggref if it contains volatile function calls */
                                390           18526 :     if (contain_volatile_functions((Node *) newagg))
                                391             179 :         return -1;
                                392                 : 
                                393                 :     /*
                                394                 :      * Search through the list of already seen aggregates.  If we find an
                                395                 :      * existing identical aggregate call, then we can re-use that one.  While
                                396                 :      * searching, we'll also collect a list of Aggrefs with the same input
                                397                 :      * parameters.  If no matching Aggref is found, the caller can potentially
                                398                 :      * still re-use the transition state of one of them.  (At this stage we
                                399                 :      * just compare the parsetrees; whether different aggregates share the
                                400                 :      * same transition function will be checked later.)
                                401                 :      */
  866 heikki.linnakangas        402 CBC       18347 :     aggno = -1;
  866 heikki.linnakangas        403 GIC       23064 :     foreach(lc, root->agginfos)
                                404                 :     {
  264 tgl                       405 GNC        5262 :         AggInfo    *agginfo = lfirst_node(AggInfo, lc);
                                406                 :         Aggref     *existingRef;
                                407                 : 
  866 heikki.linnakangas        408 CBC        5262 :         aggno++;
                                409                 : 
  250 drowley                   410 GNC        5262 :         existingRef = linitial_node(Aggref, agginfo->aggrefs);
  866 heikki.linnakangas        411 ECB             : 
                                412                 :         /* all of the following must be the same or it's no match */
  866 heikki.linnakangas        413 GIC        5262 :         if (newagg->inputcollid != existingRef->inputcollid ||
                                414            4658 :             newagg->aggtranstype != existingRef->aggtranstype ||
                                415            2875 :             newagg->aggstar != existingRef->aggstar ||
                                416            2388 :             newagg->aggvariadic != existingRef->aggvariadic ||
                                417            2388 :             newagg->aggkind != existingRef->aggkind ||
                                418            2289 :             !equal(newagg->args, existingRef->args) ||
                                419            1146 :             !equal(newagg->aggorder, existingRef->aggorder) ||
                                420            1143 :             !equal(newagg->aggdistinct, existingRef->aggdistinct) ||
                                421            1143 :             !equal(newagg->aggfilter, existingRef->aggfilter))
                                422            4149 :             continue;
  866 heikki.linnakangas        423 ECB             : 
                                424                 :         /* if it's the same aggregate function then report exact match */
  866 heikki.linnakangas        425 GIC        1113 :         if (newagg->aggfnoid == existingRef->aggfnoid &&
  866 heikki.linnakangas        426 CBC         551 :             newagg->aggtype == existingRef->aggtype &&
  866 heikki.linnakangas        427 GIC        1102 :             newagg->aggcollid == existingRef->aggcollid &&
                                428             551 :             equal(newagg->aggdirectargs, existingRef->aggdirectargs))
  866 heikki.linnakangas        429 ECB             :         {
  866 heikki.linnakangas        430 GIC         545 :             list_free(*same_input_transnos);
  866 heikki.linnakangas        431 CBC         545 :             *same_input_transnos = NIL;
  866 heikki.linnakangas        432 GIC         545 :             return aggno;
                                433                 :         }
  866 heikki.linnakangas        434 ECB             : 
                                435                 :         /*
                                436                 :          * Not identical, but it had the same inputs.  If the final function
                                437                 :          * permits sharing, return its transno to the caller, in case we can
                                438                 :          * re-use its per-trans state.  (If there's already sharing going on,
                                439                 :          * we might report a transno more than once.  find_compatible_trans is
                                440                 :          * cheap enough that it's not worth spending cycles to avoid that.)
                                441                 :          */
  866 heikki.linnakangas        442 CBC         568 :         if (agginfo->shareable)
                                443             565 :             *same_input_transnos = lappend_int(*same_input_transnos,
                                444                 :                                                agginfo->transno);
                                445                 :     }
  866 heikki.linnakangas        446 ECB             : 
  866 heikki.linnakangas        447 CBC       17802 :     return -1;
  866 heikki.linnakangas        448 ECB             : }
                                449                 : 
                                450                 : /*
                                451                 :  * find_compatible_trans - search for a previously initialized per-Trans
                                452                 :  * struct
                                453                 :  *
                                454                 :  * Searches the list of transnos for a per-Trans struct with the same
                                455                 :  * transition function and initial condition. (The inputs have already been
                                456                 :  * verified to match.)
                                457                 :  */
                                458                 : static int
  866 heikki.linnakangas        459 GIC       17981 : find_compatible_trans(PlannerInfo *root, Aggref *newagg, bool shareable,
                                460                 :                       Oid aggtransfn, Oid aggtranstype,
                                461                 :                       int transtypeLen, bool transtypeByVal,
                                462                 :                       Oid aggcombinefn,
  866 heikki.linnakangas        463 ECB             :                       Oid aggserialfn, Oid aggdeserialfn,
                                464                 :                       Datum initValue, bool initValueIsNull,
                                465                 :                       List *transnos)
                                466                 : {
                                467                 :     ListCell   *lc;
                                468                 : 
                                469                 :     /* If this aggregate can't share transition states, give up */
  866 heikki.linnakangas        470 GIC       17981 :     if (!shareable)
                                471              60 :         return -1;
                                472                 : 
                                473           18330 :     foreach(lc, transnos)
                                474                 :     {
                                475             538 :         int         transno = lfirst_int(lc);
  264 tgl                       476 GNC         538 :         AggTransInfo *pertrans = list_nth_node(AggTransInfo,
                                477                 :                                                root->aggtransinfos,
                                478                 :                                                transno);
                                479                 : 
                                480                 :         /*
                                481                 :          * if the transfns or transition state types are not the same then the
  866 heikki.linnakangas        482 ECB             :          * state can't be shared.
                                483                 :          */
  866 heikki.linnakangas        484 GIC         538 :         if (aggtransfn != pertrans->transfn_oid ||
                                485             132 :             aggtranstype != pertrans->aggtranstype)
                                486             406 :             continue;
                                487                 : 
                                488                 :         /*
                                489                 :          * The serialization and deserialization functions must match, if
                                490                 :          * present, as we're unable to share the trans state for aggregates
                                491                 :          * which will serialize or deserialize into different formats.
                                492                 :          * Remember that these will be InvalidOid if they're not required for
  866 heikki.linnakangas        493 ECB             :          * this agg node.
                                494                 :          */
  866 heikki.linnakangas        495 GIC         132 :         if (aggserialfn != pertrans->serialfn_oid ||
  866 heikki.linnakangas        496 CBC         132 :             aggdeserialfn != pertrans->deserialfn_oid)
  866 heikki.linnakangas        497 UIC           0 :             continue;
  866 heikki.linnakangas        498 ECB             : 
                                499                 :         /*
                                500                 :          * Combine function must also match.  We only care about the combine
                                501                 :          * function with partial aggregates, but it's too early in the
                                502                 :          * planning to know if we will do partial aggregation, so be
                                503                 :          * conservative.
                                504                 :          */
  866 heikki.linnakangas        505 GIC         132 :         if (aggcombinefn != pertrans->combinefn_oid)
  866 heikki.linnakangas        506 UIC           0 :             continue;
  866 heikki.linnakangas        507 ECB             : 
                                508                 :         /*
                                509                 :          * Check that the initial condition matches, too.
                                510                 :          */
  866 heikki.linnakangas        511 GIC         132 :         if (initValueIsNull && pertrans->initValueIsNull)
                                512             129 :             return transno;
                                513                 : 
                                514             168 :         if (!initValueIsNull && !pertrans->initValueIsNull &&
                                515              84 :             datumIsEqual(initValue, pertrans->initValue,
                                516                 :                          transtypeByVal, transtypeLen))
                                517              81 :             return transno;
  866 heikki.linnakangas        518 ECB             :     }
  866 heikki.linnakangas        519 CBC       17792 :     return -1;
  866 heikki.linnakangas        520 EUB             : }
                                521                 : 
                                522                 : static Datum
  866 heikki.linnakangas        523 GIC        7066 : GetAggInitVal(Datum textInitVal, Oid transtype)
                                524                 : {
                                525                 :     Oid         typinput,
                                526                 :                 typioparam;
                                527                 :     char       *strInitVal;
  866 heikki.linnakangas        528 ECB             :     Datum       initVal;
  866 heikki.linnakangas        529 EUB             : 
  866 heikki.linnakangas        530 GIC        7066 :     getTypeInputInfo(transtype, &typinput, &typioparam);
                                531            7066 :     strInitVal = TextDatumGetCString(textInitVal);
                                532            7066 :     initVal = OidInputFunctionCall(typinput, strInitVal,
                                533                 :                                    typioparam, -1);
  866 heikki.linnakangas        534 CBC        7066 :     pfree(strInitVal);
                                535            7066 :     return initVal;
                                536                 : }
  866 heikki.linnakangas        537 ECB             : 
                                538                 : 
                                539                 : /*
                                540                 :  * get_agg_clause_costs
                                541                 :  *    Process the PlannerInfo's 'aggtransinfos' and 'agginfos' lists
  622 drowley                   542                 :  *    accumulating the cost information about them.
                                543                 :  *
                                544                 :  * 'aggsplit' tells us the expected partial-aggregation mode, which affects
                                545                 :  * the cost estimates.
  866 heikki.linnakangas        546                 :  *
                                547                 :  * NOTE that the costs are ADDED to those already in *costs ... so the caller
                                548                 :  * is responsible for zeroing the struct initially.
                                549                 :  *
                                550                 :  * For each AggTransInfo, we add the cost of an aggregate transition using
                                551                 :  * either the transfn or combinefn depending on the 'aggsplit' value.  We also
                                552                 :  * account for the costs of any aggfilters and any serializations and
  622 drowley                   553                 :  * deserializations of the transition state and also estimate the total space
                                554                 :  * needed for the transition states as if each aggregate's state was stored in
                                555                 :  * memory concurrently (as would be done in a HashAgg plan).
                                556                 :  *
                                557                 :  * For each AggInfo in the 'agginfos' list we add the cost of running the
                                558                 :  * final function and the direct args, if any.
                                559                 :  */
                                560                 : void
  866 heikki.linnakangas        561 GIC       17404 : get_agg_clause_costs(PlannerInfo *root, AggSplit aggsplit, AggClauseCosts *costs)
                                562                 : {
                                563                 :     ListCell   *lc;
                                564                 : 
                                565           37178 :     foreach(lc, root->aggtransinfos)
                                566                 :     {
  264 tgl                       567 GNC       19774 :         AggTransInfo *transinfo = lfirst_node(AggTransInfo, lc);
                                568                 : 
                                569                 :         /*
                                570                 :          * Add the appropriate component function execution costs to
                                571                 :          * appropriate totals.
                                572                 :          */
  866 heikki.linnakangas        573 GIC       19774 :         if (DO_AGGSPLIT_COMBINE(aggsplit))
                                574                 :         {
                                575                 :             /* charge for combining previously aggregated states */
                                576             890 :             add_function_cost(root, transinfo->combinefn_oid, NULL,
                                577                 :                               &costs->transCost);
                                578                 :         }
                                579                 :         else
                                580           18884 :             add_function_cost(root, transinfo->transfn_oid, NULL,
                                581                 :                               &costs->transCost);
                                582           19774 :         if (DO_AGGSPLIT_DESERIALIZE(aggsplit) &&
                                583             890 :             OidIsValid(transinfo->deserialfn_oid))
  866 heikki.linnakangas        584 CBC          61 :             add_function_cost(root, transinfo->deserialfn_oid, NULL,
                                585                 :                               &costs->transCost);
  866 heikki.linnakangas        586 GIC       19774 :         if (DO_AGGSPLIT_SERIALIZE(aggsplit) &&
                                587             890 :             OidIsValid(transinfo->serialfn_oid))
  866 heikki.linnakangas        588 CBC          61 :             add_function_cost(root, transinfo->serialfn_oid, NULL,
                                589                 :                               &costs->finalCost);
  866 heikki.linnakangas        590 ECB             : 
                                591                 :         /*
                                592                 :          * These costs are incurred only by the initial aggregate node, so we
                                593                 :          * mustn't include them again at upper levels.
                                594                 :          */
  866 heikki.linnakangas        595 GIC       19774 :         if (!DO_AGGSPLIT_COMBINE(aggsplit))
  866 heikki.linnakangas        596 ECB             :         {
                                597                 :             /* add the input expressions' cost to per-input-row costs */
                                598                 :             QualCost    argcosts;
                                599                 : 
  866 heikki.linnakangas        600 GIC       18884 :             cost_qual_eval_node(&argcosts, (Node *) transinfo->args, root);
                                601           18884 :             costs->transCost.startup += argcosts.startup;
                                602           18884 :             costs->transCost.per_tuple += argcosts.per_tuple;
  866 heikki.linnakangas        603 ECB             : 
                                604                 :             /*
                                605                 :              * Add any filter's cost to per-input-row costs.
                                606                 :              *
                                607                 :              * XXX Ideally we should reduce input expression costs according
                                608                 :              * to filter selectivity, but it's not clear it's worth the
                                609                 :              * trouble.
                                610                 :              */
  866 heikki.linnakangas        611 CBC       18884 :             if (transinfo->aggfilter)
                                612                 :             {
  866 heikki.linnakangas        613 GIC         323 :                 cost_qual_eval_node(&argcosts, (Node *) transinfo->aggfilter,
                                614                 :                                     root);
                                615             323 :                 costs->transCost.startup += argcosts.startup;
                                616             323 :                 costs->transCost.per_tuple += argcosts.per_tuple;
                                617                 :             }
  866 heikki.linnakangas        618 ECB             :         }
                                619                 : 
                                620                 :         /*
                                621                 :          * If the transition type is pass-by-value then it doesn't add
                                622                 :          * anything to the required size of the hashtable.  If it is
                                623                 :          * pass-by-reference then we have to add the estimated size of the
                                624                 :          * value itself, plus palloc overhead.
                                625                 :          */
  866 heikki.linnakangas        626 GIC       19774 :         if (!transinfo->transtypeByVal)
                                627                 :         {
                                628                 :             int32       avgwidth;
                                629                 : 
                                630                 :             /* Use average width if aggregate definition gave one */
                                631            1406 :             if (transinfo->aggtransspace > 0)
                                632              45 :                 avgwidth = transinfo->aggtransspace;
                                633            1361 :             else if (transinfo->transfn_oid == F_ARRAY_APPEND)
  866 heikki.linnakangas        634 ECB             :             {
                                635                 :                 /*
                                636                 :                  * If the transition function is array_append(), it'll use an
                                637                 :                  * expanded array as transvalue, which will occupy at least
                                638                 :                  * ALLOCSET_SMALL_INITSIZE and possibly more.  Use that as the
                                639                 :                  * estimate for lack of a better idea.
                                640                 :                  */
  866 heikki.linnakangas        641 GIC           3 :                 avgwidth = ALLOCSET_SMALL_INITSIZE;
                                642                 :             }
                                643                 :             else
                                644                 :             {
                                645            1358 :                 avgwidth = get_typavgwidth(transinfo->aggtranstype, transinfo->aggtranstypmod);
                                646                 :             }
                                647                 : 
                                648            1406 :             avgwidth = MAXALIGN(avgwidth);
  866 heikki.linnakangas        649 CBC        1406 :             costs->transitionSpace += avgwidth + 2 * sizeof(void *);
                                650                 :         }
  866 heikki.linnakangas        651 GIC       18368 :         else if (transinfo->aggtranstype == INTERNALOID)
                                652                 :         {
                                653                 :             /*
  866 heikki.linnakangas        654 ECB             :              * INTERNAL transition type is a special case: although INTERNAL
                                655                 :              * is pass-by-value, it's almost certainly being used as a pointer
                                656                 :              * to some large data structure.  The aggregate definition can
                                657                 :              * provide an estimate of the size.  If it doesn't, then we assume
                                658                 :              * ALLOCSET_DEFAULT_INITSIZE, which is a good guess if the data is
                                659                 :              * being kept in a private memory context, as is done by
                                660                 :              * array_agg() for instance.
                                661                 :              */
  866 heikki.linnakangas        662 GIC        8737 :             if (transinfo->aggtransspace > 0)
                                663             525 :                 costs->transitionSpace += transinfo->aggtransspace;
  866 heikki.linnakangas        664 ECB             :             else
  866 heikki.linnakangas        665 GIC        8212 :                 costs->transitionSpace += ALLOCSET_DEFAULT_INITSIZE;
                                666                 :         }
                                667                 :     }
  866 heikki.linnakangas        668 ECB             : 
  866 heikki.linnakangas        669 GIC       37307 :     foreach(lc, root->agginfos)
                                670                 :     {
  264 tgl                       671 GNC       19903 :         AggInfo    *agginfo = lfirst_node(AggInfo, lc);
  250 drowley                   672           19903 :         Aggref     *aggref = linitial_node(Aggref, agginfo->aggrefs);
                                673                 : 
  866 heikki.linnakangas        674 ECB             :         /*
                                675                 :          * Add the appropriate component function execution costs to
                                676                 :          * appropriate totals.
                                677                 :          */
  866 heikki.linnakangas        678 GIC       19903 :         if (!DO_AGGSPLIT_SKIPFINAL(aggsplit) &&
                                679           19013 :             OidIsValid(agginfo->finalfn_oid))
                                680            9586 :             add_function_cost(root, agginfo->finalfn_oid, NULL,
                                681                 :                               &costs->finalCost);
                                682                 : 
                                683                 :         /*
                                684                 :          * If there are direct arguments, treat their evaluation cost like the
  866 heikki.linnakangas        685 ECB             :          * cost of the finalfn.
                                686                 :          */
  866 heikki.linnakangas        687 GIC       19903 :         if (aggref->aggdirectargs)
  866 heikki.linnakangas        688 ECB             :         {
                                689                 :             QualCost    argcosts;
                                690                 : 
  866 heikki.linnakangas        691 GIC         147 :             cost_qual_eval_node(&argcosts, (Node *) aggref->aggdirectargs,
  866 heikki.linnakangas        692 ECB             :                                 root);
  866 heikki.linnakangas        693 GIC         147 :             costs->finalCost.startup += argcosts.startup;
  866 heikki.linnakangas        694 CBC         147 :             costs->finalCost.per_tuple += argcosts.per_tuple;
  866 heikki.linnakangas        695 ECB             :         }
                                696                 :     }
  866 heikki.linnakangas        697 GIC       17404 : }
        

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