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 ,
8892int 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)
400406if (IsA (best_path ,ProjectionPath ))
401407{
402408plan = create_projection_plan (root ,
403- (ProjectionPath * )best_path );
409+ (ProjectionPath * )best_path ,
410+ flags );
404411}
405412else 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{
569584if (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{
15721587Plan * plan ;
15731588Plan * subplan ;
15741589List * 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 */
16001652plan = subplan ;