@ -64,6 +64,10 @@ static bool reconsider_outer_join_clause(PlannerInfo *root,
bool outer_on_left ) ;
static bool reconsider_full_join_clause ( PlannerInfo * root ,
RestrictInfo * rinfo ) ;
static Bitmapset * get_eclass_indexes_for_relids ( PlannerInfo * root ,
Relids relids ) ;
static Bitmapset * get_common_eclass_indexes ( PlannerInfo * root , Relids relids1 ,
Relids relids2 ) ;
/*
@ -341,10 +345,11 @@ process_equivalence(PlannerInfo *root,
/*
* Case 2 : need to merge ec1 and ec2 . This should never happen after
* we ' ve built any canonical pathkeys ; if it did , those pathkeys might
* be rendered non - canonical by the merge .
* the ECs have reached canonical state ; otherwise , pathkeys could be
* rendered non - canonical by the merge , and relation eclass indexes
* would get broken by removal of an eq_classes list entry .
*/
if ( root - > canon_pathkeys ! = NIL )
if ( root - > ec_merging_done )
elog ( ERROR , " too late to merge equivalence classes " ) ;
/*
@ -743,6 +748,26 @@ get_eclass_for_sort_expr(PlannerInfo *root,
root - > eq_classes = lappend ( root - > eq_classes , newec ) ;
/*
* If EC merging is already complete , we have to mop up by adding the new
* EC to the eclass_indexes of the relation ( s ) mentioned in it .
*/
if ( root - > ec_merging_done )
{
int ec_index = list_length ( root - > eq_classes ) - 1 ;
int i = - 1 ;
while ( ( i = bms_next_member ( newec - > ec_relids , i ) ) > 0 )
{
RelOptInfo * rel = root - > simple_rel_array [ i ] ;
Assert ( rel - > reloptkind = = RELOPT_BASEREL ) ;
rel - > eclass_indexes = bms_add_member ( rel - > eclass_indexes ,
ec_index ) ;
}
}
MemoryContextSwitchTo ( oldcontext ) ;
return newec ;
@ -800,42 +825,71 @@ get_eclass_for_sort_expr(PlannerInfo *root,
void
generate_base_implied_equalities ( PlannerInfo * root )
{
int ec_index ;
ListCell * lc ;
Index rti ;
/*
* At this point , we ' re done absorbing knowledge of equivalences in the
* query , so no further EC merging should happen , and ECs remaining in the
* eq_classes list can be considered canonical . ( But note that it ' s still
* possible for new single - member ECs to be added through
* get_eclass_for_sort_expr ( ) . )
*/
root - > ec_merging_done = true ;
ec_index = 0 ;
foreach ( lc , root - > eq_classes )
{
EquivalenceClass * ec = ( EquivalenceClass * ) lfirst ( lc ) ;
bool can_generate_joinclause = false ;
int i ;
Assert ( ec - > ec_merged = = NULL ) ; /* else shouldn't be in list */
Assert ( ! ec - > ec_broken ) ; /* not yet anyway... */
/* Single-member ECs won't generate any deductions */
if ( list_length ( ec - > ec_members ) < = 1 )
continue ;
/*
* Generate implied equalities that are restriction clauses .
* Single - member ECs won ' t generate any deductions , either here or at
* the join level .
*/
if ( list_length ( ec - > ec_members ) > 1 )
{
if ( ec - > ec_has_const )
generate_base_implied_equalities_const ( root , ec ) ;
else
generate_base_implied_equalities_no_const ( root , ec ) ;
/* Recover if we failed to generate required derived clauses */
if ( ec - > ec_broken )
generate_base_implied_equalities_broken ( root , ec ) ;
/* Detect whether this EC might generate join clauses */
can_generate_joinclause =
( bms_membership ( ec - > ec_relids ) = = BMS_MULTIPLE ) ;
}
if ( ec - > ec_has_const )
generate_base_implied_equalities_const ( root , ec ) ;
else
generate_base_implied_equalities_no_const ( root , ec ) ;
/*
* Mark the base rels cited in each eclass ( which should all exist by
* now ) with the eq_classes indexes of all eclasses mentioning them .
* This will let us avoid searching in subsequent lookups . While
* we ' re at it , we can mark base rels that have pending eclass joins ;
* this is a cheap version of has_relevant_eclass_joinclause ( ) .
*/
i = - 1 ;
while ( ( i = bms_next_member ( ec - > ec_relids , i ) ) > 0 )
{
RelOptInfo * rel = root - > simple_rel_array [ i ] ;
/* Recover if we failed to generate required derived clauses */
if ( ec - > ec_broken )
generate_base_implied_equalities_broken ( root , ec ) ;
}
Assert ( rel - > reloptkind = = RELOPT_BASEREL ) ;
/*
* This is also a handy place to mark base rels ( which should all exist by
* now ) with flags showing whether they have pending eclass joins .
*/
for ( rti = 1 ; rti < root - > simple_rel_array_size ; rti + + )
{
RelOptInfo * brel = root - > simple_rel_array [ rti ] ;
rel - > eclass_indexes = bms_add_member ( rel - > eclass_indexes ,
ec_index ) ;
if ( brel = = NULL )
continue ;
if ( can_generate_joinclause )
rel - > has_eclass_joins = true ;
}
brel - > has_eclass_joins = has_relevant_eclass_joinclause ( root , brel ) ;
ec_index + + ;
}
}
@ -1073,11 +1127,72 @@ generate_join_implied_equalities(PlannerInfo *root,
Relids outer_relids ,
RelOptInfo * inner_rel )
{
return generate_join_implied_equalities_for_ecs ( root ,
root - > eq_classes ,
join_relids ,
outer_relids ,
inner_rel ) ;
List * result = NIL ;
Relids inner_relids = inner_rel - > relids ;
Relids nominal_inner_relids ;
Relids nominal_join_relids ;
Bitmapset * matching_ecs ;
int i ;
/* If inner rel is a child, extra setup work is needed */
if ( IS_OTHER_REL ( inner_rel ) )
{
Assert ( ! bms_is_empty ( inner_rel - > top_parent_relids ) ) ;
/* Fetch relid set for the topmost parent rel */
nominal_inner_relids = inner_rel - > top_parent_relids ;
/* ECs will be marked with the parent's relid, not the child's */
nominal_join_relids = bms_union ( outer_relids , nominal_inner_relids ) ;
}
else
{
nominal_inner_relids = inner_relids ;
nominal_join_relids = join_relids ;
}
/*
* Get all eclasses in common between inner_rel ' s relids and outer_relids
*/
matching_ecs = get_common_eclass_indexes ( root , inner_rel - > relids ,
outer_relids ) ;
i = - 1 ;
while ( ( i = bms_next_member ( matching_ecs , i ) ) > = 0 )
{
EquivalenceClass * ec = ( EquivalenceClass * ) list_nth ( root - > eq_classes , i ) ;
List * sublist = NIL ;
/* ECs containing consts do not need any further enforcement */
if ( ec - > ec_has_const )
continue ;
/* Single-member ECs won't generate any deductions */
if ( list_length ( ec - > ec_members ) < = 1 )
continue ;
/* Sanity check that this eclass overlaps the join */
Assert ( bms_overlap ( ec - > ec_relids , nominal_join_relids ) ) ;
if ( ! ec - > ec_broken )
sublist = generate_join_implied_equalities_normal ( root ,
ec ,
join_relids ,
outer_relids ,
inner_relids ) ;
/* Recover if we failed to generate required derived clauses */
if ( ec - > ec_broken )
sublist = generate_join_implied_equalities_broken ( root ,
ec ,
nominal_join_relids ,
outer_relids ,
nominal_inner_relids ,
inner_rel ) ;
result = list_concat ( result , sublist ) ;
}
return result ;
}
/*
@ -2022,12 +2137,24 @@ match_eclasses_to_foreign_key_col(PlannerInfo *root,
Index var2varno = fkinfo - > ref_relid ;
AttrNumber var2attno = fkinfo - > confkey [ colno ] ;
Oid eqop = fkinfo - > conpfeqop [ colno ] ;
RelOptInfo * rel1 = root - > simple_rel_array [ var1varno ] ;
RelOptInfo * rel2 = root - > simple_rel_array [ var2varno ] ;
List * opfamilies = NIL ; /* compute only if needed */
ListCell * lc1 ;
foreach ( lc1 , root - > eq_classes )
Bitmapset * matching_ecs ;
int i ;
/* Consider only eclasses mentioning both relations */
Assert ( root - > ec_merging_done ) ;
Assert ( IS_SIMPLE_REL ( rel1 ) ) ;
Assert ( IS_SIMPLE_REL ( rel2 ) ) ;
matching_ecs = bms_intersect ( rel1 - > eclass_indexes ,
rel2 - > eclass_indexes ) ;
i = - 1 ;
while ( ( i = bms_next_member ( matching_ecs , i ) ) > = 0 )
{
EquivalenceClass * ec = ( EquivalenceClass * ) lfirst ( lc1 ) ;
EquivalenceClass * ec = ( EquivalenceClass * ) list_nth ( root - > eq_classes ,
i ) ;
bool item1member = false ;
bool item2member = false ;
ListCell * lc2 ;
@ -2037,14 +2164,6 @@ match_eclasses_to_foreign_key_col(PlannerInfo *root,
continue ;
/* Note: it seems okay to match to "broken" eclasses here */
/*
* If eclass visibly doesn ' t have members for both rels , there ' s no
* need to grovel through the members .
*/
if ( ! bms_is_member ( var1varno , ec - > ec_relids ) | |
! bms_is_member ( var2varno , ec - > ec_relids ) )
continue ;
foreach ( lc2 , ec - > ec_members )
{
EquivalenceMember * em = ( EquivalenceMember * ) lfirst ( lc2 ) ;
@ -2104,11 +2223,19 @@ add_child_rel_equivalences(PlannerInfo *root,
RelOptInfo * parent_rel ,
RelOptInfo * child_rel )
{
ListCell * lc1 ;
int i ;
foreach ( lc1 , root - > eq_classes )
/*
* EC merging should be complete already , so we can use the parent rel ' s
* eclass_indexes to avoid searching all of root - > eq_classes .
*/
Assert ( root - > ec_merging_done ) ;
Assert ( IS_SIMPLE_REL ( parent_rel ) ) ;
i = - 1 ;
while ( ( i = bms_next_member ( parent_rel - > eclass_indexes , i ) ) > = 0 )
{
EquivalenceClass * cur_ec = ( EquivalenceClass * ) lfirst ( lc1 ) ;
EquivalenceClass * cur_ec = ( EquivalenceClass * ) list_nth ( root - > eq_classes , i ) ;
int num_members ;
/*
@ -2119,12 +2246,8 @@ add_child_rel_equivalences(PlannerInfo *root,
if ( cur_ec - > ec_has_volatile )
continue ;
/*
* No point in searching if child ' s topmost parent rel is not
* mentioned in eclass .
*/
if ( ! bms_is_subset ( child_rel - > top_parent_relids , cur_ec - > ec_relids ) )
continue ;
/* Sanity check eclass_indexes only contain ECs for parent_rel */
Assert ( bms_is_subset ( child_rel - > top_parent_relids , cur_ec - > ec_relids ) ) ;
/*
* We don ' t use foreach ( ) here because there ' s no point in scanning
@ -2202,6 +2325,9 @@ add_child_rel_equivalences(PlannerInfo *root,
( void ) add_eq_member ( cur_ec , child_expr ,
new_relids , new_nullable_relids ,
true , cur_em - > em_datatype ) ;
/* Record this EC index for the child rel */
child_rel - > eclass_indexes = bms_add_member ( child_rel - > eclass_indexes , i ) ;
}
}
}
@ -2241,7 +2367,10 @@ generate_implied_equalities_for_column(PlannerInfo *root,
List * result = NIL ;
bool is_child_rel = ( rel - > reloptkind = = RELOPT_OTHER_MEMBER_REL ) ;
Relids parent_relids ;
ListCell * lc1 ;
int i ;
/* Should be OK to rely on eclass_indexes */
Assert ( root - > ec_merging_done ) ;
/* Indexes are available only on base or "other" member relations. */
Assert ( IS_SIMPLE_REL ( rel ) ) ;
@ -2252,12 +2381,16 @@ generate_implied_equalities_for_column(PlannerInfo *root,
else
parent_relids = NULL ; /* not used, but keep compiler quiet */
foreach ( lc1 , root - > eq_classes )
i = - 1 ;
while ( ( i = bms_next_member ( rel - > eclass_indexes , i ) ) > = 0 )
{
EquivalenceClass * cur_ec = ( EquivalenceClass * ) lfirst ( lc1 ) ;
EquivalenceClass * cur_ec = ( EquivalenceClass * ) list_nth ( root - > eq_classes , i ) ;
EquivalenceMember * cur_em ;
ListCell * lc2 ;
/* Sanity check eclass_indexes only contain ECs for rel */
Assert ( is_child_rel | | bms_is_subset ( rel - > relids , cur_ec - > ec_relids ) ) ;
/*
* Won ' t generate joinclauses if const or single - member ( the latter
* test covers the volatile case too )
@ -2265,14 +2398,6 @@ generate_implied_equalities_for_column(PlannerInfo *root,
if ( cur_ec - > ec_has_const | | list_length ( cur_ec - > ec_members ) < = 1 )
continue ;
/*
* No point in searching if rel not mentioned in eclass ( but we can ' t
* tell that for a child rel ) .
*/
if ( ! is_child_rel & &
! bms_is_subset ( rel - > relids , cur_ec - > ec_relids ) )
continue ;
/*
* Scan members , looking for a match to the target column . Note that
* child EC members are considered , but only when they belong to the
@ -2366,11 +2491,25 @@ bool
have_relevant_eclass_joinclause ( PlannerInfo * root ,
RelOptInfo * rel1 , RelOptInfo * rel2 )
{
ListCell * lc1 ;
Bitmapset * matching_ecs ;
int i ;
foreach ( lc1 , root - > eq_classes )
/* Examine only eclasses mentioning both rel1 and rel2 */
matching_ecs = get_common_eclass_indexes ( root , rel1 - > relids ,
rel2 - > relids ) ;
i = - 1 ;
while ( ( i = bms_next_member ( matching_ecs , i ) ) > = 0 )
{
EquivalenceClass * ec = ( EquivalenceClass * ) lfirst ( lc1 ) ;
EquivalenceClass * ec = ( EquivalenceClass * ) list_nth ( root - > eq_classes ,
i ) ;
/*
* Sanity check that get_common_eclass_indexes gave only ECs
* containing both rels .
*/
Assert ( bms_overlap ( rel1 - > relids , ec - > ec_relids ) ) ;
Assert ( bms_overlap ( rel2 - > relids , ec - > ec_relids ) ) ;
/*
* Won ' t generate joinclauses if single - member ( this test covers the
@ -2382,12 +2521,12 @@ have_relevant_eclass_joinclause(PlannerInfo *root,
/*
* We do not need to examine the individual members of the EC , because
* all that we care about is whether each rel overlaps the relids of
* at least one member , and a test on ec_relids is sufficient to prov e
* that . ( As with have_relevant_joinclause ( ) , it is not necessary
* that the EC be able to form a joinclause relating exactly the two
* given rels , only that it be able to form a joinclause mentioning
* both , and this will surely be true if both of them overlap
* ec_relids . )
* at least one member , and get_common_eclass_indexes ( ) and the singl e
* member check above are sufficient to prove that . ( As with
* have_relevant_joinclause ( ) , it is not necessary that the EC be able
* to form a joinclause relating exactly the two given rels , only that
* it be able to form a joinclause mentioning both , and this will
* surely be true if both of them overlap ec_relids . )
*
* Note we don ' t test ec_broken ; if we did , we ' d need a separate code
* path to look through ec_sources . Checking the membership anyway is
@ -2399,9 +2538,8 @@ have_relevant_eclass_joinclause(PlannerInfo *root,
* since the join result is likely to be small even though it ' ll end
* up being an unqualified nestloop .
*/
if ( bms_overlap ( rel1 - > relids , ec - > ec_relids ) & &
bms_overlap ( rel2 - > relids , ec - > ec_relids ) )
return true ;
return true ;
}
return false ;
@ -2419,11 +2557,17 @@ have_relevant_eclass_joinclause(PlannerInfo *root,
bool
has_relevant_eclass_joinclause ( PlannerInfo * root , RelOptInfo * rel1 )
{
ListCell * lc1 ;
Bitmapset * matched_ecs ;
int i ;
foreach ( lc1 , root - > eq_classes )
/* Examine only eclasses mentioning rel1 */
matched_ecs = get_eclass_indexes_for_relids ( root , rel1 - > relids ) ;
i = - 1 ;
while ( ( i = bms_next_member ( matched_ecs , i ) ) > = 0 )
{
EquivalenceClass * ec = ( EquivalenceClass * ) lfirst ( lc1 ) ;
EquivalenceClass * ec = ( EquivalenceClass * ) list_nth ( root - > eq_classes ,
i ) ;
/*
* Won ' t generate joinclauses if single - member ( this test covers the
@ -2436,8 +2580,7 @@ has_relevant_eclass_joinclause(PlannerInfo *root, RelOptInfo *rel1)
* Per the comment in have_relevant_eclass_joinclause , it ' s sufficient
* to find an EC that mentions both this rel and some other rel .
*/
if ( bms_overlap ( rel1 - > relids , ec - > ec_relids ) & &
! bms_is_subset ( ec - > ec_relids , rel1 - > relids ) )
if ( ! bms_is_subset ( ec - > ec_relids , rel1 - > relids ) )
return true ;
}
@ -2570,3 +2713,54 @@ is_redundant_with_indexclauses(RestrictInfo *rinfo, List *indexclauses)
return false ;
}
/*
* get_eclass_indexes_for_relids
* Build and return a Bitmapset containing the indexes into root ' s
* eq_classes list for all eclasses that mention any of these relids
*/
static Bitmapset *
get_eclass_indexes_for_relids ( PlannerInfo * root , Relids relids )
{
Bitmapset * ec_indexes = NULL ;
int i = - 1 ;
/* Should be OK to rely on eclass_indexes */
Assert ( root - > ec_merging_done ) ;
while ( ( i = bms_next_member ( relids , i ) ) > 0 )
{
RelOptInfo * rel = root - > simple_rel_array [ i ] ;
ec_indexes = bms_add_members ( ec_indexes , rel - > eclass_indexes ) ;
}
return ec_indexes ;
}
/*
* get_common_eclass_indexes
* Build and return a Bitmapset containing the indexes into root ' s
* eq_classes list for all eclasses that mention rels in both
* relids1 and relids2 .
*/
static Bitmapset *
get_common_eclass_indexes ( PlannerInfo * root , Relids relids1 , Relids relids2 )
{
Bitmapset * rel1ecs ;
Bitmapset * rel2ecs ;
int relid ;
rel1ecs = get_eclass_indexes_for_relids ( root , relids1 ) ;
/*
* We can get away with just using the relation ' s eclass_indexes directly
* when relids2 is a singleton set .
*/
if ( bms_get_singleton_member ( relids2 , & relid ) )
rel2ecs = root - > simple_rel_array [ relid ] - > eclass_indexes ;
else
rel2ecs = get_eclass_indexes_for_relids ( root , relids2 ) ;
/* Calculate and return the common EC indexes, recycling the left input. */
return bms_int_members ( rel1ecs , rel2ecs ) ;
}