9
9
*
10
10
*
11
11
* 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 $
13
13
*
14
14
*-------------------------------------------------------------------------
15
15
*/
50
50
#define is_indexable_operator (clause ,opclass ,indexkey_on_left ) \
51
51
(indexable_operator(clause,opclass,indexkey_on_left) != InvalidOid)
52
52
53
+ #define IsBooleanOpclass (opclass ) \
54
+ ((opclass) == BOOL_BTREE_OPS_OID || (opclass) == BOOL_HASH_OPS_OID)
55
+
53
56
54
57
static List * group_clauses_by_indexkey (RelOptInfo * rel , IndexOptInfo * index );
55
58
static List * group_clauses_by_indexkey_for_join (Query * root ,
@@ -72,8 +75,16 @@ static Path *make_innerjoin_index_path(Query *root,
72
75
List * clausegroups );
73
76
static bool match_index_to_operand (Node * operand , int indexcol ,
74
77
RelOptInfo * rel , IndexOptInfo * index );
78
+ static bool match_boolean_index_clause (Node * clause ,
79
+ int indexcol ,
80
+ RelOptInfo * rel ,
81
+ IndexOptInfo * index );
75
82
static bool match_special_index_operator (Expr * clause , Oid opclass ,
76
83
bool indexkey_on_left );
84
+ static Expr * expand_boolean_index_clause (Node * clause ,
85
+ int indexcol ,
86
+ RelOptInfo * rel ,
87
+ IndexOptInfo * index );
77
88
static List * expand_indexqual_condition (RestrictInfo * rinfo , Oid opclass );
78
89
static List * prefix_quals (Node * leftop , Oid opclass ,
79
90
Const * prefix , Pattern_Prefix_Status pstatus );
@@ -511,7 +522,7 @@ group_clauses_by_indexkey_for_or(RelOptInfo *rel,
511
522
* match_clause_to_indexcol()
512
523
* Determines whether a restriction clause matches a column of an index.
513
524
*
514
- * To match, the clause:
525
+ * To match a normal index , the clause:
515
526
*
516
527
* (1) must be in the form (indexkey op const) or (const op indexkey);
517
528
* and
@@ -525,6 +536,9 @@ group_clauses_by_indexkey_for_or(RelOptInfo *rel,
525
536
* We do not actually do the commuting here, but we check whether a
526
537
* suitable commutator operator is available.
527
538
*
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
+ *
528
542
* 'rel' is the relation of interest.
529
543
* 'index' is an index on 'rel'.
530
544
* 'indexcol' is a column number of 'index' (counting from 0).
@@ -547,7 +561,15 @@ match_clause_to_indexcol(RelOptInfo *rel,
547
561
Node * leftop ,
548
562
* rightop ;
549
563
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. */
551
573
if (!is_opclause (clause ))
552
574
return false;
553
575
leftop = get_leftop (clause );
@@ -606,6 +628,8 @@ match_clause_to_indexcol(RelOptInfo *rel,
606
628
* operator for this column, or is a "special" operator as recognized
607
629
* by match_special_index_operator().
608
630
*
631
+ * The boolean-index cases don't apply.
632
+ *
609
633
* As above, we must be able to commute the clause to put the indexkey
610
634
* on the left.
611
635
*
@@ -1662,7 +1686,7 @@ make_innerjoin_index_path(Query *root,
1662
1686
pathnode -> path .pathkeys = NIL ;
1663
1687
1664
1688
/* Convert clauses to indexquals the executor can handle */
1665
- indexquals = expand_indexqual_conditions (index , clausegroups );
1689
+ indexquals = expand_indexqual_conditions (rel , index , clausegroups );
1666
1690
1667
1691
/* Flatten the clausegroups list to produce indexclauses list */
1668
1692
allclauses = flatten_clausegroups_list (clausegroups );
@@ -1868,21 +1892,78 @@ match_index_to_operand(Node *operand,
1868
1892
* from LIKE to indexscan limits rather harder than one might think ...
1869
1893
* but that's the basic idea.)
1870
1894
*
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
+ *
1877
1915
* expand_indexqual_conditions() converts a list of lists of RestrictInfo
1878
1916
* nodes (with implicit AND semantics across list elements) into
1879
1917
* a list of clauses that the executor can actually handle. For operators
1880
1918
* 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.
1883
1922
*----------
1884
1923
*/
1885
1924
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
+
1886
1967
/*
1887
1968
* match_special_index_operator
1888
1969
* Recognize restriction clauses that can be used to generate
@@ -2042,9 +2123,9 @@ match_special_index_operator(Expr *clause, Oid opclass,
2042
2123
* expand_indexqual_conditions
2043
2124
* Given a list of sublists of RestrictInfo nodes, produce a flat list
2044
2125
* 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.
2048
2129
*
2049
2130
* The input list is ordered by index key, and so the output list is too.
2050
2131
* (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,
2054
2135
* someday --- tgl 7/00)
2055
2136
*/
2056
2137
List *
2057
- expand_indexqual_conditions (IndexOptInfo * index , List * clausegroups )
2138
+ expand_indexqual_conditions (RelOptInfo * rel , IndexOptInfo * index , List * clausegroups )
2058
2139
{
2059
2140
List * resultquals = NIL ;
2060
2141
ListCell * clausegroup_item ;
2142
+ int indexcol = 0 ;
2061
2143
Oid * classes = index -> classlist ;
2062
2144
2063
2145
if (clausegroups == NIL )
@@ -2073,12 +2155,32 @@ expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups)
2073
2155
{
2074
2156
RestrictInfo * rinfo = (RestrictInfo * ) lfirst (l );
2075
2157
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
+
2076
2176
resultquals = list_concat (resultquals ,
2077
2177
expand_indexqual_condition (rinfo ,
2078
- curClass ));
2178
+ curClass ));
2079
2179
}
2080
2180
2081
2181
clausegroup_item = lnext (clausegroup_item );
2182
+
2183
+ indexcol ++ ;
2082
2184
classes ++ ;
2083
2185
} while (clausegroup_item != NULL && !DoneMatchingIndexKeys (classes ));
2084
2186
@@ -2087,16 +2189,77 @@ expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups)
2087
2189
return resultquals ;
2088
2190
}
2089
2191
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
+
2090
2253
/*
2091
2254
* expand_indexqual_condition --- expand a single indexqual condition
2255
+ * (other than a boolean-qual case)
2092
2256
*
2093
2257
* The input is a single RestrictInfo, the output a list of RestrictInfos
2094
2258
*/
2095
2259
static List *
2096
2260
expand_indexqual_condition (RestrictInfo * rinfo , Oid opclass )
2097
2261
{
2098
2262
Expr * clause = rinfo -> clause ;
2099
-
2100
2263
/* we know these will succeed */
2101
2264
Node * leftop = get_leftop (clause );
2102
2265
Node * rightop = get_rightop (clause );
0 commit comments