@@ -359,6 +359,14 @@ typedef struct HashAggBatch
359
359
int64 input_tuples ; /* number of tuples in this batch */
360
360
} HashAggBatch ;
361
361
362
+ /* used to find referenced colnos */
363
+ typedef struct FindColsContext
364
+ {
365
+ bool is_aggref ; /* is under an aggref */
366
+ Bitmapset * aggregated ; /* column references under an aggref */
367
+ Bitmapset * unaggregated ; /* other column references */
368
+ } FindColsContext ;
369
+
362
370
static void select_current_set (AggState * aggstate , int setno , bool is_hash );
363
371
static void initialize_phase (AggState * aggstate , int newphase );
364
372
static TupleTableSlot * fetch_input_tuple (AggState * aggstate );
@@ -391,8 +399,9 @@ static void finalize_aggregates(AggState *aggstate,
391
399
AggStatePerAgg peragg ,
392
400
AggStatePerGroup pergroup );
393
401
static TupleTableSlot * project_aggregates (AggState * aggstate );
394
- static Bitmapset * find_unaggregated_cols (AggState * aggstate );
395
- static bool find_unaggregated_cols_walker (Node * node , Bitmapset * * colnos );
402
+ static void find_cols (AggState * aggstate , Bitmapset * * aggregated ,
403
+ Bitmapset * * unaggregated );
404
+ static bool find_cols_walker (Node * node , FindColsContext * context );
396
405
static void build_hash_tables (AggState * aggstate );
397
406
static void build_hash_table (AggState * aggstate , int setno , long nbuckets );
398
407
static void hashagg_recompile_expressions (AggState * aggstate , bool minslot ,
@@ -425,8 +434,8 @@ static MinimalTuple hashagg_batch_read(HashAggBatch *batch, uint32 *hashp);
425
434
static void hashagg_spill_init (HashAggSpill * spill , HashTapeInfo * tapeinfo ,
426
435
int used_bits , uint64 input_tuples ,
427
436
double hashentrysize );
428
- static Size hashagg_spill_tuple (HashAggSpill * spill , TupleTableSlot * slot ,
429
- uint32 hash );
437
+ static Size hashagg_spill_tuple (AggState * aggstate , HashAggSpill * spill ,
438
+ TupleTableSlot * slot , uint32 hash );
430
439
static void hashagg_spill_finish (AggState * aggstate , HashAggSpill * spill ,
431
440
int setno );
432
441
static void hashagg_tapeinfo_init (AggState * aggstate );
@@ -1375,26 +1384,28 @@ project_aggregates(AggState *aggstate)
1375
1384
}
1376
1385
1377
1386
/*
1378
- * find_unaggregated_cols
1379
- * Construct a bitmapset of the column numbers of un-aggregated Vars
1380
- * appearing in our targetlist and qual (HAVING clause)
1387
+ * Walk tlist and qual to find referenced colnos, dividing them into
1388
+ * aggregated and unaggregated sets.
1381
1389
*/
1382
- static Bitmapset *
1383
- find_unaggregated_cols (AggState * aggstate )
1390
+ static void
1391
+ find_cols (AggState * aggstate , Bitmapset * * aggregated , Bitmapset * * unaggregated )
1384
1392
{
1385
- Agg * node = (Agg * ) aggstate -> ss .ps .plan ;
1386
- Bitmapset * colnos ;
1387
-
1388
- colnos = NULL ;
1389
- (void ) find_unaggregated_cols_walker ((Node * ) node -> plan .targetlist ,
1390
- & colnos );
1391
- (void ) find_unaggregated_cols_walker ((Node * ) node -> plan .qual ,
1392
- & colnos );
1393
- return colnos ;
1393
+ Agg * agg = (Agg * ) aggstate -> ss .ps .plan ;
1394
+ FindColsContext context ;
1395
+
1396
+ context .is_aggref = false;
1397
+ context .aggregated = NULL ;
1398
+ context .unaggregated = NULL ;
1399
+
1400
+ (void ) find_cols_walker ((Node * ) agg -> plan .targetlist , & context );
1401
+ (void ) find_cols_walker ((Node * ) agg -> plan .qual , & context );
1402
+
1403
+ * aggregated = context .aggregated ;
1404
+ * unaggregated = context .unaggregated ;
1394
1405
}
1395
1406
1396
1407
static bool
1397
- find_unaggregated_cols_walker (Node * node , Bitmapset * * colnos )
1408
+ find_cols_walker (Node * node , FindColsContext * context )
1398
1409
{
1399
1410
if (node == NULL )
1400
1411
return false;
@@ -1405,16 +1416,24 @@ find_unaggregated_cols_walker(Node *node, Bitmapset **colnos)
1405
1416
/* setrefs.c should have set the varno to OUTER_VAR */
1406
1417
Assert (var -> varno == OUTER_VAR );
1407
1418
Assert (var -> varlevelsup == 0 );
1408
- * colnos = bms_add_member (* colnos , var -> varattno );
1419
+ if (context -> is_aggref )
1420
+ context -> aggregated = bms_add_member (context -> aggregated ,
1421
+ var -> varattno );
1422
+ else
1423
+ context -> unaggregated = bms_add_member (context -> unaggregated ,
1424
+ var -> varattno );
1409
1425
return false;
1410
1426
}
1411
- if (IsA (node , Aggref ) || IsA ( node , GroupingFunc ) )
1427
+ if (IsA (node , Aggref ))
1412
1428
{
1413
- /* do not descend into aggregate exprs */
1429
+ Assert (!context -> is_aggref );
1430
+ context -> is_aggref = true;
1431
+ expression_tree_walker (node , find_cols_walker , (void * ) context );
1432
+ context -> is_aggref = false;
1414
1433
return false;
1415
1434
}
1416
- return expression_tree_walker (node , find_unaggregated_cols_walker ,
1417
- (void * ) colnos );
1435
+ return expression_tree_walker (node , find_cols_walker ,
1436
+ (void * ) context );
1418
1437
}
1419
1438
1420
1439
/*
@@ -1532,13 +1551,27 @@ static void
1532
1551
find_hash_columns (AggState * aggstate )
1533
1552
{
1534
1553
Bitmapset * base_colnos ;
1554
+ Bitmapset * aggregated_colnos ;
1555
+ TupleDesc scanDesc = aggstate -> ss .ss_ScanTupleSlot -> tts_tupleDescriptor ;
1535
1556
List * outerTlist = outerPlanState (aggstate )-> plan -> targetlist ;
1536
1557
int numHashes = aggstate -> num_hashes ;
1537
1558
EState * estate = aggstate -> ss .ps .state ;
1538
1559
int j ;
1539
1560
1540
1561
/* Find Vars that will be needed in tlist and qual */
1541
- base_colnos = find_unaggregated_cols (aggstate );
1562
+ find_cols (aggstate , & aggregated_colnos , & base_colnos );
1563
+ aggstate -> colnos_needed = bms_union (base_colnos , aggregated_colnos );
1564
+ aggstate -> max_colno_needed = 0 ;
1565
+ aggstate -> all_cols_needed = true;
1566
+
1567
+ for (int i = 0 ; i < scanDesc -> natts ; i ++ )
1568
+ {
1569
+ int colno = i + 1 ;
1570
+ if (bms_is_member (colno , aggstate -> colnos_needed ))
1571
+ aggstate -> max_colno_needed = colno ;
1572
+ else
1573
+ aggstate -> all_cols_needed = false;
1574
+ }
1542
1575
1543
1576
for (j = 0 ; j < numHashes ; ++ j )
1544
1577
{
@@ -2097,7 +2130,7 @@ lookup_hash_entries(AggState *aggstate)
2097
2130
perhash -> aggnode -> numGroups ,
2098
2131
aggstate -> hashentrysize );
2099
2132
2100
- hashagg_spill_tuple (spill , slot , hash );
2133
+ hashagg_spill_tuple (aggstate , spill , slot , hash );
2101
2134
}
2102
2135
}
2103
2136
}
@@ -2619,7 +2652,7 @@ agg_refill_hash_table(AggState *aggstate)
2619
2652
HASHAGG_READ_BUFFER_SIZE );
2620
2653
for (;;)
2621
2654
{
2622
- TupleTableSlot * slot = aggstate -> hash_spill_slot ;
2655
+ TupleTableSlot * slot = aggstate -> hash_spill_rslot ;
2623
2656
MinimalTuple tuple ;
2624
2657
uint32 hash ;
2625
2658
bool in_hash_table ;
@@ -2655,7 +2688,7 @@ agg_refill_hash_table(AggState *aggstate)
2655
2688
ngroups_estimate , aggstate -> hashentrysize );
2656
2689
}
2657
2690
/* no memory for a new group, spill */
2658
- hashagg_spill_tuple (& spill , slot , hash );
2691
+ hashagg_spill_tuple (aggstate , & spill , slot , hash );
2659
2692
}
2660
2693
2661
2694
/*
@@ -2934,9 +2967,11 @@ hashagg_spill_init(HashAggSpill *spill, HashTapeInfo *tapeinfo, int used_bits,
2934
2967
* partition.
2935
2968
*/
2936
2969
static Size
2937
- hashagg_spill_tuple (HashAggSpill * spill , TupleTableSlot * slot , uint32 hash )
2970
+ hashagg_spill_tuple (AggState * aggstate , HashAggSpill * spill ,
2971
+ TupleTableSlot * inputslot , uint32 hash )
2938
2972
{
2939
2973
LogicalTapeSet * tapeset = spill -> tapeset ;
2974
+ TupleTableSlot * spillslot ;
2940
2975
int partition ;
2941
2976
MinimalTuple tuple ;
2942
2977
int tapenum ;
@@ -2945,8 +2980,28 @@ hashagg_spill_tuple(HashAggSpill *spill, TupleTableSlot *slot, uint32 hash)
2945
2980
2946
2981
Assert (spill -> partitions != NULL );
2947
2982
2948
- /* XXX: may contain unnecessary attributes, should project */
2949
- tuple = ExecFetchSlotMinimalTuple (slot , & shouldFree );
2983
+ /* spill only attributes that we actually need */
2984
+ if (!aggstate -> all_cols_needed )
2985
+ {
2986
+ spillslot = aggstate -> hash_spill_wslot ;
2987
+ slot_getsomeattrs (inputslot , aggstate -> max_colno_needed );
2988
+ ExecClearTuple (spillslot );
2989
+ for (int i = 0 ; i < spillslot -> tts_tupleDescriptor -> natts ; i ++ )
2990
+ {
2991
+ if (bms_is_member (i + 1 , aggstate -> colnos_needed ))
2992
+ {
2993
+ spillslot -> tts_values [i ] = inputslot -> tts_values [i ];
2994
+ spillslot -> tts_isnull [i ] = inputslot -> tts_isnull [i ];
2995
+ }
2996
+ else
2997
+ spillslot -> tts_isnull [i ] = true;
2998
+ }
2999
+ ExecStoreVirtualTuple (spillslot );
3000
+ }
3001
+ else
3002
+ spillslot = inputslot ;
3003
+
3004
+ tuple = ExecFetchSlotMinimalTuple (spillslot , & shouldFree );
2950
3005
2951
3006
partition = (hash & spill -> mask ) >> spill -> shift ;
2952
3007
spill -> ntuples [partition ]++ ;
@@ -3563,8 +3618,10 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
3563
3618
aggstate -> hash_metacxt = AllocSetContextCreate (aggstate -> ss .ps .state -> es_query_cxt ,
3564
3619
"HashAgg meta context" ,
3565
3620
ALLOCSET_DEFAULT_SIZES );
3566
- aggstate -> hash_spill_slot = ExecInitExtraTupleSlot (estate , scanDesc ,
3567
- & TTSOpsMinimalTuple );
3621
+ aggstate -> hash_spill_rslot = ExecInitExtraTupleSlot (estate , scanDesc ,
3622
+ & TTSOpsMinimalTuple );
3623
+ aggstate -> hash_spill_wslot = ExecInitExtraTupleSlot (estate , scanDesc ,
3624
+ & TTSOpsVirtual );
3568
3625
3569
3626
/* this is an array of pointers, not structures */
3570
3627
aggstate -> hash_pergroup = pergroups ;
0 commit comments