LCOV - differential code coverage report
Current view: top level - src/backend/executor - execGrouping.c (source / functions) Coverage Total Hit UBC GNC CBC DCB
Current: c38de3ae6098ccf1904109f2e550eb4777f66024 vs e352ac8c5c90ed6ce792f044c22145578542a330 Lines: 89.6 % 135 121 14 3 118 4
Current Date: 2026-11-05 14:14:01 +0100 Functions: 91.7 % 12 11 1 3 8
Baseline: lcov-20261105-baseline Branches: 70.8 % 48 34 14 34
Baseline Date: 2026-11-05 14:14:01 +0100 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(7,30] days: 85.7 % 7 6 1 6
(30,360] days: 100.0 % 4 4 3 1
(360..) days: 89.5 % 124 111 13 111
Function coverage date bins:
(360..) days: 91.7 % 12 11 1 3 8
Branch coverage date bins:
(7,30] days: 75.0 % 4 3 1 3
(360..) days: 70.5 % 44 31 13 31

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*-------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * execGrouping.c
                                  4                 :                :  *    executor utility routines for grouping, hashing, and aggregation
                                  5                 :                :  *
                                  6                 :                :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
                                  7                 :                :  * Portions Copyright (c) 1994, Regents of the University of California
                                  8                 :                :  *
                                  9                 :                :  *
                                 10                 :                :  * IDENTIFICATION
                                 11                 :                :  *    src/backend/executor/execGrouping.c
                                 12                 :                :  *
                                 13                 :                :  *-------------------------------------------------------------------------
                                 14                 :                :  */
                                 15                 :                : #include "postgres.h"
                                 16                 :                : 
                                 17                 :                : #include <math.h>
                                 18                 :                : 
                                 19                 :                : #include "access/htup_details.h"
                                 20                 :                : #include "access/parallel.h"
                                 21                 :                : #include "common/hashfn.h"
                                 22                 :                : #include "executor/executor.h"
                                 23                 :                : #include "miscadmin.h"
                                 24                 :                : #include "utils/lsyscache.h"
                                 25                 :                : 
                                 26                 :                : static int  TupleHashTableMatch(struct tuplehash_hash *tb, MinimalTuple tuple1, MinimalTuple tuple2);
                                 27                 :                : static inline uint32 TupleHashTableHash_internal(struct tuplehash_hash *tb,
                                 28                 :                :                                                  MinimalTuple tuple);
                                 29                 :                : static inline TupleHashEntry LookupTupleHashEntry_internal(TupleHashTable hashtable,
                                 30                 :                :                                                            TupleTableSlot *slot,
                                 31                 :                :                                                            bool *isnew, uint32 hash);
                                 32                 :                : 
                                 33                 :                : /*
                                 34                 :                :  * Define parameters for tuple hash table code generation. The interface is
                                 35                 :                :  * *also* declared in execnodes.h (to generate the types, which are externally
                                 36                 :                :  * visible).
                                 37                 :                :  */
                                 38                 :                : #define SH_PREFIX tuplehash
                                 39                 :                : #define SH_ELEMENT_TYPE TupleHashEntryData
                                 40                 :                : #define SH_KEY_TYPE MinimalTuple
                                 41                 :                : #define SH_KEY firstTuple
                                 42                 :                : #define SH_HASH_KEY(tb, key) TupleHashTableHash_internal(tb, key)
                                 43                 :                : #define SH_EQUAL(tb, a, b) TupleHashTableMatch(tb, a, b) == 0
                                 44                 :                : #define SH_SCOPE extern
                                 45                 :                : #define SH_STORE_HASH
                                 46                 :                : #define SH_GET_HASH(tb, a) a->hash
                                 47                 :                : #define SH_DEFINE
                                 48                 :                : #include "lib/simplehash.h"
                                 49                 :                : 
                                 50                 :                : 
                                 51                 :                : /*****************************************************************************
                                 52                 :                :  *      Utility routines for grouping tuples together
                                 53                 :                :  *****************************************************************************/
                                 54                 :                : 
                                 55                 :                : /*
                                 56                 :                :  * execTuplesMatchPrepare
                                 57                 :                :  *      Build expression that can be evaluated using ExecQual(), returning
                                 58                 :                :  *      whether an ExprContext's inner/outer tuples are NOT DISTINCT
                                 59                 :                :  */
                                 60                 :                : ExprState *
 3185 andres@anarazel.de         61                 :CBC        8045 : execTuplesMatchPrepare(TupleDesc desc,
                                 62                 :                :                        int numCols,
                                 63                 :                :                        const AttrNumber *keyColIdx,
                                 64                 :                :                        const Oid *eqOperators,
                                 65                 :                :                        const Oid *collations,
                                 66                 :                :                        PlanState *parent)
                                 67                 :                : {
                                 68                 :                :     Oid        *eqFunctions;
                                 69                 :                :     int         i;
                                 70                 :                :     ExprState  *expr;
                                 71                 :                : 
                                 72         [ +  + ]:           8045 :     if (numCols == 0)
                                 73                 :             35 :         return NULL;
                                 74                 :                : 
   80 michael@paquier.xyz        75                 :GNC        8010 :     eqFunctions = palloc_array(Oid, numCols);
                                 76                 :                : 
                                 77                 :                :     /* lookup equality functions */
 8700 tgl@sss.pgh.pa.us          78         [ +  + ]:CBC       21805 :     for (i = 0; i < numCols; i++)
 3185 andres@anarazel.de         79                 :          13795 :         eqFunctions[i] = get_opcode(eqOperators[i]);
                                 80                 :                : 
                                 81                 :                :     /* build actual expression */
 2912                            82                 :           8010 :     expr = ExecBuildGroupingEqual(desc, desc, NULL, NULL,
                                 83                 :                :                                   numCols, keyColIdx, eqFunctions, collations,
                                 84                 :                :                                   parent);
                                 85                 :                : 
 3185                            86                 :           8010 :     return expr;
                                 87                 :                : }
                                 88                 :                : 
                                 89                 :                : /*
                                 90                 :                :  * execTuplesHashPrepare
                                 91                 :                :  *      Look up the equality and hashing functions needed for a TupleHashTable.
                                 92                 :                :  *
                                 93                 :                :  * This is similar to execTuplesMatchPrepare, but we also need to find the
                                 94                 :                :  * hash functions associated with the equality operators.  *eqFunctions and
                                 95                 :                :  * *hashFunctions receive the palloc'd result arrays.
                                 96                 :                :  *
                                 97                 :                :  * Note: we expect that the given operators are not cross-type comparisons.
                                 98                 :                :  */
                                 99                 :                : void
 7239 tgl@sss.pgh.pa.us         100                 :           6252 : execTuplesHashPrepare(int numCols,
                                101                 :                :                       const Oid *eqOperators,
                                102                 :                :                       Oid **eqFuncOids,
                                103                 :                :                       FmgrInfo **hashFunctions)
                                104                 :                : {
                                105                 :                :     int         i;
                                106                 :                : 
   80 michael@paquier.xyz       107                 :GNC        6252 :     *eqFuncOids = palloc_array(Oid, numCols);
                                108                 :           6252 :     *hashFunctions = palloc_array(FmgrInfo, numCols);
                                109                 :                : 
 8537 tgl@sss.pgh.pa.us         110         [ +  + ]:CBC       17010 :     for (i = 0; i < numCols; i++)
                                111                 :                :     {
 7239                           112                 :          10758 :         Oid         eq_opr = eqOperators[i];
                                113                 :                :         Oid         eq_function;
                                114                 :                :         Oid         left_hash_function;
                                115                 :                :         Oid         right_hash_function;
                                116                 :                : 
                                117                 :          10758 :         eq_function = get_opcode(eq_opr);
 7219                           118         [ -  + ]:          10758 :         if (!get_op_hash_functions(eq_opr,
                                119                 :                :                                    &left_hash_function, &right_hash_function))
 8508 tgl@sss.pgh.pa.us         120         [ #  # ]:UBC           0 :             elog(ERROR, "could not find hash function for hash operator %u",
                                121                 :                :                  eq_opr);
                                122                 :                :         /* We're not supporting cross-type cases here */
 7219 tgl@sss.pgh.pa.us         123         [ -  + ]:CBC       10758 :         Assert(left_hash_function == right_hash_function);
 3185 andres@anarazel.de        124                 :          10758 :         (*eqFuncOids)[i] = eq_function;
 7219 tgl@sss.pgh.pa.us         125                 :          10758 :         fmgr_info(right_hash_function, &(*hashFunctions)[i]);
                                126                 :                :     }
 8700                           127                 :           6252 : }
                                128                 :                : 
                                129                 :                : 
                                130                 :                : /*****************************************************************************
                                131                 :                :  *      Utility routines for all-in-memory hash tables
                                132                 :                :  *
                                133                 :                :  * These routines build hash tables for grouping tuples together (eg, for
                                134                 :                :  * hash aggregation).  There is one entry for each not-distinct set of tuples
                                135                 :                :  * presented.
                                136                 :                :  *****************************************************************************/
                                137                 :                : 
                                138                 :                : /*
                                139                 :                :  * Construct an empty TupleHashTable
                                140                 :                :  *
                                141                 :                :  *  parent: PlanState node that will own this hash table
                                142                 :                :  *  inputDesc: tuple descriptor for input tuples
                                143                 :                :  *  inputOps: slot ops for input tuples, or NULL if unknown or not fixed
                                144                 :                :  *  numCols: number of columns to be compared (length of next 4 arrays)
                                145                 :                :  *  keyColIdx: indexes of tuple columns to compare
                                146                 :                :  *  eqfuncoids: OIDs of equality comparison functions to use
                                147                 :                :  *  hashfunctions: FmgrInfos of datatype-specific hashing functions to use
                                148                 :                :  *  collations: collations to use in comparisons
                                149                 :                :  *  nelements: initial estimate of hashtable size
                                150                 :                :  *  additionalsize: size of data that may be stored along with the hash entry
                                151                 :                :  *  metacxt: memory context for long-lived data and the simplehash table
                                152                 :                :  *  tuplescxt: memory context in which to store the hashed tuples themselves
                                153                 :                :  *  tempcxt: short-lived context for evaluation hash and comparison functions
                                154                 :                :  *  use_variable_hash_iv: if true, adjust hash IV per-parallel-worker
                                155                 :                :  *
                                156                 :                :  * The hashfunctions array may be made with execTuplesHashPrepare().  Note they
                                157                 :                :  * are not cross-type functions, but expect to see the table datatype(s)
                                158                 :                :  * on both sides.
                                159                 :                :  *
                                160                 :                :  * Note that the keyColIdx, hashfunctions, and collations arrays must be
                                161                 :                :  * allocated in storage that will live as long as the hashtable does.
                                162                 :                :  *
                                163                 :                :  * The metacxt and tuplescxt are separate because it's usually desirable for
                                164                 :                :  * tuplescxt to be a BumpContext to avoid memory wastage, while metacxt must
                                165                 :                :  * support pfree in case the simplehash table needs to be enlarged.  (We could
                                166                 :                :  * simplify the API of TupleHashTables by managing the tuplescxt internally.
                                167                 :                :  * But that would be disadvantageous to nodeAgg.c and nodeSubplan.c, which use
                                168                 :                :  * a single tuplescxt for multiple TupleHashTables that are reset together.)
                                169                 :                :  *
                                170                 :                :  * LookupTupleHashEntry, FindTupleHashEntry, and related functions may leak
                                171                 :                :  * memory in the tempcxt.  It is caller's responsibility to reset that context
                                172                 :                :  * reasonably often, typically once per tuple.  (We do it that way, rather
                                173                 :                :  * than managing an extra context within the hashtable, because in many cases
                                174                 :                :  * the caller can specify a tempcxt that it needs to reset per-tuple anyway.)
                                175                 :                :  *
                                176                 :                :  * We don't currently provide DestroyTupleHashTable functionality; the hash
                                177                 :                :  * table will be cleaned up at destruction of the metacxt.  (Some callers
                                178                 :                :  * bother to delete the tuplescxt explicitly, though it'd be sufficient to
                                179                 :                :  * ensure it's a child of the metacxt.)  There's not much point in working
                                180                 :                :  * harder than this so long as the expression-evaluation infrastructure
                                181                 :                :  * behaves similarly.
                                182                 :                :  */
                                183                 :                : TupleHashTable
  686                           184                 :           5360 : BuildTupleHashTable(PlanState *parent,
                                185                 :                :                     TupleDesc inputDesc,
                                186                 :                :                     const TupleTableSlotOps *inputOps,
                                187                 :                :                     int numCols,
                                188                 :                :                     AttrNumber *keyColIdx,
                                189                 :                :                     const Oid *eqfuncoids,
                                190                 :                :                     FmgrInfo *hashfunctions,
                                191                 :                :                     Oid *collations,
                                192                 :                :                     double nelements,
                                193                 :                :                     Size additionalsize,
                                194                 :                :                     MemoryContext metacxt,
                                195                 :                :                     MemoryContext tuplescxt,
                                196                 :                :                     MemoryContext tempcxt,
                                197                 :                :                     bool use_variable_hash_iv)
                                198                 :                : {
                                199                 :                :     TupleHashTable hashtable;
                                200                 :                :     uint32      nbuckets;
                                201                 :                :     MemoryContext oldcontext;
  694 drowley@postgresql.o      202                 :           5360 :     uint32      hash_iv = 0;
                                203                 :                : 
                                204                 :                :     /*
                                205                 :                :      * tuplehash_create requires a uint32 element count, so we had better
                                206                 :                :      * clamp the given nelements to fit in that.  We'd also better do
                                207                 :                :      * something sane when faced with a zero or NaN estimate.  There are
                                208                 :                :      * various reasons why the planner might not be able to provide a good
                                209                 :                :      * estimate here; for example, recursive CTEs don't base their estimate on
                                210                 :                :      * anything reliable and can yield some rather large estimates.  Here we
                                211                 :                :      * cap nbuckets to hash_mem to help prevent insane memory allocations. The
                                212                 :                :      * hash table can still grow when the bucket count is insufficient. That
                                213                 :                :      * will make the query a little slower, but that's better than outright
                                214                 :                :      * failing due to OOM if we were to request an insane bucket count.
                                215                 :                :      * Queries being slightly slower with smaller work_mem values is also
                                216                 :                :      * aligned to user expectations.  We purposefully don't include the tuple
                                217                 :                :      * width in this calculation, as that would make the cap depend on planner
                                218                 :                :      * estimates for the tuple width, which could also be unreliable.
                                219                 :                :      */
  368 tgl@sss.pgh.pa.us         220   [ +  -  -  + ]:           5360 :     if (isnan(nelements) || nelements <= 0)
  368 tgl@sss.pgh.pa.us         221                 :UBC           0 :         nbuckets = 1;
                                222                 :                :     else
                                223                 :                :     {
                                224                 :                :         size_t      entrysize;
                                225                 :                :         size_t      hash_mem_limit;
                                226                 :                : 
    8 drowley@postgresql.o      227         [ -  + ]:CBC        5360 :         if (nelements >= PG_UINT32_MAX)
    8 drowley@postgresql.o      228                 :UBC           0 :             nbuckets = PG_UINT32_MAX;
                                229                 :                :         else
    8 drowley@postgresql.o      230                 :CBC        5360 :             nbuckets = (uint32) nelements;
                                231                 :                : 
                                232                 :           5360 :         entrysize = sizeof(TupleHashEntryData) + additionalsize;
                                233                 :           5360 :         hash_mem_limit = get_hash_memory_limit() / entrysize;
                                234         [ +  + ]:           5360 :         if (nbuckets > hash_mem_limit)
                                235                 :             12 :             nbuckets = hash_mem_limit;
                                236                 :                :     }
                                237                 :                : 
                                238                 :                :     /* tuplescxt must be separate, else ResetTupleHashTable breaks things */
  371 tgl@sss.pgh.pa.us         239         [ -  + ]:           5360 :     Assert(metacxt != tuplescxt);
                                240                 :                : 
                                241                 :                :     /* ensure additionalsize is maxalign'ed */
  591 jdavis@postgresql.or      242                 :           5360 :     additionalsize = MAXALIGN(additionalsize);
                                243                 :                : 
 2826 andres@anarazel.de        244                 :           5360 :     oldcontext = MemoryContextSwitchTo(metacxt);
                                245                 :                : 
  330 michael@paquier.xyz       246                 :           5360 :     hashtable = palloc_object(TupleHashTableData);
                                247                 :                : 
 8700 tgl@sss.pgh.pa.us         248                 :           5360 :     hashtable->numCols = numCols;
                                249                 :           5360 :     hashtable->keyColIdx = keyColIdx;
 2785 peter@eisentraut.org      250                 :           5360 :     hashtable->tab_collations = collations;
  371 tgl@sss.pgh.pa.us         251                 :           5360 :     hashtable->tuplescxt = tuplescxt;
 8700                           252                 :           5360 :     hashtable->tempcxt = tempcxt;
  591 jdavis@postgresql.or      253                 :           5360 :     hashtable->additionalsize = additionalsize;
 7904 tgl@sss.pgh.pa.us         254                 :           5360 :     hashtable->inputslot = NULL;
  694 drowley@postgresql.o      255                 :           5360 :     hashtable->in_hash_expr = NULL;
 3185 andres@anarazel.de        256                 :           5360 :     hashtable->cur_eq_func = NULL;
                                257                 :                : 
                                258                 :                :     /*
                                259                 :                :      * If parallelism is in use, even if the leader backend is performing the
                                260                 :                :      * scan itself, we don't want to create the hashtable exactly the same way
                                261                 :                :      * in all workers. As hashtables are iterated over in keyspace-order,
                                262                 :                :      * doing so in all processes in the same way is likely to lead to
                                263                 :                :      * "unbalanced" hashtables when the table size initially is
                                264                 :                :      * underestimated.
                                265                 :                :      */
 3611 rhaas@postgresql.org      266         [ +  + ]:           5360 :     if (use_variable_hash_iv)
  694 drowley@postgresql.o      267                 :            678 :         hash_iv = murmurhash32(ParallelWorkerNumber);
                                268                 :                : 
 2826 andres@anarazel.de        269                 :           5360 :     hashtable->hashtab = tuplehash_create(metacxt, nbuckets, hashtable);
                                270                 :                : 
                                271                 :                :     /*
                                272                 :                :      * We copy the input tuple descriptor just for safety --- we assume all
                                273                 :                :      * input tuples will have equivalent descriptors.
                                274                 :                :      */
 2912                           275                 :           5360 :     hashtable->tableslot = MakeSingleTupleTableSlot(CreateTupleDescCopy(inputDesc),
                                276                 :                :                                                     &TTSOpsMinimalTuple);
                                277                 :                : 
                                278                 :                :     /* build hash ExprState for all columns */
  694 drowley@postgresql.o      279                 :           5360 :     hashtable->tab_hash_expr = ExecBuildHash32FromAttrs(inputDesc,
                                280                 :                :                                                         inputOps,
                                281                 :                :                                                         hashfunctions,
                                282                 :                :                                                         collations,
                                283                 :                :                                                         numCols,
                                284                 :                :                                                         keyColIdx,
                                285                 :                :                                                         parent,
                                286                 :                :                                                         hash_iv);
                                287                 :                : 
                                288                 :                :     /* build comparator for all columns */
 3185 andres@anarazel.de        289                 :           5360 :     hashtable->tab_eq_func = ExecBuildGroupingEqual(inputDesc, inputDesc,
                                290                 :                :                                                     inputOps,
                                291                 :                :                                                     &TTSOpsMinimalTuple,
                                292                 :                :                                                     numCols,
                                293                 :                :                                                     keyColIdx, eqfuncoids, collations,
                                294                 :                :                                                     parent);
                                295                 :                : 
                                296                 :                :     /*
                                297                 :                :      * While not pretty, it's ok to not shut down this context, but instead
                                298                 :                :      * rely on the containing memory context being reset, as
                                299                 :                :      * ExecBuildGroupingEqual() only builds a very simple expression calling
                                300                 :                :      * functions (i.e. nothing that'd employ RegisterExprContextCallback()).
                                301                 :                :      */
 2826                           302                 :           5360 :     hashtable->exprcontext = CreateStandaloneExprContext();
                                303                 :                : 
                                304                 :           5360 :     MemoryContextSwitchTo(oldcontext);
                                305                 :                : 
 8700 tgl@sss.pgh.pa.us         306                 :           5360 :     return hashtable;
                                307                 :                : }
                                308                 :                : 
                                309                 :                : /*
                                310                 :                :  * Reset contents of the hashtable to be empty, preserving all the non-content
                                311                 :                :  * state.
                                312                 :                :  *
                                313                 :                :  * Note: in usages where several TupleHashTables share a tuplescxt, all must
                                314                 :                :  * be reset together, as the first one's reset call will destroy all their
                                315                 :                :  * data.  The additional reset calls for the rest will redundantly reset the
                                316                 :                :  * tuplescxt.  But because of mcxt.c's isReset flag, that's cheap enough that
                                317                 :                :  * we need not avoid it.
                                318                 :                :  */
                                319                 :                : void
 2826 andres@anarazel.de        320                 :         129408 : ResetTupleHashTable(TupleHashTable hashtable)
                                321                 :                : {
                                322                 :         129408 :     tuplehash_reset(hashtable->hashtab);
  371 tgl@sss.pgh.pa.us         323                 :         129408 :     MemoryContextReset(hashtable->tuplescxt);
 2826 andres@anarazel.de        324                 :         129408 : }
                                325                 :                : 
                                326                 :                : /*
                                327                 :                :  * Estimate the amount of space needed for a TupleHashTable with nentries
                                328                 :                :  * entries, if the tuples have average data width tupleWidth and the caller
                                329                 :                :  * requires additionalsize extra space per entry.
                                330                 :                :  *
                                331                 :                :  * Return SIZE_MAX if it'd overflow size_t.
                                332                 :                :  *
                                333                 :                :  * nentries is "double" because this is meant for use by the planner,
                                334                 :                :  * which typically works with double rowcount estimates.  So we'd need to
                                335                 :                :  * clamp to integer somewhere and that might as well be here.  We do expect
                                336                 :                :  * the value not to be NaN or negative, else the result will be garbage.
                                337                 :                :  */
                                338                 :                : Size
  368 tgl@sss.pgh.pa.us         339                 :           4054 : EstimateTupleHashTableSpace(double nentries,
                                340                 :                :                             Size tupleWidth,
                                341                 :                :                             Size additionalsize)
                                342                 :                : {
                                343                 :                :     Size        sh_space;
                                344                 :                :     double      tuples_space;
                                345                 :                : 
                                346                 :                :     /* First estimate the space needed for the simplehash table */
                                347                 :           4054 :     sh_space = tuplehash_estimate_space(nentries);
                                348                 :                : 
                                349                 :                :     /* Give up if that's already too big */
                                350         [ +  + ]:           4054 :     if (sh_space >= SIZE_MAX)
                                351                 :              5 :         return sh_space;
                                352                 :                : 
                                353                 :                :     /*
                                354                 :                :      * Compute space needed for hashed tuples with additional data.  nentries
                                355                 :                :      * must be somewhat sane, so it should be safe to compute this product.
                                356                 :                :      *
                                357                 :                :      * We assume that the hashed tuples will be kept in a BumpContext so that
                                358                 :                :      * there is not additional per-tuple overhead.
                                359                 :                :      *
                                360                 :                :      * (Note that this is only accurate if MEMORY_CONTEXT_CHECKING is off,
                                361                 :                :      * else bump.c will add a MemoryChunk header to each tuple.  However, it
                                362                 :                :      * seems undesirable for debug builds to make different planning choices
                                363                 :                :      * than production builds, so we assume the production behavior always.)
                                364                 :                :      */
                                365                 :           4049 :     tuples_space = nentries * (MAXALIGN(SizeofMinimalTupleHeader) +
                                366                 :           4049 :                                MAXALIGN(tupleWidth) +
                                367                 :           4049 :                                MAXALIGN(additionalsize));
                                368                 :                : 
                                369                 :                :     /*
                                370                 :                :      * Check for size_t overflow.  This coding is trickier than it may appear,
                                371                 :                :      * because on 64-bit machines SIZE_MAX cannot be represented exactly as a
                                372                 :                :      * double.  We must cast it explicitly to suppress compiler warnings about
                                373                 :                :      * an inexact conversion, and we must trust that any double value that
                                374                 :                :      * compares strictly less than "(double) SIZE_MAX" will cast to a
                                375                 :                :      * representable size_t value.
                                376                 :                :      */
                                377         [ -  + ]:           4049 :     if (sh_space + tuples_space >= (double) SIZE_MAX)
  368 tgl@sss.pgh.pa.us         378                 :UBC           0 :         return SIZE_MAX;
                                379                 :                : 
                                380                 :                :     /* We don't bother estimating size of the miscellaneous overhead data */
  368 tgl@sss.pgh.pa.us         381                 :CBC        4049 :     return (Size) (sh_space + tuples_space);
                                382                 :                : }
                                383                 :                : 
                                384                 :                : /*
                                385                 :                :  * Find or create a hashtable entry for the tuple group containing the
                                386                 :                :  * given tuple.  The tuple must be the same type as the hashtable entries.
                                387                 :                :  *
                                388                 :                :  * If isnew is NULL, we do not create new entries; we return NULL if no
                                389                 :                :  * match is found.
                                390                 :                :  *
                                391                 :                :  * If hash is not NULL, we set it to the calculated hash value. This allows
                                392                 :                :  * callers access to the hash value even if no entry is returned.
                                393                 :                :  *
                                394                 :                :  * If isnew isn't NULL, then a new entry is created if no existing entry
                                395                 :                :  * matches.  On return, *isnew is true if the entry is newly created,
                                396                 :                :  * false if it existed already.  The additional data in the new entry has
                                397                 :                :  * been zeroed.
                                398                 :                :  */
                                399                 :                : TupleHashEntry
 8700                           400                 :        5632109 : LookupTupleHashEntry(TupleHashTable hashtable, TupleTableSlot *slot,
                                401                 :                :                      bool *isnew, uint32 *hash)
                                402                 :                : {
                                403                 :                :     TupleHashEntry entry;
                                404                 :                :     MemoryContext oldContext;
                                405                 :                :     uint32      local_hash;
                                406                 :                : 
                                407                 :                :     /* Need to run the hash functions in short-lived context */
                                408                 :        5632109 :     oldContext = MemoryContextSwitchTo(hashtable->tempcxt);
                                409                 :                : 
                                410                 :                :     /* set up data needed by hash and match functions */
 7904                           411                 :        5632109 :     hashtable->inputslot = slot;
  694 drowley@postgresql.o      412                 :        5632109 :     hashtable->in_hash_expr = hashtable->tab_hash_expr;
 3185 andres@anarazel.de        413                 :        5632109 :     hashtable->cur_eq_func = hashtable->tab_eq_func;
                                414                 :                : 
 2293 jdavis@postgresql.or      415                 :        5632109 :     local_hash = TupleHashTableHash_internal(hashtable->hashtab, NULL);
                                416                 :        5632105 :     entry = LookupTupleHashEntry_internal(hashtable, slot, isnew, local_hash);
                                417                 :                : 
                                418         [ +  + ]:        5632105 :     if (hash != NULL)
                                419                 :        4856176 :         *hash = local_hash;
                                420                 :                : 
                                421   [ +  +  -  + ]:        5632105 :     Assert(entry == NULL || entry->hash == local_hash);
                                422                 :                : 
 2464                           423                 :        5632105 :     MemoryContextSwitchTo(oldContext);
                                424                 :                : 
                                425                 :        5632105 :     return entry;
                                426                 :                : }
                                427                 :                : 
                                428                 :                : /*
                                429                 :                :  * Compute the hash value for a tuple
                                430                 :                :  */
                                431                 :                : uint32
 2460 jdavis@postgresql.or      432                 :UBC           0 : TupleHashTableHash(TupleHashTable hashtable, TupleTableSlot *slot)
                                433                 :                : {
                                434                 :                :     MemoryContext oldContext;
                                435                 :                :     uint32      hash;
                                436                 :                : 
                                437                 :              0 :     hashtable->inputslot = slot;
  694 drowley@postgresql.o      438                 :              0 :     hashtable->in_hash_expr = hashtable->tab_hash_expr;
                                439                 :                : 
                                440                 :                :     /* Need to run the hash functions in short-lived context */
 2460 jdavis@postgresql.or      441                 :              0 :     oldContext = MemoryContextSwitchTo(hashtable->tempcxt);
                                442                 :                : 
                                443                 :              0 :     hash = TupleHashTableHash_internal(hashtable->hashtab, NULL);
                                444                 :                : 
                                445                 :              0 :     MemoryContextSwitchTo(oldContext);
                                446                 :                : 
                                447                 :              0 :     return hash;
                                448                 :                : }
                                449                 :                : 
                                450                 :                : /*
                                451                 :                :  * A variant of LookupTupleHashEntry for callers that have already computed
                                452                 :                :  * the hash value.
                                453                 :                :  */
                                454                 :                : TupleHashEntry
 2464 jdavis@postgresql.or      455                 :CBC      771940 : LookupTupleHashEntryHash(TupleHashTable hashtable, TupleTableSlot *slot,
                                456                 :                :                          bool *isnew, uint32 hash)
                                457                 :                : {
                                458                 :                :     TupleHashEntry entry;
                                459                 :                :     MemoryContext oldContext;
                                460                 :                : 
                                461                 :                :     /* Need to run the hash functions in short-lived context */
                                462                 :         771940 :     oldContext = MemoryContextSwitchTo(hashtable->tempcxt);
                                463                 :                : 
                                464                 :                :     /* set up data needed by hash and match functions */
                                465                 :         771940 :     hashtable->inputslot = slot;
  694 drowley@postgresql.o      466                 :         771940 :     hashtable->in_hash_expr = hashtable->tab_hash_expr;
 2464 jdavis@postgresql.or      467                 :         771940 :     hashtable->cur_eq_func = hashtable->tab_eq_func;
                                468                 :                : 
                                469                 :         771940 :     entry = LookupTupleHashEntry_internal(hashtable, slot, isnew, hash);
 2293                           470   [ +  +  -  + ]:         771940 :     Assert(entry == NULL || entry->hash == hash);
                                471                 :                : 
 8479 tgl@sss.pgh.pa.us         472                 :         771940 :     MemoryContextSwitchTo(oldContext);
                                473                 :                : 
                                474                 :         771940 :     return entry;
                                475                 :                : }
                                476                 :                : 
                                477                 :                : /*
                                478                 :                :  * Search for a hashtable entry matching the given tuple.  No entry is
                                479                 :                :  * created if there's not a match.  This is similar to the non-creating
                                480                 :                :  * case of LookupTupleHashEntry, except that it supports cross-type
                                481                 :                :  * comparisons, in which the given tuple is not of the same type as the
                                482                 :                :  * table entries.  The caller must provide the hash ExprState to use for
                                483                 :                :  * the input tuple, as well as the equality ExprState, since these may be
                                484                 :                :  * different from the table's internal functions.
                                485                 :                :  */
                                486                 :                : TupleHashEntry
 7212                           487                 :         636741 : FindTupleHashEntry(TupleHashTable hashtable, TupleTableSlot *slot,
                                488                 :                :                    ExprState *eqcomp,
                                489                 :                :                    ExprState *hashexpr)
                                490                 :                : {
                                491                 :                :     TupleHashEntry entry;
                                492                 :                :     MemoryContext oldContext;
                                493                 :                :     MinimalTuple key;
                                494                 :                : 
                                495                 :                :     /* Need to run the hash functions in short-lived context */
                                496                 :         636741 :     oldContext = MemoryContextSwitchTo(hashtable->tempcxt);
                                497                 :                : 
                                498                 :                :     /* Set up data needed by hash and match functions */
                                499                 :         636741 :     hashtable->inputslot = slot;
  694 drowley@postgresql.o      500                 :         636741 :     hashtable->in_hash_expr = hashexpr;
 3185 andres@anarazel.de        501                 :         636741 :     hashtable->cur_eq_func = eqcomp;
                                502                 :                : 
                                503                 :                :     /* Search the hash table */
 3674                           504                 :         636741 :     key = NULL;                 /* flag to reference inputslot */
                                505                 :         636741 :     entry = tuplehash_lookup(hashtable->hashtab, key);
 7212 tgl@sss.pgh.pa.us         506                 :         636741 :     MemoryContextSwitchTo(oldContext);
                                507                 :                : 
                                508                 :         636741 :     return entry;
                                509                 :                : }
                                510                 :                : 
                                511                 :                : /*
                                512                 :                :  * If tuple is NULL, use the input slot instead. This convention avoids the
                                513                 :                :  * need to materialize virtual input tuples unless they actually need to get
                                514                 :                :  * copied into the table.
                                515                 :                :  *
                                516                 :                :  * Also, the caller must select an appropriate memory context for running
                                517                 :                :  * the hash functions.
                                518                 :                :  */
                                519                 :                : static uint32
 2460 jdavis@postgresql.or      520                 :        6268850 : TupleHashTableHash_internal(struct tuplehash_hash *tb,
                                521                 :                :                             MinimalTuple tuple)
                                522                 :                : {
 3662 peter_e@gmx.net           523                 :        6268850 :     TupleHashTable hashtable = (TupleHashTable) tb->private_data;
                                524                 :                :     uint32      hashkey;
                                525                 :                :     TupleTableSlot *slot;
                                526                 :                :     bool        isnull;
                                527                 :                : 
 7904 tgl@sss.pgh.pa.us         528         [ +  - ]:        6268850 :     if (tuple == NULL)
                                529                 :                :     {
                                530                 :                :         /* Process the current input tuple for the table */
  694 drowley@postgresql.o      531                 :        6268850 :         hashtable->exprcontext->ecxt_innertuple = hashtable->inputslot;
                                532                 :        6268850 :         hashkey = DatumGetUInt32(ExecEvalExpr(hashtable->in_hash_expr,
                                533                 :                :                                               hashtable->exprcontext,
                                534                 :                :                                               &isnull));
                                535                 :                :     }
                                536                 :                :     else
                                537                 :                :     {
                                538                 :                :         /*
                                539                 :                :          * Process a tuple already stored in the table.
                                540                 :                :          *
                                541                 :                :          * (this case never actually occurs due to the way simplehash.h is
                                542                 :                :          * used, as the hash-value is stored in the entries)
                                543                 :                :          */
  694 drowley@postgresql.o      544                 :UBC           0 :         slot = hashtable->exprcontext->ecxt_innertuple = hashtable->tableslot;
 7435 tgl@sss.pgh.pa.us         545                 :              0 :         ExecStoreMinimalTuple(tuple, slot, false);
  694 drowley@postgresql.o      546                 :              0 :         hashkey = DatumGetUInt32(ExecEvalExpr(hashtable->tab_hash_expr,
                                547                 :                :                                               hashtable->exprcontext,
                                548                 :                :                                               &isnull));
                                549                 :                :     }
                                550                 :                : 
                                551                 :                :     /*
                                552                 :                :      * The hashing done above, even with an initial value, doesn't tend to
                                553                 :                :      * result in good hash perturbation.  Running the value produced above
                                554                 :                :      * through murmurhash32 leads to near perfect hash perturbation.
                                555                 :                :      */
 3202 andres@anarazel.de        556                 :CBC     6268846 :     return murmurhash32(hashkey);
                                557                 :                : }
                                558                 :                : 
                                559                 :                : /*
                                560                 :                :  * Does the work of LookupTupleHashEntry and LookupTupleHashEntryHash. Useful
                                561                 :                :  * so that we can avoid switching the memory context multiple times for
                                562                 :                :  * LookupTupleHashEntry.
                                563                 :                :  *
                                564                 :                :  * NB: This function may or may not change the memory context. Caller is
                                565                 :                :  * expected to change it back.
                                566                 :                :  */
                                567                 :                : static inline TupleHashEntry
 2464 jdavis@postgresql.or      568                 :        6404045 : LookupTupleHashEntry_internal(TupleHashTable hashtable, TupleTableSlot *slot,
                                569                 :                :                               bool *isnew, uint32 hash)
                                570                 :                : {
                                571                 :                :     TupleHashEntryData *entry;
                                572                 :                :     bool        found;
                                573                 :                :     MinimalTuple key;
                                574                 :                : 
                                575                 :        6404045 :     key = NULL;                 /* flag to reference inputslot */
                                576                 :                : 
                                577         [ +  + ]:        6404045 :     if (isnew)
                                578                 :                :     {
                                579                 :        5293249 :         entry = tuplehash_insert_hash(hashtable->hashtab, key, hash, &found);
                                580                 :                : 
                                581         [ +  + ]:        5293249 :         if (found)
                                582                 :                :         {
                                583                 :                :             /* found pre-existing entry */
                                584                 :        4552227 :             *isnew = false;
                                585                 :                :         }
                                586                 :                :         else
                                587                 :                :         {
                                588                 :                :             /* created new entry */
                                589                 :         741022 :             *isnew = true;
                                590                 :                : 
  371 tgl@sss.pgh.pa.us         591                 :         741022 :             MemoryContextSwitchTo(hashtable->tuplescxt);
                                592                 :                : 
                                593                 :                :             /*
                                594                 :                :              * Copy the first tuple into the tuples context, and request
                                595                 :                :              * additionalsize extra bytes before the allocation.
                                596                 :                :              *
                                597                 :                :              * The caller can get a pointer to the additional data with
                                598                 :                :              * TupleHashEntryGetAdditional(), and store arbitrary data there.
                                599                 :                :              * Placing both the tuple and additional data in the same
                                600                 :                :              * allocation avoids the need to store an extra pointer in
                                601                 :                :              * TupleHashEntryData or allocate an additional chunk.
                                602                 :                :              */
  591 jdavis@postgresql.or      603                 :         741022 :             entry->firstTuple = ExecCopySlotMinimalTupleExtra(slot,
                                604                 :                :                                                               hashtable->additionalsize);
                                605                 :                :         }
                                606                 :                :     }
                                607                 :                :     else
                                608                 :                :     {
 2464                           609                 :        1110796 :         entry = tuplehash_lookup_hash(hashtable->hashtab, key, hash);
                                610                 :                :     }
                                611                 :                : 
                                612                 :        6404045 :     return entry;
                                613                 :                : }
                                614                 :                : 
                                615                 :                : /*
                                616                 :                :  * See whether two tuples (presumably of the same hash value) match
                                617                 :                :  */
                                618                 :                : static int
  371 peter@eisentraut.org      619                 :        4926781 : TupleHashTableMatch(struct tuplehash_hash *tb, MinimalTuple tuple1, MinimalTuple tuple2)
                                620                 :                : {
                                621                 :                :     TupleTableSlot *slot1;
                                622                 :                :     TupleTableSlot *slot2;
 3662 peter_e@gmx.net           623                 :        4926781 :     TupleHashTable hashtable = (TupleHashTable) tb->private_data;
 3185 andres@anarazel.de        624                 :        4926781 :     ExprContext *econtext = hashtable->exprcontext;
                                625                 :                : 
                                626                 :                :     /*
                                627                 :                :      * We assume that simplehash.h will only ever call us with the first
                                628                 :                :      * argument being an actual table entry, and the second argument being
                                629                 :                :      * LookupTupleHashEntry's dummy TupleHashEntryData.  The other direction
                                630                 :                :      * could be supported too, but is not currently required.
                                631                 :                :      */
 7904 tgl@sss.pgh.pa.us         632         [ -  + ]:        4926781 :     Assert(tuple1 != NULL);
                                633                 :        4926781 :     slot1 = hashtable->tableslot;
 7435                           634                 :        4926781 :     ExecStoreMinimalTuple(tuple1, slot1, false);
 7904                           635         [ -  + ]:        4926781 :     Assert(tuple2 == NULL);
                                636                 :        4926781 :     slot2 = hashtable->inputslot;
                                637                 :                : 
                                638                 :                :     /* For crosstype comparisons, the inputslot must be first */
 3185 andres@anarazel.de        639                 :        4926781 :     econtext->ecxt_innertuple = slot2;
                                640                 :        4926781 :     econtext->ecxt_outertuple = slot1;
                                641                 :        4926781 :     return !ExecQualAndReset(hashtable->cur_eq_func, econtext);
                                642                 :                : }
        

Generated by: LCOV version 2.0-1