62
62
* any sortgrouprefs specified in its pathtarget, with appropriate
63
63
* ressortgroupref labels. This is passed down by parent nodes such as Sort
64
64
* and Group, which need these values to be available in their inputs.
65
+ *
66
+ * CP_IGNORE_TLIST specifies that the caller plans to replace the targetlist,
67
+ * and therefore it doens't matter a bit what target list gets generated.
65
68
*/
66
69
#define CP_EXACT_TLIST 0x0001 /* Plan must return specified tlist */
67
70
#define CP_SMALL_TLIST 0x0002 /* Prefer narrower tlists */
68
71
#define CP_LABEL_TLIST 0x0004 /* tlist must contain sortgrouprefs */
72
+ #define CP_IGNORE_TLIST 0x0008 /* caller will replace tlist */
69
73
70
74
71
75
static Plan * create_plan_recurse (PlannerInfo * root , Path * best_path ,
@@ -87,7 +91,9 @@ static Material *create_material_plan(PlannerInfo *root, MaterialPath *best_path
87
91
static Plan * create_unique_plan (PlannerInfo * root , UniquePath * best_path ,
88
92
int flags );
89
93
static Gather * create_gather_plan (PlannerInfo * root , GatherPath * best_path );
90
- static Plan * create_projection_plan (PlannerInfo * root , ProjectionPath * best_path );
94
+ static Plan * create_projection_plan (PlannerInfo * root ,
95
+ ProjectionPath * best_path ,
96
+ int flags );
91
97
static Plan * inject_projection_plan (Plan * subplan , List * tlist , bool parallel_safe );
92
98
static Sort * create_sort_plan (PlannerInfo * root , SortPath * best_path , int flags );
93
99
static Group * create_group_plan (PlannerInfo * root , GroupPath * best_path );
@@ -400,7 +406,8 @@ create_plan_recurse(PlannerInfo *root, Path *best_path, int flags)
400
406
if (IsA (best_path , ProjectionPath ))
401
407
{
402
408
plan = create_projection_plan (root ,
403
- (ProjectionPath * ) best_path );
409
+ (ProjectionPath * ) best_path ,
410
+ flags );
404
411
}
405
412
else if (IsA (best_path , MinMaxAggPath ))
406
413
{
@@ -563,8 +570,16 @@ create_scan_plan(PlannerInfo *root, Path *best_path, int flags)
563
570
* only those Vars actually needed by the query), we prefer to generate a
564
571
* tlist containing all Vars in order. This will allow the executor to
565
572
* optimize away projection of the table tuples, if possible.
573
+ *
574
+ * But if the caller is going to ignore our tlist anyway, then don't
575
+ * bother generating one at all. We use an exact equality test here, so
576
+ * that this only applies when CP_IGNORE_TLIST is the only flag set.
566
577
*/
567
- if (use_physical_tlist (root , best_path , flags ))
578
+ if (flags == CP_IGNORE_TLIST )
579
+ {
580
+ tlist = NULL ;
581
+ }
582
+ else if (use_physical_tlist (root , best_path , flags ))
568
583
{
569
584
if (best_path -> pathtype == T_IndexOnlyScan )
570
585
{
@@ -1567,34 +1582,71 @@ create_gather_merge_plan(PlannerInfo *root, GatherMergePath *best_path)
1567
1582
* but sometimes we can just let the subplan do the work.
1568
1583
*/
1569
1584
static Plan *
1570
- create_projection_plan (PlannerInfo * root , ProjectionPath * best_path )
1585
+ create_projection_plan (PlannerInfo * root , ProjectionPath * best_path , int flags )
1571
1586
{
1572
1587
Plan * plan ;
1573
1588
Plan * subplan ;
1574
1589
List * tlist ;
1590
+ bool needs_result_node = false;
1575
1591
1576
- /* Since we intend to project, we don't need to constrain child tlist */
1577
- subplan = create_plan_recurse (root , best_path -> subpath , 0 );
1578
-
1579
- tlist = build_path_tlist (root , & best_path -> path );
1592
+ /*
1593
+ * Convert our subpath to a Plan and determine whether we need a Result
1594
+ * node.
1595
+ *
1596
+ * In most cases where we don't need to project, creation_projection_path
1597
+ * will have set dummypp, but not always. First, some createplan.c
1598
+ * routines change the tlists of their nodes. (An example is that
1599
+ * create_merge_append_plan might add resjunk sort columns to a
1600
+ * MergeAppend.) Second, create_projection_path has no way of knowing
1601
+ * what path node will be placed on top of the projection path and
1602
+ * therefore can't predict whether it will require an exact tlist. For
1603
+ * both of these reasons, we have to recheck here.
1604
+ */
1605
+ if (use_physical_tlist (root , & best_path -> path , flags ))
1606
+ {
1607
+ /*
1608
+ * Our caller doesn't really care what tlist we return, so we don't
1609
+ * actually need to project. However, we may still need to ensure
1610
+ * proper sortgroupref labels, if the caller cares about those.
1611
+ */
1612
+ subplan = create_plan_recurse (root , best_path -> subpath , 0 );
1613
+ tlist = subplan -> targetlist ;
1614
+ if ((flags & CP_LABEL_TLIST ) != 0 )
1615
+ apply_pathtarget_labeling_to_tlist (tlist ,
1616
+ best_path -> path .pathtarget );
1617
+ }
1618
+ else if (is_projection_capable_path (best_path -> subpath ))
1619
+ {
1620
+ /*
1621
+ * Our caller requires that we return the exact tlist, but no separate
1622
+ * result node is needed because the subpath is projection-capable.
1623
+ * Tell create_plan_recurse that we're going to ignore the tlist it
1624
+ * produces.
1625
+ */
1626
+ subplan = create_plan_recurse (root , best_path -> subpath ,
1627
+ CP_IGNORE_TLIST );
1628
+ tlist = build_path_tlist (root , & best_path -> path );
1629
+ }
1630
+ else
1631
+ {
1632
+ /*
1633
+ * It looks like we need a result node, unless by good fortune the
1634
+ * requested tlist is exactly the one the child wants to produce.
1635
+ */
1636
+ subplan = create_plan_recurse (root , best_path -> subpath , 0 );
1637
+ tlist = build_path_tlist (root , & best_path -> path );
1638
+ needs_result_node = !tlist_same_exprs (tlist , subplan -> targetlist );
1639
+ }
1580
1640
1581
1641
/*
1582
- * We might not really need a Result node here, either because the subplan
1583
- * can project or because it's returning the right list of expressions
1584
- * anyway. Usually create_projection_path will have detected that and set
1585
- * dummypp if we don't need a Result; but its decision can't be final,
1586
- * because some createplan.c routines change the tlists of their nodes.
1587
- * (An example is that create_merge_append_plan might add resjunk sort
1588
- * columns to a MergeAppend.) So we have to recheck here. If we do
1589
- * arrive at a different answer than create_projection_path did, we'll
1590
- * have made slightly wrong cost estimates; but label the plan with the
1591
- * cost estimates we actually used, not "corrected" ones. (XXX this could
1592
- * be cleaned up if we moved more of the sortcolumn setup logic into Path
1593
- * creation, but that would add expense to creating Paths we might end up
1594
- * not using.)
1642
+ * If we make a different decision about whether to include a Result node
1643
+ * than create_projection_path did, we'll have made slightly wrong cost
1644
+ * estimates; but label the plan with the cost estimates we actually used,
1645
+ * not "corrected" ones. (XXX this could be cleaned up if we moved more
1646
+ * of the sortcolumn setup logic into Path creation, but that would add
1647
+ * expense to creating Paths we might end up not using.)
1595
1648
*/
1596
- if (is_projection_capable_path (best_path -> subpath ) ||
1597
- tlist_same_exprs (tlist , subplan -> targetlist ))
1649
+ if (!needs_result_node )
1598
1650
{
1599
1651
/* Don't need a separate Result, just assign tlist to subplan */
1600
1652
plan = subplan ;
0 commit comments