aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/optimizer/path/indxpath.c199
-rw-r--r--src/backend/optimizer/path/orindxpath.c4
-rw-r--r--src/backend/optimizer/util/pathnode.c4
-rw-r--r--src/include/catalog/pg_opclass.h4
-rw-r--r--src/include/optimizer/paths.h7
5 files changed, 192 insertions, 26 deletions
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index f86206304c1..9f5ab60337e 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.169 2005/03/02 04:10:53 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.170 2005/03/26 23:29:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -50,6 +50,9 @@
#define is_indexable_operator(clause,opclass,indexkey_on_left) \
(indexable_operator(clause,opclass,indexkey_on_left) != InvalidOid)
+#define IsBooleanOpclass(opclass) \
+ ((opclass) == BOOL_BTREE_OPS_OID || (opclass) == BOOL_HASH_OPS_OID)
+
static List *group_clauses_by_indexkey(RelOptInfo *rel, IndexOptInfo *index);
static List *group_clauses_by_indexkey_for_join(Query *root,
@@ -72,8 +75,16 @@ static Path *make_innerjoin_index_path(Query *root,
List *clausegroups);
static bool match_index_to_operand(Node *operand, int indexcol,
RelOptInfo *rel, IndexOptInfo *index);
+static bool match_boolean_index_clause(Node *clause,
+ int indexcol,
+ RelOptInfo *rel,
+ IndexOptInfo *index);
static bool match_special_index_operator(Expr *clause, Oid opclass,
bool indexkey_on_left);
+static Expr *expand_boolean_index_clause(Node *clause,
+ int indexcol,
+ RelOptInfo *rel,
+ IndexOptInfo *index);
static List *expand_indexqual_condition(RestrictInfo *rinfo, Oid opclass);
static List *prefix_quals(Node *leftop, Oid opclass,
Const *prefix, Pattern_Prefix_Status pstatus);
@@ -511,7 +522,7 @@ group_clauses_by_indexkey_for_or(RelOptInfo *rel,
* match_clause_to_indexcol()
* Determines whether a restriction clause matches a column of an index.
*
- * To match, the clause:
+ * To match a normal index, the clause:
*
* (1) must be in the form (indexkey op const) or (const op indexkey);
* and
@@ -525,6 +536,9 @@ group_clauses_by_indexkey_for_or(RelOptInfo *rel,
* We do not actually do the commuting here, but we check whether a
* suitable commutator operator is available.
*
+ * For boolean indexes, it is also possible to match the clause directly
+ * to the indexkey; or perhaps the clause is (NOT indexkey).
+ *
* 'rel' is the relation of interest.
* 'index' is an index on 'rel'.
* 'indexcol' is a column number of 'index' (counting from 0).
@@ -547,7 +561,15 @@ match_clause_to_indexcol(RelOptInfo *rel,
Node *leftop,
*rightop;
- /* Clause must be a binary opclause. */
+ /* First check for boolean-index cases. */
+ if (IsBooleanOpclass(opclass))
+ {
+ if (match_boolean_index_clause((Node *) clause,
+ indexcol, rel, index))
+ return true;
+ }
+
+ /* Else clause must be a binary opclause. */
if (!is_opclause(clause))
return false;
leftop = get_leftop(clause);
@@ -606,6 +628,8 @@ match_clause_to_indexcol(RelOptInfo *rel,
* operator for this column, or is a "special" operator as recognized
* by match_special_index_operator().
*
+ * The boolean-index cases don't apply.
+ *
* As above, we must be able to commute the clause to put the indexkey
* on the left.
*
@@ -1662,7 +1686,7 @@ make_innerjoin_index_path(Query *root,
pathnode->path.pathkeys = NIL;
/* Convert clauses to indexquals the executor can handle */
- indexquals = expand_indexqual_conditions(index, clausegroups);
+ indexquals = expand_indexqual_conditions(rel, index, clausegroups);
/* Flatten the clausegroups list to produce indexclauses list */
allclauses = flatten_clausegroups_list(clausegroups);
@@ -1868,22 +1892,79 @@ match_index_to_operand(Node *operand,
* from LIKE to indexscan limits rather harder than one might think ...
* but that's the basic idea.)
*
- * Two routines are provided here, match_special_index_operator() and
- * expand_indexqual_conditions(). match_special_index_operator() is
- * just an auxiliary function for match_clause_to_indexcol(); after
- * the latter fails to recognize a restriction opclause's operator
- * as a member of an index's opclass, it asks match_special_index_operator()
- * whether the clause should be considered an indexqual anyway.
+ * Another thing that we do with this machinery is to provide special
+ * smarts for "boolean" indexes (that is, indexes on boolean columns
+ * that support boolean equality). We can transform a plain reference
+ * to the indexkey into "indexkey = true", or "NOT indexkey" into
+ * "indexkey = false", so as to make the expression indexable using the
+ * regular index operators. (As of Postgres 8.1, we must do this here
+ * because constant simplification does the reverse transformation;
+ * without this code there'd be no way to use such an index at all.)
+ *
+ * Three routines are provided here:
+ *
+ * match_special_index_operator() is just an auxiliary function for
+ * match_clause_to_indexcol(); after the latter fails to recognize a
+ * restriction opclause's operator as a member of an index's opclass,
+ * it asks match_special_index_operator() whether the clause should be
+ * considered an indexqual anyway.
+ *
+ * match_boolean_index_clause() similarly detects clauses that can be
+ * converted into boolean equality operators.
+ *
* expand_indexqual_conditions() converts a list of lists of RestrictInfo
* nodes (with implicit AND semantics across list elements) into
* a list of clauses that the executor can actually handle. For operators
* that are members of the index's opclass this transformation is a no-op,
- * but operators recognized by match_special_index_operator() must be
- * converted into one or more "regular" indexqual conditions.
+ * but clauses recognized by match_special_index_operator() or
+ * match_boolean_index_clause() must be converted into one or more "regular"
+ * indexqual conditions.
*----------
*/
/*
+ * match_boolean_index_clause
+ * Recognize restriction clauses that can be matched to a boolean index.
+ *
+ * This should be called only when IsBooleanOpclass() recognizes the
+ * index's operator class. We check to see if the clause matches the
+ * index's key.
+ */
+static bool
+match_boolean_index_clause(Node *clause,
+ int indexcol,
+ RelOptInfo *rel,
+ IndexOptInfo *index)
+{
+ /* Direct match? */
+ if (match_index_to_operand(clause, indexcol, rel, index))
+ return true;
+ /* NOT clause? */
+ if (not_clause(clause))
+ {
+ if (match_index_to_operand((Node *) get_notclausearg((Expr *) clause),
+ indexcol, rel, index))
+ return true;
+ }
+ /*
+ * Since we only consider clauses at top level of WHERE, we can convert
+ * indexkey IS TRUE and indexkey IS FALSE to index searches as well.
+ * The different meaning for NULL isn't important.
+ */
+ else if (clause && IsA(clause, BooleanTest))
+ {
+ BooleanTest *btest = (BooleanTest *) clause;
+
+ if (btest->booltesttype == IS_TRUE ||
+ btest->booltesttype == IS_FALSE)
+ if (match_index_to_operand((Node *) btest->arg,
+ indexcol, rel, index))
+ return true;
+ }
+ return false;
+}
+
+/*
* match_special_index_operator
* Recognize restriction clauses that can be used to generate
* additional indexscanable qualifications.
@@ -2042,9 +2123,9 @@ match_special_index_operator(Expr *clause, Oid opclass,
* expand_indexqual_conditions
* Given a list of sublists of RestrictInfo nodes, produce a flat list
* of index qual clauses. Standard qual clauses (those in the index's
- * opclass) are passed through unchanged. "Special" index operators
- * are expanded into clauses that the indexscan machinery will know
- * what to do with.
+ * opclass) are passed through unchanged. Boolean clauses and "special"
+ * index operators are expanded into clauses that the indexscan machinery
+ * will know what to do with.
*
* The input list is ordered by index key, and so the output list is too.
* (The latter is not depended on by any part of the planner, so far as I can
@@ -2054,10 +2135,11 @@ match_special_index_operator(Expr *clause, Oid opclass,
* someday --- tgl 7/00)
*/
List *
-expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups)
+expand_indexqual_conditions(RelOptInfo *rel, IndexOptInfo *index, List *clausegroups)
{
List *resultquals = NIL;
ListCell *clausegroup_item;
+ int indexcol = 0;
Oid *classes = index->classlist;
if (clausegroups == NIL)
@@ -2073,12 +2155,32 @@ expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups)
{
RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
+ /* First check for boolean cases */
+ if (IsBooleanOpclass(curClass))
+ {
+ Expr *boolqual;
+
+ boolqual = expand_boolean_index_clause((Node *) rinfo->clause,
+ indexcol,
+ rel,
+ index);
+ if (boolqual)
+ {
+ resultquals = lappend(resultquals,
+ make_restrictinfo(boolqual,
+ true, true));
+ continue;
+ }
+ }
+
resultquals = list_concat(resultquals,
expand_indexqual_condition(rinfo,
- curClass));
+ curClass));
}
clausegroup_item = lnext(clausegroup_item);
+
+ indexcol++;
classes++;
} while (clausegroup_item != NULL && !DoneMatchingIndexKeys(classes));
@@ -2088,7 +2190,69 @@ expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups)
}
/*
+ * expand_boolean_index_clause
+ * Convert a clause recognized by match_boolean_index_clause into
+ * a boolean equality operator clause.
+ *
+ * Returns NULL if the clause isn't a boolean index qual.
+ */
+static Expr *
+expand_boolean_index_clause(Node *clause,
+ int indexcol,
+ RelOptInfo *rel,
+ IndexOptInfo *index)
+{
+ /* Direct match? */
+ if (match_index_to_operand(clause, indexcol, rel, index))
+ {
+ /* convert to indexkey = TRUE */
+ return make_opclause(BooleanEqualOperator, BOOLOID, false,
+ (Expr *) clause,
+ (Expr *) makeBoolConst(true, false));
+ }
+ /* NOT clause? */
+ if (not_clause(clause))
+ {
+ Node *arg = (Node *) get_notclausearg((Expr *) clause);
+
+ /* It must have matched the indexkey */
+ Assert(match_index_to_operand(arg, indexcol, rel, index));
+ /* convert to indexkey = FALSE */
+ return make_opclause(BooleanEqualOperator, BOOLOID, false,
+ (Expr *) arg,
+ (Expr *) makeBoolConst(false, false));
+ }
+ if (clause && IsA(clause, BooleanTest))
+ {
+ BooleanTest *btest = (BooleanTest *) clause;
+ Node *arg = (Node *) btest->arg;
+
+ /* It must have matched the indexkey */
+ Assert(match_index_to_operand(arg, indexcol, rel, index));
+ if (btest->booltesttype == IS_TRUE)
+ {
+ /* convert to indexkey = TRUE */
+ return make_opclause(BooleanEqualOperator, BOOLOID, false,
+ (Expr *) arg,
+ (Expr *) makeBoolConst(true, false));
+ }
+ if (btest->booltesttype == IS_FALSE)
+ {
+ /* convert to indexkey = FALSE */
+ return make_opclause(BooleanEqualOperator, BOOLOID, false,
+ (Expr *) arg,
+ (Expr *) makeBoolConst(false, false));
+ }
+ /* Oops */
+ Assert(false);
+ }
+
+ return NULL;
+}
+
+/*
* expand_indexqual_condition --- expand a single indexqual condition
+ * (other than a boolean-qual case)
*
* The input is a single RestrictInfo, the output a list of RestrictInfos
*/
@@ -2096,7 +2260,6 @@ static List *
expand_indexqual_condition(RestrictInfo *rinfo, Oid opclass)
{
Expr *clause = rinfo->clause;
-
/* we know these will succeed */
Node *leftop = get_leftop(clause);
Node *rightop = get_rightop(clause);
diff --git a/src/backend/optimizer/path/orindxpath.c b/src/backend/optimizer/path/orindxpath.c
index ffd08c738cb..1cda19c8fa7 100644
--- a/src/backend/optimizer/path/orindxpath.c
+++ b/src/backend/optimizer/path/orindxpath.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/path/orindxpath.c,v 1.65 2005/03/01 01:40:05 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/path/orindxpath.c,v 1.66 2005/03/26 23:29:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -398,7 +398,7 @@ best_or_subclause_index(Query *root,
continue;
/* Convert clauses to indexquals the executor can handle */
- indexquals = expand_indexqual_conditions(index, indexclauses);
+ indexquals = expand_indexqual_conditions(rel, index, indexclauses);
cost_index(&subclause_path, root, rel, index, indexquals, false);
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index f20c95299f3..53b2197edd4 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/util/pathnode.c,v 1.112 2005/03/10 23:21:22 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/util/pathnode.c,v 1.113 2005/03/26 23:29:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -444,7 +444,7 @@ create_index_path(Query *root,
pathnode->path.pathkeys = pathkeys;
/* Convert clauses to indexquals the executor can handle */
- indexquals = expand_indexqual_conditions(index, restriction_clauses);
+ indexquals = expand_indexqual_conditions(rel, index, restriction_clauses);
/* Flatten the clause-groups list to produce indexclauses list */
restriction_clauses = flatten_clausegroups_list(restriction_clauses);
diff --git a/src/include/catalog/pg_opclass.h b/src/include/catalog/pg_opclass.h
index b6213f2f3a8..3e4c1759162 100644
--- a/src/include/catalog/pg_opclass.h
+++ b/src/include/catalog/pg_opclass.h
@@ -27,7 +27,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/pg_opclass.h,v 1.62 2004/12/31 22:03:24 pgsql Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_opclass.h,v 1.63 2005/03/26 23:29:19 tgl Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
@@ -92,6 +92,7 @@ DATA(insert OID = 397 ( 403 array_ops PGNSP PGUID 2277 t 0 ));
#define ARRAY_BTREE_OPS_OID 397
DATA(insert OID = 423 ( 403 bit_ops PGNSP PGUID 1560 t 0 ));
DATA(insert OID = 424 ( 403 bool_ops PGNSP PGUID 16 t 0 ));
+#define BOOL_BTREE_OPS_OID 424
DATA(insert OID = 425 ( 402 box_ops PGNSP PGUID 603 t 0 ));
DATA(insert OID = 426 ( 403 bpchar_ops PGNSP PGUID 1042 t 0 ));
#define BPCHAR_BTREE_OPS_OID 426
@@ -159,6 +160,7 @@ DATA(insert OID = 2098 ( 403 name_pattern_ops PGNSP PGUID 19 f 0 ));
#define NAME_PATTERN_BTREE_OPS_OID 2098
DATA(insert OID = 2099 ( 403 money_ops PGNSP PGUID 790 t 0 ));
DATA(insert OID = 2222 ( 405 bool_ops PGNSP PGUID 16 t 0 ));
+#define BOOL_HASH_OPS_OID 2222
DATA(insert OID = 2223 ( 405 bytea_ops PGNSP PGUID 17 t 0 ));
DATA(insert OID = 2224 ( 405 int2vector_ops PGNSP PGUID 22 t 0 ));
DATA(insert OID = 2225 ( 405 xid_ops PGNSP PGUID 28 t 0 ));
diff --git a/src/include/optimizer/paths.h b/src/include/optimizer/paths.h
index db1a9f4affc..d159e1ecf4e 100644
--- a/src/include/optimizer/paths.h
+++ b/src/include/optimizer/paths.h
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/optimizer/paths.h,v 1.78 2005/01/23 02:21:36 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/paths.h,v 1.79 2005/03/26 23:29:20 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -41,8 +41,9 @@ extern Path *best_inner_indexscan(Query *root, RelOptInfo *rel,
extern List *group_clauses_by_indexkey_for_or(RelOptInfo *rel,
IndexOptInfo *index,
Expr *orsubclause);
-extern List *expand_indexqual_conditions(IndexOptInfo *index,
- List *clausegroups);
+extern List *expand_indexqual_conditions(RelOptInfo *rel,
+ IndexOptInfo *index,
+ List *clausegroups);
extern void check_partial_indexes(Query *root, RelOptInfo *rel);
extern bool pred_test(List *predicate_list, List *restrictinfo_list);
extern List *flatten_clausegroups_list(List *clausegroups);