@ -34,11 +34,23 @@
# include "utils/lsyscache.h"
# include "utils/lsyscache.h"
static EquivalenceMember * make_eq_member ( EquivalenceClass * ec ,
Expr * expr , Relids relids ,
JoinDomain * jdomain ,
EquivalenceMember * parent ,
Oid datatype ) ;
static EquivalenceMember * add_eq_member ( EquivalenceClass * ec ,
static EquivalenceMember * add_eq_member ( EquivalenceClass * ec ,
Expr * expr , Relids relids ,
Expr * expr , Relids relids ,
JoinDomain * jdomain ,
JoinDomain * jdomain ,
EquivalenceMember * parent ,
Oid datatype ) ;
Oid datatype ) ;
static EquivalenceMember * add_child_eq_member ( PlannerInfo * root ,
EquivalenceClass * ec ,
int ec_index , Expr * expr ,
Relids relids ,
JoinDomain * jdomain ,
EquivalenceMember * parent_em ,
Oid datatype ,
Index child_relid ) ;
static void generate_base_implied_equalities_const ( PlannerInfo * root ,
static void generate_base_implied_equalities_const ( PlannerInfo * root ,
EquivalenceClass * ec ) ;
EquivalenceClass * ec ) ;
static void generate_base_implied_equalities_no_const ( PlannerInfo * root ,
static void generate_base_implied_equalities_no_const ( PlannerInfo * root ,
@ -314,11 +326,15 @@ process_equivalence(PlannerInfo *root,
if ( ! equal ( opfamilies , cur_ec - > ec_opfamilies ) )
if ( ! equal ( opfamilies , cur_ec - > ec_opfamilies ) )
continue ;
continue ;
/* We don't expect any children yet */
Assert ( cur_ec - > ec_childmembers = = NULL ) ;
foreach ( lc2 , cur_ec - > ec_members )
foreach ( lc2 , cur_ec - > ec_members )
{
{
EquivalenceMember * cur_em = ( EquivalenceMember * ) lfirst ( lc2 ) ;
EquivalenceMember * cur_em = ( EquivalenceMember * ) lfirst ( lc2 ) ;
Assert ( ! cur_em - > em_is_child ) ; /* no children yet */
/* Child members should not exist in ec_members */
Assert ( ! cur_em - > em_is_child ) ;
/*
/*
* Match constants only within the same JoinDomain ( see
* Match constants only within the same JoinDomain ( see
@ -428,7 +444,7 @@ process_equivalence(PlannerInfo *root,
{
{
/* Case 3: add item2 to ec1 */
/* Case 3: add item2 to ec1 */
em2 = add_eq_member ( ec1 , item2 , item2_relids ,
em2 = add_eq_member ( ec1 , item2 , item2_relids ,
jdomain , NULL , item2_type ) ;
jdomain , item2_type ) ;
ec1 - > ec_sources = lappend ( ec1 - > ec_sources , restrictinfo ) ;
ec1 - > ec_sources = lappend ( ec1 - > ec_sources , restrictinfo ) ;
ec1 - > ec_min_security = Min ( ec1 - > ec_min_security ,
ec1 - > ec_min_security = Min ( ec1 - > ec_min_security ,
restrictinfo - > security_level ) ;
restrictinfo - > security_level ) ;
@ -445,7 +461,7 @@ process_equivalence(PlannerInfo *root,
{
{
/* Case 3: add item1 to ec2 */
/* Case 3: add item1 to ec2 */
em1 = add_eq_member ( ec2 , item1 , item1_relids ,
em1 = add_eq_member ( ec2 , item1 , item1_relids ,
jdomain , NULL , item1_type ) ;
jdomain , item1_type ) ;
ec2 - > ec_sources = lappend ( ec2 - > ec_sources , restrictinfo ) ;
ec2 - > ec_sources = lappend ( ec2 - > ec_sources , restrictinfo ) ;
ec2 - > ec_min_security = Min ( ec2 - > ec_min_security ,
ec2 - > ec_min_security = Min ( ec2 - > ec_min_security ,
restrictinfo - > security_level ) ;
restrictinfo - > security_level ) ;
@ -465,7 +481,9 @@ process_equivalence(PlannerInfo *root,
ec - > ec_opfamilies = opfamilies ;
ec - > ec_opfamilies = opfamilies ;
ec - > ec_collation = collation ;
ec - > ec_collation = collation ;
ec - > ec_childmembers_size = 0 ;
ec - > ec_members = NIL ;
ec - > ec_members = NIL ;
ec - > ec_childmembers = NULL ;
ec - > ec_sources = list_make1 ( restrictinfo ) ;
ec - > ec_sources = list_make1 ( restrictinfo ) ;
ec - > ec_derives_list = NIL ;
ec - > ec_derives_list = NIL ;
ec - > ec_derives_hash = NULL ;
ec - > ec_derives_hash = NULL ;
@ -478,9 +496,9 @@ process_equivalence(PlannerInfo *root,
ec - > ec_max_security = restrictinfo - > security_level ;
ec - > ec_max_security = restrictinfo - > security_level ;
ec - > ec_merged = NULL ;
ec - > ec_merged = NULL ;
em1 = add_eq_member ( ec , item1 , item1_relids ,
em1 = add_eq_member ( ec , item1 , item1_relids ,
jdomain , NULL , item1_type ) ;
jdomain , item1_type ) ;
em2 = add_eq_member ( ec , item2 , item2_relids ,
em2 = add_eq_member ( ec , item2 , item2_relids ,
jdomain , NULL , item2_type ) ;
jdomain , item2_type ) ;
root - > eq_classes = lappend ( root - > eq_classes , ec ) ;
root - > eq_classes = lappend ( root - > eq_classes , ec ) ;
@ -566,11 +584,13 @@ canonicalize_ec_expression(Expr *expr, Oid req_type, Oid req_collation)
}
}
/*
/*
* add_eq_member - build a new EquivalenceMember and add it to an EC
* make_eq_member
* Build a new EquivalenceMember without adding it to an EC . If ' parent '
* is NULL , the result will be a parent member , otherwise a child member .
*/
*/
static EquivalenceMember *
static EquivalenceMember *
add _eq_member( EquivalenceClass * ec , Expr * expr , Relids relids ,
make _eq_member( EquivalenceClass * ec , Expr * expr , Relids relids ,
JoinDomain * jdomain , EquivalenceMember * parent , Oid datatype )
JoinDomain * jdomain , EquivalenceMember * parent , Oid datatype )
{
{
EquivalenceMember * em = makeNode ( EquivalenceMember ) ;
EquivalenceMember * em = makeNode ( EquivalenceMember ) ;
@ -597,11 +617,85 @@ add_eq_member(EquivalenceClass *ec, Expr *expr, Relids relids,
ec - > ec_has_const = true ;
ec - > ec_has_const = true ;
/* it can't affect ec_relids */
/* it can't affect ec_relids */
}
}
else if ( ! parent ) /* child members don't add to ec_relids */
return em ;
}
/*
* add_eq_member - build a new non - child EquivalenceMember and add it to ' ec ' .
*/
static EquivalenceMember *
add_eq_member ( EquivalenceClass * ec , Expr * expr , Relids relids ,
JoinDomain * jdomain , Oid datatype )
{
EquivalenceMember * em = make_eq_member ( ec , expr , relids , jdomain ,
NULL , datatype ) ;
/* add to the members list */
ec - > ec_members = lappend ( ec - > ec_members , em ) ;
/* record the relids for parent members */
ec - > ec_relids = bms_add_members ( ec - > ec_relids , relids ) ;
return em ;
}
/*
* add_child_eq_member
* Create an em_is_child = true EquivalenceMember and add it to ' ec ' .
*
* ' root ' is the PlannerInfo that ' ec ' belongs to .
* ' ec ' is the EquivalenceClass to add the child member to .
* ' ec_index ' the index of ' ec ' within root - > eq_classes , or - 1 if maintaining
* the RelOptInfo . eclass_indexes isn ' t needed .
* ' expr ' is the em_expr for the new member .
* ' relids ' is the ' em_relids ' for the new member .
* ' jdomain ' is the ' em_jdomain ' for the new member .
* ' parent_em ' is the parent member of the child to create .
* ' datatype ' is the em_datatype of the new member .
* ' child_relid ' defines which element of ec_childmembers to add this member
* to . This is generally a RELOPT_OTHER_MEMBER_REL , but for set operations
* can be a RELOPT_BASEREL representing the set - op children .
*/
static EquivalenceMember *
add_child_eq_member ( PlannerInfo * root , EquivalenceClass * ec , int ec_index ,
Expr * expr , Relids relids , JoinDomain * jdomain ,
EquivalenceMember * parent_em , Oid datatype ,
Index child_relid )
{
EquivalenceMember * em ;
Assert ( parent_em ! = NULL ) ;
/*
* Allocate the array to store child members ; an array of Lists indexed by
* relid , or expand the existing one , if necessary .
*/
if ( unlikely ( ec - > ec_childmembers_size < root - > simple_rel_array_size ) )
{
{
ec - > ec_relids = bms_add_members ( ec - > ec_relids , relids ) ;
if ( ec - > ec_childmembers = = NULL )
ec - > ec_childmembers = palloc0_array ( List * , root - > simple_rel_array_size ) ;
else
ec - > ec_childmembers = repalloc0_array ( ec - > ec_childmembers , List * ,
ec - > ec_childmembers_size ,
root - > simple_rel_array_size ) ;
ec - > ec_childmembers_size = root - > simple_rel_array_size ;
}
em = make_eq_member ( ec , expr , relids , jdomain , parent_em , datatype ) ;
/* add member to the ec_childmembers List for the given child_relid */
ec - > ec_childmembers [ child_relid ] = lappend ( ec - > ec_childmembers [ child_relid ] , em ) ;
/* Record this EC index for the child rel */
if ( ec_index > = 0 )
{
RelOptInfo * child_rel = root - > simple_rel_array [ child_relid ] ;
child_rel - > eclass_indexes =
bms_add_member ( child_rel - > eclass_indexes , ec_index ) ;
}
}
ec - > ec_members = lappend ( ec - > ec_members , em ) ;
return em ;
return em ;
}
}
@ -672,7 +766,8 @@ get_eclass_for_sort_expr(PlannerInfo *root,
foreach ( lc1 , root - > eq_classes )
foreach ( lc1 , root - > eq_classes )
{
{
EquivalenceClass * cur_ec = ( EquivalenceClass * ) lfirst ( lc1 ) ;
EquivalenceClass * cur_ec = ( EquivalenceClass * ) lfirst ( lc1 ) ;
ListCell * lc2 ;
EquivalenceMemberIterator it ;
EquivalenceMember * cur_em ;
/*
/*
* Never match to a volatile EC , except when we are looking at another
* Never match to a volatile EC , except when we are looking at another
@ -687,10 +782,9 @@ get_eclass_for_sort_expr(PlannerInfo *root,
if ( ! equal ( opfamilies , cur_ec - > ec_opfamilies ) )
if ( ! equal ( opfamilies , cur_ec - > ec_opfamilies ) )
continue ;
continue ;
foreach ( lc2 , cur_ec - > ec_members )
setup_eclass_member_iterator ( & it , cur_ec , rel ) ;
while ( ( cur_em = eclass_member_iterator_next ( & it ) ) ! = NULL )
{
{
EquivalenceMember * cur_em = ( EquivalenceMember * ) lfirst ( lc2 ) ;
/*
/*
* Ignore child members unless they match the request .
* Ignore child members unless they match the request .
*/
*/
@ -725,7 +819,9 @@ get_eclass_for_sort_expr(PlannerInfo *root,
newec = makeNode ( EquivalenceClass ) ;
newec = makeNode ( EquivalenceClass ) ;
newec - > ec_opfamilies = list_copy ( opfamilies ) ;
newec - > ec_opfamilies = list_copy ( opfamilies ) ;
newec - > ec_collation = collation ;
newec - > ec_collation = collation ;
newec - > ec_childmembers_size = 0 ;
newec - > ec_members = NIL ;
newec - > ec_members = NIL ;
newec - > ec_childmembers = NULL ;
newec - > ec_sources = NIL ;
newec - > ec_sources = NIL ;
newec - > ec_derives_list = NIL ;
newec - > ec_derives_list = NIL ;
newec - > ec_derives_hash = NULL ;
newec - > ec_derives_hash = NULL ;
@ -747,7 +843,7 @@ get_eclass_for_sort_expr(PlannerInfo *root,
expr_relids = pull_varnos ( root , ( Node * ) expr ) ;
expr_relids = pull_varnos ( root , ( Node * ) expr ) ;
newem = add_eq_member ( newec , copyObject ( expr ) , expr_relids ,
newem = add_eq_member ( newec , copyObject ( expr ) , expr_relids ,
jdomain , NULL , opcintype ) ;
jdomain , opcintype ) ;
/*
/*
* add_eq_member doesn ' t check for volatile functions , set - returning
* add_eq_member doesn ' t check for volatile functions , set - returning
@ -821,15 +917,16 @@ find_ec_member_matching_expr(EquivalenceClass *ec,
Expr * expr ,
Expr * expr ,
Relids relids )
Relids relids )
{
{
ListCell * lc ;
EquivalenceMemberIterator it ;
EquivalenceMember * em ;
/* We ignore binary-compatible relabeling on both ends */
/* We ignore binary-compatible relabeling on both ends */
while ( expr & & IsA ( expr , RelabelType ) )
while ( expr & & IsA ( expr , RelabelType ) )
expr = ( ( RelabelType * ) expr ) - > arg ;
expr = ( ( RelabelType * ) expr ) - > arg ;
foreach ( lc , ec - > ec_members )
setup_eclass_member_iterator ( & it , ec , relids ) ;
while ( ( em = eclass_member_iterator_next ( & it ) ) ! = NULL )
{
{
EquivalenceMember * em = ( EquivalenceMember * ) lfirst ( lc ) ;
Expr * emexpr ;
Expr * emexpr ;
/*
/*
@ -898,7 +995,8 @@ find_computable_ec_member(PlannerInfo *root,
bool require_parallel_safe )
bool require_parallel_safe )
{
{
List * exprvars ;
List * exprvars ;
ListCell * lc ;
EquivalenceMemberIterator it ;
EquivalenceMember * em ;
/*
/*
* Pull out the Vars and quasi - Vars present in " exprs " . In the typical
* Pull out the Vars and quasi - Vars present in " exprs " . In the typical
@ -912,9 +1010,9 @@ find_computable_ec_member(PlannerInfo *root,
PVC_INCLUDE_PLACEHOLDERS |
PVC_INCLUDE_PLACEHOLDERS |
PVC_INCLUDE_CONVERTROWTYPES ) ;
PVC_INCLUDE_CONVERTROWTYPES ) ;
foreach ( lc , ec - > ec_members )
setup_eclass_member_iterator ( & it , ec , relids ) ;
while ( ( em = eclass_member_iterator_next ( & it ) ) ! = NULL )
{
{
EquivalenceMember * em = ( EquivalenceMember * ) lfirst ( lc ) ;
List * emvars ;
List * emvars ;
ListCell * lc2 ;
ListCell * lc2 ;
@ -1193,6 +1291,9 @@ generate_base_implied_equalities_const(PlannerInfo *root,
return ;
return ;
}
}
/* We don't expect any children yet */
Assert ( ec - > ec_childmembers = = NULL ) ;
/*
/*
* Find the constant member to use . We prefer an actual constant to
* Find the constant member to use . We prefer an actual constant to
* pseudo - constants ( such as Params ) , because the constraint exclusion
* pseudo - constants ( such as Params ) , because the constraint exclusion
@ -1219,7 +1320,8 @@ generate_base_implied_equalities_const(PlannerInfo *root,
Oid eq_op ;
Oid eq_op ;
RestrictInfo * rinfo ;
RestrictInfo * rinfo ;
Assert ( ! cur_em - > em_is_child ) ; /* no children yet */
/* Child members should not exist in ec_members */
Assert ( ! cur_em - > em_is_child ) ;
if ( cur_em = = const_em )
if ( cur_em = = const_em )
continue ;
continue ;
eq_op = select_equality_operator ( ec ,
eq_op = select_equality_operator ( ec ,
@ -1283,12 +1385,17 @@ generate_base_implied_equalities_no_const(PlannerInfo *root,
prev_ems = ( EquivalenceMember * * )
prev_ems = ( EquivalenceMember * * )
palloc0 ( root - > simple_rel_array_size * sizeof ( EquivalenceMember * ) ) ;
palloc0 ( root - > simple_rel_array_size * sizeof ( EquivalenceMember * ) ) ;
/* We don't expect any children yet */
Assert ( ec - > ec_childmembers = = NULL ) ;
foreach ( lc , ec - > ec_members )
foreach ( lc , ec - > ec_members )
{
{
EquivalenceMember * cur_em = ( EquivalenceMember * ) lfirst ( lc ) ;
EquivalenceMember * cur_em = ( EquivalenceMember * ) lfirst ( lc ) ;
int relid ;
int relid ;
Assert ( ! cur_em - > em_is_child ) ; /* no children yet */
/* Child members should not exist in ec_members */
Assert ( ! cur_em - > em_is_child ) ;
if ( ! bms_get_singleton_member ( cur_em - > em_relids , & relid ) )
if ( ! bms_get_singleton_member ( cur_em - > em_relids , & relid ) )
continue ;
continue ;
Assert ( relid < root - > simple_rel_array_size ) ;
Assert ( relid < root - > simple_rel_array_size ) ;
@ -1621,7 +1728,8 @@ generate_join_implied_equalities_normal(PlannerInfo *root,
List * new_members = NIL ;
List * new_members = NIL ;
List * outer_members = NIL ;
List * outer_members = NIL ;
List * inner_members = NIL ;
List * inner_members = NIL ;
ListCell * lc1 ;
EquivalenceMemberIterator it ;
EquivalenceMember * cur_em ;
/*
/*
* First , scan the EC to identify member values that are computable at the
* First , scan the EC to identify member values that are computable at the
@ -1632,10 +1740,9 @@ generate_join_implied_equalities_normal(PlannerInfo *root,
* as well as to at least one input member , plus enforce at least one
* as well as to at least one input member , plus enforce at least one
* outer - rel member equal to at least one inner - rel member .
* outer - rel member equal to at least one inner - rel member .
*/
*/
foreach ( lc1 , ec - > ec_members )
setup_eclass_member_iterator ( & it , ec , join_relids ) ;
while ( ( cur_em = eclass_member_iterator_next ( & it ) ) ! = NULL )
{
{
EquivalenceMember * cur_em = ( EquivalenceMember * ) lfirst ( lc1 ) ;
/*
/*
* We don ' t need to check explicitly for child EC members . This test
* We don ' t need to check explicitly for child EC members . This test
* against join_relids will cause them to be ignored except when
* against join_relids will cause them to be ignored except when
@ -1668,6 +1775,7 @@ generate_join_implied_equalities_normal(PlannerInfo *root,
Oid best_eq_op = InvalidOid ;
Oid best_eq_op = InvalidOid ;
int best_score = - 1 ;
int best_score = - 1 ;
RestrictInfo * rinfo ;
RestrictInfo * rinfo ;
ListCell * lc1 ;
foreach ( lc1 , outer_members )
foreach ( lc1 , outer_members )
{
{
@ -1742,6 +1850,7 @@ generate_join_implied_equalities_normal(PlannerInfo *root,
List * old_members = list_concat ( outer_members , inner_members ) ;
List * old_members = list_concat ( outer_members , inner_members ) ;
EquivalenceMember * prev_em = NULL ;
EquivalenceMember * prev_em = NULL ;
RestrictInfo * rinfo ;
RestrictInfo * rinfo ;
ListCell * lc1 ;
/* For now, arbitrarily take the first old_member as the one to use */
/* For now, arbitrarily take the first old_member as the one to use */
if ( old_members )
if ( old_members )
@ -1749,7 +1858,7 @@ generate_join_implied_equalities_normal(PlannerInfo *root,
foreach ( lc1 , new_members )
foreach ( lc1 , new_members )
{
{
EquivalenceMember * cur_em = ( EquivalenceMember * ) lfirst ( lc1 ) ;
cur_em = ( EquivalenceMember * ) lfirst ( lc1 ) ;
if ( prev_em ! = NULL )
if ( prev_em ! = NULL )
{
{
@ -2188,6 +2297,9 @@ reconsider_outer_join_clause(PlannerInfo *root, OuterJoinClauseInfo *ojcinfo,
bool match ;
bool match ;
ListCell * lc2 ;
ListCell * lc2 ;
/* We don't expect any children yet */
Assert ( cur_ec - > ec_childmembers = = NULL ) ;
/* Ignore EC unless it contains pseudoconstants */
/* Ignore EC unless it contains pseudoconstants */
if ( ! cur_ec - > ec_has_const )
if ( ! cur_ec - > ec_has_const )
continue ;
continue ;
@ -2205,7 +2317,8 @@ reconsider_outer_join_clause(PlannerInfo *root, OuterJoinClauseInfo *ojcinfo,
{
{
EquivalenceMember * cur_em = ( EquivalenceMember * ) lfirst ( lc2 ) ;
EquivalenceMember * cur_em = ( EquivalenceMember * ) lfirst ( lc2 ) ;
Assert ( ! cur_em - > em_is_child ) ; /* no children yet */
/* Child members should not exist in ec_members */
Assert ( ! cur_em - > em_is_child ) ;
if ( equal ( outervar , cur_em - > em_expr ) )
if ( equal ( outervar , cur_em - > em_expr ) )
{
{
match = true ;
match = true ;
@ -2303,6 +2416,9 @@ reconsider_full_join_clause(PlannerInfo *root, OuterJoinClauseInfo *ojcinfo)
ListCell * lc2 ;
ListCell * lc2 ;
int coal_idx = - 1 ;
int coal_idx = - 1 ;
/* We don't expect any children yet */
Assert ( cur_ec - > ec_childmembers = = NULL ) ;
/* Ignore EC unless it contains pseudoconstants */
/* Ignore EC unless it contains pseudoconstants */
if ( ! cur_ec - > ec_has_const )
if ( ! cur_ec - > ec_has_const )
continue ;
continue ;
@ -2332,7 +2448,9 @@ reconsider_full_join_clause(PlannerInfo *root, OuterJoinClauseInfo *ojcinfo)
foreach ( lc2 , cur_ec - > ec_members )
foreach ( lc2 , cur_ec - > ec_members )
{
{
coal_em = ( EquivalenceMember * ) lfirst ( lc2 ) ;
coal_em = ( EquivalenceMember * ) lfirst ( lc2 ) ;
Assert ( ! coal_em - > em_is_child ) ; /* no children yet */
/* Child members should not exist in ec_members */
Assert ( ! coal_em - > em_is_child ) ;
if ( IsA ( coal_em - > em_expr , CoalesceExpr ) )
if ( IsA ( coal_em - > em_expr , CoalesceExpr ) )
{
{
CoalesceExpr * cexpr = ( CoalesceExpr * ) coal_em - > em_expr ;
CoalesceExpr * cexpr = ( CoalesceExpr * ) coal_em - > em_expr ;
@ -2461,6 +2579,13 @@ rebuild_eclass_attr_needed(PlannerInfo *root)
{
{
EquivalenceClass * ec = ( EquivalenceClass * ) lfirst ( lc ) ;
EquivalenceClass * ec = ( EquivalenceClass * ) lfirst ( lc ) ;
/*
* We don ' t expect any EC child members to exist at this point . Ensure
* that ' s the case , otherwise , we might be getting asked to do
* something this function hasn ' t been coded for .
*/
Assert ( ec - > ec_childmembers = = NULL ) ;
/* Need do anything only for a multi-member, no-const EC. */
/* Need do anything only for a multi-member, no-const EC. */
if ( list_length ( ec - > ec_members ) > 1 & & ! ec - > ec_has_const )
if ( list_length ( ec - > ec_members ) > 1 & & ! ec - > ec_has_const )
{
{
@ -2546,12 +2671,13 @@ exprs_known_equal(PlannerInfo *root, Node *item1, Node *item2, Oid opfamily)
! list_member_oid ( ec - > ec_opfamilies , opfamily ) )
! list_member_oid ( ec - > ec_opfamilies , opfamily ) )
continue ;
continue ;
/* Ignore children here */
foreach ( lc2 , ec - > ec_members )
foreach ( lc2 , ec - > ec_members )
{
{
EquivalenceMember * em = ( EquivalenceMember * ) lfirst ( lc2 ) ;
EquivalenceMember * em = ( EquivalenceMember * ) lfirst ( lc2 ) ;
if ( em - > em_is_child )
/* Child members should not exist in ec_members */
continue ; /* ignore children here */
Assert ( ! em - > em_is_child ) ;
if ( equal ( item1 , em - > em_expr ) )
if ( equal ( item1 , em - > em_expr ) )
item1member = true ;
item1member = true ;
else if ( equal ( item2 , em - > em_expr ) )
else if ( equal ( item2 , em - > em_expr ) )
@ -2615,15 +2741,18 @@ match_eclasses_to_foreign_key_col(PlannerInfo *root,
/* Never match to a volatile EC */
/* Never match to a volatile EC */
if ( ec - > ec_has_volatile )
if ( ec - > ec_has_volatile )
continue ;
continue ;
/* It's okay to consider "broken" ECs here, see exprs_known_equal */
/*
* It ' s okay to consider " broken " ECs here , see exprs_known_equal .
* Ignore children here .
*/
foreach ( lc2 , ec - > ec_members )
foreach ( lc2 , ec - > ec_members )
{
{
EquivalenceMember * em = ( EquivalenceMember * ) lfirst ( lc2 ) ;
EquivalenceMember * em = ( EquivalenceMember * ) lfirst ( lc2 ) ;
Var * var ;
Var * var ;
if ( em - > em_is_child )
/* Child members should not exist in ec_members */
continue ; /* ignore children here */
Assert ( ! em - > em_is_child ) ;
/* EM must be a Var, possibly with RelabelType */
/* EM must be a Var, possibly with RelabelType */
var = ( Var * ) em - > em_expr ;
var = ( Var * ) em - > em_expr ;
@ -2721,7 +2850,6 @@ add_child_rel_equivalences(PlannerInfo *root,
while ( ( i = bms_next_member ( parent_rel - > eclass_indexes , i ) ) > = 0 )
while ( ( i = bms_next_member ( parent_rel - > eclass_indexes , i ) ) > = 0 )
{
{
EquivalenceClass * cur_ec = ( EquivalenceClass * ) list_nth ( root - > eq_classes , i ) ;
EquivalenceClass * cur_ec = ( EquivalenceClass * ) list_nth ( root - > eq_classes , i ) ;
int num_members ;
/*
/*
* If this EC contains a volatile expression , then generating child
* If this EC contains a volatile expression , then generating child
@ -2734,29 +2862,13 @@ add_child_rel_equivalences(PlannerInfo *root,
/* Sanity check eclass_indexes only contain ECs for parent_rel */
/* Sanity check eclass_indexes only contain ECs for parent_rel */
Assert ( bms_is_subset ( top_parent_relids , cur_ec - > ec_relids ) ) ;
Assert ( bms_is_subset ( top_parent_relids , cur_ec - > ec_relids ) ) ;
/*
foreach_node ( EquivalenceMember , cur_em , cur_ec - > ec_members )
* We don ' t use foreach ( ) here because there ' s no point in scanning
* newly - added child members , so we can stop after the last
* pre - existing EC member .
*/
num_members = list_length ( cur_ec - > ec_members ) ;
for ( int pos = 0 ; pos < num_members ; pos + + )
{
{
EquivalenceMember * cur_em = ( EquivalenceMember * ) list_nth ( cur_ec - > ec_members , pos ) ;
if ( cur_em - > em_is_const )
if ( cur_em - > em_is_const )
continue ; /* ignore consts here */
continue ; /* ignore consts here */
/*
/* Child members should not exist in ec_members */
* We consider only original EC members here , not
Assert ( ! cur_em - > em_is_child ) ;
* already - transformed child members . Otherwise , if some original
* member expression references more than one appendrel , we ' d get
* an O ( N ^ 2 ) explosion of useless derived expressions for
* combinations of children . ( But add_child_join_rel_equivalences
* may add targeted combinations for partitionwise - join purposes . )
*/
if ( cur_em - > em_is_child )
continue ; /* ignore children here */
/*
/*
* Consider only members that reference and can be computed at
* Consider only members that reference and can be computed at
@ -2801,12 +2913,15 @@ add_child_rel_equivalences(PlannerInfo *root,
top_parent_relids ) ;
top_parent_relids ) ;
new_relids = bms_add_members ( new_relids , child_relids ) ;
new_relids = bms_add_members ( new_relids , child_relids ) ;
( void ) add_eq_member ( cur_ec , child_expr , new_relids ,
add_child_eq_member ( root ,
cur_em - > em_jdomain ,
cur_ec ,
cur_em , cur_em - > em_datatype ) ;
i ,
child_expr ,
/* Record this EC index for the child rel */
new_relids ,
child_rel - > eclass_indexes = bms_add_member ( child_rel - > eclass_indexes , i ) ;
cur_em - > em_jdomain ,
cur_em ,
cur_em - > em_datatype ,
child_rel - > relid ) ;
}
}
}
}
}
}
@ -2853,7 +2968,6 @@ add_child_join_rel_equivalences(PlannerInfo *root,
while ( ( i = bms_next_member ( matching_ecs , i ) ) > = 0 )
while ( ( i = bms_next_member ( matching_ecs , i ) ) > = 0 )
{
{
EquivalenceClass * cur_ec = ( EquivalenceClass * ) list_nth ( root - > eq_classes , i ) ;
EquivalenceClass * cur_ec = ( EquivalenceClass * ) list_nth ( root - > eq_classes , i ) ;
int num_members ;
/*
/*
* If this EC contains a volatile expression , then generating child
* If this EC contains a volatile expression , then generating child
@ -2866,25 +2980,13 @@ add_child_join_rel_equivalences(PlannerInfo *root,
/* Sanity check on get_eclass_indexes_for_relids result */
/* Sanity check on get_eclass_indexes_for_relids result */
Assert ( bms_overlap ( top_parent_relids , cur_ec - > ec_relids ) ) ;
Assert ( bms_overlap ( top_parent_relids , cur_ec - > ec_relids ) ) ;
/*
foreach_node ( EquivalenceMember , cur_em , cur_ec - > ec_members )
* We don ' t use foreach ( ) here because there ' s no point in scanning
* newly - added child members , so we can stop after the last
* pre - existing EC member .
*/
num_members = list_length ( cur_ec - > ec_members ) ;
for ( int pos = 0 ; pos < num_members ; pos + + )
{
{
EquivalenceMember * cur_em = ( EquivalenceMember * ) list_nth ( cur_ec - > ec_members , pos ) ;
if ( cur_em - > em_is_const )
if ( cur_em - > em_is_const )
continue ; /* ignore consts here */
continue ; /* ignore consts here */
/*
/* Child members should not exist in ec_members */
* We consider only original EC members here , not
Assert ( ! cur_em - > em_is_child ) ;
* already - transformed child members .
*/
if ( cur_em - > em_is_child )
continue ; /* ignore children here */
/*
/*
* We may ignore expressions that reference a single baserel ,
* We may ignore expressions that reference a single baserel ,
@ -2929,9 +3031,35 @@ add_child_join_rel_equivalences(PlannerInfo *root,
top_parent_relids ) ;
top_parent_relids ) ;
new_relids = bms_add_members ( new_relids , child_relids ) ;
new_relids = bms_add_members ( new_relids , child_relids ) ;
( void ) add_eq_member ( cur_ec , child_expr , new_relids ,
/*
cur_em - > em_jdomain ,
* Add new child member to the EquivalenceClass . Because this
cur_em , cur_em - > em_datatype ) ;
* is a RELOPT_OTHER_JOINREL which has multiple component
* relids , there is no ideal place to store these members in
* the class . Ordinarily , child members are stored in the
* ec_childmembers [ ] array element corresponding to their
* relid , however , here we have multiple component relids , so
* there ' s no single ec_childmembers [ ] array element to store
* this member . So that we still correctly find this member
* in loops iterating over an EquivalenceMemberIterator , we
* opt to store the member in the ec_childmembers array in
* only the first component relid slot of the array . This
* allows the member to be found , providing callers of
* setup_eclass_member_iterator ( ) specify all the component
* relids for the RELOPT_OTHER_JOINREL , which they do . If we
* opted to store the member in each ec_childmembers [ ] element
* for all the component relids , then that would just result
* in eclass_member_iterator_next ( ) finding the member
* multiple times , which is a waste of effort .
*/
add_child_eq_member ( root ,
cur_ec ,
- 1 ,
child_expr ,
new_relids ,
cur_em - > em_jdomain ,
cur_em ,
cur_em - > em_datatype ,
bms_next_member ( child_joinrel - > relids , - 1 ) ) ;
}
}
}
}
}
}
@ -2978,14 +3106,18 @@ add_setop_child_rel_equivalences(PlannerInfo *root, RelOptInfo *child_rel,
* We can safely pass the parent member as the first member in the
* We can safely pass the parent member as the first member in the
* ec_members list as this is added first in generate_union_paths ,
* ec_members list as this is added first in generate_union_paths ,
* likewise , the JoinDomain can be that of the initial member of the
* likewise , the JoinDomain can be that of the initial member of the
* Pathkey ' s EquivalenceClass .
* Pathkey ' s EquivalenceClass . We pass - 1 for ec_index since we
* maintain the eclass_indexes for the child_rel after the loop .
*/
*/
add_eq_member ( pk - > pk_eclass ,
add_child_eq_member ( root ,
tle - > expr ,
pk - > pk_eclass ,
child_rel - > relids ,
- 1 ,
parent_em - > em_jdomain ,
tle - > expr ,
parent_em ,
child_rel - > relids ,
exprType ( ( Node * ) tle - > expr ) ) ;
parent_em - > em_jdomain ,
parent_em ,
exprType ( ( Node * ) tle - > expr ) ,
child_rel - > relid ) ;
lc2 = lnext ( setop_pathkeys , lc2 ) ;
lc2 = lnext ( setop_pathkeys , lc2 ) ;
}
}
@ -3000,6 +3132,85 @@ add_setop_child_rel_equivalences(PlannerInfo *root, RelOptInfo *child_rel,
list_length ( root - > eq_classes ) - 1 ) ;
list_length ( root - > eq_classes ) - 1 ) ;
}
}
/*
* setup_eclass_member_iterator
* Setup an EquivalenceMemberIterator ' it ' to iterate over all parent
* EquivalenceMembers and child members belonging to the given ' ec ' .
*
* This iterator returns :
* - All parent members stored directly in ec_members for ' ec ' , and ;
* - Any child member added to the given ec by add_child_eq_member ( ) where
* the child_relid specified in the add_child_eq_member ( ) call is a member
* of the ' child_relids ' parameter .
*
* Note :
* The given ' child_relids ' must remain allocated and not be changed for the
* lifetime of the iterator .
*
* Parameters :
* ' it ' is a pointer to the iterator to set up . Normally stack allocated .
* ' ec ' is the EquivalenceClass from which to iterate members for .
* ' child_relids ' is the relids to return child members for .
*/
void
setup_eclass_member_iterator ( EquivalenceMemberIterator * it ,
EquivalenceClass * ec , Relids child_relids )
{
it - > ec = ec ;
/* no need to set this if the class has no child members array set */
it - > child_relids = ec - > ec_childmembers ! = NULL ? child_relids : NULL ;
it - > current_relid = - 1 ;
it - > current_list = ec - > ec_members ;
it - > current_cell = list_head ( it - > current_list ) ;
}
/*
* eclass_member_iterator_next
* Get the next EquivalenceMember from the EquivalenceMemberIterator ' it ' ,
* as setup by setup_eclass_member_iterator ( ) . NULL is returned if there
* are no members left , after which callers must not call
* eclass_member_iterator_next ( ) again for the given iterator .
*/
EquivalenceMember *
eclass_member_iterator_next ( EquivalenceMemberIterator * it )
{
while ( it - > current_list ! = NULL )
{
while ( it - > current_cell ! = NULL )
{
EquivalenceMember * em ;
nextcell :
em = lfirst_node ( EquivalenceMember , it - > current_cell ) ;
it - > current_cell = lnext ( it - > current_list , it - > current_cell ) ;
return em ;
}
/* Search for the next list to return members from */
while ( ( it - > current_relid = bms_next_member ( it - > child_relids , it - > current_relid ) ) > 0 )
{
/*
* Be paranoid in case we ' re given relids above what we ' ve sized
* the ec_childmembers array to .
*/
if ( it - > current_relid > = it - > ec - > ec_childmembers_size )
return NULL ;
it - > current_list = it - > ec - > ec_childmembers [ it - > current_relid ] ;
/* If there are members in this list, use it. */
if ( it - > current_list ! = NIL )
{
/* point current_cell to the head of this list */
it - > current_cell = list_head ( it - > current_list ) ;
goto nextcell ;
}
}
return NULL ;
}
return NULL ;
}
/*
/*
* generate_implied_equalities_for_column
* generate_implied_equalities_for_column
@ -3052,6 +3263,7 @@ generate_implied_equalities_for_column(PlannerInfo *root,
while ( ( i = bms_next_member ( rel - > eclass_indexes , i ) ) > = 0 )
while ( ( i = bms_next_member ( rel - > eclass_indexes , i ) ) > = 0 )
{
{
EquivalenceClass * cur_ec = ( EquivalenceClass * ) list_nth ( root - > eq_classes , i ) ;
EquivalenceClass * cur_ec = ( EquivalenceClass * ) list_nth ( root - > eq_classes , i ) ;
EquivalenceMemberIterator it ;
EquivalenceMember * cur_em ;
EquivalenceMember * cur_em ;
ListCell * lc2 ;
ListCell * lc2 ;
@ -3075,14 +3287,12 @@ generate_implied_equalities_for_column(PlannerInfo *root,
* corner cases , so for now we live with just reporting the first
* corner cases , so for now we live with just reporting the first
* match . See also get_eclass_for_sort_expr . )
* match . See also get_eclass_for_sort_expr . )
*/
*/
cur_em = NULL ;
setup_eclass_member_iterator ( & it , cur_ec , rel - > relids ) ;
foreach ( lc2 , cur_ec - > ec_members )
while ( ( cur_em = eclass_member_iterator_next ( & it ) ) ! = NULL )
{
{
cur_em = ( EquivalenceMember * ) lfirst ( lc2 ) ;
if ( bms_equal ( cur_em - > em_relids , rel - > relids ) & &
if ( bms_equal ( cur_em - > em_relids , rel - > relids ) & &
callback ( root , rel , cur_ec , cur_em , callback_arg ) )
callback ( root , rel , cur_ec , cur_em , callback_arg ) )
break ;
break ;
cur_em = NULL ;
}
}
if ( ! cur_em )
if ( ! cur_em )
@ -3090,7 +3300,7 @@ generate_implied_equalities_for_column(PlannerInfo *root,
/*
/*
* Found our match . Scan the other EC members and attempt to generate
* Found our match . Scan the other EC members and attempt to generate
* joinclauses .
* joinclauses . Ignore children here .
*/
*/
foreach ( lc2 , cur_ec - > ec_members )
foreach ( lc2 , cur_ec - > ec_members )
{
{
@ -3098,8 +3308,8 @@ generate_implied_equalities_for_column(PlannerInfo *root,
Oid eq_op ;
Oid eq_op ;
RestrictInfo * rinfo ;
RestrictInfo * rinfo ;
if ( other_em - > em_is_child )
/* Child members should not exist in ec_members */
continue ; /* ignore children here */
Assert ( ! other_em - > em_is_child ) ;
/* Make sure it'll be a join to a different rel */
/* Make sure it'll be a join to a different rel */
if ( other_em = = cur_em | |
if ( other_em = = cur_em | |
@ -3312,13 +3522,15 @@ eclass_useful_for_merging(PlannerInfo *root,
if ( bms_is_subset ( eclass - > ec_relids , relids ) )
if ( bms_is_subset ( eclass - > ec_relids , relids ) )
return false ;
return false ;
/* To join, we need a member not in the given rel */
/*
* To join , we need a member not in the given rel . Ignore children here .
*/
foreach ( lc , eclass - > ec_members )
foreach ( lc , eclass - > ec_members )
{
{
EquivalenceMember * cur_em = ( EquivalenceMember * ) lfirst ( lc ) ;
EquivalenceMember * cur_em = ( EquivalenceMember * ) lfirst ( lc ) ;
if ( cur_em - > em_is_child )
/* Child members should not exist in ec_members */
continue ; /* ignore children here */
Assert ( ! cur_em - > em_is_child ) ;
if ( ! bms_overlap ( cur_em - > em_relids , relids ) )
if ( ! bms_overlap ( cur_em - > em_relids , relids ) )
return true ;
return true ;