@@ -85,6 +85,7 @@ static bool choose_hashed_distinct(PlannerInfo *root,
85
85
double dNumDistinctRows );
86
86
static List * make_subplanTargetList (PlannerInfo * root , List * tlist ,
87
87
AttrNumber * * groupColIdx , bool * need_tlist_eval );
88
+ static int get_grouping_column_index (Query * parse , TargetEntry * tle );
88
89
static void locate_grouping_columns (PlannerInfo * root ,
89
90
List * tlist ,
90
91
List * sub_tlist ,
@@ -2536,14 +2537,9 @@ choose_hashed_distinct(PlannerInfo *root,
2536
2537
* For example, given a query like
2537
2538
* SELECT a+b,SUM(c+d) FROM table GROUP BY a+b;
2538
2539
* we want to pass this targetlist to the subplan:
2539
- * a, b,c,d,a+b
2540
+ * a+ b,c,d
2540
2541
* where the a+b target will be used by the Sort/Group steps, and the
2541
- * other targets will be used for computing the final results. (In the
2542
- * above example we could theoretically suppress the a and b targets and
2543
- * pass down only c,d,a+b, but it's not really worth the trouble to
2544
- * eliminate simple var references from the subplan. We will avoid doing
2545
- * the extra computation to recompute a+b at the outer level; see
2546
- * fix_upper_expr() in setrefs.c.)
2542
+ * other targets will be used for computing the final results.
2547
2543
*
2548
2544
* If we are grouping or aggregating, *and* there are no non-Var grouping
2549
2545
* expressions, then the returned tlist is effectively dummy; we do not
@@ -2569,7 +2565,8 @@ make_subplanTargetList(PlannerInfo *root,
2569
2565
{
2570
2566
Query * parse = root -> parse ;
2571
2567
List * sub_tlist ;
2572
- List * extravars ;
2568
+ List * non_group_cols ;
2569
+ List * non_group_vars ;
2573
2570
int numCols ;
2574
2571
2575
2572
* groupColIdx = NULL ;
@@ -2586,71 +2583,132 @@ make_subplanTargetList(PlannerInfo *root,
2586
2583
}
2587
2584
2588
2585
/*
2589
- * Otherwise, start with a "flattened" tlist (having just the Vars
2590
- * mentioned in the targetlist and HAVING qual). Note this includes Vars
2591
- * used in resjunk items, so we are covering the needs of ORDER BY and
2592
- * window specifications. Vars used within Aggrefs will be pulled out
2593
- * here, too.
2586
+ * Otherwise, we must build a tlist containing all grouping columns,
2587
+ * plus any other Vars mentioned in the targetlist and HAVING qual.
2594
2588
*/
2595
- sub_tlist = flatten_tlist (tlist ,
2596
- PVC_RECURSE_AGGREGATES ,
2597
- PVC_INCLUDE_PLACEHOLDERS );
2598
- extravars = pull_var_clause (parse -> havingQual ,
2599
- PVC_RECURSE_AGGREGATES ,
2600
- PVC_INCLUDE_PLACEHOLDERS );
2601
- sub_tlist = add_to_flat_tlist (sub_tlist , extravars );
2602
- list_free (extravars );
2589
+ sub_tlist = NIL ;
2590
+ non_group_cols = NIL ;
2603
2591
* need_tlist_eval = false; /* only eval if not flat tlist */
2604
2592
2605
- /*
2606
- * If grouping, create sub_tlist entries for all GROUP BY expressions
2607
- * (GROUP BY items that are simple Vars should be in the list already),
2608
- * and make an array showing where the group columns are in the sub_tlist.
2609
- */
2610
2593
numCols = list_length (parse -> groupClause );
2611
2594
if (numCols > 0 )
2612
2595
{
2613
- int keyno = 0 ;
2596
+ /*
2597
+ * If grouping, create sub_tlist entries for all GROUP BY columns, and
2598
+ * make an array showing where the group columns are in the sub_tlist.
2599
+ *
2600
+ * Note: with this implementation, the array entries will always be
2601
+ * 1..N, but we don't want callers to assume that.
2602
+ */
2614
2603
AttrNumber * grpColIdx ;
2615
- ListCell * gl ;
2604
+ ListCell * tl ;
2616
2605
2617
- grpColIdx = (AttrNumber * ) palloc (sizeof (AttrNumber ) * numCols );
2606
+ grpColIdx = (AttrNumber * ) palloc0 (sizeof (AttrNumber ) * numCols );
2618
2607
* groupColIdx = grpColIdx ;
2619
2608
2620
- foreach (gl , parse -> groupClause )
2609
+ foreach (tl , tlist )
2621
2610
{
2622
- SortGroupClause * grpcl = (SortGroupClause * ) lfirst (gl );
2623
- Node * groupexpr = get_sortgroupclause_expr (grpcl , tlist );
2624
- TargetEntry * te ;
2611
+ TargetEntry * tle = (TargetEntry * ) lfirst (tl );
2612
+ int colno ;
2625
2613
2626
- /*
2627
- * Find or make a matching sub_tlist entry. If the groupexpr
2628
- * isn't a Var, no point in searching. (Note that the parser
2629
- * won't make multiple groupClause entries for the same TLE.)
2630
- */
2631
- if (groupexpr && IsA (groupexpr , Var ))
2632
- te = tlist_member (groupexpr , sub_tlist );
2633
- else
2634
- te = NULL ;
2614
+ colno = get_grouping_column_index (parse , tle );
2615
+ if (colno >= 0 )
2616
+ {
2617
+ /*
2618
+ * It's a grouping column, so add it to the result tlist and
2619
+ * remember its resno in grpColIdx[].
2620
+ */
2621
+ TargetEntry * newtle ;
2635
2622
2636
- if (!te )
2623
+ newtle = makeTargetEntry (tle -> expr ,
2624
+ list_length (sub_tlist ) + 1 ,
2625
+ NULL ,
2626
+ false);
2627
+ sub_tlist = lappend (sub_tlist , newtle );
2628
+
2629
+ Assert (grpColIdx [colno ] == 0 ); /* no dups expected */
2630
+ grpColIdx [colno ] = newtle -> resno ;
2631
+
2632
+ if (!(newtle -> expr && IsA (newtle -> expr , Var )))
2633
+ * need_tlist_eval = true; /* tlist contains non Vars */
2634
+ }
2635
+ else
2637
2636
{
2638
- te = makeTargetEntry (( Expr * ) groupexpr ,
2639
- list_length ( sub_tlist ) + 1 ,
2640
- NULL ,
2641
- false);
2642
- sub_tlist = lappend ( sub_tlist , te );
2643
- * need_tlist_eval = true; /* it's not flat anymore */
2637
+ /*
2638
+ * Non-grouping column, so just remember the expression
2639
+ * for later call to pull_var_clause. There's no need for
2640
+ * pull_var_clause to examine the TargetEntry node itself.
2641
+ */
2642
+ non_group_cols = lappend ( non_group_cols , tle -> expr );
2644
2643
}
2645
-
2646
- /* and save its resno */
2647
- grpColIdx [keyno ++ ] = te -> resno ;
2648
2644
}
2649
2645
}
2646
+ else
2647
+ {
2648
+ /*
2649
+ * With no grouping columns, just pass whole tlist to pull_var_clause.
2650
+ * Need (shallow) copy to avoid damaging input tlist below.
2651
+ */
2652
+ non_group_cols = list_copy (tlist );
2653
+ }
2654
+
2655
+ /*
2656
+ * If there's a HAVING clause, we'll need the Vars it uses, too.
2657
+ */
2658
+ if (parse -> havingQual )
2659
+ non_group_cols = lappend (non_group_cols , parse -> havingQual );
2660
+
2661
+ /*
2662
+ * Pull out all the Vars mentioned in non-group cols (plus HAVING), and
2663
+ * add them to the result tlist if not already present. (A Var used
2664
+ * directly as a GROUP BY item will be present already.) Note this
2665
+ * includes Vars used in resjunk items, so we are covering the needs of
2666
+ * ORDER BY and window specifications. Vars used within Aggrefs will be
2667
+ * pulled out here, too.
2668
+ */
2669
+ non_group_vars = pull_var_clause ((Node * ) non_group_cols ,
2670
+ PVC_RECURSE_AGGREGATES ,
2671
+ PVC_INCLUDE_PLACEHOLDERS );
2672
+ sub_tlist = add_to_flat_tlist (sub_tlist , non_group_vars );
2673
+
2674
+ /* clean up cruft */
2675
+ list_free (non_group_vars );
2676
+ list_free (non_group_cols );
2650
2677
2651
2678
return sub_tlist ;
2652
2679
}
2653
2680
2681
+ /*
2682
+ * get_grouping_column_index
2683
+ * Get the GROUP BY column position, if any, of a targetlist entry.
2684
+ *
2685
+ * Returns the index (counting from 0) of the TLE in the GROUP BY list, or -1
2686
+ * if it's not a grouping column. Note: the result is unique because the
2687
+ * parser won't make multiple groupClause entries for the same TLE.
2688
+ */
2689
+ static int
2690
+ get_grouping_column_index (Query * parse , TargetEntry * tle )
2691
+ {
2692
+ int colno = 0 ;
2693
+ Index ressortgroupref = tle -> ressortgroupref ;
2694
+ ListCell * gl ;
2695
+
2696
+ /* No need to search groupClause if TLE hasn't got a sortgroupref */
2697
+ if (ressortgroupref == 0 )
2698
+ return -1 ;
2699
+
2700
+ foreach (gl , parse -> groupClause )
2701
+ {
2702
+ SortGroupClause * grpcl = (SortGroupClause * ) lfirst (gl );
2703
+
2704
+ if (grpcl -> tleSortGroupRef == ressortgroupref )
2705
+ return colno ;
2706
+ colno ++ ;
2707
+ }
2708
+
2709
+ return -1 ;
2710
+ }
2711
+
2654
2712
/*
2655
2713
* locate_grouping_columns
2656
2714
* Locate grouping columns in the tlist chosen by create_plan.
0 commit comments