1 /*
2 Copyright (c) 2009, 2012, Monty Program Ab
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; version 2 of the License.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
16
17 #include "mariadb.h"
18 #include "sql_select.h"
19 #include "sql_test.h"
20
21 /****************************************************************************
22 * Index Condition Pushdown code starts
23 ***************************************************************************/
24 /*
25 Check if given expression uses only table fields covered by the given index
26
27 SYNOPSIS
28 uses_index_fields_only()
29 item Expression to check
30 tbl The table having the index
31 keyno The index number
32 other_tbls_ok TRUE <=> Fields of other non-const tables are allowed
33
34 DESCRIPTION
35 Check if given expression only uses fields covered by index #keyno in the
36 table tbl. The expression can use any fields in any other tables.
37
38 The expression is guaranteed not to be AND or OR - those constructs are
39 handled outside of this function.
40
41 RETURN
42 TRUE Yes
43 FALSE No
44 */
45
uses_index_fields_only(Item * item,TABLE * tbl,uint keyno,bool other_tbls_ok)46 bool uses_index_fields_only(Item *item, TABLE *tbl, uint keyno,
47 bool other_tbls_ok)
48 {
49 if (item->walk(&Item::limit_index_condition_pushdown_processor, FALSE, NULL))
50 {
51 return FALSE;
52 }
53
54 if (item->const_item())
55 return TRUE;
56
57 /*
58 Don't push down the triggered conditions. Nested outer joins execution
59 code may need to evaluate a condition several times (both triggered and
60 untriggered), and there is no way to put thi
61 TODO: Consider cloning the triggered condition and using the copies for:
62 1. push the first copy down, to have most restrictive index condition
63 possible
64 2. Put the second copy into tab->select_cond.
65 */
66 if (item->type() == Item::FUNC_ITEM &&
67 ((Item_func*)item)->functype() == Item_func::TRIG_COND_FUNC)
68 return FALSE;
69
70 if (!(item->used_tables() & tbl->map))
71 return other_tbls_ok;
72
73 Item::Type item_type= item->type();
74 switch (item_type) {
75 case Item::FUNC_ITEM:
76 {
77 /* This is a function, apply condition recursively to arguments */
78 Item_func *item_func= (Item_func*)item;
79 Item **child;
80 Item **item_end= (item_func->arguments()) + item_func->argument_count();
81 for (child= item_func->arguments(); child != item_end; child++)
82 {
83 if (!uses_index_fields_only(*child, tbl, keyno, other_tbls_ok))
84 return FALSE;
85 }
86 return TRUE;
87 }
88 case Item::COND_ITEM:
89 {
90 /*
91 This is a AND/OR condition. Regular AND/OR clauses are handled by
92 make_cond_for_index() which will chop off the part that can be
93 checked with index. This code is for handling non-top-level AND/ORs,
94 e.g. func(x AND y).
95 */
96 List_iterator<Item> li(*((Item_cond*)item)->argument_list());
97 Item *item;
98 while ((item=li++))
99 {
100 if (!uses_index_fields_only(item, tbl, keyno, other_tbls_ok))
101 return FALSE;
102 }
103 return TRUE;
104 }
105 case Item::FIELD_ITEM:
106 {
107 Item_field *item_field= (Item_field*)item;
108 Field *field= item_field->field;
109 if (field->table != tbl)
110 return TRUE;
111 /*
112 The below is probably a repetition - the first part checks the
113 other two, but let's play it safe:
114 */
115 if(!field->part_of_key.is_set(keyno) ||
116 field->type() == MYSQL_TYPE_GEOMETRY ||
117 field->type() == MYSQL_TYPE_BLOB)
118 return FALSE;
119 KEY *key_info= tbl->key_info + keyno;
120 KEY_PART_INFO *key_part= key_info->key_part;
121 KEY_PART_INFO *key_part_end= key_part + key_info->user_defined_key_parts;
122 for ( ; key_part < key_part_end; key_part++)
123 {
124 if (field->eq(key_part->field))
125 return !(key_part->key_part_flag & HA_PART_KEY_SEG);
126 }
127 if ((tbl->file->ha_table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX) &&
128 tbl->s->primary_key != MAX_KEY &&
129 tbl->s->primary_key != keyno)
130 {
131 key_info= tbl->key_info + tbl->s->primary_key;
132 key_part= key_info->key_part;
133 key_part_end= key_part + key_info->user_defined_key_parts;
134 for ( ; key_part < key_part_end; key_part++)
135 {
136 /*
137 It does not make sense to use the fact that the engine can read in
138 a full field if the key if the index is built only over a part
139 of this field.
140 */
141 if (field->eq(key_part->field))
142 return !(key_part->key_part_flag & HA_PART_KEY_SEG);
143 }
144 }
145 return FALSE;
146 }
147 case Item::REF_ITEM:
148 return uses_index_fields_only(item->real_item(), tbl, keyno,
149 other_tbls_ok);
150 default:
151 return FALSE; /* Play it safe, don't push unknown non-const items */
152 }
153 }
154
155 #define ICP_COND_USES_INDEX_ONLY 10
156
157 /*
158 Get a part of the condition that can be checked using only index fields
159
160 SYNOPSIS
161 make_cond_for_index()
162 cond The source condition
163 table The table that is partially available
164 keyno The index in the above table. Only fields covered by the index
165 are available
166 other_tbls_ok TRUE <=> Fields of other non-const tables are allowed
167
168 DESCRIPTION
169 Get a part of the condition that can be checked when for the given table
170 we have values only of fields covered by some index. The condition may
171 refer to other tables, it is assumed that we have values of all of their
172 fields.
173
174 Example:
175 make_cond_for_index(
176 "cond(t1.field) AND cond(t2.key1) AND cond(t2.non_key) AND cond(t2.key2)",
177 t2, keyno(t2.key1))
178 will return
179 "cond(t1.field) AND cond(t2.key2)"
180
181 RETURN
182 Index condition, or NULL if no condition could be inferred.
183 */
184
make_cond_for_index(THD * thd,Item * cond,TABLE * table,uint keyno,bool other_tbls_ok)185 static Item *make_cond_for_index(THD *thd, Item *cond, TABLE *table, uint keyno,
186 bool other_tbls_ok)
187 {
188 if (!cond)
189 return NULL;
190 if (cond->type() == Item::COND_ITEM)
191 {
192 uint n_marked= 0;
193 if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)
194 {
195 table_map used_tables= 0;
196 Item_cond_and *new_cond= new (thd->mem_root) Item_cond_and(thd);
197 if (!new_cond)
198 return (COND*) 0;
199 List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
200 Item *item;
201 while ((item=li++))
202 {
203 Item *fix= make_cond_for_index(thd, item, table, keyno, other_tbls_ok);
204 if (fix)
205 {
206 new_cond->argument_list()->push_back(fix, thd->mem_root);
207 used_tables|= fix->used_tables();
208 }
209 if (item->marker == ICP_COND_USES_INDEX_ONLY)
210 {
211 n_marked++;
212 item->marker= 0;
213 }
214 }
215 if (n_marked ==((Item_cond*)cond)->argument_list()->elements)
216 cond->marker= ICP_COND_USES_INDEX_ONLY;
217 switch (new_cond->argument_list()->elements) {
218 case 0:
219 return (COND*) 0;
220 case 1:
221 new_cond->used_tables_cache= used_tables;
222 return new_cond->argument_list()->head();
223 default:
224 new_cond->quick_fix_field();
225 new_cond->used_tables_cache= used_tables;
226 return new_cond;
227 }
228 }
229 else /* It's OR */
230 {
231 Item_cond_or *new_cond= new (thd->mem_root) Item_cond_or(thd);
232 if (!new_cond)
233 return (COND*) 0;
234 List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
235 Item *item;
236 while ((item=li++))
237 {
238 Item *fix= make_cond_for_index(thd, item, table, keyno, other_tbls_ok);
239 if (!fix)
240 return (COND*) 0;
241 new_cond->argument_list()->push_back(fix, thd->mem_root);
242 if (item->marker == ICP_COND_USES_INDEX_ONLY)
243 {
244 n_marked++;
245 item->marker= 0;
246 }
247 }
248 if (n_marked ==((Item_cond*)cond)->argument_list()->elements)
249 cond->marker= ICP_COND_USES_INDEX_ONLY;
250 new_cond->quick_fix_field();
251 new_cond->used_tables_cache= ((Item_cond_or*) cond)->used_tables_cache;
252 new_cond->top_level_item();
253 return new_cond;
254 }
255 }
256
257 if (!uses_index_fields_only(cond, table, keyno, other_tbls_ok))
258 return (COND*) 0;
259 cond->marker= ICP_COND_USES_INDEX_ONLY;
260 return cond;
261 }
262
263
make_cond_remainder(THD * thd,Item * cond,TABLE * table,uint keyno,bool other_tbls_ok,bool exclude_index)264 static Item *make_cond_remainder(THD *thd, Item *cond, TABLE *table, uint keyno,
265 bool other_tbls_ok, bool exclude_index)
266 {
267 if (exclude_index &&
268 uses_index_fields_only(cond, table, keyno, other_tbls_ok))
269 return 0;
270
271 if (cond->type() == Item::COND_ITEM)
272 {
273 table_map tbl_map= 0;
274 if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)
275 {
276 /* Create new top level AND item */
277 Item_cond_and *new_cond= new (thd->mem_root) Item_cond_and(thd);
278 if (!new_cond)
279 return (COND*) 0;
280 List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
281 Item *item;
282 while ((item=li++))
283 {
284 Item *fix= make_cond_remainder(thd, item, table, keyno,
285 other_tbls_ok, exclude_index);
286 if (fix)
287 {
288 new_cond->argument_list()->push_back(fix, thd->mem_root);
289 tbl_map |= fix->used_tables();
290 }
291 }
292 switch (new_cond->argument_list()->elements) {
293 case 0:
294 return (COND*) 0;
295 case 1:
296 return new_cond->argument_list()->head();
297 default:
298 new_cond->quick_fix_field();
299 ((Item_cond*)new_cond)->used_tables_cache= tbl_map;
300 return new_cond;
301 }
302 }
303 else /* It's OR */
304 {
305 Item_cond_or *new_cond= new (thd->mem_root) Item_cond_or(thd);
306 if (!new_cond)
307 return (COND*) 0;
308 List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
309 Item *item;
310 while ((item=li++))
311 {
312 Item *fix= make_cond_remainder(thd, item, table, keyno,
313 other_tbls_ok, FALSE);
314 if (!fix)
315 return (COND*) 0;
316 new_cond->argument_list()->push_back(fix, thd->mem_root);
317 tbl_map |= fix->used_tables();
318 }
319 new_cond->quick_fix_field();
320 ((Item_cond*)new_cond)->used_tables_cache= tbl_map;
321 new_cond->top_level_item();
322 return new_cond;
323 }
324 }
325 return cond;
326 }
327
328
329 /*
330 Try to extract and push the index condition
331
332 SYNOPSIS
333 push_index_cond()
334 tab A join tab that has tab->table->file and its condition
335 in tab->select_cond
336 keyno Index for which extract and push the condition
337
338 DESCRIPTION
339 Try to extract and push the index condition down to table handler
340 */
341
push_index_cond(JOIN_TAB * tab,uint keyno)342 void push_index_cond(JOIN_TAB *tab, uint keyno)
343 {
344 DBUG_ENTER("push_index_cond");
345 Item *idx_cond;
346
347 /*
348 Backported the following from MySQL 5.6:
349 6. The index is not a clustered index. The performance improvement
350 of pushing an index condition on a clustered key is much lower
351 than on a non-clustered key. This restriction should be
352 re-evaluated when WL#6061 is implemented.
353 */
354 if ((tab->table->file->index_flags(keyno, 0, 1) &
355 HA_DO_INDEX_COND_PUSHDOWN) &&
356 optimizer_flag(tab->join->thd, OPTIMIZER_SWITCH_INDEX_COND_PUSHDOWN) &&
357 tab->join->thd->lex->sql_command != SQLCOM_UPDATE_MULTI &&
358 tab->join->thd->lex->sql_command != SQLCOM_DELETE_MULTI &&
359 tab->type != JT_CONST && tab->type != JT_SYSTEM &&
360 !tab->table->file->is_clustering_key(keyno)) // 6
361 {
362 DBUG_EXECUTE("where",
363 print_where(tab->select_cond, "full cond", QT_ORDINARY););
364
365 idx_cond= make_cond_for_index(tab->join->thd, tab->select_cond, tab->table,
366 keyno, tab->icp_other_tables_ok);
367
368 DBUG_EXECUTE("where",
369 print_where(idx_cond, "idx cond", QT_ORDINARY););
370
371 if (idx_cond)
372 {
373 Item *idx_remainder_cond= 0;
374 tab->pre_idx_push_select_cond= tab->select_cond;
375 /*
376 For BKA cache we store condition to special BKA cache field
377 because evaluation of the condition requires additional operations
378 before the evaluation. This condition is used in
379 JOIN_CACHE_BKA[_UNIQUE]::skip_index_tuple() functions.
380 */
381 if (tab->use_join_cache &&
382 /*
383 if cache is used then the value is TRUE only
384 for BKA[_UNIQUE] cache (see check_join_cache_usage func).
385 */
386 tab->icp_other_tables_ok &&
387 (idx_cond->used_tables() &
388 ~(tab->table->map | tab->join->const_table_map)))
389 tab->cache_idx_cond= idx_cond;
390 else
391 {
392 idx_remainder_cond= tab->table->file->idx_cond_push(keyno, idx_cond);
393
394 /*
395 If (1) there is an index condition that we couldn't push using ICP,
396 (2) we are using Join Buffering
397 (3) and we are using BKA
398 then use BKA's Index Condition Pushdown mechanism to check it.
399 */
400 if (idx_remainder_cond && tab->use_join_cache && // (1) && (2)
401 tab->icp_other_tables_ok) // (3)
402 {
403 tab->cache_idx_cond= idx_remainder_cond;
404 idx_remainder_cond= NULL;
405 }
406 }
407
408 /*
409 Disable eq_ref's "lookup cache" if we've pushed down an index
410 condition.
411 TODO: This check happens to work on current ICP implementations, but
412 there may exist a compliant implementation that will not work
413 correctly with it. Sort this out when we stabilize the condition
414 pushdown APIs.
415 */
416 if (idx_remainder_cond != idx_cond)
417 tab->ref.disable_cache= TRUE;
418
419 Item *row_cond= tab->idx_cond_fact_out ?
420 make_cond_remainder(tab->join->thd, tab->select_cond,
421 tab->table, keyno,
422 tab->icp_other_tables_ok, TRUE) :
423 tab->pre_idx_push_select_cond;
424
425 DBUG_EXECUTE("where",
426 print_where(row_cond, "remainder cond", QT_ORDINARY););
427
428 if (row_cond)
429 {
430 if (!idx_remainder_cond)
431 tab->select_cond= row_cond;
432 else
433 {
434 COND *new_cond= new (tab->join->thd->mem_root)
435 Item_cond_and(tab->join->thd, row_cond, idx_remainder_cond);
436 tab->select_cond= new_cond;
437 tab->select_cond->quick_fix_field();
438 ((Item_cond_and*)tab->select_cond)->used_tables_cache=
439 row_cond->used_tables() | idx_remainder_cond->used_tables();
440 }
441 }
442 else
443 tab->select_cond= idx_remainder_cond;
444 if (tab->select)
445 {
446 DBUG_EXECUTE("where",
447 print_where(tab->select->cond,
448 "select_cond",
449 QT_ORDINARY););
450
451 tab->select->cond= tab->select_cond;
452 tab->select->pre_idx_push_select_cond= tab->pre_idx_push_select_cond;
453 }
454 }
455 }
456 DBUG_VOID_RETURN;
457 }
458
459
460