@ -24,7 +24,7 @@
/* Local functions */
static Relids find_placeholders_recurse ( PlannerInfo * root , Node * jtnode ) ;
static void find_placeholders_in_qual ( PlannerInfo * root , Node * qual ,
static void mark_placeholders_in_expr ( PlannerInfo * root , Node * expr ,
Relids relids ) ;
@ -50,7 +50,10 @@ make_placeholder_expr(PlannerInfo *root, Expr *expr, Relids phrels)
/*
* find_placeholder_info
* Fetch the PlaceHolderInfo for the given PHV ; create it if not found
* Fetch the PlaceHolderInfo for the given PHV
*
* If the PlaceHolderInfo doesn ' t exist yet , create it if create_new_ph is
* true , else throw an error .
*
* This is separate from make_placeholder_expr because subquery pullup has
* to make PlaceHolderVars for expressions that might not be used at all in
@ -58,10 +61,13 @@ make_placeholder_expr(PlannerInfo *root, Expr *expr, Relids phrels)
* We build PlaceHolderInfos only for PHVs that are still present in the
* simplified query passed to query_planner ( ) .
*
* Note : this should only be called after query_planner ( ) has started .
* Note : this should only be called after query_planner ( ) has started . Also ,
* create_new_ph must not be TRUE after deconstruct_jointree begins , because
* make_outerjoininfo assumes that we already know about all placeholders .
*/
PlaceHolderInfo *
find_placeholder_info ( PlannerInfo * root , PlaceHolderVar * phv )
find_placeholder_info ( PlannerInfo * root , PlaceHolderVar * phv ,
bool create_new_ph )
{
PlaceHolderInfo * phinfo ;
ListCell * lc ;
@ -77,6 +83,9 @@ find_placeholder_info(PlannerInfo *root, PlaceHolderVar *phv)
}
/* Not found, so create it */
if ( ! create_new_ph )
elog ( ERROR , " too late to create a new PlaceHolderInfo " ) ;
phinfo = makeNode ( PlaceHolderInfo ) ;
phinfo - > phid = phv - > phid ;
@ -157,7 +166,7 @@ find_placeholders_recurse(PlannerInfo *root, Node *jtnode)
/*
* Now process the top - level quals .
*/
find_placeholders_in_qual ( root , f - > quals , jtrelids ) ;
mark_placeholders_in_expr ( root , f - > quals , jtrelids ) ;
}
else if ( IsA ( jtnode , JoinExpr ) )
{
@ -173,7 +182,7 @@ find_placeholders_recurse(PlannerInfo *root, Node *jtnode)
jtrelids = bms_join ( leftids , rightids ) ;
/* Process the qual clauses */
find_placeholders_in_qual ( root , j - > quals , jtrelids ) ;
mark_placeholders_in_expr ( root , j - > quals , jtrelids ) ;
}
else
{
@ -185,14 +194,15 @@ find_placeholders_recurse(PlannerInfo *root, Node *jtnode)
}
/*
* find_placeholders_in_qual
* Process a qual clause for find_placeholders_in_jointree .
* mark_placeholders_in_expr
* Find all PlaceHolderVars in the given expression , and mark them
* as possibly needed at the specified join level .
*
* relids is the syntactic join level to mark as the " maybe needed " level
* for each PlaceHolderVar found in the qual clause .
* for each PlaceHolderVar found in the expression .
*/
static void
find_placeholders_in_qual ( PlannerInfo * root , Node * qual , Relids relids )
mark_placeholders_in_expr ( PlannerInfo * root , Node * expr , Relids relids )
{
List * vars ;
ListCell * vl ;
@ -201,7 +211,7 @@ find_placeholders_in_qual(PlannerInfo *root, Node *qual, Relids relids)
* pull_var_clause does more than we need here , but it ' ll do and it ' s
* convenient to use .
*/
vars = pull_var_clause ( qual ,
vars = pull_var_clause ( expr ,
PVC_RECURSE_AGGREGATES ,
PVC_INCLUDE_PLACEHOLDERS ) ;
foreach ( vl , vars )
@ -214,25 +224,47 @@ find_placeholders_in_qual(PlannerInfo *root, Node *qual, Relids relids)
continue ;
/* Create a PlaceHolderInfo entry if there's not one already */
phinfo = find_placeholder_info ( root , phv ) ;
/* Mark the PHV as possibly needed at the qual's syntactic level */
phinfo - > ph_may_need = bms_add_members ( phinfo - > ph_may_need , relids ) ;
phinfo = find_placeholder_info ( root , phv , true ) ;
/*
* This is a bit tricky : the PHV ' s contained expression may contain
* other , lower - level PHVs . We need to get those into the
* PlaceHolderInfo list , but they aren ' t going to be needed where the
* outer PHV is referenced . Rather , they ' ll be needed where the outer
* PHV is evaluated . We can estimate that ( conservatively ) as the
* syntactic location of the PHV ' s expression . Recurse to take care
* of any such PHVs .
*/
find_placeholders_in_qual ( root , ( Node * ) phv - > phexpr , phv - > phrels ) ;
/* Mark it, and recursively process any contained placeholders */
mark_placeholder_maybe_needed ( root , phinfo , relids ) ;
}
list_free ( vars ) ;
}
/*
* mark_placeholder_maybe_needed
* Mark a placeholder as possibly needed at the specified join level .
*
* relids is the syntactic join level to mark as the " maybe needed " level
* for the placeholder .
*
* This is called during an initial scan of the query ' s targetlist and quals
* before we begin deconstruct_jointree . Once we begin deconstruct_jointree ,
* all active placeholders must be present in root - > placeholder_list with
* their correct ph_may_need values , because make_outerjoininfo and
* update_placeholder_eval_levels require this info to be available while
* we crawl up the join tree .
*/
void
mark_placeholder_maybe_needed ( PlannerInfo * root , PlaceHolderInfo * phinfo ,
Relids relids )
{
/* Mark the PHV as possibly needed at the given syntactic level */
phinfo - > ph_may_need = bms_add_members ( phinfo - > ph_may_need , relids ) ;
/*
* This is a bit tricky : the PHV ' s contained expression may contain other ,
* lower - level PHVs . We need to get those into the PlaceHolderInfo list ,
* but they aren ' t going to be needed where the outer PHV is referenced .
* Rather , they ' ll be needed where the outer PHV is evaluated . We can
* estimate that ( conservatively ) as the syntactic location of the PHV ' s
* expression . Recurse to take care of any such PHVs .
*/
mark_placeholders_in_expr ( root , ( Node * ) phinfo - > ph_var - > phexpr ,
phinfo - > ph_var - > phrels ) ;
}
/*
* update_placeholder_eval_levels
* Adjust the target evaluation levels for placeholders
@ -353,7 +385,7 @@ fix_placeholder_input_needed_levels(PlannerInfo *root)
PVC_RECURSE_AGGREGATES ,
PVC_INCLUDE_PLACEHOLDERS ) ;
add_vars_to_targetlist ( root , vars , eval_at ) ;
add_vars_to_targetlist ( root , vars , eval_at , false ) ;
list_free ( vars ) ;
}
}