diff options
Diffstat (limited to 'src/backend/optimizer/path/indxpath.c')
-rw-r--r-- | src/backend/optimizer/path/indxpath.c | 114 |
1 files changed, 102 insertions, 12 deletions
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c index 77df5a24ea2..74bc7ac7c63 100644 --- a/src/backend/optimizer/path/indxpath.c +++ b/src/backend/optimizer/path/indxpath.c @@ -2253,21 +2253,74 @@ find_clauses_for_join(PlannerInfo *root, RelOptInfo *rel, * a set of equality conditions, because the conditions constrain all * columns of some unique index. * - * The conditions are provided as a list of RestrictInfo nodes, where the - * caller has already determined that each condition is a mergejoinable - * equality with an expression in this relation on one side, and an - * expression not involving this relation on the other. The transient - * outer_is_left flag is used to identify which side we should look at: - * left side if outer_is_left is false, right side if it is true. + * The conditions can be represented in either or both of two ways: + * 1. A list of RestrictInfo nodes, where the caller has already determined + * that each condition is a mergejoinable equality with an expression in + * this relation on one side, and an expression not involving this relation + * on the other. The transient outer_is_left flag is used to identify which + * side we should look at: left side if outer_is_left is false, right side + * if it is true. + * 2. A list of expressions in this relation, and a corresponding list of + * equality operators. The caller must have already checked that the operators + * represent equality. (Note: the operators could be cross-type; the + * expressions should correspond to their RHS inputs.) + * + * The caller need only supply equality conditions arising from joins; + * this routine automatically adds in any usable baserestrictinfo clauses. + * (Note that the passed-in restrictlist will be destructively modified!) */ bool relation_has_unique_index_for(PlannerInfo *root, RelOptInfo *rel, - List *restrictlist) + List *restrictlist, + List *exprlist, List *oprlist) { ListCell *ic; + Assert(list_length(exprlist) == list_length(oprlist)); + + /* Short-circuit if no indexes... */ + if (rel->indexlist == NIL) + return false; + + /* + * Examine the rel's restriction clauses for usable var = const clauses + * that we can add to the restrictlist. + */ + foreach(ic, rel->baserestrictinfo) + { + RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(ic); + + /* + * Note: can_join won't be set for a restriction clause, but + * mergeopfamilies will be if it has a mergejoinable operator and + * doesn't contain volatile functions. + */ + if (restrictinfo->mergeopfamilies == NIL) + continue; /* not mergejoinable */ + + /* + * The clause certainly doesn't refer to anything but the given rel. + * If either side is pseudoconstant then we can use it. + */ + if (bms_is_empty(restrictinfo->left_relids)) + { + /* righthand side is inner */ + restrictinfo->outer_is_left = true; + } + else if (bms_is_empty(restrictinfo->right_relids)) + { + /* lefthand side is inner */ + restrictinfo->outer_is_left = false; + } + else + continue; + + /* OK, add to list */ + restrictlist = lappend(restrictlist, restrictinfo); + } + /* Short-circuit the easy case */ - if (restrictlist == NIL) + if (restrictlist == NIL && exprlist == NIL) return false; /* Examine each index of the relation ... */ @@ -2285,12 +2338,14 @@ relation_has_unique_index_for(PlannerInfo *root, RelOptInfo *rel, continue; /* - * Try to find each index column in the list of conditions. This is - * O(n^2) or worse, but we expect all the lists to be short. + * Try to find each index column in the lists of conditions. This is + * O(N^2) or worse, but we expect all the lists to be short. */ for (c = 0; c < ind->ncolumns; c++) { + bool matched = false; ListCell *lc; + ListCell *lc2; foreach(lc, restrictlist) { @@ -2319,10 +2374,45 @@ relation_has_unique_index_for(PlannerInfo *root, RelOptInfo *rel, rexpr = get_leftop(rinfo->clause); if (match_index_to_operand(rexpr, c, ind)) - break; /* found a match; column is unique */ + { + matched = true; /* column is unique */ + break; + } + } + + if (matched) + continue; + + forboth(lc, exprlist, lc2, oprlist) + { + Node *expr = (Node *) lfirst(lc); + Oid opr = lfirst_oid(lc2); + + /* See if the expression matches the index key */ + if (!match_index_to_operand(expr, c, ind)) + continue; + + /* + * The equality operator must be a member of the index + * opfamily, else it is not asserting the right kind of + * equality behavior for this index. We assume the caller + * determined it is an equality operator, so we don't need to + * check any more tightly than this. + */ + if (!op_in_opfamily(opr, ind->opfamily[c])) + continue; + + /* + * XXX at some point we may need to check collations here too. + * For the moment we assume all collations reduce to the same + * notion of equality. + */ + + matched = true; /* column is unique */ + break; } - if (lc == NULL) + if (!matched) break; /* no match; this index doesn't help us */ } |