diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c index e34b9553bd..562177296c 100644 --- a/src/backend/optimizer/path/equivclass.c +++ b/src/backend/optimizer/path/equivclass.c @@ -1969,11 +1969,15 @@ mutate_eclass_expressions(PlannerInfo *root, * is no value in using more than one. (But it *is* worthwhile to create * a separate parameterized path for each one, since that leads to different * join orders.) + * + * The caller can pass a Relids set of rels we aren't interested in joining + * to, so as to save the work of creating useless clauses. */ List * generate_implied_equalities_for_indexcol(PlannerInfo *root, IndexOptInfo *index, - int indexcol) + int indexcol, + Relids prohibited_rels) { List *result = NIL; RelOptInfo *rel = index->rel; @@ -2050,6 +2054,10 @@ generate_implied_equalities_for_indexcol(PlannerInfo *root, bms_overlap(other_em->em_relids, rel->relids)) continue; + /* Forget it if caller doesn't want joins to this rel */ + if (bms_overlap(other_em->em_relids, prohibited_rels)) + continue; + /* * Also, if this is a child rel, avoid generating a useless join * to its parent rel. diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c index 69fcf90e36..6a32173910 100644 --- a/src/backend/optimizer/path/indxpath.c +++ b/src/backend/optimizer/path/indxpath.c @@ -121,10 +121,12 @@ static void match_restriction_clauses_to_index(RelOptInfo *rel, IndexClauseSet *clauseset); static void match_join_clauses_to_index(PlannerInfo *root, RelOptInfo *rel, IndexOptInfo *index, + Relids lateral_referencers, IndexClauseSet *clauseset, List **joinorclauses); static void match_eclass_clauses_to_index(PlannerInfo *root, IndexOptInfo *index, + Relids lateral_referencers, IndexClauseSet *clauseset); static void match_clauses_to_index(IndexOptInfo *index, List *clauses, @@ -211,22 +213,40 @@ create_index_paths(PlannerInfo *root, RelOptInfo *rel) List *bitindexpaths; List *bitjoinpaths; List *joinorclauses; + Relids lateral_referencers; IndexClauseSet rclauseset; IndexClauseSet jclauseset; IndexClauseSet eclauseset; - ListCell *ilist; + ListCell *lc; /* Skip the whole mess if no indexes */ if (rel->indexlist == NIL) return; + /* + * If there are any rels that have LATERAL references to this one, we + * cannot use join quals referencing them as index quals for this one, + * since such rels would have to be on the inside not the outside of a + * nestloop join relative to this one. Create a Relids set listing all + * such rels, for use in checks of potential join clauses. + */ + lateral_referencers = NULL; + foreach(lc, root->lateral_info_list) + { + LateralJoinInfo *ljinfo = (LateralJoinInfo *) lfirst(lc); + + if (bms_is_member(rel->relid, ljinfo->lateral_lhs)) + lateral_referencers = bms_add_member(lateral_referencers, + ljinfo->lateral_rhs); + } + /* Bitmap paths are collected and then dealt with at the end */ bitindexpaths = bitjoinpaths = joinorclauses = NIL; /* Examine each index in turn */ - foreach(ilist, rel->indexlist) + foreach(lc, rel->indexlist) { - IndexOptInfo *index = (IndexOptInfo *) lfirst(ilist); + IndexOptInfo *index = (IndexOptInfo *) lfirst(lc); /* Protect limited-size array in IndexClauseSets */ Assert(index->ncolumns <= INDEX_MAX_KEYS); @@ -260,7 +280,7 @@ create_index_paths(PlannerInfo *root, RelOptInfo *rel) * EquivalenceClasses. Also, collect join OR clauses for later. */ MemSet(&jclauseset, 0, sizeof(jclauseset)); - match_join_clauses_to_index(root, rel, index, + match_join_clauses_to_index(root, rel, index, lateral_referencers, &jclauseset, &joinorclauses); /* @@ -268,7 +288,8 @@ create_index_paths(PlannerInfo *root, RelOptInfo *rel) * the index. */ MemSet(&eclauseset, 0, sizeof(eclauseset)); - match_eclass_clauses_to_index(root, index, &eclauseset); + match_eclass_clauses_to_index(root, index, lateral_referencers, + &eclauseset); /* * If we found any plain or eclass join clauses, decide what to do @@ -1796,6 +1817,7 @@ match_restriction_clauses_to_index(RelOptInfo *rel, IndexOptInfo *index, static void match_join_clauses_to_index(PlannerInfo *root, RelOptInfo *rel, IndexOptInfo *index, + Relids lateral_referencers, IndexClauseSet *clauseset, List **joinorclauses) { @@ -1810,6 +1832,10 @@ match_join_clauses_to_index(PlannerInfo *root, if (!join_clause_is_movable_to(rinfo, rel->relid)) continue; + /* Not useful if it conflicts with any LATERAL references */ + if (bms_overlap(rinfo->clause_relids, lateral_referencers)) + continue; + /* Potentially usable, so see if it matches the index or is an OR */ if (restriction_is_or_clause(rinfo)) *joinorclauses = lappend(*joinorclauses, rinfo); @@ -1825,6 +1851,7 @@ match_join_clauses_to_index(PlannerInfo *root, */ static void match_eclass_clauses_to_index(PlannerInfo *root, IndexOptInfo *index, + Relids lateral_referencers, IndexClauseSet *clauseset) { int indexcol; @@ -1837,9 +1864,11 @@ match_eclass_clauses_to_index(PlannerInfo *root, IndexOptInfo *index, { List *clauses; + /* Generate clauses, skipping any that join to lateral_referencers */ clauses = generate_implied_equalities_for_indexcol(root, index, - indexcol); + indexcol, + lateral_referencers); /* * We have to check whether the results actually do match the index, diff --git a/src/include/optimizer/paths.h b/src/include/optimizer/paths.h index b6fb8ee5ce..165856de0b 100644 --- a/src/include/optimizer/paths.h +++ b/src/include/optimizer/paths.h @@ -127,7 +127,8 @@ extern void mutate_eclass_expressions(PlannerInfo *root, void *context); extern List *generate_implied_equalities_for_indexcol(PlannerInfo *root, IndexOptInfo *index, - int indexcol); + int indexcol, + Relids prohibited_rels); extern bool have_relevant_eclass_joinclause(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2); extern bool has_relevant_eclass_joinclause(PlannerInfo *root,