@ -23,9 +23,8 @@
# include "utils/lsyscache.h"
# include "utils/lsyscache.h"
/* Local functions */
/* Local functions */
static Relids find_placeholders_recurse ( PlannerInfo * root , Node * jtnode ) ;
static void find_placeholders_recurse ( PlannerInfo * root , Node * jtnode ) ;
static void mark_placeholders_in_expr ( PlannerInfo * root , Node * expr ,
static void find_placeholders_in_expr ( PlannerInfo * root , Node * expr ) ;
Relids relids ) ;
/*
/*
@ -90,16 +89,23 @@ find_placeholder_info(PlannerInfo *root, PlaceHolderVar *phv,
phinfo - > phid = phv - > phid ;
phinfo - > phid = phv - > phid ;
phinfo - > ph_var = copyObject ( phv ) ;
phinfo - > ph_var = copyObject ( phv ) ;
/* initialize ph_eval_at as the set of contained relids */
phinfo - > ph_eval_at = pull_varnos ( ( Node * ) phv ) ;
phinfo - > ph_eval_at = pull_varnos ( ( Node * ) phv ) ;
/* ph_eval_at may change later, see update_placeholder_eval_levels */
/* ph_eval_at may change later, see update_placeholder_eval_levels */
phinfo - > ph_needed = NULL ; /* initially it's unused */
phinfo - > ph_needed = NULL ; /* initially it's unused */
phinfo - > ph_may_need = NULL ;
/* for the moment, estimate width using just the datatype info */
/* for the moment, estimate width using just the datatype info */
phinfo - > ph_width = get_typavgwidth ( exprType ( ( Node * ) phv - > phexpr ) ,
phinfo - > ph_width = get_typavgwidth ( exprType ( ( Node * ) phv - > phexpr ) ,
exprTypmod ( ( Node * ) phv - > phexpr ) ) ;
exprTypmod ( ( Node * ) phv - > phexpr ) ) ;
root - > placeholder_list = lappend ( root - > placeholder_list , phinfo ) ;
root - > placeholder_list = lappend ( root - > placeholder_list , phinfo ) ;
/*
* The PHV ' s contained expression may contain other , lower - level PHVs . We
* now know we need to get those into the PlaceHolderInfo list , too , so we
* may as well do that immediately .
*/
find_placeholders_in_expr ( root , ( Node * ) phinfo - > ph_var - > phexpr ) ;
return phinfo ;
return phinfo ;
}
}
@ -119,7 +125,7 @@ find_placeholders_in_jointree(PlannerInfo *root)
/* Start recursion at top of jointree */
/* Start recursion at top of jointree */
Assert ( root - > parse - > jointree ! = NULL & &
Assert ( root - > parse - > jointree ! = NULL & &
IsA ( root - > parse - > jointree , FromExpr ) ) ;
IsA ( root - > parse - > jointree , FromExpr ) ) ;
( void ) find_placeholders_recurse ( root , ( Node * ) root - > parse - > jointree ) ;
find_placeholders_recurse ( root , ( Node * ) root - > parse - > jointree ) ;
}
}
}
}
@ -128,23 +134,15 @@ find_placeholders_in_jointree(PlannerInfo *root)
* One recursion level of find_placeholders_in_jointree .
* One recursion level of find_placeholders_in_jointree .
*
*
* jtnode is the current jointree node to examine .
* jtnode is the current jointree node to examine .
*
* The result is the set of base Relids contained in or below jtnode .
* This is just an internal convenience , it ' s not used at the top level .
*/
*/
static Relids
static void
find_placeholders_recurse ( PlannerInfo * root , Node * jtnode )
find_placeholders_recurse ( PlannerInfo * root , Node * jtnode )
{
{
Relids jtrelids ;
if ( jtnode = = NULL )
if ( jtnode = = NULL )
return NULL ;
return ;
if ( IsA ( jtnode , RangeTblRef ) )
if ( IsA ( jtnode , RangeTblRef ) )
{
{
int varno = ( ( RangeTblRef * ) jtnode ) - > rtindex ;
/* No quals to deal with here */
/* No quals to deal with, just return correct result */
jtrelids = bms_make_singleton ( varno ) ;
}
}
else if ( IsA ( jtnode , FromExpr ) )
else if ( IsA ( jtnode , FromExpr ) )
{
{
@ -152,57 +150,43 @@ find_placeholders_recurse(PlannerInfo *root, Node *jtnode)
ListCell * l ;
ListCell * l ;
/*
/*
* First , recurse to handle child joins , and form their relid set .
* First , recurse to handle child joins .
*/
*/
jtrelids = NULL ;
foreach ( l , f - > fromlist )
foreach ( l , f - > fromlist )
{
{
Relids sub_relids ;
find_placeholders_recurse ( root , lfirst ( l ) ) ;
sub_relids = find_placeholders_recurse ( root , lfirst ( l ) ) ;
jtrelids = bms_join ( jtrelids , sub_relids ) ;
}
}
/*
/*
* Now process the top - level quals .
* Now process the top - level quals .
*/
*/
mark _placeholders_in_expr( root , f - > quals , jtrelid s ) ;
find _placeholders_in_expr( root , f - > quals ) ;
}
}
else if ( IsA ( jtnode , JoinExpr ) )
else if ( IsA ( jtnode , JoinExpr ) )
{
{
JoinExpr * j = ( JoinExpr * ) jtnode ;
JoinExpr * j = ( JoinExpr * ) jtnode ;
Relids leftids ,
rightids ;
/*
/*
* First , recurse to handle child joins , and form their relid set .
* First , recurse to handle child joins .
*/
*/
leftids = find_placeholders_recurse ( root , j - > larg ) ;
find_placeholders_recurse ( root , j - > larg ) ;
rightids = find_placeholders_recurse ( root , j - > rarg ) ;
find_placeholders_recurse ( root , j - > rarg ) ;
jtrelids = bms_join ( leftids , rightids ) ;
/* Process the qual clauses */
/* Process the qual clauses */
mark _placeholders_in_expr( root , j - > quals , jtrelid s ) ;
find _placeholders_in_expr( root , j - > quals ) ;
}
}
else
else
{
elog ( ERROR , " unrecognized node type: %d " ,
elog ( ERROR , " unrecognized node type: %d " ,
( int ) nodeTag ( jtnode ) ) ;
( int ) nodeTag ( jtnode ) ) ;
jtrelids = NULL ; /* keep compiler quiet */
}
return jtrelids ;
}
}
/*
/*
* mark_placeholders_in_expr
* find_placeholders_in_expr
* Find all PlaceHolderVars in the given expression , and mark them
* Find all PlaceHolderVars in the given expression , and create
* as possibly needed at the specified join level .
* PlaceHolderInfo entries for them .
*
* relids is the syntactic join level to mark as the " maybe needed " level
* for each PlaceHolderVar found in the expression .
*/
*/
static void
static void
mark _placeholders_in_expr( PlannerInfo * root , Node * expr , Relids relids )
find_placeholders_in_expr ( PlannerInfo * root , Node * expr )
{
{
List * vars ;
List * vars ;
ListCell * vl ;
ListCell * vl ;
@ -217,63 +201,17 @@ mark_placeholders_in_expr(PlannerInfo *root, Node *expr, Relids relids)
foreach ( vl , vars )
foreach ( vl , vars )
{
{
PlaceHolderVar * phv = ( PlaceHolderVar * ) lfirst ( vl ) ;
PlaceHolderVar * phv = ( PlaceHolderVar * ) lfirst ( vl ) ;
PlaceHolderInfo * phinfo ;
/* Ignore any plain Vars */
/* Ignore any plain Vars */
if ( ! IsA ( phv , PlaceHolderVar ) )
if ( ! IsA ( phv , PlaceHolderVar ) )
continue ;
continue ;
/* Create a PlaceHolderInfo entry if there's not one already */
/* Create a PlaceHolderInfo entry if there's not one already */
phinfo = find_placeholder_info ( root , phv , true ) ;
( void ) find_placeholder_info ( root , phv , true ) ;
/* Mark it, and recursively process any contained placeholders */
mark_placeholder_maybe_needed ( root , phinfo , relids ) ;
}
}
list_free ( vars ) ;
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 )
{
Relids est_eval_level ;
/* 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 , but not less than the level of any Vars it contains .
* ( Normally the Vars would come from below the syntactic location anyway ,
* but this might not be true if the PHV contains any LATERAL references . )
*/
est_eval_level = bms_union ( phinfo - > ph_var - > phrels , phinfo - > ph_eval_at ) ;
/* Now recurse to take care of any such PHVs */
mark_placeholders_in_expr ( root , ( Node * ) phinfo - > ph_var - > phexpr ,
est_eval_level ) ;
bms_free ( est_eval_level ) ;
}
/*
/*
* update_placeholder_eval_levels
* update_placeholder_eval_levels
* Adjust the target evaluation levels for placeholders
* Adjust the target evaluation levels for placeholders