6262 * any sortgrouprefs specified in its pathtarget, with appropriate
6363 * ressortgroupref labels. This is passed down by parent nodes such as Sort
6464 * 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.
6568 */
6669#define CP_EXACT_TLIST 0x0001 /* Plan must return specified tlist */
6770#define CP_SMALL_TLIST 0x0002 /* Prefer narrower tlists */
6871#define CP_LABEL_TLIST 0x0004 /* tlist must contain sortgrouprefs */
72+ #define CP_IGNORE_TLIST 0x0008 /* caller will replace tlist */
6973
7074
7175static Plan * create_plan_recurse (PlannerInfo * root , Path * best_path ,
@@ -87,7 +91,9 @@ static Material *create_material_plan(PlannerInfo *root, MaterialPath *best_path
8791static Plan * create_unique_plan (PlannerInfo * root , UniquePath * best_path ,
8892 int flags );
8993static 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 );
9197static Plan * inject_projection_plan (Plan * subplan , List * tlist , bool parallel_safe );
9298static Sort * create_sort_plan (PlannerInfo * root , SortPath * best_path , int flags );
9399static Group * create_group_plan (PlannerInfo * root , GroupPath * best_path );
@@ -400,7 +406,8 @@ create_plan_recurse(PlannerInfo *root, Path *best_path, int flags)
400406 if (IsA (best_path , ProjectionPath ))
401407 {
402408 plan = create_projection_plan (root ,
403- (ProjectionPath * ) best_path );
409+ (ProjectionPath * ) best_path ,
410+ flags );
404411 }
405412 else if (IsA (best_path , MinMaxAggPath ))
406413 {
@@ -563,8 +570,16 @@ create_scan_plan(PlannerInfo *root, Path *best_path, int flags)
563570 * only those Vars actually needed by the query), we prefer to generate a
564571 * tlist containing all Vars in order. This will allow the executor to
565572 * 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.
566577 */
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 ))
568583 {
569584 if (best_path -> pathtype == T_IndexOnlyScan )
570585 {
@@ -1567,34 +1582,71 @@ create_gather_merge_plan(PlannerInfo *root, GatherMergePath *best_path)
15671582 * but sometimes we can just let the subplan do the work.
15681583 */
15691584static Plan *
1570- create_projection_plan (PlannerInfo * root , ProjectionPath * best_path )
1585+ create_projection_plan (PlannerInfo * root , ProjectionPath * best_path , int flags )
15711586{
15721587 Plan * plan ;
15731588 Plan * subplan ;
15741589 List * tlist ;
1590+ bool needs_result_node = false;
15751591
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+ }
15801640
15811641 /*
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.)
15951648 */
1596- if (is_projection_capable_path (best_path -> subpath ) ||
1597- tlist_same_exprs (tlist , subplan -> targetlist ))
1649+ if (!needs_result_node )
15981650 {
15991651 /* Don't need a separate Result, just assign tlist to subplan */
16001652 plan = subplan ;
0 commit comments