@@ -57,6 +57,15 @@ typedef struct nullingrel_info
5757 int rtlength ; /* used only for assertion checks */
5858} nullingrel_info ;
5959
60+ /* Options for wrapping an expression for identification purposes */
61+ typedef enum ReplaceWrapOption
62+ {
63+ REPLACE_WRAP_NONE , /* no expressions need to be wrapped */
64+ REPLACE_WRAP_ALL , /* all expressions need to be wrapped */
65+ REPLACE_WRAP_VARFREE , /* variable-free expressions need to be
66+ * wrapped */
67+ } ReplaceWrapOption ;
68+
6069typedef struct pullup_replace_vars_context
6170{
6271 PlannerInfo * root ;
@@ -70,7 +79,7 @@ typedef struct pullup_replace_vars_context
7079 * target_rte->lateral) */
7180 bool * outer_hasSubLinks ; /* -> outer query's hasSubLinks */
7281 int varno ; /* varno of subquery */
73- bool wrap_non_vars ; /* do we need all non-Var outputs to be PHVs? */
82+ ReplaceWrapOption wrap_option ; /* do we need certain outputs to be PHVs? */
7483 Node * * rv_cache ; /* cache for results with PHVs */
7584} pullup_replace_vars_context ;
7685
@@ -1025,23 +1034,18 @@ expand_virtual_generated_columns(PlannerInfo *root)
10251034 rvcontext .outer_hasSubLinks = NULL ;
10261035 rvcontext .varno = rt_index ;
10271036 /* this flag will be set below, if needed */
1028- rvcontext .wrap_non_vars = false ;
1037+ rvcontext .wrap_option = REPLACE_WRAP_NONE ;
10291038 /* initialize cache array with indexes 0 .. length(tlist) */
10301039 rvcontext .rv_cache = palloc0 ((list_length (tlist ) + 1 ) *
10311040 sizeof (Node * ));
10321041
10331042 /*
10341043 * If the query uses grouping sets, we need a PlaceHolderVar for
1035- * anything that's not a simple Var. Again, this ensures that
1036- * expressions retain their separate identity so that they will
1037- * match grouping set columns when appropriate. (It'd be
1038- * sufficient to wrap values used in grouping set columns, and do
1039- * so only in non-aggregated portions of the tlist and havingQual,
1040- * but that would require a lot of infrastructure that
1041- * pullup_replace_vars hasn't currently got.)
1044+ * each expression of the relation's targetlist items. (See
1045+ * comments in pull_up_simple_subquery().)
10421046 */
10431047 if (parse -> groupingSets )
1044- rvcontext .wrap_non_vars = true ;
1048+ rvcontext .wrap_option = REPLACE_WRAP_ALL ;
10451049
10461050 /*
10471051 * Apply pullup variable replacement throughout the query tree.
@@ -1435,22 +1439,22 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte,
14351439 rvcontext .outer_hasSubLinks = & parse -> hasSubLinks ;
14361440 rvcontext .varno = varno ;
14371441 /* this flag will be set below, if needed */
1438- rvcontext .wrap_non_vars = false ;
1442+ rvcontext .wrap_option = REPLACE_WRAP_NONE ;
14391443 /* initialize cache array with indexes 0 .. length(tlist) */
14401444 rvcontext .rv_cache = palloc0 ((list_length (subquery -> targetList ) + 1 ) *
14411445 sizeof (Node * ));
14421446
14431447 /*
14441448 * If the parent query uses grouping sets, we need a PlaceHolderVar for
1445- * anything that's not a simple Var . This ensures that expressions retain
1446- * their separate identity so that they will match grouping set columns
1447- * when appropriate. (It'd be sufficient to wrap values used in grouping
1448- * set columns, and do so only in non-aggregated portions of the tlist and
1449- * havingQual, but that would require a lot of infrastructure that
1450- * pullup_replace_vars hasn't currently got.)
1449+ * each expression of the subquery's targetlist items . This ensures that
1450+ * expressions retain their separate identity so that they will match
1451+ * grouping set columns when appropriate. (It'd be sufficient to wrap
1452+ * values used in grouping set columns, and do so only in non-aggregated
1453+ * portions of the tlist and havingQual, but that would require a lot of
1454+ * infrastructure that pullup_replace_vars hasn't currently got.)
14511455 */
14521456 if (parse -> groupingSets )
1453- rvcontext .wrap_non_vars = true ;
1457+ rvcontext .wrap_option = REPLACE_WRAP_ALL ;
14541458
14551459 /*
14561460 * Replace all of the top query's references to the subquery's outputs
@@ -1976,7 +1980,7 @@ pull_up_simple_values(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte)
19761980 rvcontext .nullinfo = NULL ;
19771981 rvcontext .outer_hasSubLinks = & parse -> hasSubLinks ;
19781982 rvcontext .varno = varno ;
1979- rvcontext .wrap_non_vars = false ;
1983+ rvcontext .wrap_option = REPLACE_WRAP_NONE ;
19801984 /* initialize cache array with indexes 0 .. length(tlist) */
19811985 rvcontext .rv_cache = palloc0 ((list_length (tlist ) + 1 ) *
19821986 sizeof (Node * ));
@@ -2144,18 +2148,18 @@ pull_up_constant_function(PlannerInfo *root, Node *jtnode,
21442148 rvcontext .outer_hasSubLinks = & parse -> hasSubLinks ;
21452149 rvcontext .varno = ((RangeTblRef * ) jtnode )-> rtindex ;
21462150 /* this flag will be set below, if needed */
2147- rvcontext .wrap_non_vars = false ;
2151+ rvcontext .wrap_option = REPLACE_WRAP_NONE ;
21482152 /* initialize cache array with indexes 0 .. length(tlist) */
21492153 rvcontext .rv_cache = palloc0 ((list_length (rvcontext .targetlist ) + 1 ) *
21502154 sizeof (Node * ));
21512155
21522156 /*
21532157 * If the parent query uses grouping sets, we need a PlaceHolderVar for
2154- * anything that's not a simple Var . (See comments in
2158+ * each expression of the subquery's targetlist items . (See comments in
21552159 * pull_up_simple_subquery().)
21562160 */
21572161 if (parse -> groupingSets )
2158- rvcontext .wrap_non_vars = true ;
2162+ rvcontext .wrap_option = REPLACE_WRAP_ALL ;
21592163
21602164 /*
21612165 * Replace all of the top query's references to the RTE's output with
@@ -2406,13 +2410,13 @@ perform_pullup_replace_vars(PlannerInfo *root,
24062410 */
24072411 if (containing_appendrel )
24082412 {
2409- bool save_wrap_non_vars = rvcontext -> wrap_non_vars ;
2413+ ReplaceWrapOption save_wrap_option = rvcontext -> wrap_option ;
24102414
2411- rvcontext -> wrap_non_vars = false ;
2415+ rvcontext -> wrap_option = REPLACE_WRAP_NONE ;
24122416 containing_appendrel -> translated_vars = (List * )
24132417 pullup_replace_vars ((Node * ) containing_appendrel -> translated_vars ,
24142418 rvcontext );
2415- rvcontext -> wrap_non_vars = save_wrap_non_vars ;
2419+ rvcontext -> wrap_option = save_wrap_option ;
24162420 return ;
24172421 }
24182422
@@ -2573,24 +2577,24 @@ replace_vars_in_jointree(Node *jtnode,
25732577 else if (IsA (jtnode , JoinExpr ))
25742578 {
25752579 JoinExpr * j = (JoinExpr * ) jtnode ;
2576- bool save_wrap_non_vars = context -> wrap_non_vars ;
2580+ ReplaceWrapOption save_wrap_option = context -> wrap_option ;
25772581
25782582 replace_vars_in_jointree (j -> larg , context );
25792583 replace_vars_in_jointree (j -> rarg , context );
25802584
25812585 /*
2582- * Use PHVs within the join quals of a full join. Otherwise, we
2583- * cannot identify which side of the join a pulled-up var-free
2584- * expression came from, which can lead to failure to make a plan at
2585- * all because none of the quals appear to be mergeable or hashable
2586- * conditions.
2586+ * Use PHVs within the join quals of a full join for variable-free
2587+ * expressions. Otherwise, we cannot identify which side of the join
2588+ * a pulled-up variable-free expression came from, which can lead to
2589+ * failure to make a plan at all because none of the quals appear to
2590+ * be mergeable or hashable conditions.
25872591 */
25882592 if (j -> jointype == JOIN_FULL )
2589- context -> wrap_non_vars = true ;
2593+ context -> wrap_option = REPLACE_WRAP_VARFREE ;
25902594
25912595 j -> quals = pullup_replace_vars (j -> quals , context );
25922596
2593- context -> wrap_non_vars = save_wrap_non_vars ;
2597+ context -> wrap_option = save_wrap_option ;
25942598 }
25952599 else
25962600 elog (ERROR , "unrecognized node type: %d" ,
@@ -2630,10 +2634,11 @@ pullup_replace_vars_callback(Var *var,
26302634 * We need a PlaceHolderVar if the Var-to-be-replaced has nonempty
26312635 * varnullingrels (unless we find below that the replacement expression is
26322636 * a Var or PlaceHolderVar that we can just add the nullingrels to). We
2633- * also need one if the caller has instructed us that all non-Var/PHV
2637+ * also need one if the caller has instructed us that certain expression
26342638 * replacements need to be wrapped for identification purposes.
26352639 */
2636- need_phv = (var -> varnullingrels != NULL ) || rcon -> wrap_non_vars ;
2640+ need_phv = (var -> varnullingrels != NULL ) ||
2641+ (rcon -> wrap_option != REPLACE_WRAP_NONE );
26372642
26382643 /*
26392644 * If PlaceHolderVars are needed, we cache the modified expressions in
@@ -2673,7 +2678,12 @@ pullup_replace_vars_callback(Var *var,
26732678 {
26742679 bool wrap ;
26752680
2676- if (varattno == InvalidAttrNumber )
2681+ if (rcon -> wrap_option == REPLACE_WRAP_ALL )
2682+ {
2683+ /* Caller told us to wrap all expressions in a PlaceHolderVar */
2684+ wrap = true;
2685+ }
2686+ else if (varattno == InvalidAttrNumber )
26772687 {
26782688 /*
26792689 * Insert PlaceHolderVar for whole-tuple reference. Notice
@@ -2733,11 +2743,6 @@ pullup_replace_vars_callback(Var *var,
27332743 }
27342744 }
27352745 }
2736- else if (rcon -> wrap_non_vars )
2737- {
2738- /* Caller told us to wrap all non-Vars in a PlaceHolderVar */
2739- wrap = true;
2740- }
27412746 else
27422747 {
27432748 /*
@@ -2769,7 +2774,11 @@ pullup_replace_vars_callback(Var *var,
27692774 * This analysis could be tighter: in particular, a non-strict
27702775 * construct hidden within a lower-level PlaceHolderVar is not
27712776 * reason to add another PHV. But for now it doesn't seem
2772- * worth the code to be more exact.
2777+ * worth the code to be more exact. This is also why it's
2778+ * preferable to handle bare PHVs in the above branch, rather
2779+ * than this branch. We also prefer to handle bare Vars in a
2780+ * separate branch, as it's cheaper this way and parallels the
2781+ * handling of PHVs.
27732782 *
27742783 * For a LATERAL subquery, we have to check the actual var
27752784 * membership of the node, but if it's non-lateral then any
0 commit comments