@ -61,7 +61,7 @@ typedef struct JoinTreeItem
{
/* Fields filled during deconstruct_recurse: */
Node * jtnode ; /* jointree node to examine */
bool below_outer_join ; /* is it below an outer join? */
JoinDomain * jdomain ; /* join domain for its ON/WHERE clauses */
Relids qualscope ; /* base+OJ Relids syntactically included in
* this jointree node */
Relids inner_join_rels ; /* base+OJ Relids syntactically included
@ -87,13 +87,13 @@ typedef struct PostponedQual
static void extract_lateral_references ( PlannerInfo * root , RelOptInfo * brel ,
Index rtindex ) ;
static List * deconstruct_recurse ( PlannerInfo * root , Node * jtnode ,
bool below_outer_jo in,
JoinDomain * parent_doma in,
List * * item_list ) ;
static void deconstruct_distribute ( PlannerInfo * root , JoinTreeItem * jtitem ,
List * * postponed_qual_list ) ;
static void process_security_barrier_quals ( PlannerInfo * root ,
int rti , Relids qualscope ,
bool below_outer_jo in) ;
JoinDomain * jdoma in) ;
static void mark_rels_nulled_by_join ( PlannerInfo * root , Index ojrelid ,
Relids lower_rels ) ;
static SpecialJoinInfo * make_outerjoininfo ( PlannerInfo * root ,
@ -107,7 +107,7 @@ static void deconstruct_distribute_oj_quals(PlannerInfo *root,
List * jtitems ,
JoinTreeItem * jtitem ) ;
static void distribute_quals_to_rels ( PlannerInfo * root , List * clauses ,
bool below_outer_jo in,
JoinDomain * jdoma in,
SpecialJoinInfo * sjinfo ,
Index security_level ,
Relids qualscope ,
@ -119,7 +119,7 @@ static void distribute_quals_to_rels(PlannerInfo *root, List *clauses,
List * * postponed_qual_list ,
List * * postponed_oj_qual_list ) ;
static void distribute_qual_to_rels ( PlannerInfo * root , Node * clause ,
bool below_outer_jo in,
JoinDomain * jdoma in,
SpecialJoinInfo * sjinfo ,
Index security_level ,
Relids qualscope ,
@ -740,6 +740,7 @@ List *
deconstruct_jointree ( PlannerInfo * root )
{
List * result ;
JoinDomain * top_jdomain ;
List * item_list = NIL ;
List * postponed_qual_list = NIL ;
ListCell * lc ;
@ -751,6 +752,10 @@ deconstruct_jointree(PlannerInfo *root)
*/
root - > placeholdersFrozen = true ;
/* Fetch the already-created top-level join domain for the query */
top_jdomain = linitial_node ( JoinDomain , root - > join_domains ) ;
top_jdomain - > jd_relids = NULL ; /* filled during deconstruct_recurse */
/* Start recursion at top of jointree */
Assert ( root - > parse - > jointree ! = NULL & &
IsA ( root - > parse - > jointree , FromExpr ) ) ;
@ -761,12 +766,15 @@ deconstruct_jointree(PlannerInfo *root)
/* Perform the initial scan of the jointree */
result = deconstruct_recurse ( root , ( Node * ) root - > parse - > jointree ,
false ,
top_jdomain ,
& item_list ) ;
/* Now we can form the value of all_query_rels, too */
root - > all_query_rels = bms_union ( root - > all_baserels , root - > outer_join_rels ) ;
/* ... which should match what we computed for the top join domain */
Assert ( bms_equal ( root - > all_query_rels , top_jdomain - > jd_relids ) ) ;
/* Now scan all the jointree nodes again, and distribute quals */
foreach ( lc , item_list )
{
@ -804,10 +812,9 @@ deconstruct_jointree(PlannerInfo *root)
* deconstruct_recurse
* One recursion level of deconstruct_jointree ' s initial jointree scan .
*
* Inputs :
* jtnode is the jointree node to examine
* below_outer_join is true if this node is within the nullable side of a
* higher - level outer join
* jtnode is the jointree node to examine , and parent_domain is the
* enclosing join domain . ( We must add all base + OJ relids appearing
* here or below to parent_domain . )
*
* item_list is an in / out parameter : we add a JoinTreeItem struct to
* that list for each jointree node , in depth - first traversal order .
@ -817,7 +824,7 @@ deconstruct_jointree(PlannerInfo *root)
*/
static List *
deconstruct_recurse ( PlannerInfo * root , Node * jtnode ,
bool below_outer_jo in,
JoinDomain * parent_doma in,
List * * item_list )
{
List * joinlist ;
@ -828,7 +835,6 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode,
/* Make the new JoinTreeItem, but don't add it to item_list yet */
jtitem = palloc0_object ( JoinTreeItem ) ;
jtitem - > jtnode = jtnode ;
jtitem - > below_outer_join = below_outer_join ;
if ( IsA ( jtnode , RangeTblRef ) )
{
@ -836,6 +842,10 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode,
/* Fill all_baserels as we encounter baserel jointree nodes */
root - > all_baserels = bms_add_member ( root - > all_baserels , varno ) ;
/* This node belongs to parent_domain */
jtitem - > jdomain = parent_domain ;
parent_domain - > jd_relids = bms_add_member ( parent_domain - > jd_relids ,
varno ) ;
/* qualscope is just the one RTE */
jtitem - > qualscope = bms_make_singleton ( varno ) ;
/* A single baserel does not create an inner join */
@ -848,6 +858,9 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode,
int remaining ;
ListCell * l ;
/* This node belongs to parent_domain, as do its children */
jtitem - > jdomain = parent_domain ;
/*
* Recurse to handle child nodes , and compute output joinlist . We
* collapse subproblems into a single joinlist whenever the resulting
@ -866,7 +879,7 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode,
int sub_members ;
sub_joinlist = deconstruct_recurse ( root , lfirst ( l ) ,
below_outer_jo in,
parent_doma in,
item_list ) ;
sub_item = ( JoinTreeItem * ) llast ( * item_list ) ;
jtitem - > qualscope = bms_add_members ( jtitem - > qualscope ,
@ -894,6 +907,8 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode,
else if ( IsA ( jtnode , JoinExpr ) )
{
JoinExpr * j = ( JoinExpr * ) jtnode ;
JoinDomain * child_domain ,
* fj_domain ;
JoinTreeItem * left_item ,
* right_item ;
List * leftjoinlist ,
@ -902,13 +917,15 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode,
switch ( j - > jointype )
{
case JOIN_INNER :
/* This node belongs to parent_domain, as do its children */
jtitem - > jdomain = parent_domain ;
/* Recurse */
leftjoinlist = deconstruct_recurse ( root , j - > larg ,
below_outer_jo in,
parent_doma in,
item_list ) ;
left_item = ( JoinTreeItem * ) llast ( * item_list ) ;
rightjoinlist = deconstruct_recurse ( root , j - > rarg ,
below_outer_jo in,
parent_doma in,
item_list ) ;
right_item = ( JoinTreeItem * ) llast ( * item_list ) ;
/* Compute qualscope etc */
@ -922,21 +939,32 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode,
break ;
case JOIN_LEFT :
case JOIN_ANTI :
/* Make new join domain for my quals and the RHS */
child_domain = makeNode ( JoinDomain ) ;
child_domain - > jd_relids = NULL ; /* filled by recursion */
root - > join_domains = lappend ( root - > join_domains , child_domain ) ;
jtitem - > jdomain = child_domain ;
/* Recurse */
leftjoinlist = deconstruct_recurse ( root , j - > larg ,
below_outer_join ,
parent_doma in,
item_list ) ;
left_item = ( JoinTreeItem * ) llast ( * item_list ) ;
rightjoinlist = deconstruct_recurse ( root , j - > rarg ,
true ,
child_domain ,
item_list ) ;
right_item = ( JoinTreeItem * ) llast ( * item_list ) ;
/* Compute qualscope etc */
/* Compute join domain contents, qualscope etc */
parent_domain - > jd_relids =
bms_add_members ( parent_domain - > jd_relids ,
child_domain - > jd_relids ) ;
jtitem - > qualscope = bms_union ( left_item - > qualscope ,
right_item - > qualscope ) ;
/* caution: ANTI join derived from SEMI will lack rtindex */
if ( j - > rtindex ! = 0 )
{
parent_domain - > jd_relids =
bms_add_member ( parent_domain - > jd_relids ,
j - > rtindex ) ;
jtitem - > qualscope = bms_add_member ( jtitem - > qualscope ,
j - > rtindex ) ;
root - > outer_join_rels = bms_add_member ( root - > outer_join_rels ,
@ -951,13 +979,15 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode,
jtitem - > nonnullable_rels = left_item - > qualscope ;
break ;
case JOIN_SEMI :
/* This node belongs to parent_domain, as do its children */
jtitem - > jdomain = parent_domain ;
/* Recurse */
leftjoinlist = deconstruct_recurse ( root , j - > larg ,
below_outer_jo in,
parent_doma in,
item_list ) ;
left_item = ( JoinTreeItem * ) llast ( * item_list ) ;
rightjoinlist = deconstruct_recurse ( root , j - > rarg ,
below_outer_jo in,
parent_doma in,
item_list ) ;
right_item = ( JoinTreeItem * ) llast ( * item_list ) ;
/* Compute qualscope etc */
@ -973,19 +1003,36 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode,
jtitem - > nonnullable_rels = NULL ;
break ;
case JOIN_FULL :
/* Recurse */
/* The FULL JOIN's quals need their very own domain */
fj_domain = makeNode ( JoinDomain ) ;
root - > join_domains = lappend ( root - > join_domains , fj_domain ) ;
jtitem - > jdomain = fj_domain ;
/* Recurse, giving each side its own join domain */
child_domain = makeNode ( JoinDomain ) ;
child_domain - > jd_relids = NULL ; /* filled by recursion */
root - > join_domains = lappend ( root - > join_domains , child_domain ) ;
leftjoinlist = deconstruct_recurse ( root , j - > larg ,
true ,
child_domain ,
item_list ) ;
left_item = ( JoinTreeItem * ) llast ( * item_list ) ;
fj_domain - > jd_relids = bms_copy ( child_domain - > jd_relids ) ;
child_domain = makeNode ( JoinDomain ) ;
child_domain - > jd_relids = NULL ; /* filled by recursion */
root - > join_domains = lappend ( root - > join_domains , child_domain ) ;
rightjoinlist = deconstruct_recurse ( root , j - > rarg ,
true ,
child_domain ,
item_list ) ;
right_item = ( JoinTreeItem * ) llast ( * item_list ) ;
/* Compute qualscope etc */
fj_domain - > jd_relids = bms_add_members ( fj_domain - > jd_relids ,
child_domain - > jd_relids ) ;
parent_domain - > jd_relids = bms_add_members ( parent_domain - > jd_relids ,
fj_domain - > jd_relids ) ;
jtitem - > qualscope = bms_union ( left_item - > qualscope ,
right_item - > qualscope ) ;
Assert ( j - > rtindex ! = 0 ) ;
parent_domain - > jd_relids = bms_add_member ( parent_domain - > jd_relids ,
j - > rtindex ) ;
jtitem - > qualscope = bms_add_member ( jtitem - > qualscope ,
j - > rtindex ) ;
root - > outer_join_rels = bms_add_member ( root - > outer_join_rels ,
@ -1087,7 +1134,7 @@ deconstruct_distribute(PlannerInfo *root, JoinTreeItem *jtitem,
process_security_barrier_quals ( root ,
varno ,
jtitem - > qualscope ,
jtitem - > below_outer_ join) ;
jtitem - > jd oma in ) ;
}
else if ( IsA ( jtnode , FromExpr ) )
{
@ -1105,7 +1152,7 @@ deconstruct_distribute(PlannerInfo *root, JoinTreeItem *jtitem,
if ( bms_is_subset ( pq - > relids , jtitem - > qualscope ) )
distribute_qual_to_rels ( root , pq - > qual ,
jtitem - > below_outer_ join,
jtitem - > jd oma in ,
NULL ,
root - > qual_security_level ,
jtitem - > qualscope , NULL , NULL ,
@ -1120,7 +1167,7 @@ deconstruct_distribute(PlannerInfo *root, JoinTreeItem *jtitem,
* Now process the top - level quals .
*/
distribute_quals_to_rels ( root , ( List * ) f - > quals ,
jtitem - > below_outer_ join,
jtitem - > jd oma in ,
NULL ,
root - > qual_security_level ,
jtitem - > qualscope , NULL , NULL ,
@ -1221,7 +1268,7 @@ deconstruct_distribute(PlannerInfo *root, JoinTreeItem *jtitem,
/* Process the JOIN's qual clauses */
distribute_quals_to_rels ( root , my_quals ,
jtitem - > below_outer_ join,
jtitem - > jd oma in ,
sjinfo ,
root - > qual_security_level ,
jtitem - > qualscope ,
@ -1258,7 +1305,7 @@ deconstruct_distribute(PlannerInfo *root, JoinTreeItem *jtitem,
static void
process_security_barrier_quals ( PlannerInfo * root ,
int rti , Relids qualscope ,
bool below_outer_jo in)
JoinDomain * jdoma in)
{
RangeTblEntry * rte = root - > simple_rte_array [ rti ] ;
Index security_level = 0 ;
@ -1281,7 +1328,7 @@ process_security_barrier_quals(PlannerInfo *root,
* pushed up to top of tree , which we don ' t want .
*/
distribute_quals_to_rels ( root , qualset ,
below_outer_ join,
jd oma in ,
NULL ,
security_level ,
qualscope ,
@ -1991,7 +2038,7 @@ deconstruct_distribute_oj_quals(PlannerInfo *root,
is_clone = ! has_clone ;
distribute_quals_to_rels ( root , quals ,
true ,
otherjtitem - > jdomain ,
sjinfo ,
root - > qual_security_level ,
this_qualscope ,
@ -2020,7 +2067,7 @@ deconstruct_distribute_oj_quals(PlannerInfo *root,
{
/* No commutation possible, just process the postponed clauses */
distribute_quals_to_rels ( root , jtitem - > oj_joinclauses ,
true ,
jtitem - > jdomain ,
sjinfo ,
root - > qual_security_level ,
qualscope ,
@ -2045,7 +2092,7 @@ deconstruct_distribute_oj_quals(PlannerInfo *root,
*/
static void
distribute_quals_to_rels ( PlannerInfo * root , List * clauses ,
bool below_outer_jo in,
JoinDomain * jdoma in,
SpecialJoinInfo * sjinfo ,
Index security_level ,
Relids qualscope ,
@ -2064,7 +2111,7 @@ distribute_quals_to_rels(PlannerInfo *root, List *clauses,
Node * clause = ( Node * ) lfirst ( lc ) ;
distribute_qual_to_rels ( root , clause ,
below_outer_ join,
jd oma in ,
sjinfo ,
security_level ,
qualscope ,
@ -2092,8 +2139,7 @@ distribute_quals_to_rels(PlannerInfo *root, List *clauses,
* These will be dealt with in later steps of deconstruct_jointree .
*
* ' clause ' : the qual clause to be distributed
* ' below_outer_join ' : true if the qual is from a JOIN / ON that is below the
* nullable side of a higher - level outer join
* ' jdomain ' : the join domain containing the clause
* ' sjinfo ' : join ' s SpecialJoinInfo ( NULL for an inner join or WHERE clause )
* ' security_level ' : security_level to assign to the qual
* ' qualscope ' : set of base + OJ rels the qual ' s syntactic scope covers
@ -2124,7 +2170,7 @@ distribute_quals_to_rels(PlannerInfo *root, List *clauses,
*/
static void
distribute_qual_to_rels ( PlannerInfo * root , Node * clause ,
bool below_outer_jo in,
JoinDomain * jdoma in,
SpecialJoinInfo * sjinfo ,
Index security_level ,
Relids qualscope ,
@ -2196,12 +2242,8 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
* RestrictInfo lists for the moment , but eventually createplan . c will
* pull it out and make a gating Result node immediately above whatever
* plan node the pseudoconstant clause is assigned to . It ' s usually best
* to put a gating node as high in the plan tree as possible . If we are
* not below an outer join , we can actually push the pseudoconstant qual
* all the way to the top of the tree . If we are below an outer join , we
* leave the qual at its original syntactic level ( we could push it up to
* just below the outer join , but that seems more complex than it ' s
* worth ) .
* to put a gating node as high in the plan tree as possible , which we can
* do by assigning it the full relid set of the current JoinDomain .
*/
if ( bms_is_empty ( relids ) )
{
@ -2211,25 +2253,20 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
relids = bms_copy ( ojscope ) ;
/* mustn't use as gating qual, so don't mark pseudoconstant */
}
else
else if ( contain_volatile_functions ( clause ) )
{
/* eval at original syntactic level */
relids = bms_copy ( qualscope ) ;
if ( ! contain_volatile_functions ( clause ) )
{
/* mark as gating qual */
pseudoconstant = true ;
/* tell createplan.c to check for gating quals */
root - > hasPseudoConstantQuals = true ;
/* if not below outer join, push it to top of tree */
if ( ! below_outer_join )
{
relids =
get_relids_in_jointree ( ( Node * ) root - > parse - > jointree ,
true , false ) ;
qualscope = bms_copy ( relids ) ;
}
}
/* again, can't mark pseudoconstant */
}
else
{
/* eval at join domain level */
relids = bms_copy ( jdomain - > jd_relids ) ;
/* mark as gating qual */
pseudoconstant = true ;
/* tell createplan.c to check for gating quals */
root - > hasPseudoConstantQuals = true ;
}
}
@ -2319,23 +2356,8 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
if ( check_redundant_nullability_qual ( root , clause ) )
return ;
if ( ! allow_equivalence )
{
/* Caller says it mustn't become an equivalence class */
maybe_equivalence = false ;
}
else
{
/*
* Consider feeding qual to the equivalence machinery . However ,
* if it ' s itself within an outer - join clause , treat it as though
* it appeared below that outer join ( note that we can only get
* here when the clause references only nullable - side rels ) .
*/
maybe_equivalence = true ;
if ( outerjoin_nonnullable ! = NULL )
below_outer_join = true ;
}
/* Feed qual to the equivalence machinery, if allowed by caller */
maybe_equivalence = allow_equivalence ;
/*
* Since it doesn ' t mention the LHS , it ' s certainly not useful as a
@ -2401,16 +2423,14 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
check_mergejoinable ( restrictinfo ) ;
/*
* XXX rewrite :
*
* If it is a true equivalence clause , send it to the EquivalenceClass
* machinery . We do * not * attach it directly to any restriction or join
* lists . The EC code will propagate it to the appropriate places later .
*
* If the clause has a mergejoinable operator and is not
* outerjoin - delayed , yet isn ' t an equivalence because it is an outer - join
* clause , the EC code may yet be able to do something with it . We add it
* to appropriate lists for further consideration later . Specifically :
* If the clause has a mergejoinable operator , yet isn ' t an equivalence
* because it is an outer - join clause , the EC code may still be able to do
* something with it . We add it to appropriate lists for further
* consideration later . Specifically :
*
* If it is a left or right outer - join qualification that relates the two
* sides of the outer join ( no funny business like leftvar1 = leftvar2 +
@ -2438,7 +2458,7 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
{
if ( maybe_equivalence )
{
if ( process_equivalence ( root , & restrictinfo , below_outer_ join) )
if ( process_equivalence ( root , & restrictinfo , jd oma in ) )
return ;
/* EC rejected it, so set left_ec/right_ec the hard way ... */
if ( restrictinfo - > mergeopfamilies ) /* EC might have changed this */
@ -2628,8 +2648,9 @@ distribute_restrictinfo_to_rels(PlannerInfo *root,
* " qualscope " is the nominal syntactic level to impute to the restrictinfo .
* This must contain at least all the rels used in the expressions , but it
* is used only to set the qual application level when both exprs are
* variable - free . Otherwise the qual is applied at the lowest join level
* that provides all its variables .
* variable - free . ( Hence , it should usually match the join domain in which
* the clause applies . ) Otherwise the qual is applied at the lowest join
* level that provides all its variables .
*
* " security_level " is the security level to assign to the new restrictinfo .
*
@ -2657,7 +2678,6 @@ process_implied_equality(PlannerInfo *root,
Expr * item2 ,
Relids qualscope ,
Index security_level ,
bool below_outer_join ,
bool both_const )
{
RestrictInfo * restrictinfo ;
@ -2706,27 +2726,16 @@ process_implied_equality(PlannerInfo *root,
/*
* If the clause is variable - free , our normal heuristic for pushing it
* down to just the mentioned rels doesn ' t work , because there are none .
* Apply at the given qualscope , or at the top of tree if it ' s nonvolatile
* ( which it very likely is , but we ' ll check , just to be sure ) .
* Apply it as a gating qual at the given qualscope .
*/
if ( bms_is_empty ( relids ) )
{
/* eval at original syntactic level */
/* eval at join domain level */
relids = bms_copy ( qualscope ) ;
if ( ! contain_volatile_functions ( clause ) )
{
/* mark as gating qual */
pseudoconstant = true ;
/* tell createplan.c to check for gating quals */
root - > hasPseudoConstantQuals = true ;
/* if not below outer join, push it to top of tree */
if ( ! below_outer_join )
{
relids =
get_relids_in_jointree ( ( Node * ) root - > parse - > jointree ,
true , false ) ;
}
}
/* mark as gating qual */
pseudoconstant = true ;
/* tell createplan.c to check for gating quals */
root - > hasPseudoConstantQuals = true ;
}
/*