MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
pars0opt.cc
Go to the documentation of this file.
1 /*****************************************************************************
2 
3 Copyright (c) 1997, 2011, Oracle and/or its affiliates. All Rights Reserved.
4 
5 This program is free software; you can redistribute it and/or modify it under
6 the terms of the GNU General Public License as published by the Free Software
7 Foundation; version 2 of the License.
8 
9 This program is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12 
13 You should have received a copy of the GNU General Public License along with
14 this program; if not, write to the Free Software Foundation, Inc.,
15 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
16 
17 *****************************************************************************/
18 
19 /**************************************************/
26 #include "pars0opt.h"
27 
28 #ifdef UNIV_NONINL
29 #include "pars0opt.ic"
30 #endif
31 
32 #include "row0sel.h"
33 #include "row0ins.h"
34 #include "row0upd.h"
35 #include "dict0dict.h"
36 #include "dict0mem.h"
37 #include "que0que.h"
38 #include "pars0grm.h"
39 #include "pars0pars.h"
40 #include "lock0lock.h"
41 
42 #define OPT_EQUAL 1 /* comparison by = */
43 #define OPT_COMPARISON 2 /* comparison by <, >, <=, or >= */
44 
45 #define OPT_NOT_COND 1
46 #define OPT_END_COND 2
47 #define OPT_TEST_COND 3
48 #define OPT_SCROLL_COND 4
49 
50 
51 /*******************************************************************/
54 static
55 int
56 opt_invert_cmp_op(
57 /*==============*/
58  int op)
59 {
60  if (op == '<') {
61  return('>');
62  } else if (op == '>') {
63  return('<');
64  } else if (op == '=') {
65  return('=');
66  } else if (op == PARS_LE_TOKEN) {
67  return(PARS_GE_TOKEN);
68  } else if (op == PARS_GE_TOKEN) {
69  return(PARS_LE_TOKEN);
70  } else {
71  /* TODO: LIKE operator */
72  ut_error;
73  }
74 
75  return(0);
76 }
77 
78 /*******************************************************************/
83 static
84 ibool
85 opt_check_exp_determined_before(
86 /*============================*/
87  que_node_t* exp,
88  sel_node_t* sel_node,
89  ulint nth_table)
90 {
91  func_node_t* func_node;
92  sym_node_t* sym_node;
94  que_node_t* arg;
95  ulint i;
96 
97  ut_ad(exp && sel_node);
98 
99  if (que_node_get_type(exp) == QUE_NODE_FUNC) {
100  func_node = static_cast<func_node_t*>(exp);
101 
102  arg = func_node->args;
103 
104  while (arg) {
105  if (!opt_check_exp_determined_before(arg, sel_node,
106  nth_table)) {
107  return(FALSE);
108  }
109 
110  arg = que_node_get_next(arg);
111  }
112 
113  return(TRUE);
114  }
115 
116  ut_a(que_node_get_type(exp) == QUE_NODE_SYMBOL);
117 
118  sym_node = static_cast<sym_node_t*>(exp);
119 
120  if (sym_node->token_type != SYM_COLUMN) {
121 
122  return(TRUE);
123  }
124 
125  for (i = 0; i < nth_table; i++) {
126 
127  table = sel_node_get_nth_plan(sel_node, i)->table;
128 
129  if (sym_node->table == table) {
130 
131  return(TRUE);
132  }
133  }
134 
135  return(FALSE);
136 }
137 
138 /*******************************************************************/
142 static
143 que_node_t*
144 opt_look_for_col_in_comparison_before(
145 /*==================================*/
146  ulint cmp_type,
147  ulint col_no,
148  func_node_t* search_cond,
149  sel_node_t* sel_node,
150  ulint nth_table,
153  ulint* op)
157 {
158  sym_node_t* sym_node;
160  que_node_t* exp;
161  que_node_t* arg;
162 
163  ut_ad(search_cond);
164 
165  ut_a((search_cond->func == '<')
166  || (search_cond->func == '>')
167  || (search_cond->func == '=')
168  || (search_cond->func == PARS_GE_TOKEN)
169  || (search_cond->func == PARS_LE_TOKEN)
170  || (search_cond->func == PARS_LIKE_TOKEN_EXACT)
171  || (search_cond->func == PARS_LIKE_TOKEN_PREFIX)
172  || (search_cond->func == PARS_LIKE_TOKEN_SUFFIX)
173  || (search_cond->func == PARS_LIKE_TOKEN_SUBSTR));
174 
175  table = sel_node_get_nth_plan(sel_node, nth_table)->table;
176 
177  if ((cmp_type == OPT_EQUAL)
178  && (search_cond->func != '=')
179  && (search_cond->func != PARS_LIKE_TOKEN_EXACT)
180  && (search_cond->func != PARS_LIKE_TOKEN_PREFIX)) {
181 
182  return(NULL);
183 
184  } else if ((cmp_type == OPT_COMPARISON)
185  && (search_cond->func != '<')
186  && (search_cond->func != '>')
187  && (search_cond->func != PARS_GE_TOKEN)
188  && (search_cond->func != PARS_LE_TOKEN)
189  && (search_cond->func != PARS_LIKE_TOKEN_PREFIX)
190  && (search_cond->func != PARS_LIKE_TOKEN_SUFFIX)) {
191 
192  return(NULL);
193  }
194 
195  arg = search_cond->args;
196 
197  if (que_node_get_type(arg) == QUE_NODE_SYMBOL) {
198  sym_node = static_cast<sym_node_t*>(arg);
199 
200  if ((sym_node->token_type == SYM_COLUMN)
201  && (sym_node->table == table)
202  && (sym_node->col_no == col_no)) {
203 
204  /* sym_node contains the desired column id */
205 
206  /* Check if the expression on the right side of the
207  operator is already determined */
208 
209  exp = que_node_get_next(arg);
210 
211  if (opt_check_exp_determined_before(exp, sel_node,
212  nth_table)) {
213  *op = search_cond->func;
214 
215  return(exp);
216  }
217  }
218  }
219 
220  exp = search_cond->args;
221  arg = que_node_get_next(arg);
222 
223  if (que_node_get_type(arg) == QUE_NODE_SYMBOL) {
224  sym_node = static_cast<sym_node_t*>(arg);
225 
226  if ((sym_node->token_type == SYM_COLUMN)
227  && (sym_node->table == table)
228  && (sym_node->col_no == col_no)) {
229 
230  if (opt_check_exp_determined_before(exp, sel_node,
231  nth_table)) {
232  *op = opt_invert_cmp_op(search_cond->func);
233 
234  return(exp);
235  }
236  }
237  }
238 
239  return(NULL);
240 }
241 
242 /*******************************************************************/
248 static
249 que_node_t*
250 opt_look_for_col_in_cond_before(
251 /*============================*/
252  ulint cmp_type,
253  ulint col_no,
254  func_node_t* search_cond,
255  sel_node_t* sel_node,
256  ulint nth_table,
259  ulint* op)
261 {
262  func_node_t* new_cond;
263  que_node_t* exp;
264 
265  if (search_cond == NULL) {
266 
267  return(NULL);
268  }
269 
270  ut_a(que_node_get_type(search_cond) == QUE_NODE_FUNC);
271  ut_a(search_cond->func != PARS_OR_TOKEN);
272  ut_a(search_cond->func != PARS_NOT_TOKEN);
273 
274  if (search_cond->func == PARS_AND_TOKEN) {
275  new_cond = static_cast<func_node_t*>(search_cond->args);
276 
277  exp = opt_look_for_col_in_cond_before(cmp_type, col_no,
278  new_cond, sel_node,
279  nth_table, op);
280  if (exp) {
281 
282  return(exp);
283  }
284 
285  new_cond = static_cast<func_node_t*>(
286  que_node_get_next(new_cond));
287 
288  exp = opt_look_for_col_in_cond_before(cmp_type, col_no,
289  new_cond, sel_node,
290  nth_table, op);
291  return(exp);
292  }
293 
294  exp = opt_look_for_col_in_comparison_before(cmp_type, col_no,
295  search_cond, sel_node,
296  nth_table, op);
297  if (exp == NULL) {
298 
299  return(NULL);
300  }
301 
302  /* If we will fetch in an ascending order, we cannot utilize an upper
303  limit for a column value; in a descending order, respectively, a lower
304  limit */
305 
306  if (sel_node->asc && ((*op == '<') || (*op == PARS_LE_TOKEN))) {
307 
308  return(NULL);
309 
310  } else if (!sel_node->asc
311  && ((*op == '>') || (*op == PARS_GE_TOKEN))) {
312 
313  return(NULL);
314  }
315 
316  return(exp);
317 }
318 
319 /*******************************************************************/
327 static
328 ulint
329 opt_calc_index_goodness(
330 /*====================*/
332  sel_node_t* sel_node,
333  ulint nth_table,
334  que_node_t** index_plan,
336  ulint* last_op)
338 {
339  que_node_t* exp;
340  ulint goodness;
341  ulint n_fields;
342  ulint col_no;
343  ulint op;
344  ulint j;
345 
346  /* At least for now we don't support using FTS indexes for queries
347  done through InnoDB's own SQL parser. */
348  if (dict_index_is_online_ddl(index) || (index->type & DICT_FTS)) {
349  return(0);
350  }
351 
352  goodness = 0;
353 
354  /* Note that as higher level node pointers in the B-tree contain
355  page addresses as the last field, we must not put more fields in
356  the search tuple than dict_index_get_n_unique_in_tree(index); see
357  the note in btr_cur_search_to_nth_level. */
358 
359  n_fields = dict_index_get_n_unique_in_tree(index);
360 
361  for (j = 0; j < n_fields; j++) {
362 
363  col_no = dict_index_get_nth_col_no(index, j);
364 
365  exp = opt_look_for_col_in_cond_before(
366  OPT_EQUAL, col_no,
367  static_cast<func_node_t*>(sel_node->search_cond),
368  sel_node, nth_table, &op);
369  if (exp) {
370  /* The value for this column is exactly known already
371  at this stage of the join */
372 
373  index_plan[j] = exp;
374  *last_op = op;
375  goodness += 4;
376  } else {
377  /* Look for non-equality comparisons */
378 
379  exp = opt_look_for_col_in_cond_before(
380  OPT_COMPARISON, col_no,
381  static_cast<func_node_t*>(
382  sel_node->search_cond),
383  sel_node, nth_table, &op);
384  if (exp) {
385  index_plan[j] = exp;
386  *last_op = op;
387  goodness += 2;
388  }
389 
390  break;
391  }
392  }
393 
394  if (goodness >= 4 * dict_index_get_n_unique(index)) {
395  goodness += 1024;
396 
397  if (dict_index_is_clust(index)) {
398 
399  goodness += 1024;
400  }
401  }
402 
403  /* We have to test for goodness here, as last_op may not be set */
404  if (goodness && dict_index_is_clust(index)) {
405 
406  goodness++;
407  }
408 
409  return(goodness);
410 }
411 
412 /*******************************************************************/
415 UNIV_INLINE
416 ulint
418 /*============================*/
419  ulint goodness)
420 {
421  return(((goodness % 1024) + 2) / 4);
422 }
423 
424 /*******************************************************************/
428 UNIV_INLINE
429 ulint
431 /*==================*/
432  ibool asc,
434  ulint op)
435 {
436  if (op == '='
437  || op == PARS_LIKE_TOKEN_EXACT
438  || op == PARS_LIKE_TOKEN_PREFIX
439  || op == PARS_LIKE_TOKEN_SUFFIX
440  || op == PARS_LIKE_TOKEN_SUBSTR) {
441 
442  if (asc) {
443  return(PAGE_CUR_GE);
444  } else {
445  return(PAGE_CUR_LE);
446  }
447  } else if (op == '<') {
448  ut_a(!asc);
449  return(PAGE_CUR_L);
450  } else if (op == '>') {
451  ut_a(asc);
452  return(PAGE_CUR_G);
453  } else if (op == PARS_GE_TOKEN) {
454  ut_a(asc);
455  return(PAGE_CUR_GE);
456  } else if (op == PARS_LE_TOKEN) {
457  ut_a(!asc);
458  return(PAGE_CUR_LE);
459  } else {
460  ut_error;
461  }
462 
463  return(0);
464 }
465 
466 /*******************************************************************/
469 static
470 ibool
471 opt_is_arg(
472 /*=======*/
473  que_node_t* arg_node,
474  func_node_t* func_node)
475 {
476  que_node_t* arg;
477 
478  arg = func_node->args;
479 
480  while (arg) {
481  if (arg == arg_node) {
482 
483  return(TRUE);
484  }
485 
486  arg = que_node_get_next(arg);
487  }
488 
489  return(FALSE);
490 }
491 
492 /*******************************************************************/
496 static
497 void
498 opt_check_order_by(
499 /*===============*/
500  sel_node_t* sel_node)
503 {
504  order_node_t* order_node;
505  dict_table_t* order_table;
506  ulint order_col_no;
507  plan_t* plan;
508  ulint i;
509 
510  if (!sel_node->order_by) {
511 
512  return;
513  }
514 
515  order_node = sel_node->order_by;
516  order_col_no = order_node->column->col_no;
517  order_table = order_node->column->table;
518 
519  /* If there is an order-by clause, the first non-exactly matched field
520  in the index used for the last table in the table list should be the
521  column defined in the order-by clause, and for all the other tables
522  we should get only at most a single row, otherwise we cannot presently
523  calculate the order-by, as we have no sort utility */
524 
525  for (i = 0; i < sel_node->n_tables; i++) {
526 
527  plan = sel_node_get_nth_plan(sel_node, i);
528 
529  if (i < sel_node->n_tables - 1) {
531  <= plan->n_exact_match);
532  } else {
533  ut_a(plan->table == order_table);
534 
536  <= plan->n_exact_match)
538  plan->n_exact_match)
539  == order_col_no));
540  }
541  }
542 }
543 
544 /*******************************************************************/
548 static
549 void
550 opt_search_plan_for_table(
551 /*======================*/
552  sel_node_t* sel_node,
553  ulint i,
554  dict_table_t* table)
555 {
556  plan_t* plan;
558  dict_index_t* best_index;
559  ulint n_fields;
560  ulint goodness;
561  ulint last_op = 75946965; /* Eliminate a Purify
562  warning */
563  ulint best_goodness;
564  ulint best_last_op = 0; /* remove warning */
565  que_node_t* index_plan[256];
566  que_node_t* best_index_plan[256];
567 
568  plan = sel_node_get_nth_plan(sel_node, i);
569 
570  plan->table = table;
571  plan->asc = sel_node->asc;
572  plan->pcur_is_open = FALSE;
573  plan->cursor_at_end = FALSE;
574 
575  /* Calculate goodness for each index of the table */
576 
577  index = dict_table_get_first_index(table);
578  best_index = index; /* Eliminate compiler warning */
579  best_goodness = 0;
580 
581  /* should be do ... until ? comment by Jani */
582  while (index) {
583  goodness = opt_calc_index_goodness(index, sel_node, i,
584  index_plan, &last_op);
585  if (goodness > best_goodness) {
586 
587  best_index = index;
588  best_goodness = goodness;
589  n_fields = opt_calc_n_fields_from_goodness(goodness);
590 
591  ut_memcpy(best_index_plan, index_plan,
592  n_fields * sizeof(void*));
593  best_last_op = last_op;
594  }
595 
596  dict_table_next_uncorrupted_index(index);
597  }
598 
599  plan->index = best_index;
600 
601  n_fields = opt_calc_n_fields_from_goodness(best_goodness);
602 
603  if (n_fields == 0) {
604  plan->tuple = NULL;
605  plan->n_exact_match = 0;
606  } else {
607  plan->tuple = dtuple_create(pars_sym_tab_global->heap,
608  n_fields);
609  dict_index_copy_types(plan->tuple, plan->index, n_fields);
610 
611  plan->tuple_exps = static_cast<que_node_t**>(
613  pars_sym_tab_global->heap,
614  n_fields * sizeof(void*)));
615 
616  ut_memcpy(plan->tuple_exps, best_index_plan,
617  n_fields * sizeof(void*));
618  if (best_last_op == '='
619  || best_last_op == PARS_LIKE_TOKEN_EXACT
620  || best_last_op == PARS_LIKE_TOKEN_PREFIX
621  || best_last_op == PARS_LIKE_TOKEN_SUFFIX
622  || best_last_op == PARS_LIKE_TOKEN_SUBSTR) {
623  plan->n_exact_match = n_fields;
624  } else {
625  plan->n_exact_match = n_fields - 1;
626  }
627 
628  plan->mode = opt_op_to_search_mode(sel_node->asc,
629  best_last_op);
630  }
631 
632  if (dict_index_is_clust(best_index)
633  && (plan->n_exact_match >= dict_index_get_n_unique(best_index))) {
634 
635  plan->unique_search = TRUE;
636  } else {
637  plan->unique_search = FALSE;
638  }
639 
640  plan->old_vers_heap = NULL;
641 
642  btr_pcur_init(&(plan->pcur));
643  btr_pcur_init(&(plan->clust_pcur));
644 }
645 
646 /*******************************************************************/
652 static
653 ulint
654 opt_classify_comparison(
655 /*====================*/
656  sel_node_t* sel_node,
657  ulint i,
658  func_node_t* cond)
659 {
660  plan_t* plan;
661  ulint n_fields;
662  ulint op;
663  ulint j;
664 
665  ut_ad(cond && sel_node);
666 
667  plan = sel_node_get_nth_plan(sel_node, i);
668 
669  /* Check if the condition is determined after the ith table has been
670  accessed, but not after the i - 1:th */
671 
672  if (!opt_check_exp_determined_before(cond, sel_node, i + 1)) {
673 
674  return(OPT_NOT_COND);
675  }
676 
677  if ((i > 0) && opt_check_exp_determined_before(cond, sel_node, i)) {
678 
679  return(OPT_NOT_COND);
680  }
681 
682  /* If the condition is an exact match condition used in constructing
683  the search tuple, it is classified as OPT_END_COND */
684 
685  if (plan->tuple) {
686  n_fields = dtuple_get_n_fields(plan->tuple);
687  } else {
688  n_fields = 0;
689  }
690 
691  for (j = 0; j < plan->n_exact_match; j++) {
692 
693  if (opt_is_arg(plan->tuple_exps[j], cond)) {
694 
695  return(OPT_END_COND);
696  }
697  }
698 
699  /* If the condition is an non-exact match condition used in
700  constructing the search tuple, it is classified as OPT_SCROLL_COND.
701  When the cursor is positioned, and if a non-scroll cursor is used,
702  there is no need to test this condition; if a scroll cursor is used
703  the testing is necessary when the cursor is reversed. */
704 
705  if ((n_fields > plan->n_exact_match)
706  && opt_is_arg(plan->tuple_exps[n_fields - 1], cond)) {
707 
708  return(OPT_SCROLL_COND);
709  }
710 
711  /* If the condition is a non-exact match condition on the first field
712  in index for which there is no exact match, and it limits the search
713  range from the opposite side of the search tuple already BEFORE we
714  access the table, it is classified as OPT_END_COND */
715 
716  if ((dict_index_get_n_fields(plan->index) > plan->n_exact_match)
717  && opt_look_for_col_in_comparison_before(
718  OPT_COMPARISON,
720  plan->n_exact_match),
721  cond, sel_node, i, &op)) {
722 
723  if (sel_node->asc && ((op == '<') || (op == PARS_LE_TOKEN))) {
724 
725  return(OPT_END_COND);
726  }
727 
728  if (!sel_node->asc && ((op == '>') || (op == PARS_GE_TOKEN))) {
729 
730  return(OPT_END_COND);
731  }
732  }
733 
734  /* Otherwise, cond is classified as OPT_TEST_COND */
735 
736  return(OPT_TEST_COND);
737 }
738 
739 /*******************************************************************/
741 static
742 void
743 opt_find_test_conds(
744 /*================*/
745  sel_node_t* sel_node,
746  ulint i,
747  func_node_t* cond)
749 {
750  func_node_t* new_cond;
751  ulint fclass;
752  plan_t* plan;
753 
754  if (cond == NULL) {
755 
756  return;
757  }
758 
759  if (cond->func == PARS_AND_TOKEN) {
760  new_cond = static_cast<func_node_t*>(cond->args);
761 
762  opt_find_test_conds(sel_node, i, new_cond);
763 
764  new_cond = static_cast<func_node_t*>(
765  que_node_get_next(new_cond));
766 
767  opt_find_test_conds(sel_node, i, new_cond);
768 
769  return;
770  }
771 
772  plan = sel_node_get_nth_plan(sel_node, i);
773 
774  fclass = opt_classify_comparison(sel_node, i, cond);
775 
776  if (fclass == OPT_END_COND) {
777  UT_LIST_ADD_LAST(cond_list, plan->end_conds, cond);
778 
779  } else if (fclass == OPT_TEST_COND) {
780  UT_LIST_ADD_LAST(cond_list, plan->other_conds, cond);
781 
782  }
783 }
784 
785 /*******************************************************************/
789 static
790 void
791 opt_normalize_cmp_conds(
792 /*====================*/
793  func_node_t* cond,
795  dict_table_t* table)
796 {
797  que_node_t* arg1;
798  que_node_t* arg2;
799  sym_node_t* sym_node;
800 
801  while (cond) {
802  arg1 = cond->args;
803  arg2 = que_node_get_next(arg1);
804 
805  if (que_node_get_type(arg2) == QUE_NODE_SYMBOL) {
806 
807  sym_node = static_cast<sym_node_t*>(arg2);
808 
809  if ((sym_node->token_type == SYM_COLUMN)
810  && (sym_node->table == table)) {
811 
812  /* Switch the order of the arguments */
813 
814  cond->args = arg2;
815  que_node_list_add_last(NULL, arg2);
816  que_node_list_add_last(arg2, arg1);
817 
818  /* Invert the operator */
819  cond->func = opt_invert_cmp_op(cond->func);
820  }
821  }
822 
823  cond = UT_LIST_GET_NEXT(cond_list, cond);
824  }
825 }
826 
827 /*******************************************************************/
831 static
832 void
833 opt_determine_and_normalize_test_conds(
834 /*===================================*/
835  sel_node_t* sel_node,
836  ulint i)
837 {
838  plan_t* plan;
839 
840  plan = sel_node_get_nth_plan(sel_node, i);
841 
842  UT_LIST_INIT(plan->end_conds);
843  UT_LIST_INIT(plan->other_conds);
844 
845  /* Recursively go through the conjuncts and classify them */
846 
847  opt_find_test_conds(
848  sel_node,
849  i,
850  static_cast<func_node_t*>(sel_node->search_cond));
851 
852  opt_normalize_cmp_conds(UT_LIST_GET_FIRST(plan->end_conds),
853  plan->table);
854 
855  ut_a(UT_LIST_GET_LEN(plan->end_conds) >= plan->n_exact_match);
856 }
857 
858 /*******************************************************************/
865 UNIV_INTERN
866 void
868 /*==============*/
869  ibool copy_val,
871  dict_index_t* index,
872  sym_node_list_t* col_list,
874  plan_t* plan,
875  que_node_t* exp)
877 {
878  func_node_t* func_node;
879  que_node_t* arg;
880  sym_node_t* sym_node;
881  sym_node_t* col_node;
882  ulint col_pos;
883 
884  if (exp == NULL) {
885 
886  return;
887  }
888 
889  if (que_node_get_type(exp) == QUE_NODE_FUNC) {
890  func_node = static_cast<func_node_t*>(exp);
891 
892  for (arg = func_node->args;
893  arg != 0;
894  arg = que_node_get_next(arg)) {
895 
897  copy_val, index, col_list, plan, arg);
898  }
899 
900  return;
901  }
902 
903  ut_a(que_node_get_type(exp) == QUE_NODE_SYMBOL);
904 
905  sym_node = static_cast<sym_node_t*>(exp);
906 
907  if (sym_node->token_type != SYM_COLUMN) {
908 
909  return;
910  }
911 
912  if (sym_node->table != index->table) {
913 
914  return;
915  }
916 
917  /* Look for an occurrence of the same column in the plan column
918  list */
919 
920  col_node = UT_LIST_GET_FIRST(*col_list);
921 
922  while (col_node) {
923  if (col_node->col_no == sym_node->col_no) {
924 
925  if (col_node == sym_node) {
926  /* sym_node was already in a list: do
927  nothing */
928 
929  return;
930  }
931 
932  /* Put an indirection */
933  sym_node->indirection = col_node;
934  sym_node->alias = col_node;
935 
936  return;
937  }
938 
939  col_node = UT_LIST_GET_NEXT(col_var_list, col_node);
940  }
941 
942  /* The same column did not occur in the list: add it */
943 
944  UT_LIST_ADD_LAST(col_var_list, *col_list, sym_node);
945 
946  sym_node->copy_val = copy_val;
947 
948  /* Fill in the field_no fields in sym_node */
949 
951  dict_table_get_first_index(index->table), sym_node->col_no);
952  if (!dict_index_is_clust(index)) {
953 
954  ut_a(plan);
955 
956  col_pos = dict_index_get_nth_col_pos(index, sym_node->col_no);
957 
958  if (col_pos == ULINT_UNDEFINED) {
959 
960  plan->must_get_clust = TRUE;
961  }
962 
963  sym_node->field_nos[SYM_SEC_FIELD_NO] = col_pos;
964  }
965 }
966 
967 /*******************************************************************/
972 static
973 void
974 opt_find_copy_cols(
975 /*===============*/
976  sel_node_t* sel_node,
977  ulint i,
978  func_node_t* search_cond)
979 {
980  func_node_t* new_cond;
981  plan_t* plan;
982 
983  if (search_cond == NULL) {
984 
985  return;
986  }
987 
988  ut_ad(que_node_get_type(search_cond) == QUE_NODE_FUNC);
989 
990  if (search_cond->func == PARS_AND_TOKEN) {
991  new_cond = static_cast<func_node_t*>(search_cond->args);
992 
993  opt_find_copy_cols(sel_node, i, new_cond);
994 
995  new_cond = static_cast<func_node_t*>(
996  que_node_get_next(new_cond));
997 
998  opt_find_copy_cols(sel_node, i, new_cond);
999 
1000  return;
1001  }
1002 
1003  if (!opt_check_exp_determined_before(search_cond, sel_node, i + 1)) {
1004 
1005  /* Any ith table columns occurring in search_cond should be
1006  copied, as this condition cannot be tested already on the
1007  fetch from the ith table */
1008 
1009  plan = sel_node_get_nth_plan(sel_node, i);
1010 
1011  opt_find_all_cols(TRUE, plan->index, &(plan->columns), plan,
1012  search_cond);
1013  }
1014 }
1015 
1016 /*******************************************************************/
1021 static
1022 void
1023 opt_classify_cols(
1024 /*==============*/
1025  sel_node_t* sel_node,
1026  ulint i)
1027 {
1028  plan_t* plan;
1029  que_node_t* exp;
1030 
1031  plan = sel_node_get_nth_plan(sel_node, i);
1032 
1033  /* The final value of the following field will depend on the
1034  environment of the select statement: */
1035 
1036  plan->must_get_clust = FALSE;
1037 
1038  UT_LIST_INIT(plan->columns);
1039 
1040  /* All select list columns should be copied: therefore TRUE as the
1041  first argument */
1042 
1043  for (exp = sel_node->select_list;
1044  exp != 0;
1045  exp = que_node_get_next(exp)) {
1046 
1048  TRUE, plan->index, &(plan->columns), plan, exp);
1049  }
1050 
1051  opt_find_copy_cols(
1052  sel_node, i, static_cast<func_node_t*>(sel_node->search_cond));
1053 
1054  /* All remaining columns in the search condition are temporary
1055  columns: therefore FALSE */
1056 
1058  FALSE, plan->index, &plan->columns, plan,
1059  static_cast<func_node_t*>(sel_node->search_cond));
1060 }
1061 
1062 /*******************************************************************/
1065 static
1066 void
1067 opt_clust_access(
1068 /*=============*/
1069  sel_node_t* sel_node,
1070  ulint n)
1071 {
1072  plan_t* plan;
1074  dict_index_t* clust_index;
1076  mem_heap_t* heap;
1077  ulint n_fields;
1078  ulint pos;
1079  ulint i;
1080 
1081  plan = sel_node_get_nth_plan(sel_node, n);
1082 
1083  index = plan->index;
1084 
1085  /* The final value of the following field depends on the environment
1086  of the select statement: */
1087 
1088  plan->no_prefetch = FALSE;
1089 
1090  if (dict_index_is_clust(index)) {
1091  plan->clust_map = NULL;
1092  plan->clust_ref = NULL;
1093 
1094  return;
1095  }
1096 
1097  table = index->table;
1098 
1099  clust_index = dict_table_get_first_index(table);
1100 
1101  n_fields = dict_index_get_n_unique(clust_index);
1102 
1103  heap = pars_sym_tab_global->heap;
1104 
1105  plan->clust_ref = dtuple_create(heap, n_fields);
1106 
1107  dict_index_copy_types(plan->clust_ref, clust_index, n_fields);
1108 
1109  plan->clust_map = static_cast<ulint*>(
1110  mem_heap_alloc(heap, n_fields * sizeof(ulint)));
1111 
1112  for (i = 0; i < n_fields; i++) {
1113  pos = dict_index_get_nth_field_pos(index, clust_index, i);
1114 
1115  ut_a(pos != ULINT_UNDEFINED);
1116 
1117  /* We optimize here only queries to InnoDB's internal system
1118  tables, and they should not contain column prefix indexes. */
1119 
1120  if (dict_index_get_nth_field(index, pos)->prefix_len != 0
1121  || dict_index_get_nth_field(clust_index, i)
1122  ->prefix_len != 0) {
1123  fprintf(stderr,
1124  "InnoDB: Error in pars0opt.cc:"
1125  " table %s has prefix_len != 0\n",
1126  index->table_name);
1127  }
1128 
1129  *(plan->clust_map + i) = pos;
1130 
1131  ut_ad(pos != ULINT_UNDEFINED);
1132  }
1133 }
1134 
1135 /*******************************************************************/
1139 UNIV_INTERN
1140 void
1142 /*============*/
1143  sel_node_t* sel_node)
1144 {
1145  sym_node_t* table_node;
1147  order_node_t* order_by;
1148  ulint i;
1149 
1150  sel_node->plans = static_cast<plan_t*>(
1152  pars_sym_tab_global->heap,
1153  sel_node->n_tables * sizeof(plan_t)));
1154 
1155  /* Analyze the search condition to find out what we know at each
1156  join stage about the conditions that the columns of a table should
1157  satisfy */
1158 
1159  table_node = sel_node->table_list;
1160 
1161  if (sel_node->order_by == NULL) {
1162  sel_node->asc = TRUE;
1163  } else {
1164  order_by = sel_node->order_by;
1165 
1166  sel_node->asc = order_by->asc;
1167  }
1168 
1169  for (i = 0; i < sel_node->n_tables; i++) {
1170 
1171  table = table_node->table;
1172 
1173  /* Choose index through which to access the table */
1174 
1175  opt_search_plan_for_table(sel_node, i, table);
1176 
1177  /* Determine the search condition conjuncts we can test at
1178  this table; normalize the end conditions */
1179 
1180  opt_determine_and_normalize_test_conds(sel_node, i);
1181 
1182  table_node = static_cast<sym_node_t*>(
1183  que_node_get_next(table_node));
1184  }
1185 
1186  table_node = sel_node->table_list;
1187 
1188  for (i = 0; i < sel_node->n_tables; i++) {
1189 
1190  /* Classify the table columns into those we only need to access
1191  but not copy, and to those we must copy to dynamic memory */
1192 
1193  opt_classify_cols(sel_node, i);
1194 
1195  /* Calculate possible info for accessing the clustered index
1196  record */
1197 
1198  opt_clust_access(sel_node, i);
1199 
1200  table_node = static_cast<sym_node_t*>(
1201  que_node_get_next(table_node));
1202  }
1203 
1204  /* Check that the plan obeys a possible order-by clause: if not,
1205  an assertion error occurs */
1206 
1207  opt_check_order_by(sel_node);
1208 
1209 #ifdef UNIV_SQL_DEBUG
1210  opt_print_query_plan(sel_node);
1211 #endif
1212 }
1213 
1214 /********************************************************************/
1216 UNIV_INTERN
1217 void
1219 /*=================*/
1220  sel_node_t* sel_node)
1221 {
1222  plan_t* plan;
1223  ulint n_fields;
1224  ulint i;
1225 
1226  fputs("QUERY PLAN FOR A SELECT NODE\n", stderr);
1227 
1228  fputs(sel_node->asc ? "Asc. search; " : "Desc. search; ", stderr);
1229 
1230  if (sel_node->set_x_locks) {
1231  fputs("sets row x-locks; ", stderr);
1232  ut_a(sel_node->row_lock_mode == LOCK_X);
1233  ut_a(!sel_node->consistent_read);
1234  } else if (sel_node->consistent_read) {
1235  fputs("consistent read; ", stderr);
1236  } else {
1237  ut_a(sel_node->row_lock_mode == LOCK_S);
1238  fputs("sets row s-locks; ", stderr);
1239  }
1240 
1241  putc('\n', stderr);
1242 
1243  for (i = 0; i < sel_node->n_tables; i++) {
1244  plan = sel_node_get_nth_plan(sel_node, i);
1245 
1246  if (plan->tuple) {
1247  n_fields = dtuple_get_n_fields(plan->tuple);
1248  } else {
1249  n_fields = 0;
1250  }
1251 
1252  fputs("Table ", stderr);
1253  dict_index_name_print(stderr, NULL, plan->index);
1254  fprintf(stderr,"; exact m. %lu, match %lu, end conds %lu\n",
1255  (unsigned long) plan->n_exact_match,
1256  (unsigned long) n_fields,
1257  (unsigned long) UT_LIST_GET_LEN(plan->end_conds));
1258  }
1259 }