@@ -57,6 +57,15 @@ typedef struct nullingrel_info
57
57
int rtlength ; /* used only for assertion checks */
58
58
} nullingrel_info ;
59
59
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
+
60
69
typedef struct pullup_replace_vars_context
61
70
{
62
71
PlannerInfo * root ;
@@ -70,7 +79,7 @@ typedef struct pullup_replace_vars_context
70
79
* target_rte->lateral) */
71
80
bool * outer_hasSubLinks ; /* -> outer query's hasSubLinks */
72
81
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? */
74
83
Node * * rv_cache ; /* cache for results with PHVs */
75
84
} pullup_replace_vars_context ;
76
85
@@ -1025,23 +1034,18 @@ expand_virtual_generated_columns(PlannerInfo *root)
1025
1034
rvcontext .outer_hasSubLinks = NULL ;
1026
1035
rvcontext .varno = rt_index ;
1027
1036
/* this flag will be set below, if needed */
1028
- rvcontext .wrap_non_vars = false ;
1037
+ rvcontext .wrap_option = REPLACE_WRAP_NONE ;
1029
1038
/* initialize cache array with indexes 0 .. length(tlist) */
1030
1039
rvcontext .rv_cache = palloc0 ((list_length (tlist ) + 1 ) *
1031
1040
sizeof (Node * ));
1032
1041
1033
1042
/*
1034
1043
* 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().)
1042
1046
*/
1043
1047
if (parse -> groupingSets )
1044
- rvcontext .wrap_non_vars = true ;
1048
+ rvcontext .wrap_option = REPLACE_WRAP_ALL ;
1045
1049
1046
1050
/*
1047
1051
* Apply pullup variable replacement throughout the query tree.
@@ -1435,22 +1439,22 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte,
1435
1439
rvcontext .outer_hasSubLinks = & parse -> hasSubLinks ;
1436
1440
rvcontext .varno = varno ;
1437
1441
/* this flag will be set below, if needed */
1438
- rvcontext .wrap_non_vars = false ;
1442
+ rvcontext .wrap_option = REPLACE_WRAP_NONE ;
1439
1443
/* initialize cache array with indexes 0 .. length(tlist) */
1440
1444
rvcontext .rv_cache = palloc0 ((list_length (subquery -> targetList ) + 1 ) *
1441
1445
sizeof (Node * ));
1442
1446
1443
1447
/*
1444
1448
* 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.)
1451
1455
*/
1452
1456
if (parse -> groupingSets )
1453
- rvcontext .wrap_non_vars = true ;
1457
+ rvcontext .wrap_option = REPLACE_WRAP_ALL ;
1454
1458
1455
1459
/*
1456
1460
* 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)
1976
1980
rvcontext .nullinfo = NULL ;
1977
1981
rvcontext .outer_hasSubLinks = & parse -> hasSubLinks ;
1978
1982
rvcontext .varno = varno ;
1979
- rvcontext .wrap_non_vars = false ;
1983
+ rvcontext .wrap_option = REPLACE_WRAP_NONE ;
1980
1984
/* initialize cache array with indexes 0 .. length(tlist) */
1981
1985
rvcontext .rv_cache = palloc0 ((list_length (tlist ) + 1 ) *
1982
1986
sizeof (Node * ));
@@ -2144,18 +2148,18 @@ pull_up_constant_function(PlannerInfo *root, Node *jtnode,
2144
2148
rvcontext .outer_hasSubLinks = & parse -> hasSubLinks ;
2145
2149
rvcontext .varno = ((RangeTblRef * ) jtnode )-> rtindex ;
2146
2150
/* this flag will be set below, if needed */
2147
- rvcontext .wrap_non_vars = false ;
2151
+ rvcontext .wrap_option = REPLACE_WRAP_NONE ;
2148
2152
/* initialize cache array with indexes 0 .. length(tlist) */
2149
2153
rvcontext .rv_cache = palloc0 ((list_length (rvcontext .targetlist ) + 1 ) *
2150
2154
sizeof (Node * ));
2151
2155
2152
2156
/*
2153
2157
* 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
2155
2159
* pull_up_simple_subquery().)
2156
2160
*/
2157
2161
if (parse -> groupingSets )
2158
- rvcontext .wrap_non_vars = true ;
2162
+ rvcontext .wrap_option = REPLACE_WRAP_ALL ;
2159
2163
2160
2164
/*
2161
2165
* Replace all of the top query's references to the RTE's output with
@@ -2406,13 +2410,13 @@ perform_pullup_replace_vars(PlannerInfo *root,
2406
2410
*/
2407
2411
if (containing_appendrel )
2408
2412
{
2409
- bool save_wrap_non_vars = rvcontext -> wrap_non_vars ;
2413
+ ReplaceWrapOption save_wrap_option = rvcontext -> wrap_option ;
2410
2414
2411
- rvcontext -> wrap_non_vars = false ;
2415
+ rvcontext -> wrap_option = REPLACE_WRAP_NONE ;
2412
2416
containing_appendrel -> translated_vars = (List * )
2413
2417
pullup_replace_vars ((Node * ) containing_appendrel -> translated_vars ,
2414
2418
rvcontext );
2415
- rvcontext -> wrap_non_vars = save_wrap_non_vars ;
2419
+ rvcontext -> wrap_option = save_wrap_option ;
2416
2420
return ;
2417
2421
}
2418
2422
@@ -2573,24 +2577,24 @@ replace_vars_in_jointree(Node *jtnode,
2573
2577
else if (IsA (jtnode , JoinExpr ))
2574
2578
{
2575
2579
JoinExpr * j = (JoinExpr * ) jtnode ;
2576
- bool save_wrap_non_vars = context -> wrap_non_vars ;
2580
+ ReplaceWrapOption save_wrap_option = context -> wrap_option ;
2577
2581
2578
2582
replace_vars_in_jointree (j -> larg , context );
2579
2583
replace_vars_in_jointree (j -> rarg , context );
2580
2584
2581
2585
/*
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.
2587
2591
*/
2588
2592
if (j -> jointype == JOIN_FULL )
2589
- context -> wrap_non_vars = true ;
2593
+ context -> wrap_option = REPLACE_WRAP_VARFREE ;
2590
2594
2591
2595
j -> quals = pullup_replace_vars (j -> quals , context );
2592
2596
2593
- context -> wrap_non_vars = save_wrap_non_vars ;
2597
+ context -> wrap_option = save_wrap_option ;
2594
2598
}
2595
2599
else
2596
2600
elog (ERROR , "unrecognized node type: %d" ,
@@ -2630,10 +2634,11 @@ pullup_replace_vars_callback(Var *var,
2630
2634
* We need a PlaceHolderVar if the Var-to-be-replaced has nonempty
2631
2635
* varnullingrels (unless we find below that the replacement expression is
2632
2636
* 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
2634
2638
* replacements need to be wrapped for identification purposes.
2635
2639
*/
2636
- need_phv = (var -> varnullingrels != NULL ) || rcon -> wrap_non_vars ;
2640
+ need_phv = (var -> varnullingrels != NULL ) ||
2641
+ (rcon -> wrap_option != REPLACE_WRAP_NONE );
2637
2642
2638
2643
/*
2639
2644
* If PlaceHolderVars are needed, we cache the modified expressions in
@@ -2673,7 +2678,12 @@ pullup_replace_vars_callback(Var *var,
2673
2678
{
2674
2679
bool wrap ;
2675
2680
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 )
2677
2687
{
2678
2688
/*
2679
2689
* Insert PlaceHolderVar for whole-tuple reference. Notice
@@ -2733,11 +2743,6 @@ pullup_replace_vars_callback(Var *var,
2733
2743
}
2734
2744
}
2735
2745
}
2736
- else if (rcon -> wrap_non_vars )
2737
- {
2738
- /* Caller told us to wrap all non-Vars in a PlaceHolderVar */
2739
- wrap = true;
2740
- }
2741
2746
else
2742
2747
{
2743
2748
/*
@@ -2769,7 +2774,11 @@ pullup_replace_vars_callback(Var *var,
2769
2774
* This analysis could be tighter: in particular, a non-strict
2770
2775
* construct hidden within a lower-level PlaceHolderVar is not
2771
2776
* 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.
2773
2782
*
2774
2783
* For a LATERAL subquery, we have to check the actual var
2775
2784
* membership of the node, but if it's non-lateral then any
0 commit comments