| 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 02111-1301 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 | |
| 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 | |
| 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 (MY_TEST(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 (MY_TEST(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 | |
| 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 (cond->type() == Item::COND_ITEM) |
| 268 | { |
| 269 | table_map tbl_map= 0; |
| 270 | if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC) |
| 271 | { |
| 272 | /* Create new top level AND item */ |
| 273 | Item_cond_and *new_cond= new (thd->mem_root) Item_cond_and(thd); |
| 274 | if (!new_cond) |
| 275 | return (COND*) 0; |
| 276 | List_iterator<Item> li(*((Item_cond*) cond)->argument_list()); |
| 277 | Item *item; |
| 278 | while ((item=li++)) |
| 279 | { |
| 280 | Item *fix= make_cond_remainder(thd, item, table, keyno, |
| 281 | other_tbls_ok, exclude_index); |
| 282 | if (fix) |
| 283 | { |
| 284 | new_cond->argument_list()->push_back(fix, thd->mem_root); |
| 285 | tbl_map |= fix->used_tables(); |
| 286 | } |
| 287 | } |
| 288 | switch (new_cond->argument_list()->elements) { |
| 289 | case 0: |
| 290 | return (COND*) 0; |
| 291 | case 1: |
| 292 | return new_cond->argument_list()->head(); |
| 293 | default: |
| 294 | new_cond->quick_fix_field(); |
| 295 | ((Item_cond*)new_cond)->used_tables_cache= tbl_map; |
| 296 | return new_cond; |
| 297 | } |
| 298 | } |
| 299 | else /* It's OR */ |
| 300 | { |
| 301 | Item_cond_or *new_cond= new (thd->mem_root) Item_cond_or(thd); |
| 302 | if (!new_cond) |
| 303 | return (COND*) 0; |
| 304 | List_iterator<Item> li(*((Item_cond*) cond)->argument_list()); |
| 305 | Item *item; |
| 306 | while ((item=li++)) |
| 307 | { |
| 308 | Item *fix= make_cond_remainder(thd, item, table, keyno, |
| 309 | other_tbls_ok, FALSE); |
| 310 | if (!fix) |
| 311 | return (COND*) 0; |
| 312 | new_cond->argument_list()->push_back(fix, thd->mem_root); |
| 313 | tbl_map |= fix->used_tables(); |
| 314 | } |
| 315 | new_cond->quick_fix_field(); |
| 316 | ((Item_cond*)new_cond)->used_tables_cache= tbl_map; |
| 317 | new_cond->top_level_item(); |
| 318 | return new_cond; |
| 319 | } |
| 320 | } |
| 321 | else |
| 322 | { |
| 323 | if (exclude_index && |
| 324 | uses_index_fields_only(cond, table, keyno, other_tbls_ok)) |
| 325 | return 0; |
| 326 | else |
| 327 | return cond; |
| 328 | } |
| 329 | } |
| 330 | |
| 331 | |
| 332 | /* |
| 333 | Try to extract and push the index condition |
| 334 | |
| 335 | SYNOPSIS |
| 336 | push_index_cond() |
| 337 | tab A join tab that has tab->table->file and its condition |
| 338 | in tab->select_cond |
| 339 | keyno Index for which extract and push the condition |
| 340 | |
| 341 | DESCRIPTION |
| 342 | Try to extract and push the index condition down to table handler |
| 343 | */ |
| 344 | |
| 345 | void push_index_cond(JOIN_TAB *tab, uint keyno) |
| 346 | { |
| 347 | DBUG_ENTER("push_index_cond" ); |
| 348 | Item *idx_cond; |
| 349 | |
| 350 | /* |
| 351 | Backported the following from MySQL 5.6: |
| 352 | 6. The index is not a clustered index. The performance improvement |
| 353 | of pushing an index condition on a clustered key is much lower |
| 354 | than on a non-clustered key. This restriction should be |
| 355 | re-evaluated when WL#6061 is implemented. |
| 356 | */ |
| 357 | if ((tab->table->file->index_flags(keyno, 0, 1) & |
| 358 | HA_DO_INDEX_COND_PUSHDOWN) && |
| 359 | optimizer_flag(tab->join->thd, OPTIMIZER_SWITCH_INDEX_COND_PUSHDOWN) && |
| 360 | tab->join->thd->lex->sql_command != SQLCOM_UPDATE_MULTI && |
| 361 | tab->join->thd->lex->sql_command != SQLCOM_DELETE_MULTI && |
| 362 | tab->type != JT_CONST && tab->type != JT_SYSTEM && |
| 363 | !(keyno == tab->table->s->primary_key && // (6) |
| 364 | tab->table->file->primary_key_is_clustered())) // (6) |
| 365 | |
| 366 | { |
| 367 | DBUG_EXECUTE("where" , |
| 368 | print_where(tab->select_cond, "full cond" , QT_ORDINARY);); |
| 369 | |
| 370 | idx_cond= make_cond_for_index(tab->join->thd, tab->select_cond, tab->table, |
| 371 | keyno, tab->icp_other_tables_ok); |
| 372 | |
| 373 | DBUG_EXECUTE("where" , |
| 374 | print_where(idx_cond, "idx cond" , QT_ORDINARY);); |
| 375 | |
| 376 | if (idx_cond) |
| 377 | { |
| 378 | Item *idx_remainder_cond= 0; |
| 379 | tab->pre_idx_push_select_cond= tab->select_cond; |
| 380 | /* |
| 381 | For BKA cache we store condition to special BKA cache field |
| 382 | because evaluation of the condition requires additional operations |
| 383 | before the evaluation. This condition is used in |
| 384 | JOIN_CACHE_BKA[_UNIQUE]::skip_index_tuple() functions. |
| 385 | */ |
| 386 | if (tab->use_join_cache && |
| 387 | /* |
| 388 | if cache is used then the value is TRUE only |
| 389 | for BKA[_UNIQUE] cache (see check_join_cache_usage func). |
| 390 | */ |
| 391 | tab->icp_other_tables_ok && |
| 392 | (idx_cond->used_tables() & |
| 393 | ~(tab->table->map | tab->join->const_table_map))) |
| 394 | tab->cache_idx_cond= idx_cond; |
| 395 | else |
| 396 | idx_remainder_cond= tab->table->file->idx_cond_push(keyno, idx_cond); |
| 397 | |
| 398 | /* |
| 399 | Disable eq_ref's "lookup cache" if we've pushed down an index |
| 400 | condition. |
| 401 | TODO: This check happens to work on current ICP implementations, but |
| 402 | there may exist a compliant implementation that will not work |
| 403 | correctly with it. Sort this out when we stabilize the condition |
| 404 | pushdown APIs. |
| 405 | */ |
| 406 | if (idx_remainder_cond != idx_cond) |
| 407 | tab->ref.disable_cache= TRUE; |
| 408 | |
| 409 | Item *row_cond= tab->idx_cond_fact_out ? |
| 410 | make_cond_remainder(tab->join->thd, tab->select_cond, |
| 411 | tab->table, keyno, |
| 412 | tab->icp_other_tables_ok, TRUE) : |
| 413 | tab->pre_idx_push_select_cond; |
| 414 | |
| 415 | DBUG_EXECUTE("where" , |
| 416 | print_where(row_cond, "remainder cond" , QT_ORDINARY);); |
| 417 | |
| 418 | if (row_cond) |
| 419 | { |
| 420 | if (!idx_remainder_cond) |
| 421 | tab->select_cond= row_cond; |
| 422 | else |
| 423 | { |
| 424 | COND *new_cond= new (tab->join->thd->mem_root) |
| 425 | Item_cond_and(tab->join->thd, row_cond, idx_remainder_cond); |
| 426 | tab->select_cond= new_cond; |
| 427 | tab->select_cond->quick_fix_field(); |
| 428 | ((Item_cond_and*)tab->select_cond)->used_tables_cache= |
| 429 | row_cond->used_tables() | idx_remainder_cond->used_tables(); |
| 430 | } |
| 431 | } |
| 432 | else |
| 433 | tab->select_cond= idx_remainder_cond; |
| 434 | if (tab->select) |
| 435 | { |
| 436 | DBUG_EXECUTE("where" , |
| 437 | print_where(tab->select->cond, |
| 438 | "select_cond" , |
| 439 | QT_ORDINARY);); |
| 440 | |
| 441 | tab->select->cond= tab->select_cond; |
| 442 | tab->select->pre_idx_push_select_cond= tab->pre_idx_push_select_cond; |
| 443 | } |
| 444 | } |
| 445 | } |
| 446 | DBUG_VOID_RETURN; |
| 447 | } |
| 448 | |
| 449 | |
| 450 | |