@ -57,6 +57,15 @@ typedef struct nullingrel_info
int rtlength ; /* used only for assertion checks */
} nullingrel_info ;
/* Options for wrapping an expression for identification purposes */
typedef enum ReplaceWrapOption
{
REPLACE_WRAP_NONE , /* no expressions need to be wrapped */
REPLACE_WRAP_ALL , /* all expressions need to be wrapped */
REPLACE_WRAP_VARFREE , /* variable-free expressions need to be
* wrapped */
} ReplaceWrapOption ;
typedef struct pullup_replace_vars_context
{
PlannerInfo * root ;
@ -70,7 +79,7 @@ typedef struct pullup_replace_vars_context
* target_rte - > lateral ) */
bool * outer_hasSubLinks ; /* -> outer query's hasSubLinks */
int varno ; /* varno of subquery */
bool wrap_non_vars ; /* do we need all non-Var outputs to be PHVs? */
ReplaceWrapOption wrap_option ; /* do we need certain outputs to be PHVs? */
Node * * rv_cache ; /* cache for results with PHVs */
} pullup_replace_vars_context ;
@ -1025,23 +1034,18 @@ expand_virtual_generated_columns(PlannerInfo *root)
rvcontext . outer_hasSubLinks = NULL ;
rvcontext . varno = rt_index ;
/* this flag will be set below, if needed */
rvcontext . wrap_non_vars = false ;
rvcontext . wrap_option = REPLACE_WRAP_NONE ;
/* initialize cache array with indexes 0 .. length(tlist) */
rvcontext . rv_cache = palloc0 ( ( list_length ( tlist ) + 1 ) *
sizeof ( Node * ) ) ;
/*
* If the query uses grouping sets , we need a PlaceHolderVar for
* anything that ' s not a simple Var . Again , this ensures that
* expressions retain their separate identity so that they will
* match grouping set columns when appropriate . ( It ' d be
* sufficient to wrap values used in grouping set columns , and do
* so only in non - aggregated portions of the tlist and havingQual ,
* but that would require a lot of infrastructure that
* pullup_replace_vars hasn ' t currently got . )
* each expression of the relation ' s targetlist items . ( See
* comments in pull_up_simple_subquery ( ) . )
*/
if ( parse - > groupingSets )
rvcontext . wrap_non_vars = true ;
rvcontext . wrap_option = REPLACE_WRAP_ALL ;
/*
* Apply pullup variable replacement throughout the query tree .
@ -1435,22 +1439,22 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte,
rvcontext . outer_hasSubLinks = & parse - > hasSubLinks ;
rvcontext . varno = varno ;
/* this flag will be set below, if needed */
rvcontext . wrap_non_vars = false ;
rvcontext . wrap_option = REPLACE_WRAP_NONE ;
/* initialize cache array with indexes 0 .. length(tlist) */
rvcontext . rv_cache = palloc0 ( ( list_length ( subquery - > targetList ) + 1 ) *
sizeof ( Node * ) ) ;
/*
* If the parent query uses grouping sets , we need a PlaceHolderVar for
* anything that ' s not a simple Var . This ensures that expressions retain
* their separate identity so that they will match grouping set columns
* when appropriate . ( It ' d be sufficient to wrap values used in grouping
* set columns , and do so only in non - aggregated portions of the tlist an d
* havingQual , but that would require a lot of infrastructure that
* pullup_replace_vars hasn ' t currently got . )
* each expression of the subquery ' s targetlist items . This ensures that
* expressions retain their separate identity so that they will match
* grouping set columns when appropriate . ( It ' d be sufficient to wrap
* values used in grouping set columns , and do so only in non - aggregated
* portions of the tlist and havingQual , but that would require a lot of
* infrastructure that pullup_replace_vars hasn ' t currently got . )
*/
if ( parse - > groupingSets )
rvcontext . wrap_non_vars = true ;
rvcontext . wrap_option = REPLACE_WRAP_ALL ;
/*
* 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)
rvcontext . nullinfo = NULL ;
rvcontext . outer_hasSubLinks = & parse - > hasSubLinks ;
rvcontext . varno = varno ;
rvcontext . wrap_non_vars = false ;
rvcontext . wrap_option = REPLACE_WRAP_NONE ;
/* initialize cache array with indexes 0 .. length(tlist) */
rvcontext . rv_cache = palloc0 ( ( list_length ( tlist ) + 1 ) *
sizeof ( Node * ) ) ;
@ -2144,18 +2148,18 @@ pull_up_constant_function(PlannerInfo *root, Node *jtnode,
rvcontext . outer_hasSubLinks = & parse - > hasSubLinks ;
rvcontext . varno = ( ( RangeTblRef * ) jtnode ) - > rtindex ;
/* this flag will be set below, if needed */
rvcontext . wrap_non_vars = false ;
rvcontext . wrap_option = REPLACE_WRAP_NONE ;
/* initialize cache array with indexes 0 .. length(tlist) */
rvcontext . rv_cache = palloc0 ( ( list_length ( rvcontext . targetlist ) + 1 ) *
sizeof ( Node * ) ) ;
/*
* If the parent query uses grouping sets , we need a PlaceHolderVar for
* anything that ' s not a simple Var . ( See comments in
* each expression of the subquery ' s targetlist items . ( See comments in
* pull_up_simple_subquery ( ) . )
*/
if ( parse - > groupingSets )
rvcontext . wrap_non_vars = true ;
rvcontext . wrap_option = REPLACE_WRAP_ALL ;
/*
* Replace all of the top query ' s references to the RTE ' s output with
@ -2406,13 +2410,13 @@ perform_pullup_replace_vars(PlannerInfo *root,
*/
if ( containing_appendrel )
{
bool save_wrap_non_vars = rvcontext - > wrap_non_vars ;
ReplaceWrapOption save_wrap_option = rvcontext - > wrap_option ;
rvcontext - > wrap_non_vars = false ;
rvcontext - > wrap_option = REPLACE_WRAP_NONE ;
containing_appendrel - > translated_vars = ( List * )
pullup_replace_vars ( ( Node * ) containing_appendrel - > translated_vars ,
rvcontext ) ;
rvcontext - > wrap_non_vars = save_wrap_non_vars ;
rvcontext - > wrap_option = save_wrap_option ;
return ;
}
@ -2573,24 +2577,24 @@ replace_vars_in_jointree(Node *jtnode,
else if ( IsA ( jtnode , JoinExpr ) )
{
JoinExpr * j = ( JoinExpr * ) jtnode ;
bool save_wrap_non_vars = context - > wrap_non_vars ;
ReplaceWrapOption save_wrap_option = context - > wrap_option ;
replace_vars_in_jointree ( j - > larg , context ) ;
replace_vars_in_jointree ( j - > rarg , context ) ;
/*
* Use PHVs within the join quals of a full join . Otherwise , w e
* cannot identify which side of the join a pulled - up var - free
* expression came from , which can lead to failure to make a plan at
* all because none of the quals appear to be mergeable or hashable
* conditions .
* Use PHVs within the join quals of a full join for variable - fre e
* expressions . Otherwise , we cannot identify which side of the join
* a pulled - up variable - free expression came from , which can lead to
* failure to make a plan at all because none of the quals appear to
* be mergeable or hashable conditions .
*/
if ( j - > jointype = = JOIN_FULL )
context - > wrap_non_vars = true ;
context - > wrap_option = REPLACE_WRAP_VARFREE ;
j - > quals = pullup_replace_vars ( j - > quals , context ) ;
context - > wrap_non_vars = save_wrap_non_vars ;
context - > wrap_option = save_wrap_option ;
}
else
elog ( ERROR , " unrecognized node type: %d " ,
@ -2630,10 +2634,11 @@ pullup_replace_vars_callback(Var *var,
* We need a PlaceHolderVar if the Var - to - be - replaced has nonempty
* varnullingrels ( unless we find below that the replacement expression is
* a Var or PlaceHolderVar that we can just add the nullingrels to ) . We
* also need one if the caller has instructed us that all non - Var / PHV
* also need one if the caller has instructed us that certain expression
* replacements need to be wrapped for identification purposes .
*/
need_phv = ( var - > varnullingrels ! = NULL ) | | rcon - > wrap_non_vars ;
need_phv = ( var - > varnullingrels ! = NULL ) | |
( rcon - > wrap_option ! = REPLACE_WRAP_NONE ) ;
/*
* If PlaceHolderVars are needed , we cache the modified expressions in
@ -2673,7 +2678,12 @@ pullup_replace_vars_callback(Var *var,
{
bool wrap ;
if ( varattno = = InvalidAttrNumber )
if ( rcon - > wrap_option = = REPLACE_WRAP_ALL )
{
/* Caller told us to wrap all expressions in a PlaceHolderVar */
wrap = true ;
}
else if ( varattno = = InvalidAttrNumber )
{
/*
* Insert PlaceHolderVar for whole - tuple reference . Notice
@ -2733,11 +2743,6 @@ pullup_replace_vars_callback(Var *var,
}
}
}
else if ( rcon - > wrap_non_vars )
{
/* Caller told us to wrap all non-Vars in a PlaceHolderVar */
wrap = true ;
}
else
{
/*
@ -2769,7 +2774,11 @@ pullup_replace_vars_callback(Var *var,
* This analysis could be tighter : in particular , a non - strict
* construct hidden within a lower - level PlaceHolderVar is not
* reason to add another PHV . But for now it doesn ' t seem
* worth the code to be more exact .
* worth the code to be more exact . This is also why it ' s
* preferable to handle bare PHVs in the above branch , rather
* than this branch . We also prefer to handle bare Vars in a
* separate branch , as it ' s cheaper this way and parallels the
* handling of PHVs .
*
* For a LATERAL subquery , we have to check the actual var
* membership of the node , but if it ' s non - lateral then any