aboutsummaryrefslogtreecommitdiff
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.c404
1 files changed, 213 insertions, 191 deletions
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index 7e1a3908f12..51d2da56832 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -56,7 +56,7 @@ typedef enum
typedef struct
{
bool nonempty; /* True if lists are not all empty */
- /* Lists of RestrictInfos, one per index column */
+ /* Lists of IndexClause nodes, one list per index column */
List *indexclauses[INDEX_MAX_KEYS];
} IndexClauseSet;
@@ -175,13 +175,19 @@ static bool match_boolean_index_clause(Node *clause, int indexcol,
static bool match_special_index_operator(Expr *clause,
Oid opfamily, Oid idxcollation,
bool indexkey_on_left);
+static IndexClause *expand_indexqual_conditions(IndexOptInfo *index,
+ int indexcol,
+ RestrictInfo *rinfo);
static Expr *expand_boolean_index_clause(Node *clause, int indexcol,
IndexOptInfo *index);
static List *expand_indexqual_opclause(RestrictInfo *rinfo,
- Oid opfamily, Oid idxcollation);
+ Oid opfamily, Oid idxcollation,
+ bool *lossy);
static RestrictInfo *expand_indexqual_rowcompare(RestrictInfo *rinfo,
IndexOptInfo *index,
- int indexcol);
+ int indexcol,
+ List **indexcolnos,
+ bool *lossy);
static List *prefix_quals(Node *leftop, Oid opfamily, Oid collation,
Const *prefix, Pattern_Prefix_Status pstatus);
static List *network_prefix_quals(Node *leftop, Oid expr_op, Oid opfamily,
@@ -496,7 +502,7 @@ consider_index_join_clauses(PlannerInfo *root, RelOptInfo *rel,
*
* 'rel', 'index', 'rclauseset', 'jclauseset', 'eclauseset', and
* 'bitindexpaths' as above
- * 'indexjoinclauses' is a list of RestrictInfos for join clauses
+ * 'indexjoinclauses' is a list of IndexClauses for join clauses
* 'considered_clauses' is the total number of clauses considered (so far)
* '*considered_relids' is a list of all relids sets already considered
*/
@@ -516,8 +522,9 @@ consider_index_join_outer_rels(PlannerInfo *root, RelOptInfo *rel,
/* Examine relids of each joinclause in the given list */
foreach(lc, indexjoinclauses)
{
- RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
- Relids clause_relids = rinfo->clause_relids;
+ IndexClause *iclause = (IndexClause *) lfirst(lc);
+ Relids clause_relids = iclause->rinfo->clause_relids;
+ EquivalenceClass *parent_ec = iclause->rinfo->parent_ec;
ListCell *lc2;
/* If we already tried its relids set, no need to do so again */
@@ -558,8 +565,8 @@ consider_index_join_outer_rels(PlannerInfo *root, RelOptInfo *rel,
* parameterization; so skip if any clause derived from the same
* eclass would already have been included when using oldrelids.
*/
- if (rinfo->parent_ec &&
- eclass_already_used(rinfo->parent_ec, oldrelids,
+ if (parent_ec &&
+ eclass_already_used(parent_ec, oldrelids,
indexjoinclauses))
continue;
@@ -628,11 +635,11 @@ get_join_index_paths(PlannerInfo *root, RelOptInfo *rel,
/* First find applicable simple join clauses */
foreach(lc, jclauseset->indexclauses[indexcol])
{
- RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
+ IndexClause *iclause = (IndexClause *) lfirst(lc);
- if (bms_is_subset(rinfo->clause_relids, relids))
+ if (bms_is_subset(iclause->rinfo->clause_relids, relids))
clauseset.indexclauses[indexcol] =
- lappend(clauseset.indexclauses[indexcol], rinfo);
+ lappend(clauseset.indexclauses[indexcol], iclause);
}
/*
@@ -643,12 +650,12 @@ get_join_index_paths(PlannerInfo *root, RelOptInfo *rel,
*/
foreach(lc, eclauseset->indexclauses[indexcol])
{
- RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
+ IndexClause *iclause = (IndexClause *) lfirst(lc);
- if (bms_is_subset(rinfo->clause_relids, relids))
+ if (bms_is_subset(iclause->rinfo->clause_relids, relids))
{
clauseset.indexclauses[indexcol] =
- lappend(clauseset.indexclauses[indexcol], rinfo);
+ lappend(clauseset.indexclauses[indexcol], iclause);
break;
}
}
@@ -688,7 +695,8 @@ eclass_already_used(EquivalenceClass *parent_ec, Relids oldrelids,
foreach(lc, indexjoinclauses)
{
- RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
+ IndexClause *iclause = (IndexClause *) lfirst(lc);
+ RestrictInfo *rinfo = iclause->rinfo;
if (rinfo->parent_ec == parent_ec &&
bms_is_subset(rinfo->clause_relids, oldrelids))
@@ -848,7 +856,7 @@ get_index_paths(PlannerInfo *root, RelOptInfo *rel,
*
* 'rel' is the index's heap relation
* 'index' is the index for which we want to generate paths
- * 'clauses' is the collection of indexable clauses (RestrictInfo nodes)
+ * 'clauses' is the collection of indexable clauses (IndexClause nodes)
* 'useful_predicate' indicates whether the index has a useful predicate
* 'scantype' indicates whether we need plain or bitmap scan support
* 'skip_nonnative_saop' indicates whether to accept SAOP if index AM doesn't
@@ -865,7 +873,6 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
List *result = NIL;
IndexPath *ipath;
List *index_clauses;
- List *clause_columns;
Relids outer_relids;
double loop_count;
List *orderbyclauses;
@@ -897,14 +904,12 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
}
/*
- * 1. Collect the index clauses into a single list.
+ * 1. Combine the per-column IndexClause lists into an overall list.
*
- * We build a list of RestrictInfo nodes for clauses to be used with this
- * index, along with an integer list of the index column numbers (zero
- * based) that each clause should be used with. The clauses are ordered
- * by index key, so that the column numbers form a nondecreasing sequence.
- * (This order is depended on by btree and possibly other places.) The
- * lists can be empty, if the index AM allows that.
+ * In the resulting list, clauses are ordered by index key, so that the
+ * column numbers form a nondecreasing sequence. (This order is depended
+ * on by btree and possibly other places.) The list can be empty, if the
+ * index AM allows that.
*
* found_lower_saop_clause is set true if we accept a ScalarArrayOpExpr
* index clause for a non-first index column. This prevents us from
@@ -918,7 +923,6 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
* otherwise accounted for.
*/
index_clauses = NIL;
- clause_columns = NIL;
found_lower_saop_clause = false;
outer_relids = bms_copy(rel->lateral_relids);
for (indexcol = 0; indexcol < index->ncolumns; indexcol++)
@@ -927,8 +931,10 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
foreach(lc, clauses->indexclauses[indexcol])
{
- RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
+ IndexClause *iclause = (IndexClause *) lfirst(lc);
+ RestrictInfo *rinfo = iclause->rinfo;
+ /* We might need to omit ScalarArrayOpExpr clauses */
if (IsA(rinfo->clause, ScalarArrayOpExpr))
{
if (!index->amsearcharray)
@@ -953,8 +959,9 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
found_lower_saop_clause = true;
}
}
- index_clauses = lappend(index_clauses, rinfo);
- clause_columns = lappend_int(clause_columns, indexcol);
+
+ /* OK to include this clause */
+ index_clauses = lappend(index_clauses, iclause);
outer_relids = bms_add_members(outer_relids,
rinfo->clause_relids);
}
@@ -1036,7 +1043,6 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
{
ipath = create_index_path(root, index,
index_clauses,
- clause_columns,
orderbyclauses,
orderbyclausecols,
useful_pathkeys,
@@ -1059,7 +1065,6 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
{
ipath = create_index_path(root, index,
index_clauses,
- clause_columns,
orderbyclauses,
orderbyclausecols,
useful_pathkeys,
@@ -1095,7 +1100,6 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
{
ipath = create_index_path(root, index,
index_clauses,
- clause_columns,
NIL,
NIL,
useful_pathkeys,
@@ -1113,7 +1117,6 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
{
ipath = create_index_path(root, index,
index_clauses,
- clause_columns,
NIL,
NIL,
useful_pathkeys,
@@ -1810,7 +1813,7 @@ get_bitmap_tree_required_outer(Path *bitmapqual)
* find_indexpath_quals
*
* Given the Path structure for a plain or bitmap indexscan, extract lists
- * of all the indexquals and index predicate conditions used in the Path.
+ * of all the index clauses and index predicate conditions used in the Path.
* These are appended to the initial contents of *quals and *preds (hence
* caller should initialize those to NIL).
*
@@ -1847,8 +1850,14 @@ find_indexpath_quals(Path *bitmapqual, List **quals, List **preds)
else if (IsA(bitmapqual, IndexPath))
{
IndexPath *ipath = (IndexPath *) bitmapqual;
+ ListCell *l;
- *quals = list_concat(*quals, get_actual_clauses(ipath->indexclauses));
+ foreach(l, ipath->indexclauses)
+ {
+ IndexClause *iclause = (IndexClause *) lfirst(l);
+
+ *quals = lappend(*quals, iclause->rinfo->clause);
+ }
*preds = list_concat(*preds, list_copy(ipath->indexinfo->indpred));
}
else
@@ -2239,8 +2248,9 @@ match_clauses_to_index(IndexOptInfo *index,
* match_clause_to_index
* Test whether a qual clause can be used with an index.
*
- * If the clause is usable, add it to the appropriate list in *clauseset.
- * *clauseset must be initialized to zeroes before first call.
+ * If the clause is usable, add an IndexClause entry for it to the appropriate
+ * list in *clauseset. (*clauseset must be initialized to zeroes before first
+ * call.)
*
* Note: in some circumstances we may find the same RestrictInfos coming from
* multiple places. Defend against redundant outputs by refusing to add a
@@ -2277,13 +2287,30 @@ match_clause_to_index(IndexOptInfo *index,
/* OK, check each index key column for a match */
for (indexcol = 0; indexcol < index->nkeycolumns; indexcol++)
{
+ ListCell *lc;
+
+ /* Ignore duplicates */
+ foreach(lc, clauseset->indexclauses[indexcol])
+ {
+ IndexClause *iclause = (IndexClause *) lfirst(lc);
+
+ if (iclause->rinfo == rinfo)
+ return;
+ }
+
+ /*
+ * XXX this should be changed so that we generate an IndexClause
+ * immediately upon matching, to avoid repeated work. To-do soon.
+ */
if (match_clause_to_indexcol(index,
indexcol,
rinfo))
{
+ IndexClause *iclause;
+
+ iclause = expand_indexqual_conditions(index, indexcol, rinfo);
clauseset->indexclauses[indexcol] =
- list_append_unique_ptr(clauseset->indexclauses[indexcol],
- rinfo);
+ lappend(clauseset->indexclauses[indexcol], iclause);
clauseset->nonempty = true;
return;
}
@@ -2335,7 +2362,7 @@ match_clause_to_index(IndexOptInfo *index,
* target index column. This is sufficient to guarantee that some index
* condition can be constructed from the RowCompareExpr --- whether the
* remaining columns match the index too is considered in
- * adjust_rowcompare_for_index().
+ * expand_indexqual_rowcompare().
*
* It is also possible to match ScalarArrayOpExpr clauses to indexes, when
* the clause is of the form "indexkey op ANY (arrayconst)".
@@ -3342,8 +3369,8 @@ match_index_to_operand(Node *operand,
* match_boolean_index_clause() similarly detects clauses that can be
* converted into boolean equality operators.
*
- * expand_indexqual_conditions() converts a list of RestrictInfo nodes
- * (with implicit AND semantics across list elements) into a list of clauses
+ * expand_indexqual_conditions() converts a RestrictInfo node
+ * into an IndexClause, which contains clauses
* that the executor can actually handle. For operators that are members of
* the index's opfamily this transformation is a no-op, but clauses recognized
* by match_special_index_operator() or match_boolean_index_clause() must be
@@ -3556,38 +3583,28 @@ match_special_index_operator(Expr *clause, Oid opfamily, Oid idxcollation,
/*
* expand_indexqual_conditions
- * Given a list of RestrictInfo nodes, produce a list of directly usable
- * index qual clauses.
+ * Given a RestrictInfo node, create an IndexClause.
*
* Standard qual clauses (those in the index's opfamily) are passed through
* unchanged. Boolean clauses and "special" index operators are expanded
* into clauses that the indexscan machinery will know what to do with.
* RowCompare clauses are simplified if necessary to create a clause that is
* fully checkable by the index.
- *
- * In addition to the expressions themselves, there are auxiliary lists
- * of the index column numbers that the clauses are meant to be used with;
- * we generate an updated column number list for the result. (This is not
- * the identical list because one input clause sometimes produces more than
- * one output clause.)
- *
- * The input clauses are sorted by column number, and so the output is too.
- * (This is depended on in various places in both planner and executor.)
*/
-void
+static IndexClause *
expand_indexqual_conditions(IndexOptInfo *index,
- List *indexclauses, List *indexclausecols,
- List **indexquals_p, List **indexqualcols_p)
+ int indexcol,
+ RestrictInfo *rinfo)
{
+ IndexClause *iclause = makeNode(IndexClause);
List *indexquals = NIL;
- List *indexqualcols = NIL;
- ListCell *lcc,
- *lci;
- forboth(lcc, indexclauses, lci, indexclausecols)
+ iclause->rinfo = rinfo;
+ iclause->lossy = false; /* might get changed below */
+ iclause->indexcol = indexcol;
+ iclause->indexcols = NIL; /* might get changed below */
+
{
- RestrictInfo *rinfo = (RestrictInfo *) lfirst(lcc);
- int indexcol = lfirst_int(lci);
Expr *clause = rinfo->clause;
Oid curFamily;
Oid curCollation;
@@ -3607,10 +3624,9 @@ expand_indexqual_conditions(IndexOptInfo *index,
index);
if (boolqual)
{
- indexquals = lappend(indexquals,
- make_simple_restrictinfo(boolqual));
- indexqualcols = lappend_int(indexqualcols, indexcol);
- continue;
+ iclause->indexquals =
+ list_make1(make_simple_restrictinfo(boolqual));
+ return iclause;
}
}
@@ -3620,41 +3636,63 @@ expand_indexqual_conditions(IndexOptInfo *index,
*/
if (is_opclause(clause))
{
- indexquals = list_concat(indexquals,
- expand_indexqual_opclause(rinfo,
- curFamily,
- curCollation));
- /* expand_indexqual_opclause can produce multiple clauses */
- while (list_length(indexqualcols) < list_length(indexquals))
- indexqualcols = lappend_int(indexqualcols, indexcol);
+ /*
+ * Check to see if the indexkey is on the right; if so, commute
+ * the clause. The indexkey should be the side that refers to
+ * (only) the base relation.
+ */
+ if (!bms_equal(rinfo->left_relids, index->rel->relids))
+ {
+ Oid opno = ((OpExpr *) clause)->opno;
+ RestrictInfo *newrinfo;
+
+ newrinfo = commute_restrictinfo(rinfo,
+ get_commutator(opno));
+
+ /*
+ * For now, assume it couldn't be any case that requires
+ * expansion. (This is OK for the current capabilities of
+ * expand_indexqual_opclause, but we'll need to remove the
+ * restriction when we open this up for extensions.)
+ */
+ indexquals = list_make1(newrinfo);
+ }
+ else
+ indexquals = expand_indexqual_opclause(rinfo,
+ curFamily,
+ curCollation,
+ &iclause->lossy);
}
else if (IsA(clause, ScalarArrayOpExpr))
{
/* no extra work at this time */
- indexquals = lappend(indexquals, rinfo);
- indexqualcols = lappend_int(indexqualcols, indexcol);
}
else if (IsA(clause, RowCompareExpr))
{
- indexquals = lappend(indexquals,
- expand_indexqual_rowcompare(rinfo,
- index,
- indexcol));
- indexqualcols = lappend_int(indexqualcols, indexcol);
+ RestrictInfo *newrinfo;
+
+ newrinfo = expand_indexqual_rowcompare(rinfo,
+ index,
+ indexcol,
+ &iclause->indexcols,
+ &iclause->lossy);
+ if (newrinfo != rinfo)
+ {
+ /* We need to report a derived expression */
+ indexquals = list_make1(newrinfo);
+ }
}
else if (IsA(clause, NullTest))
{
Assert(index->amsearchnulls);
- indexquals = lappend(indexquals, rinfo);
- indexqualcols = lappend_int(indexqualcols, indexcol);
}
else
elog(ERROR, "unsupported indexqual type: %d",
(int) nodeTag(clause));
}
- *indexquals_p = indexquals;
- *indexqualcols_p = indexqualcols;
+ iclause->indexquals = indexquals;
+ return iclause;
}
/*
@@ -3725,13 +3763,15 @@ expand_boolean_index_clause(Node *clause,
* expand_indexqual_opclause --- expand a single indexqual condition
* that is an operator clause
*
- * The input is a single RestrictInfo, the output a list of RestrictInfos.
+ * The input is a single RestrictInfo, the output a list of RestrictInfos,
+ * or NIL if the RestrictInfo's clause can be used as-is.
*
- * In the base case this is just list_make1(), but we have to be prepared to
+ * In the base case this is just "return NIL", but we have to be prepared to
* expand special cases that were accepted by match_special_index_operator().
*/
static List *
-expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily, Oid idxcollation)
+expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily, Oid idxcollation,
+ bool *lossy)
{
Expr *clause = rinfo->clause;
@@ -3760,6 +3800,7 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily, Oid idxcollation)
case OID_BYTEA_LIKE_OP:
if (!op_in_opfamily(expr_op, opfamily))
{
+ *lossy = true;
pstatus = pattern_fixed_prefix(patt, Pattern_Type_Like, expr_coll,
&prefix, NULL);
return prefix_quals(leftop, opfamily, idxcollation, prefix, pstatus);
@@ -3771,6 +3812,7 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily, Oid idxcollation)
case OID_NAME_ICLIKE_OP:
if (!op_in_opfamily(expr_op, opfamily))
{
+ *lossy = true;
/* the right-hand const is type text for all of these */
pstatus = pattern_fixed_prefix(patt, Pattern_Type_Like_IC, expr_coll,
&prefix, NULL);
@@ -3783,6 +3825,7 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily, Oid idxcollation)
case OID_NAME_REGEXEQ_OP:
if (!op_in_opfamily(expr_op, opfamily))
{
+ *lossy = true;
/* the right-hand const is type text for all of these */
pstatus = pattern_fixed_prefix(patt, Pattern_Type_Regex, expr_coll,
&prefix, NULL);
@@ -3795,6 +3838,7 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily, Oid idxcollation)
case OID_NAME_ICREGEXEQ_OP:
if (!op_in_opfamily(expr_op, opfamily))
{
+ *lossy = true;
/* the right-hand const is type text for all of these */
pstatus = pattern_fixed_prefix(patt, Pattern_Type_Regex_IC, expr_coll,
&prefix, NULL);
@@ -3806,96 +3850,65 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily, Oid idxcollation)
case OID_INET_SUBEQ_OP:
if (!op_in_opfamily(expr_op, opfamily))
{
+ *lossy = true;
return network_prefix_quals(leftop, expr_op, opfamily,
patt->constvalue);
}
break;
}
- /* Default case: just make a list of the unmodified indexqual */
- return list_make1(rinfo);
+ /* Default case: the clause can be used as-is. */
+ *lossy = false;
+ return NIL;
}
/*
* expand_indexqual_rowcompare --- expand a single indexqual condition
* that is a RowCompareExpr
*
- * This is a thin wrapper around adjust_rowcompare_for_index; we export the
- * latter so that createplan.c can use it to re-discover which columns of the
- * index are used by a row comparison indexqual.
- */
-static RestrictInfo *
-expand_indexqual_rowcompare(RestrictInfo *rinfo,
- IndexOptInfo *index,
- int indexcol)
-{
- RowCompareExpr *clause = (RowCompareExpr *) rinfo->clause;
- Expr *newclause;
- List *indexcolnos;
- bool var_on_left;
-
- newclause = adjust_rowcompare_for_index(clause,
- index,
- indexcol,
- &indexcolnos,
- &var_on_left);
-
- /*
- * If we didn't have to change the RowCompareExpr, return the original
- * RestrictInfo.
- */
- if (newclause == (Expr *) clause)
- return rinfo;
-
- /* Else we need a new RestrictInfo */
- return make_simple_restrictinfo(newclause);
-}
-
-/*
- * adjust_rowcompare_for_index --- expand a single indexqual condition
- * that is a RowCompareExpr
- *
* It's already known that the first column of the row comparison matches
* the specified column of the index. We can use additional columns of the
* row comparison as index qualifications, so long as they match the index
* in the "same direction", ie, the indexkeys are all on the same side of the
* clause and the operators are all the same-type members of the opfamilies.
+ *
* If all the columns of the RowCompareExpr match in this way, we just use it
- * as-is. Otherwise, we build a shortened RowCompareExpr (if more than one
+ * as-is, except for possibly commuting it to put the indexkeys on the left.
+ *
+ * Otherwise, we build a shortened RowCompareExpr (if more than one
* column matches) or a simple OpExpr (if the first-column match is all
* there is). In these cases the modified clause is always "<=" or ">="
* even when the original was "<" or ">" --- this is necessary to match all
- * the rows that could match the original. (We are essentially building a
- * lossy version of the row comparison when we do this.)
+ * the rows that could match the original. (We are building a lossy version
+ * of the row comparison when we do this, so we set *lossy = true.)
*
* *indexcolnos receives an integer list of the index column numbers (zero
- * based) used in the resulting expression. The reason we need to return
- * that is that if the index is selected for use, createplan.c will need to
- * call this again to extract that list. (This is a bit grotty, but row
- * comparison indexquals aren't used enough to justify finding someplace to
- * keep the information in the Path representation.) Since createplan.c
- * also needs to know which side of the RowCompareExpr is the index side,
- * we also return *var_on_left_p rather than re-deducing that there.
+ * based) used in the resulting expression. We have to pass that back
+ * because createplan.c will need it.
*/
-Expr *
-adjust_rowcompare_for_index(RowCompareExpr *clause,
+static RestrictInfo *
+expand_indexqual_rowcompare(RestrictInfo *rinfo,
IndexOptInfo *index,
int indexcol,
List **indexcolnos,
- bool *var_on_left_p)
+ bool *lossy)
{
+ RowCompareExpr *clause = castNode(RowCompareExpr, rinfo->clause);
bool var_on_left;
int op_strategy;
Oid op_lefttype;
Oid op_righttype;
int matching_cols;
Oid expr_op;
+ List *expr_ops;
List *opfamilies;
List *lefttypes;
List *righttypes;
List *new_ops;
- ListCell *largs_cell;
- ListCell *rargs_cell;
+ List *var_args;
+ List *non_var_args;
+ ListCell *vargs_cell;
+ ListCell *nargs_cell;
ListCell *opnos_cell;
ListCell *collids_cell;
@@ -3905,7 +3918,17 @@ adjust_rowcompare_for_index(RowCompareExpr *clause,
Assert(var_on_left ||
match_index_to_operand((Node *) linitial(clause->rargs),
indexcol, index));
- *var_on_left_p = var_on_left;
+
+ if (var_on_left)
+ {
+ var_args = clause->largs;
+ non_var_args = clause->rargs;
+ }
+ else
+ {
+ var_args = clause->rargs;
+ non_var_args = clause->largs;
+ }
expr_op = linitial_oid(clause->opnos);
if (!var_on_left)
@@ -3918,7 +3941,8 @@ adjust_rowcompare_for_index(RowCompareExpr *clause,
/* Initialize returned list of which index columns are used */
*indexcolnos = list_make1_int(indexcol);
- /* Build lists of the opfamilies and operator datatypes in case needed */
+ /* Build lists of ops, opfamilies and operator datatypes in case needed */
+ expr_ops = list_make1_oid(expr_op);
opfamilies = list_make1_oid(index->opfamily[indexcol]);
lefttypes = list_make1_oid(op_lefttype);
righttypes = list_make1_oid(op_righttype);
@@ -3930,27 +3954,20 @@ adjust_rowcompare_for_index(RowCompareExpr *clause,
* indexed relation.
*/
matching_cols = 1;
- largs_cell = lnext(list_head(clause->largs));
- rargs_cell = lnext(list_head(clause->rargs));
+ vargs_cell = lnext(list_head(var_args));
+ nargs_cell = lnext(list_head(non_var_args));
opnos_cell = lnext(list_head(clause->opnos));
collids_cell = lnext(list_head(clause->inputcollids));
- while (largs_cell != NULL)
+ while (vargs_cell != NULL)
{
- Node *varop;
- Node *constop;
+ Node *varop = (Node *) lfirst(vargs_cell);
+ Node *constop = (Node *) lfirst(nargs_cell);
int i;
expr_op = lfirst_oid(opnos_cell);
- if (var_on_left)
+ if (!var_on_left)
{
- varop = (Node *) lfirst(largs_cell);
- constop = (Node *) lfirst(rargs_cell);
- }
- else
- {
- varop = (Node *) lfirst(rargs_cell);
- constop = (Node *) lfirst(largs_cell);
/* indexkey is on right, so commute the operator */
expr_op = get_commutator(expr_op);
if (expr_op == InvalidOid)
@@ -3980,37 +3997,49 @@ adjust_rowcompare_for_index(RowCompareExpr *clause,
/* Add column number to returned list */
*indexcolnos = lappend_int(*indexcolnos, i);
- /* Add opfamily and datatypes to lists */
+ /* Add operator info to lists */
get_op_opfamily_properties(expr_op, index->opfamily[i], false,
&op_strategy,
&op_lefttype,
&op_righttype);
+ expr_ops = lappend_oid(expr_ops, expr_op);
opfamilies = lappend_oid(opfamilies, index->opfamily[i]);
lefttypes = lappend_oid(lefttypes, op_lefttype);
righttypes = lappend_oid(righttypes, op_righttype);
/* This column matches, keep scanning */
matching_cols++;
- largs_cell = lnext(largs_cell);
- rargs_cell = lnext(rargs_cell);
+ vargs_cell = lnext(vargs_cell);
+ nargs_cell = lnext(nargs_cell);
opnos_cell = lnext(opnos_cell);
collids_cell = lnext(collids_cell);
}
- /* Return clause as-is if it's all usable as index quals */
- if (matching_cols == list_length(clause->opnos))
- return (Expr *) clause;
+ /* Result is non-lossy if all columns are usable as index quals */
+ *lossy = (matching_cols != list_length(clause->opnos));
/*
- * We have to generate a subset rowcompare (possibly just one OpExpr). The
- * painful part of this is changing < to <= or > to >=, so deal with that
- * first.
+ * Return clause as-is if we have var on left and it's all usable as index
+ * quals
*/
- if (op_strategy == BTLessEqualStrategyNumber ||
- op_strategy == BTGreaterEqualStrategyNumber)
+ if (var_on_left && !*lossy)
+ return rinfo;
+
+ /*
+ * We have to generate a modified rowcompare (possibly just one OpExpr).
+ * The painful part of this is changing < to <= or > to >=, so deal with
+ * that first.
+ */
+ if (!*lossy)
{
- /* easy, just use the same operators */
- new_ops = list_truncate(list_copy(clause->opnos), matching_cols);
+ /* very easy, just use the commuted operators */
+ new_ops = expr_ops;
+ }
+ else if (op_strategy == BTLessEqualStrategyNumber ||
+ op_strategy == BTGreaterEqualStrategyNumber)
+ {
+ /* easy, just use the same (possibly commuted) operators */
+ new_ops = list_truncate(expr_ops, matching_cols);
}
else
{
@@ -4025,9 +4054,9 @@ adjust_rowcompare_for_index(RowCompareExpr *clause,
else
elog(ERROR, "unexpected strategy number %d", op_strategy);
new_ops = NIL;
- lefttypes_cell = list_head(lefttypes);
- righttypes_cell = list_head(righttypes);
- foreach(opfamilies_cell, opfamilies)
+ forthree(opfamilies_cell, opfamilies,
+ lefttypes_cell, lefttypes,
+ righttypes_cell, righttypes)
{
Oid opfam = lfirst_oid(opfamilies_cell);
Oid lefttype = lfirst_oid(lefttypes_cell);
@@ -4038,16 +4067,7 @@ adjust_rowcompare_for_index(RowCompareExpr *clause,
if (!OidIsValid(expr_op)) /* should not happen */
elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
op_strategy, lefttype, righttype, opfam);
- if (!var_on_left)
- {
- expr_op = get_commutator(expr_op);
- if (!OidIsValid(expr_op)) /* should not happen */
- elog(ERROR, "could not find commutator of operator %d(%u,%u) of opfamily %u",
- op_strategy, lefttype, righttype, opfam);
- }
new_ops = lappend_oid(new_ops, expr_op);
- lefttypes_cell = lnext(lefttypes_cell);
- righttypes_cell = lnext(righttypes_cell);
}
}
@@ -4056,29 +4076,31 @@ adjust_rowcompare_for_index(RowCompareExpr *clause,
{
RowCompareExpr *rc = makeNode(RowCompareExpr);
- if (var_on_left)
- rc->rctype = (RowCompareType) op_strategy;
- else
- rc->rctype = (op_strategy == BTLessEqualStrategyNumber) ?
- ROWCOMPARE_GE : ROWCOMPARE_LE;
+ rc->rctype = (RowCompareType) op_strategy;
rc->opnos = new_ops;
rc->opfamilies = list_truncate(list_copy(clause->opfamilies),
matching_cols);
rc->inputcollids = list_truncate(list_copy(clause->inputcollids),
matching_cols);
- rc->largs = list_truncate(copyObject(clause->largs),
+ rc->largs = list_truncate(copyObject(var_args),
matching_cols);
- rc->rargs = list_truncate(copyObject(clause->rargs),
+ rc->rargs = list_truncate(copyObject(non_var_args),
matching_cols);
- return (Expr *) rc;
+ return make_simple_restrictinfo((Expr *) rc);
}
else
{
- return make_opclause(linitial_oid(new_ops), BOOLOID, false,
- copyObject(linitial(clause->largs)),
- copyObject(linitial(clause->rargs)),
- InvalidOid,
- linitial_oid(clause->inputcollids));
+ Expr *op;
+
+ /* We don't report an index column list in this case */
+ *indexcolnos = NIL;
+
+ op = make_opclause(linitial_oid(new_ops), BOOLOID, false,
+ copyObject(linitial(var_args)),
+ copyObject(linitial(non_var_args)),
+ InvalidOid,
+ linitial_oid(clause->inputcollids));
+ return make_simple_restrictinfo(op);
}
}