99 *
1010 *
1111 * IDENTIFICATION
12- * $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.169 2005/03/02 04:10:53 tgl Exp $
12+ * $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.170 2005/03/26 23:29:17 tgl Exp $
1313 *
1414 *-------------------------------------------------------------------------
1515 */
5050#define is_indexable_operator (clause ,opclass ,indexkey_on_left ) \
5151 (indexable_operator(clause,opclass,indexkey_on_left) != InvalidOid)
5252
53+ #define IsBooleanOpclass (opclass ) \
54+ ((opclass) == BOOL_BTREE_OPS_OID || (opclass) == BOOL_HASH_OPS_OID)
55+
5356
5457static List * group_clauses_by_indexkey (RelOptInfo * rel , IndexOptInfo * index );
5558static List * group_clauses_by_indexkey_for_join (Query * root ,
@@ -72,8 +75,16 @@ static Path *make_innerjoin_index_path(Query *root,
7275 List * clausegroups );
7376static bool match_index_to_operand (Node * operand , int indexcol ,
7477 RelOptInfo * rel , IndexOptInfo * index );
78+ static bool match_boolean_index_clause (Node * clause ,
79+ int indexcol ,
80+ RelOptInfo * rel ,
81+ IndexOptInfo * index );
7582static bool match_special_index_operator (Expr * clause , Oid opclass ,
7683 bool indexkey_on_left );
84+ static Expr * expand_boolean_index_clause (Node * clause ,
85+ int indexcol ,
86+ RelOptInfo * rel ,
87+ IndexOptInfo * index );
7788static List * expand_indexqual_condition (RestrictInfo * rinfo , Oid opclass );
7889static List * prefix_quals (Node * leftop , Oid opclass ,
7990 Const * prefix , Pattern_Prefix_Status pstatus );
@@ -511,7 +522,7 @@ group_clauses_by_indexkey_for_or(RelOptInfo *rel,
511522 * match_clause_to_indexcol()
512523 * Determines whether a restriction clause matches a column of an index.
513524 *
514- * To match, the clause:
525+ * To match a normal index , the clause:
515526 *
516527 * (1) must be in the form (indexkey op const) or (const op indexkey);
517528 * and
@@ -525,6 +536,9 @@ group_clauses_by_indexkey_for_or(RelOptInfo *rel,
525536 * We do not actually do the commuting here, but we check whether a
526537 * suitable commutator operator is available.
527538 *
539+ * For boolean indexes, it is also possible to match the clause directly
540+ * to the indexkey; or perhaps the clause is (NOT indexkey).
541+ *
528542 * 'rel' is the relation of interest.
529543 * 'index' is an index on 'rel'.
530544 * 'indexcol' is a column number of 'index' (counting from 0).
@@ -547,7 +561,15 @@ match_clause_to_indexcol(RelOptInfo *rel,
547561 Node * leftop ,
548562 * rightop ;
549563
550- /* Clause must be a binary opclause. */
564+ /* First check for boolean-index cases. */
565+ if (IsBooleanOpclass (opclass ))
566+ {
567+ if (match_boolean_index_clause ((Node * ) clause ,
568+ indexcol , rel , index ))
569+ return true;
570+ }
571+
572+ /* Else clause must be a binary opclause. */
551573 if (!is_opclause (clause ))
552574 return false;
553575 leftop = get_leftop (clause );
@@ -606,6 +628,8 @@ match_clause_to_indexcol(RelOptInfo *rel,
606628 * operator for this column, or is a "special" operator as recognized
607629 * by match_special_index_operator().
608630 *
631+ * The boolean-index cases don't apply.
632+ *
609633 * As above, we must be able to commute the clause to put the indexkey
610634 * on the left.
611635 *
@@ -1662,7 +1686,7 @@ make_innerjoin_index_path(Query *root,
16621686 pathnode -> path .pathkeys = NIL ;
16631687
16641688 /* Convert clauses to indexquals the executor can handle */
1665- indexquals = expand_indexqual_conditions (index , clausegroups );
1689+ indexquals = expand_indexqual_conditions (rel , index , clausegroups );
16661690
16671691 /* Flatten the clausegroups list to produce indexclauses list */
16681692 allclauses = flatten_clausegroups_list (clausegroups );
@@ -1868,21 +1892,78 @@ match_index_to_operand(Node *operand,
18681892 * from LIKE to indexscan limits rather harder than one might think ...
18691893 * but that's the basic idea.)
18701894 *
1871- * Two routines are provided here, match_special_index_operator() and
1872- * expand_indexqual_conditions(). match_special_index_operator() is
1873- * just an auxiliary function for match_clause_to_indexcol(); after
1874- * the latter fails to recognize a restriction opclause's operator
1875- * as a member of an index's opclass, it asks match_special_index_operator()
1876- * whether the clause should be considered an indexqual anyway.
1895+ * Another thing that we do with this machinery is to provide special
1896+ * smarts for "boolean" indexes (that is, indexes on boolean columns
1897+ * that support boolean equality). We can transform a plain reference
1898+ * to the indexkey into "indexkey = true", or "NOT indexkey" into
1899+ * "indexkey = false", so as to make the expression indexable using the
1900+ * regular index operators. (As of Postgres 8.1, we must do this here
1901+ * because constant simplification does the reverse transformation;
1902+ * without this code there'd be no way to use such an index at all.)
1903+ *
1904+ * Three routines are provided here:
1905+ *
1906+ * match_special_index_operator() is just an auxiliary function for
1907+ * match_clause_to_indexcol(); after the latter fails to recognize a
1908+ * restriction opclause's operator as a member of an index's opclass,
1909+ * it asks match_special_index_operator() whether the clause should be
1910+ * considered an indexqual anyway.
1911+ *
1912+ * match_boolean_index_clause() similarly detects clauses that can be
1913+ * converted into boolean equality operators.
1914+ *
18771915 * expand_indexqual_conditions() converts a list of lists of RestrictInfo
18781916 * nodes (with implicit AND semantics across list elements) into
18791917 * a list of clauses that the executor can actually handle. For operators
18801918 * that are members of the index's opclass this transformation is a no-op,
1881- * but operators recognized by match_special_index_operator() must be
1882- * converted into one or more "regular" indexqual conditions.
1919+ * but clauses recognized by match_special_index_operator() or
1920+ * match_boolean_index_clause() must be converted into one or more "regular"
1921+ * indexqual conditions.
18831922 *----------
18841923 */
18851924
1925+ /*
1926+ * match_boolean_index_clause
1927+ * Recognize restriction clauses that can be matched to a boolean index.
1928+ *
1929+ * This should be called only when IsBooleanOpclass() recognizes the
1930+ * index's operator class. We check to see if the clause matches the
1931+ * index's key.
1932+ */
1933+ static bool
1934+ match_boolean_index_clause (Node * clause ,
1935+ int indexcol ,
1936+ RelOptInfo * rel ,
1937+ IndexOptInfo * index )
1938+ {
1939+ /* Direct match? */
1940+ if (match_index_to_operand (clause , indexcol , rel , index ))
1941+ return true;
1942+ /* NOT clause? */
1943+ if (not_clause (clause ))
1944+ {
1945+ if (match_index_to_operand ((Node * ) get_notclausearg ((Expr * ) clause ),
1946+ indexcol , rel , index ))
1947+ return true;
1948+ }
1949+ /*
1950+ * Since we only consider clauses at top level of WHERE, we can convert
1951+ * indexkey IS TRUE and indexkey IS FALSE to index searches as well.
1952+ * The different meaning for NULL isn't important.
1953+ */
1954+ else if (clause && IsA (clause , BooleanTest ))
1955+ {
1956+ BooleanTest * btest = (BooleanTest * ) clause ;
1957+
1958+ if (btest -> booltesttype == IS_TRUE ||
1959+ btest -> booltesttype == IS_FALSE )
1960+ if (match_index_to_operand ((Node * ) btest -> arg ,
1961+ indexcol , rel , index ))
1962+ return true;
1963+ }
1964+ return false;
1965+ }
1966+
18861967/*
18871968 * match_special_index_operator
18881969 * Recognize restriction clauses that can be used to generate
@@ -2042,9 +2123,9 @@ match_special_index_operator(Expr *clause, Oid opclass,
20422123 * expand_indexqual_conditions
20432124 * Given a list of sublists of RestrictInfo nodes, produce a flat list
20442125 * of index qual clauses. Standard qual clauses (those in the index's
2045- * opclass) are passed through unchanged. "Special" index operators
2046- * are expanded into clauses that the indexscan machinery will know
2047- * what to do with.
2126+ * opclass) are passed through unchanged. Boolean clauses and "special"
2127+ * index operators are expanded into clauses that the indexscan machinery
2128+ * will know what to do with.
20482129 *
20492130 * The input list is ordered by index key, and so the output list is too.
20502131 * (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,
20542135 * someday --- tgl 7/00)
20552136 */
20562137List *
2057- expand_indexqual_conditions (IndexOptInfo * index , List * clausegroups )
2138+ expand_indexqual_conditions (RelOptInfo * rel , IndexOptInfo * index , List * clausegroups )
20582139{
20592140 List * resultquals = NIL ;
20602141 ListCell * clausegroup_item ;
2142+ int indexcol = 0 ;
20612143 Oid * classes = index -> classlist ;
20622144
20632145 if (clausegroups == NIL )
@@ -2073,12 +2155,32 @@ expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups)
20732155 {
20742156 RestrictInfo * rinfo = (RestrictInfo * ) lfirst (l );
20752157
2158+ /* First check for boolean cases */
2159+ if (IsBooleanOpclass (curClass ))
2160+ {
2161+ Expr * boolqual ;
2162+
2163+ boolqual = expand_boolean_index_clause ((Node * ) rinfo -> clause ,
2164+ indexcol ,
2165+ rel ,
2166+ index );
2167+ if (boolqual )
2168+ {
2169+ resultquals = lappend (resultquals ,
2170+ make_restrictinfo (boolqual ,
2171+ true, true));
2172+ continue ;
2173+ }
2174+ }
2175+
20762176 resultquals = list_concat (resultquals ,
20772177 expand_indexqual_condition (rinfo ,
2078- curClass ));
2178+ curClass ));
20792179 }
20802180
20812181 clausegroup_item = lnext (clausegroup_item );
2182+
2183+ indexcol ++ ;
20822184 classes ++ ;
20832185 } while (clausegroup_item != NULL && !DoneMatchingIndexKeys (classes ));
20842186
@@ -2087,16 +2189,77 @@ expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups)
20872189 return resultquals ;
20882190}
20892191
2192+ /*
2193+ * expand_boolean_index_clause
2194+ * Convert a clause recognized by match_boolean_index_clause into
2195+ * a boolean equality operator clause.
2196+ *
2197+ * Returns NULL if the clause isn't a boolean index qual.
2198+ */
2199+ static Expr *
2200+ expand_boolean_index_clause (Node * clause ,
2201+ int indexcol ,
2202+ RelOptInfo * rel ,
2203+ IndexOptInfo * index )
2204+ {
2205+ /* Direct match? */
2206+ if (match_index_to_operand (clause , indexcol , rel , index ))
2207+ {
2208+ /* convert to indexkey = TRUE */
2209+ return make_opclause (BooleanEqualOperator , BOOLOID , false,
2210+ (Expr * ) clause ,
2211+ (Expr * ) makeBoolConst (true, false));
2212+ }
2213+ /* NOT clause? */
2214+ if (not_clause (clause ))
2215+ {
2216+ Node * arg = (Node * ) get_notclausearg ((Expr * ) clause );
2217+
2218+ /* It must have matched the indexkey */
2219+ Assert (match_index_to_operand (arg , indexcol , rel , index ));
2220+ /* convert to indexkey = FALSE */
2221+ return make_opclause (BooleanEqualOperator , BOOLOID , false,
2222+ (Expr * ) arg ,
2223+ (Expr * ) makeBoolConst (false, false));
2224+ }
2225+ if (clause && IsA (clause , BooleanTest ))
2226+ {
2227+ BooleanTest * btest = (BooleanTest * ) clause ;
2228+ Node * arg = (Node * ) btest -> arg ;
2229+
2230+ /* It must have matched the indexkey */
2231+ Assert (match_index_to_operand (arg , indexcol , rel , index ));
2232+ if (btest -> booltesttype == IS_TRUE )
2233+ {
2234+ /* convert to indexkey = TRUE */
2235+ return make_opclause (BooleanEqualOperator , BOOLOID , false,
2236+ (Expr * ) arg ,
2237+ (Expr * ) makeBoolConst (true, false));
2238+ }
2239+ if (btest -> booltesttype == IS_FALSE )
2240+ {
2241+ /* convert to indexkey = FALSE */
2242+ return make_opclause (BooleanEqualOperator , BOOLOID , false,
2243+ (Expr * ) arg ,
2244+ (Expr * ) makeBoolConst (false, false));
2245+ }
2246+ /* Oops */
2247+ Assert (false);
2248+ }
2249+
2250+ return NULL ;
2251+ }
2252+
20902253/*
20912254 * expand_indexqual_condition --- expand a single indexqual condition
2255+ * (other than a boolean-qual case)
20922256 *
20932257 * The input is a single RestrictInfo, the output a list of RestrictInfos
20942258 */
20952259static List *
20962260expand_indexqual_condition (RestrictInfo * rinfo , Oid opclass )
20972261{
20982262 Expr * clause = rinfo -> clause ;
2099-
21002263 /* we know these will succeed */
21012264 Node * leftop = get_leftop (clause );
21022265 Node * rightop = get_rightop (clause );
0 commit comments