@@ -263,6 +263,7 @@ static void finalize_partialaggregate(AggState *aggstate,
263263 AggStatePerAgg peragg ,
264264 AggStatePerGroup pergroupstate ,
265265 Datum * resultVal , bool * resultIsNull );
266+ static void prepare_hash_slot (AggState * aggstate );
266267static void prepare_projection_slot (AggState * aggstate ,
267268 TupleTableSlot * slot ,
268269 int currentSet );
@@ -272,8 +273,9 @@ static void finalize_aggregates(AggState *aggstate,
272273static TupleTableSlot * project_aggregates (AggState * aggstate );
273274static Bitmapset * find_unaggregated_cols (AggState * aggstate );
274275static bool find_unaggregated_cols_walker (Node * node , Bitmapset * * colnos );
275- static void build_hash_table (AggState * aggstate );
276- static TupleHashEntryData * lookup_hash_entry (AggState * aggstate );
276+ static void build_hash_tables (AggState * aggstate );
277+ static void build_hash_table (AggState * aggstate , int setno , long nbuckets );
278+ static AggStatePerGroup lookup_hash_entry (AggState * aggstate , uint32 hash );
277279static void lookup_hash_entries (AggState * aggstate );
278280static TupleTableSlot * agg_retrieve_direct (AggState * aggstate );
279281static void agg_fill_hash_table (AggState * aggstate );
@@ -1035,6 +1037,32 @@ finalize_partialaggregate(AggState *aggstate,
10351037 MemoryContextSwitchTo (oldContext );
10361038}
10371039
1040+ /*
1041+ * Extract the attributes that make up the grouping key into the
1042+ * hashslot. This is necessary to compute the hash or perform a lookup.
1043+ */
1044+ static void
1045+ prepare_hash_slot (AggState * aggstate )
1046+ {
1047+ TupleTableSlot * inputslot = aggstate -> tmpcontext -> ecxt_outertuple ;
1048+ AggStatePerHash perhash = & aggstate -> perhash [aggstate -> current_set ];
1049+ TupleTableSlot * hashslot = perhash -> hashslot ;
1050+ int i ;
1051+
1052+ /* transfer just the needed columns into hashslot */
1053+ slot_getsomeattrs (inputslot , perhash -> largestGrpColIdx );
1054+ ExecClearTuple (hashslot );
1055+
1056+ for (i = 0 ; i < perhash -> numhashGrpCols ; i ++ )
1057+ {
1058+ int varNumber = perhash -> hashGrpColIdxInput [i ] - 1 ;
1059+
1060+ hashslot -> tts_values [i ] = inputslot -> tts_values [varNumber ];
1061+ hashslot -> tts_isnull [i ] = inputslot -> tts_isnull [varNumber ];
1062+ }
1063+ ExecStoreVirtualTuple (hashslot );
1064+ }
1065+
10381066/*
10391067 * Prepare to finalize and project based on the specified representative tuple
10401068 * slot and grouping set.
@@ -1249,41 +1277,59 @@ find_unaggregated_cols_walker(Node *node, Bitmapset **colnos)
12491277 * they are all reset at the same time).
12501278 */
12511279static void
1252- build_hash_table (AggState * aggstate )
1280+ build_hash_tables (AggState * aggstate )
12531281{
1254- MemoryContext tmpmem = aggstate -> tmpcontext -> ecxt_per_tuple_memory ;
1255- Size additionalsize ;
1256- int i ;
1282+ int setno ;
12571283
1258- Assert (aggstate -> aggstrategy == AGG_HASHED || aggstate -> aggstrategy == AGG_MIXED );
1259-
1260- additionalsize = aggstate -> numtrans * sizeof (AggStatePerGroupData );
1261-
1262- for (i = 0 ; i < aggstate -> num_hashes ; ++ i )
1284+ for (setno = 0 ; setno < aggstate -> num_hashes ; ++ setno )
12631285 {
1264- AggStatePerHash perhash = & aggstate -> perhash [i ];
1286+ AggStatePerHash perhash = & aggstate -> perhash [setno ];
12651287
12661288 Assert (perhash -> aggnode -> numGroups > 0 );
12671289
1268- if (perhash -> hashtable )
1269- ResetTupleHashTable (perhash -> hashtable );
1270- else
1271- perhash -> hashtable = BuildTupleHashTableExt (& aggstate -> ss .ps ,
1272- perhash -> hashslot -> tts_tupleDescriptor ,
1273- perhash -> numCols ,
1274- perhash -> hashGrpColIdxHash ,
1275- perhash -> eqfuncoids ,
1276- perhash -> hashfunctions ,
1277- perhash -> aggnode -> grpCollations ,
1278- perhash -> aggnode -> numGroups ,
1279- additionalsize ,
1280- aggstate -> ss .ps .state -> es_query_cxt ,
1281- aggstate -> hashcontext -> ecxt_per_tuple_memory ,
1282- tmpmem ,
1283- DO_AGGSPLIT_SKIPFINAL (aggstate -> aggsplit ));
1290+ build_hash_table (aggstate , setno , perhash -> aggnode -> numGroups );
12841291 }
12851292}
12861293
1294+ /*
1295+ * Build a single hashtable for this grouping set.
1296+ */
1297+ static void
1298+ build_hash_table (AggState * aggstate , int setno , long nbuckets )
1299+ {
1300+ AggStatePerHash perhash = & aggstate -> perhash [setno ];
1301+ MemoryContext metacxt = aggstate -> ss .ps .state -> es_query_cxt ;
1302+ MemoryContext hashcxt = aggstate -> hashcontext -> ecxt_per_tuple_memory ;
1303+ MemoryContext tmpcxt = aggstate -> tmpcontext -> ecxt_per_tuple_memory ;
1304+ Size additionalsize ;
1305+
1306+ Assert (aggstate -> aggstrategy == AGG_HASHED ||
1307+ aggstate -> aggstrategy == AGG_MIXED );
1308+
1309+ /*
1310+ * Used to make sure initial hash table allocation does not exceed
1311+ * work_mem. Note that the estimate does not include space for
1312+ * pass-by-reference transition data values, nor for the representative
1313+ * tuple of each group.
1314+ */
1315+ additionalsize = aggstate -> numtrans * sizeof (AggStatePerGroupData );
1316+
1317+ perhash -> hashtable = BuildTupleHashTableExt (
1318+ & aggstate -> ss .ps ,
1319+ perhash -> hashslot -> tts_tupleDescriptor ,
1320+ perhash -> numCols ,
1321+ perhash -> hashGrpColIdxHash ,
1322+ perhash -> eqfuncoids ,
1323+ perhash -> hashfunctions ,
1324+ perhash -> aggnode -> grpCollations ,
1325+ nbuckets ,
1326+ additionalsize ,
1327+ metacxt ,
1328+ hashcxt ,
1329+ tmpcxt ,
1330+ DO_AGGSPLIT_SKIPFINAL (aggstate -> aggsplit ));
1331+ }
1332+
12871333/*
12881334 * Compute columns that actually need to be stored in hashtable entries. The
12891335 * incoming tuples from the child plan node will contain grouping columns,
@@ -1441,33 +1487,20 @@ hash_agg_entry_size(int numAggs, Size tupleWidth, Size transitionSpace)
14411487 * set (which the caller must have selected - note that initialize_aggregate
14421488 * depends on this).
14431489 *
1444- * When called, CurrentMemoryContext should be the per-query context.
1490+ * When called, CurrentMemoryContext should be the per-query context. The
1491+ * already-calculated hash value for the tuple must be specified.
14451492 */
1446- static TupleHashEntryData *
1447- lookup_hash_entry (AggState * aggstate )
1493+ static AggStatePerGroup
1494+ lookup_hash_entry (AggState * aggstate , uint32 hash )
14481495{
1449- TupleTableSlot * inputslot = aggstate -> tmpcontext -> ecxt_outertuple ;
14501496 AggStatePerHash perhash = & aggstate -> perhash [aggstate -> current_set ];
14511497 TupleTableSlot * hashslot = perhash -> hashslot ;
14521498 TupleHashEntryData * entry ;
14531499 bool isnew ;
1454- int i ;
1455-
1456- /* transfer just the needed columns into hashslot */
1457- slot_getsomeattrs (inputslot , perhash -> largestGrpColIdx );
1458- ExecClearTuple (hashslot );
1459-
1460- for (i = 0 ; i < perhash -> numhashGrpCols ; i ++ )
1461- {
1462- int varNumber = perhash -> hashGrpColIdxInput [i ] - 1 ;
1463-
1464- hashslot -> tts_values [i ] = inputslot -> tts_values [varNumber ];
1465- hashslot -> tts_isnull [i ] = inputslot -> tts_isnull [varNumber ];
1466- }
1467- ExecStoreVirtualTuple (hashslot );
14681500
14691501 /* find or create the hashtable entry using the filtered tuple */
1470- entry = LookupTupleHashEntry (perhash -> hashtable , hashslot , & isnew );
1502+ entry = LookupTupleHashEntryHash (perhash -> hashtable , hashslot , & isnew ,
1503+ hash );
14711504
14721505 if (isnew )
14731506 {
@@ -1492,7 +1525,7 @@ lookup_hash_entry(AggState *aggstate)
14921525 }
14931526 }
14941527
1495- return entry ;
1528+ return entry -> additional ;
14961529}
14971530
14981531/*
@@ -1510,8 +1543,13 @@ lookup_hash_entries(AggState *aggstate)
15101543
15111544 for (setno = 0 ; setno < numHashes ; setno ++ )
15121545 {
1546+ AggStatePerHash perhash = & aggstate -> perhash [setno ];
1547+ uint32 hash ;
1548+
15131549 select_current_set (aggstate , setno , true);
1514- pergroup [setno ] = lookup_hash_entry (aggstate )-> additional ;
1550+ prepare_hash_slot (aggstate );
1551+ hash = TupleHashTableHash (perhash -> hashtable , perhash -> hashslot );
1552+ pergroup [setno ] = lookup_hash_entry (aggstate , hash );
15151553 }
15161554}
15171555
@@ -2478,7 +2516,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
24782516 aggstate -> hash_pergroup = pergroups ;
24792517
24802518 find_hash_columns (aggstate );
2481- build_hash_table (aggstate );
2519+ build_hash_tables (aggstate );
24822520 aggstate -> table_filled = false;
24832521 }
24842522
@@ -3498,7 +3536,7 @@ ExecReScanAgg(AggState *node)
34983536 {
34993537 ReScanExprContext (node -> hashcontext );
35003538 /* Rebuild an empty hash table */
3501- build_hash_table (node );
3539+ build_hash_tables (node );
35023540 node -> table_filled = false;
35033541 /* iterator will be reset when the table is filled */
35043542 }
0 commit comments