|
9 | 9 | *
|
10 | 10 | *
|
11 | 11 | * IDENTIFICATION
|
12 |
| - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.99 2000/11/25 20:33:51 tgl Exp $ |
| 12 | + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.100 2000/12/14 22:30:43 tgl Exp $ |
13 | 13 | *
|
14 | 14 | *-------------------------------------------------------------------------
|
15 | 15 | */
|
@@ -87,11 +87,6 @@ static void indexable_joinclauses(RelOptInfo *rel, IndexOptInfo *index,
|
87 | 87 | List **clausegroups, List **outerrelids);
|
88 | 88 | static List *index_innerjoin(Query *root, RelOptInfo *rel, IndexOptInfo *index,
|
89 | 89 | List *clausegroup_list, List *outerrelids_list);
|
90 |
| -static bool useful_for_mergejoin(RelOptInfo *rel, IndexOptInfo *index, |
91 |
| - List *joininfo_list); |
92 |
| -static bool useful_for_ordering(Query *root, RelOptInfo *rel, |
93 |
| - IndexOptInfo *index, |
94 |
| - ScanDirection scandir); |
95 | 90 | static bool match_index_to_operand(int indexkey, Var *operand,
|
96 | 91 | RelOptInfo *rel, IndexOptInfo *index);
|
97 | 92 | static bool function_index_operand(Expr *funcOpnd, RelOptInfo *rel,
|
@@ -125,31 +120,31 @@ static Const *string_to_const(const char *str, Oid datatype);
|
125 | 120 | * attributes are available and fixed during any one scan of the indexpath.
|
126 | 121 | *
|
127 | 122 | * An IndexPath is generated and submitted to add_path() for each index
|
128 |
| - * this routine deems potentially interesting for the current query |
129 |
| - * (at most one IndexPath per index on the given relation). An innerjoin |
130 |
| - * path is also generated for each interesting combination of outer join |
131 |
| - * relations. The innerjoin paths are *not* passed to add_path(), but are |
132 |
| - * appended to the "innerjoin" list of the relation for later consideration |
133 |
| - * in nested-loop joins. |
| 123 | + * this routine deems potentially interesting for the current query. |
| 124 | + * An innerjoin path is also generated for each interesting combination of |
| 125 | + * outer join relations. The innerjoin paths are *not* passed to add_path(), |
| 126 | + * but are appended to the "innerjoin" list of the relation for later |
| 127 | + * consideration in nested-loop joins. |
134 | 128 | *
|
135 | 129 | * 'rel' is the relation for which we want to generate index paths
|
136 | 130 | * 'indices' is a list of available indexes for 'rel'
|
137 |
| - * 'restrictinfo_list' is a list of restrictinfo nodes for 'rel' |
138 |
| - * 'joininfo_list' is a list of joininfo nodes for 'rel' |
139 | 131 | */
|
140 | 132 | void
|
141 | 133 | create_index_paths(Query *root,
|
142 | 134 | RelOptInfo *rel,
|
143 |
| - List *indices, |
144 |
| - List *restrictinfo_list, |
145 |
| - List *joininfo_list) |
| 135 | + List *indices) |
146 | 136 | {
|
| 137 | + List *restrictinfo_list = rel->baserestrictinfo; |
| 138 | + List *joininfo_list = rel->joininfo; |
147 | 139 | List *ilist;
|
148 | 140 |
|
149 | 141 | foreach(ilist, indices)
|
150 | 142 | {
|
151 | 143 | IndexOptInfo *index = (IndexOptInfo *) lfirst(ilist);
|
152 | 144 | List *restrictclauses;
|
| 145 | + List *index_pathkeys; |
| 146 | + List *useful_pathkeys; |
| 147 | + bool index_is_ordered; |
153 | 148 | List *joinclausegroups;
|
154 | 149 | List *joinouterrelids;
|
155 | 150 |
|
@@ -179,53 +174,58 @@ create_index_paths(Query *root,
|
179 | 174 | match_index_orclauses(rel, index, restrictinfo_list);
|
180 | 175 |
|
181 | 176 | /*
|
182 |
| - * 2. If the keys of this index match any of the available |
183 |
| - * non-'or' restriction clauses, then create a path using those |
184 |
| - * clauses as indexquals. |
| 177 | + * 2. Match the index against non-'or' restriction clauses. |
185 | 178 | */
|
186 | 179 | restrictclauses = group_clauses_by_indexkey(rel,
|
187 | 180 | index,
|
188 | 181 | index->indexkeys,
|
189 | 182 | index->classlist,
|
190 | 183 | restrictinfo_list);
|
191 | 184 |
|
192 |
| - if (restrictclauses != NIL) |
193 |
| - add_path(rel, (Path *) create_index_path(root, rel, index, |
194 |
| - restrictclauses, |
195 |
| - NoMovementScanDirection)); |
196 |
| - |
197 | 185 | /*
|
198 |
| - * 3. If this index can be used for a mergejoin, then create an |
199 |
| - * index path for it even if there were no restriction clauses. |
200 |
| - * (If there were, there is no need to make another index path.) |
201 |
| - * This will allow the index to be considered as a base for a |
202 |
| - * mergejoin in later processing. Similarly, if the index matches |
203 |
| - * the ordering that is needed for the overall query result, make |
204 |
| - * an index path for it even if there is no other reason to do so. |
| 186 | + * 3. Compute pathkeys describing index's ordering, if any, |
| 187 | + * then see how many of them are actually useful for this query. |
205 | 188 | */
|
206 |
| - if (restrictclauses == NIL) |
207 |
| - { |
208 |
| - if (useful_for_mergejoin(rel, index, joininfo_list) || |
209 |
| - useful_for_ordering(root, rel, index, ForwardScanDirection)) |
210 |
| - add_path(rel, (Path *) |
211 |
| - create_index_path(root, rel, index, |
212 |
| - restrictclauses, |
213 |
| - ForwardScanDirection)); |
214 |
| - } |
| 189 | + index_pathkeys = build_index_pathkeys(root, rel, index, |
| 190 | + ForwardScanDirection); |
| 191 | + index_is_ordered = (index_pathkeys != NIL); |
| 192 | + useful_pathkeys = truncate_useless_pathkeys(root, rel, |
| 193 | + index_pathkeys); |
215 | 194 |
|
216 | 195 | /*
|
217 |
| - * Currently, backwards scan is never considered except for the |
218 |
| - * case of matching a query result ordering. Possibly should |
219 |
| - * consider it in other places? |
| 196 | + * 4. Generate an indexscan path if there are relevant restriction |
| 197 | + * clauses OR the index ordering is potentially useful for later |
| 198 | + * merging or final output ordering. |
220 | 199 | */
|
221 |
| - if (useful_for_ordering(root, rel, index, BackwardScanDirection)) |
| 200 | + if (restrictclauses != NIL || useful_pathkeys != NIL) |
222 | 201 | add_path(rel, (Path *)
|
223 | 202 | create_index_path(root, rel, index,
|
224 | 203 | restrictclauses,
|
225 |
| - BackwardScanDirection)); |
| 204 | + useful_pathkeys, |
| 205 | + index_is_ordered ? |
| 206 | + ForwardScanDirection : |
| 207 | + NoMovementScanDirection)); |
| 208 | + |
| 209 | + /* |
| 210 | + * 5. If the index is ordered, a backwards scan might be interesting. |
| 211 | + * Currently this is only possible for a DESC query result ordering. |
| 212 | + */ |
| 213 | + if (index_is_ordered) |
| 214 | + { |
| 215 | + index_pathkeys = build_index_pathkeys(root, rel, index, |
| 216 | + BackwardScanDirection); |
| 217 | + useful_pathkeys = truncate_useless_pathkeys(root, rel, |
| 218 | + index_pathkeys); |
| 219 | + if (useful_pathkeys != NIL) |
| 220 | + add_path(rel, (Path *) |
| 221 | + create_index_path(root, rel, index, |
| 222 | + restrictclauses, |
| 223 | + useful_pathkeys, |
| 224 | + BackwardScanDirection)); |
| 225 | + } |
226 | 226 |
|
227 | 227 | /*
|
228 |
| - * 4. Create an innerjoin index path for each combination of other |
| 228 | + * 6. Create an innerjoin index path for each combination of other |
229 | 229 | * rels used in available join clauses. These paths will be
|
230 | 230 | * considered as the inner side of nestloop joins against those
|
231 | 231 | * sets of other rels. indexable_joinclauses() finds sets of
|
@@ -904,88 +904,6 @@ indexable_operator(Expr *clause, Oid opclass, Oid relam,
|
904 | 904 | return InvalidOid;
|
905 | 905 | }
|
906 | 906 |
|
907 |
| -/* |
908 |
| - * useful_for_mergejoin |
909 |
| - * Determine whether the given index can support a mergejoin based |
910 |
| - * on any available join clause. |
911 |
| - * |
912 |
| - * We look to see whether the first indexkey of the index matches the |
913 |
| - * left or right sides of any of the mergejoinable clauses and provides |
914 |
| - * the ordering needed for that side. If so, the index is useful. |
915 |
| - * Matching a second or later indexkey is not useful unless there is |
916 |
| - * also a mergeclause for the first indexkey, so we need not consider |
917 |
| - * secondary indexkeys at this stage. |
918 |
| - * |
919 |
| - * 'rel' is the relation for which 'index' is defined |
920 |
| - * 'joininfo_list' is the list of JoinInfo nodes for 'rel' |
921 |
| - */ |
922 |
| -static bool |
923 |
| -useful_for_mergejoin(RelOptInfo *rel, |
924 |
| - IndexOptInfo *index, |
925 |
| - List *joininfo_list) |
926 |
| -{ |
927 |
| - int *indexkeys = index->indexkeys; |
928 |
| - Oid *ordering = index->ordering; |
929 |
| - List *i; |
930 |
| - |
931 |
| - if (!indexkeys || indexkeys[0] == 0 || |
932 |
| - !ordering || ordering[0] == InvalidOid) |
933 |
| - return false; /* unordered index is not useful */ |
934 |
| - |
935 |
| - foreach(i, joininfo_list) |
936 |
| - { |
937 |
| - JoinInfo *joininfo = (JoinInfo *) lfirst(i); |
938 |
| - List *j; |
939 |
| - |
940 |
| - foreach(j, joininfo->jinfo_restrictinfo) |
941 |
| - { |
942 |
| - RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(j); |
943 |
| - |
944 |
| - if (restrictinfo->mergejoinoperator) |
945 |
| - { |
946 |
| - if (restrictinfo->left_sortop == ordering[0] && |
947 |
| - match_index_to_operand(indexkeys[0], |
948 |
| - get_leftop(restrictinfo->clause), |
949 |
| - rel, index)) |
950 |
| - return true; |
951 |
| - if (restrictinfo->right_sortop == ordering[0] && |
952 |
| - match_index_to_operand(indexkeys[0], |
953 |
| - get_rightop(restrictinfo->clause), |
954 |
| - rel, index)) |
955 |
| - return true; |
956 |
| - } |
957 |
| - } |
958 |
| - } |
959 |
| - return false; |
960 |
| -} |
961 |
| - |
962 |
| -/* |
963 |
| - * useful_for_ordering |
964 |
| - * Determine whether the given index can produce an ordering matching |
965 |
| - * the order that is wanted for the query result. |
966 |
| - * |
967 |
| - * 'rel' is the relation for which 'index' is defined |
968 |
| - * 'scandir' is the contemplated scan direction |
969 |
| - */ |
970 |
| -static bool |
971 |
| -useful_for_ordering(Query *root, |
972 |
| - RelOptInfo *rel, |
973 |
| - IndexOptInfo *index, |
974 |
| - ScanDirection scandir) |
975 |
| -{ |
976 |
| - List *index_pathkeys; |
977 |
| - |
978 |
| - if (root->query_pathkeys == NIL) |
979 |
| - return false; /* no special ordering requested */ |
980 |
| - |
981 |
| - index_pathkeys = build_index_pathkeys(root, rel, index, scandir); |
982 |
| - |
983 |
| - if (index_pathkeys == NIL) |
984 |
| - return false; /* unordered index */ |
985 |
| - |
986 |
| - return pathkeys_contained_in(root->query_pathkeys, index_pathkeys); |
987 |
| -} |
988 |
| - |
989 | 907 | /****************************************************************************
|
990 | 908 | * ---- ROUTINES TO DO PARTIAL INDEX PREDICATE TESTS ----
|
991 | 909 | ****************************************************************************/
|
|
0 commit comments