summaryrefslogtreecommitdiff
path: root/src/backend/optimizer/path/indxpath.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/path/indxpath.c')
-rw-r--r--src/backend/optimizer/path/indxpath.c114
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 */
}