mySQL 5.0.11 sources for tomato
[tomato.git] / release / src / router / mysql / storage / innobase / pars / pars0opt.c
blob2abe67202352458b2654ff8036a7512b89b21b8e
1 /******************************************************
2 Simple SQL optimizer
4 (c) 1997 Innobase Oy
6 Created 12/21/1997 Heikki Tuuri
7 *******************************************************/
9 #include "pars0opt.h"
11 #ifdef UNIV_NONINL
12 #include "pars0opt.ic"
13 #endif
15 #include "row0sel.h"
16 #include "row0ins.h"
17 #include "row0upd.h"
18 #include "dict0dict.h"
19 #include "dict0mem.h"
20 #include "que0que.h"
21 #include "pars0grm.h"
22 #include "pars0pars.h"
23 #include "lock0lock.h"
25 #define OPT_EQUAL 1 /* comparison by = */
26 #define OPT_COMPARISON 2 /* comparison by <, >, <=, or >= */
28 #define OPT_NOT_COND 1
29 #define OPT_END_COND 2
30 #define OPT_TEST_COND 3
31 #define OPT_SCROLL_COND 4
34 /***********************************************************************
35 Inverts a comparison operator. */
36 static
37 int
38 opt_invert_cmp_op(
39 /*==============*/
40 /* out: the equivalent operator when the order of
41 the arguments is switched */
42 int op) /* in: operator */
44 if (op == '<') {
45 return('>');
46 } else if (op == '>') {
47 return('<');
48 } else if (op == '=') {
49 return('=');
50 } else if (op == PARS_LE_TOKEN) {
51 return(PARS_GE_TOKEN);
52 } else if (op == PARS_GE_TOKEN) {
53 return(PARS_LE_TOKEN);
54 } else {
55 ut_error;
58 return(0);
61 /***********************************************************************
62 Checks if the value of an expression can be calculated BEFORE the nth table
63 in a join is accessed. If this is the case, it can possibly be used in an
64 index search for the nth table. */
65 static
66 ibool
67 opt_check_exp_determined_before(
68 /*============================*/
69 /* out: TRUE if already determined */
70 que_node_t* exp, /* in: expression */
71 sel_node_t* sel_node, /* in: select node */
72 ulint nth_table) /* in: nth table will be accessed */
74 func_node_t* func_node;
75 sym_node_t* sym_node;
76 dict_table_t* table;
77 que_node_t* arg;
78 ulint i;
80 ut_ad(exp && sel_node);
82 if (que_node_get_type(exp) == QUE_NODE_FUNC) {
83 func_node = exp;
85 arg = func_node->args;
87 while (arg) {
88 if (!opt_check_exp_determined_before(arg, sel_node,
89 nth_table)) {
90 return(FALSE);
93 arg = que_node_get_next(arg);
96 return(TRUE);
99 ut_a(que_node_get_type(exp) == QUE_NODE_SYMBOL);
101 sym_node = exp;
103 if (sym_node->token_type != SYM_COLUMN) {
105 return(TRUE);
108 for (i = 0; i < nth_table; i++) {
110 table = sel_node_get_nth_plan(sel_node, i)->table;
112 if (sym_node->table == table) {
114 return(TRUE);
118 return(FALSE);
121 /***********************************************************************
122 Looks in a comparison condition if a column value is already restricted by
123 it BEFORE the nth table is accessed. */
124 static
125 que_node_t*
126 opt_look_for_col_in_comparison_before(
127 /*==================================*/
128 /* out: expression restricting the
129 value of the column, or NULL if not
130 known */
131 ulint cmp_type, /* in: OPT_EQUAL, OPT_COMPARISON */
132 ulint col_no, /* in: column number */
133 func_node_t* search_cond, /* in: comparison condition */
134 sel_node_t* sel_node, /* in: select node */
135 ulint nth_table, /* in: nth table in a join (a query
136 from a single table is considered a
137 join of 1 table) */
138 ulint* op) /* out: comparison operator ('=',
139 PARS_GE_TOKEN, ... ); this is inverted
140 if the column appears on the right
141 side */
143 sym_node_t* sym_node;
144 dict_table_t* table;
145 que_node_t* exp;
146 que_node_t* arg;
148 ut_ad(search_cond);
150 ut_a((search_cond->func == '<')
151 || (search_cond->func == '>')
152 || (search_cond->func == '=')
153 || (search_cond->func == PARS_GE_TOKEN)
154 || (search_cond->func == PARS_LE_TOKEN));
156 table = sel_node_get_nth_plan(sel_node, nth_table)->table;
158 if ((cmp_type == OPT_EQUAL) && (search_cond->func != '=')) {
160 return(NULL);
162 } else if ((cmp_type == OPT_COMPARISON)
163 && (search_cond->func != '<')
164 && (search_cond->func != '>')
165 && (search_cond->func != PARS_GE_TOKEN)
166 && (search_cond->func != PARS_LE_TOKEN)) {
168 return(NULL);
171 arg = search_cond->args;
173 if (que_node_get_type(arg) == QUE_NODE_SYMBOL) {
174 sym_node = arg;
176 if ((sym_node->token_type == SYM_COLUMN)
177 && (sym_node->table == table)
178 && (sym_node->col_no == col_no)) {
180 /* sym_node contains the desired column id */
182 /* Check if the expression on the right side of the
183 operator is already determined */
185 exp = que_node_get_next(arg);
187 if (opt_check_exp_determined_before(exp, sel_node,
188 nth_table)) {
189 *op = search_cond->func;
191 return(exp);
196 exp = search_cond->args;
197 arg = que_node_get_next(arg);
199 if (que_node_get_type(arg) == QUE_NODE_SYMBOL) {
200 sym_node = arg;
202 if ((sym_node->token_type == SYM_COLUMN)
203 && (sym_node->table == table)
204 && (sym_node->col_no == col_no)) {
206 if (opt_check_exp_determined_before(exp, sel_node,
207 nth_table)) {
208 *op = opt_invert_cmp_op(search_cond->func);
210 return(exp);
215 return(NULL);
218 /***********************************************************************
219 Looks in a search condition if a column value is already restricted by the
220 search condition BEFORE the nth table is accessed. Takes into account that
221 if we will fetch in an ascending order, we cannot utilize an upper limit for
222 a column value; in a descending order, respectively, a lower limit. */
223 static
224 que_node_t*
225 opt_look_for_col_in_cond_before(
226 /*============================*/
227 /* out: expression restricting the
228 value of the column, or NULL if not
229 known */
230 ulint cmp_type, /* in: OPT_EQUAL, OPT_COMPARISON */
231 ulint col_no, /* in: column number */
232 func_node_t* search_cond, /* in: search condition or NULL */
233 sel_node_t* sel_node, /* in: select node */
234 ulint nth_table, /* in: nth table in a join (a query
235 from a single table is considered a
236 join of 1 table) */
237 ulint* op) /* out: comparison operator ('=',
238 PARS_GE_TOKEN, ... ) */
240 func_node_t* new_cond;
241 que_node_t* exp;
243 if (search_cond == NULL) {
245 return(NULL);
248 ut_a(que_node_get_type(search_cond) == QUE_NODE_FUNC);
249 ut_a(search_cond->func != PARS_OR_TOKEN);
250 ut_a(search_cond->func != PARS_NOT_TOKEN);
252 if (search_cond->func == PARS_AND_TOKEN) {
253 new_cond = search_cond->args;
255 exp = opt_look_for_col_in_cond_before(cmp_type, col_no,
256 new_cond, sel_node,
257 nth_table, op);
258 if (exp) {
260 return(exp);
263 new_cond = que_node_get_next(new_cond);
265 exp = opt_look_for_col_in_cond_before(cmp_type, col_no,
266 new_cond, sel_node,
267 nth_table, op);
268 return(exp);
271 exp = opt_look_for_col_in_comparison_before(cmp_type, col_no,
272 search_cond, sel_node,
273 nth_table, op);
274 if (exp == NULL) {
276 return(NULL);
279 /* If we will fetch in an ascending order, we cannot utilize an upper
280 limit for a column value; in a descending order, respectively, a lower
281 limit */
283 if (sel_node->asc && ((*op == '<') || (*op == PARS_LE_TOKEN))) {
285 return(NULL);
287 } else if (!sel_node->asc
288 && ((*op == '>') || (*op == PARS_GE_TOKEN))) {
290 return(NULL);
293 return(exp);
296 /***********************************************************************
297 Calculates the goodness for an index according to a select node. The
298 goodness is 4 times the number of first fields in index whose values we
299 already know exactly in the query. If we have a comparison condition for
300 an additional field, 2 point are added. If the index is unique, and we know
301 all the unique fields for the index we add 1024 points. For a clustered index
302 we add 1 point. */
303 static
304 ulint
305 opt_calc_index_goodness(
306 /*====================*/
307 /* out: goodness */
308 dict_index_t* index, /* in: index */
309 sel_node_t* sel_node, /* in: parsed select node */
310 ulint nth_table, /* in: nth table in a join */
311 que_node_t** index_plan, /* in/out: comparison expressions for
312 this index */
313 ulint* last_op) /* out: last comparison operator, if
314 goodness > 1 */
316 que_node_t* exp;
317 ulint goodness;
318 ulint n_fields;
319 ulint col_no;
320 ulint op;
321 ulint j;
323 goodness = 0;
325 /* Note that as higher level node pointers in the B-tree contain
326 page addresses as the last field, we must not put more fields in
327 the search tuple than dict_index_get_n_unique_in_tree(index); see
328 the note in btr_cur_search_to_nth_level. */
330 n_fields = dict_index_get_n_unique_in_tree(index);
332 for (j = 0; j < n_fields; j++) {
334 col_no = dict_index_get_nth_col_no(index, j);
336 exp = opt_look_for_col_in_cond_before(
337 OPT_EQUAL, col_no, sel_node->search_cond,
338 sel_node, nth_table, &op);
339 if (exp) {
340 /* The value for this column is exactly known already
341 at this stage of the join */
343 index_plan[j] = exp;
344 *last_op = op;
345 goodness += 4;
346 } else {
347 /* Look for non-equality comparisons */
349 exp = opt_look_for_col_in_cond_before(
350 OPT_COMPARISON, col_no, sel_node->search_cond,
351 sel_node, nth_table, &op);
352 if (exp) {
353 index_plan[j] = exp;
354 *last_op = op;
355 goodness += 2;
358 break;
362 if (goodness >= 4 * dict_index_get_n_unique(index)) {
363 goodness += 1024;
365 if (index->type & DICT_CLUSTERED) {
367 goodness += 1024;
371 /* We have to test for goodness here, as last_op may note be set */
372 if (goodness && index->type & DICT_CLUSTERED) {
374 goodness++;
377 return(goodness);
380 /***********************************************************************
381 Calculates the number of matched fields based on an index goodness. */
382 UNIV_INLINE
383 ulint
384 opt_calc_n_fields_from_goodness(
385 /*============================*/
386 /* out: number of excatly or partially matched
387 fields */
388 ulint goodness) /* in: goodness */
390 return(((goodness % 1024) + 2) / 4);
393 /***********************************************************************
394 Converts a comparison operator to the corresponding search mode PAGE_CUR_GE,
395 ... */
396 UNIV_INLINE
397 ulint
398 opt_op_to_search_mode(
399 /*==================*/
400 /* out: search mode */
401 ibool asc, /* in: TRUE if the rows should be fetched in an
402 ascending order */
403 ulint op) /* in: operator '=', PARS_GE_TOKEN, ... */
405 if (op == '=') {
406 if (asc) {
407 return(PAGE_CUR_GE);
408 } else {
409 return(PAGE_CUR_LE);
411 } else if (op == '<') {
412 ut_a(!asc);
413 return(PAGE_CUR_L);
414 } else if (op == '>') {
415 ut_a(asc);
416 return(PAGE_CUR_G);
417 } else if (op == PARS_GE_TOKEN) {
418 ut_a(asc);
419 return(PAGE_CUR_GE);
420 } else if (op == PARS_LE_TOKEN) {
421 ut_a(!asc);
422 return(PAGE_CUR_LE);
423 } else {
424 ut_error;
427 return(0);
430 /***********************************************************************
431 Determines if a node is an argument node of a function node. */
432 static
433 ibool
434 opt_is_arg(
435 /*=======*/
436 /* out: TRUE if is an argument */
437 que_node_t* arg_node, /* in: possible argument node */
438 func_node_t* func_node) /* in: function node */
440 que_node_t* arg;
442 arg = func_node->args;
444 while (arg) {
445 if (arg == arg_node) {
447 return(TRUE);
450 arg = que_node_get_next(arg);
453 return(FALSE);
456 /***********************************************************************
457 Decides if the fetching of rows should be made in a descending order, and
458 also checks that the chosen query plan produces a result which satisfies
459 the order-by. */
460 static
461 void
462 opt_check_order_by(
463 /*===============*/
464 sel_node_t* sel_node) /* in: select node; asserts an error
465 if the plan does not agree with the
466 order-by */
468 order_node_t* order_node;
469 dict_table_t* order_table;
470 ulint order_col_no;
471 plan_t* plan;
472 ulint i;
474 if (!sel_node->order_by) {
476 return;
479 order_node = sel_node->order_by;
480 order_col_no = order_node->column->col_no;
481 order_table = order_node->column->table;
483 /* If there is an order-by clause, the first non-exactly matched field
484 in the index used for the last table in the table list should be the
485 column defined in the order-by clause, and for all the other tables
486 we should get only at most a single row, otherwise we cannot presently
487 calculate the order-by, as we have no sort utility */
489 for (i = 0; i < sel_node->n_tables; i++) {
491 plan = sel_node_get_nth_plan(sel_node, i);
493 if (i < sel_node->n_tables - 1) {
494 ut_a(dict_index_get_n_unique(plan->index)
495 <= plan->n_exact_match);
496 } else {
497 ut_a(plan->table == order_table);
499 ut_a((dict_index_get_n_unique(plan->index)
500 <= plan->n_exact_match)
501 || (dict_index_get_nth_col_no(plan->index,
502 plan->n_exact_match)
503 == order_col_no));
508 /***********************************************************************
509 Optimizes a select. Decides which indexes to tables to use. The tables
510 are accessed in the order that they were written to the FROM part in the
511 select statement. */
512 static
513 void
514 opt_search_plan_for_table(
515 /*======================*/
516 sel_node_t* sel_node, /* in: parsed select node */
517 ulint i, /* in: this is the ith table */
518 dict_table_t* table) /* in: table */
520 plan_t* plan;
521 dict_index_t* index;
522 dict_index_t* best_index;
523 ulint n_fields;
524 ulint goodness;
525 ulint last_op = 75946965; /* Eliminate a Purify
526 warning */
527 ulint best_goodness;
528 ulint best_last_op = 0; /* remove warning */
529 que_node_t* index_plan[256];
530 que_node_t* best_index_plan[256];
532 plan = sel_node_get_nth_plan(sel_node, i);
534 plan->table = table;
535 plan->asc = sel_node->asc;
536 plan->pcur_is_open = FALSE;
537 plan->cursor_at_end = FALSE;
539 /* Calculate goodness for each index of the table */
541 index = dict_table_get_first_index(table);
542 best_index = index; /* Eliminate compiler warning */
543 best_goodness = 0;
545 /* should be do ... until ? comment by Jani */
546 while (index) {
547 goodness = opt_calc_index_goodness(index, sel_node, i,
548 index_plan, &last_op);
549 if (goodness > best_goodness) {
551 best_index = index;
552 best_goodness = goodness;
553 n_fields = opt_calc_n_fields_from_goodness(goodness);
555 ut_memcpy(best_index_plan, index_plan,
556 n_fields * sizeof(void*));
557 best_last_op = last_op;
560 index = dict_table_get_next_index(index);
563 plan->index = best_index;
565 n_fields = opt_calc_n_fields_from_goodness(best_goodness);
567 if (n_fields == 0) {
568 plan->tuple = NULL;
569 plan->n_exact_match = 0;
570 } else {
571 plan->tuple = dtuple_create(pars_sym_tab_global->heap,
572 n_fields);
573 dict_index_copy_types(plan->tuple, plan->index, n_fields);
575 plan->tuple_exps = mem_heap_alloc(pars_sym_tab_global->heap,
576 n_fields * sizeof(void*));
578 ut_memcpy(plan->tuple_exps, best_index_plan,
579 n_fields * sizeof(void*));
580 if (best_last_op == '=') {
581 plan->n_exact_match = n_fields;
582 } else {
583 plan->n_exact_match = n_fields - 1;
586 plan->mode = opt_op_to_search_mode(sel_node->asc,
587 best_last_op);
590 if ((best_index->type & DICT_CLUSTERED)
591 && (plan->n_exact_match >= dict_index_get_n_unique(best_index))) {
593 plan->unique_search = TRUE;
594 } else {
595 plan->unique_search = FALSE;
598 plan->old_vers_heap = NULL;
600 btr_pcur_init(&(plan->pcur));
601 btr_pcur_init(&(plan->clust_pcur));
604 /***********************************************************************
605 Looks at a comparison condition and decides if it can, and need, be tested for
606 a table AFTER the table has been accessed. */
607 static
608 ulint
609 opt_classify_comparison(
610 /*====================*/
611 /* out: OPT_NOT_COND if not for this
612 table, else OPT_END_COND,
613 OPT_TEST_COND, or OPT_SCROLL_COND,
614 where the last means that the
615 condition need not be tested, except
616 when scroll cursors are used */
617 sel_node_t* sel_node, /* in: select node */
618 ulint i, /* in: ith table in the join */
619 func_node_t* cond) /* in: comparison condition */
621 plan_t* plan;
622 ulint n_fields;
623 ulint op;
624 ulint j;
626 ut_ad(cond && sel_node);
628 plan = sel_node_get_nth_plan(sel_node, i);
630 /* Check if the condition is determined after the ith table has been
631 accessed, but not after the i - 1:th */
633 if (!opt_check_exp_determined_before(cond, sel_node, i + 1)) {
635 return(OPT_NOT_COND);
638 if ((i > 0) && opt_check_exp_determined_before(cond, sel_node, i)) {
640 return(OPT_NOT_COND);
643 /* If the condition is an exact match condition used in constructing
644 the search tuple, it is classified as OPT_END_COND */
646 if (plan->tuple) {
647 n_fields = dtuple_get_n_fields(plan->tuple);
648 } else {
649 n_fields = 0;
652 for (j = 0; j < plan->n_exact_match; j++) {
654 if (opt_is_arg(plan->tuple_exps[j], cond)) {
656 return(OPT_END_COND);
660 /* If the condition is an non-exact match condition used in
661 constructing the search tuple, it is classified as OPT_SCROLL_COND.
662 When the cursor is positioned, and if a non-scroll cursor is used,
663 there is no need to test this condition; if a scroll cursor is used
664 the testing is necessary when the cursor is reversed. */
666 if ((n_fields > plan->n_exact_match)
667 && opt_is_arg(plan->tuple_exps[n_fields - 1], cond)) {
669 return(OPT_SCROLL_COND);
672 /* If the condition is a non-exact match condition on the first field
673 in index for which there is no exact match, and it limits the search
674 range from the opposite side of the search tuple already BEFORE we
675 access the table, it is classified as OPT_END_COND */
677 if ((dict_index_get_n_fields(plan->index) > plan->n_exact_match)
678 && opt_look_for_col_in_comparison_before(
679 OPT_COMPARISON,
680 dict_index_get_nth_col_no(plan->index,
681 plan->n_exact_match),
682 cond, sel_node, i, &op)) {
684 if (sel_node->asc && ((op == '<') || (op == PARS_LE_TOKEN))) {
686 return(OPT_END_COND);
689 if (!sel_node->asc && ((op == '>') || (op == PARS_GE_TOKEN))) {
691 return(OPT_END_COND);
695 /* Otherwise, cond is classified as OPT_TEST_COND */
697 return(OPT_TEST_COND);
700 /***********************************************************************
701 Recursively looks for test conditions for a table in a join. */
702 static
703 void
704 opt_find_test_conds(
705 /*================*/
706 sel_node_t* sel_node, /* in: select node */
707 ulint i, /* in: ith table in the join */
708 func_node_t* cond) /* in: conjunction of search
709 conditions or NULL */
711 func_node_t* new_cond;
712 ulint class;
713 plan_t* plan;
715 if (cond == NULL) {
717 return;
720 if (cond->func == PARS_AND_TOKEN) {
721 new_cond = cond->args;
723 opt_find_test_conds(sel_node, i, new_cond);
725 new_cond = que_node_get_next(new_cond);
727 opt_find_test_conds(sel_node, i, new_cond);
729 return;
732 plan = sel_node_get_nth_plan(sel_node, i);
734 class = opt_classify_comparison(sel_node, i, cond);
736 if (class == OPT_END_COND) {
737 UT_LIST_ADD_LAST(cond_list, plan->end_conds, cond);
739 } else if (class == OPT_TEST_COND) {
740 UT_LIST_ADD_LAST(cond_list, plan->other_conds, cond);
745 /***********************************************************************
746 Normalizes a list of comparison conditions so that a column of the table
747 appears on the left side of the comparison if possible. This is accomplished
748 by switching the arguments of the operator. */
749 static
750 void
751 opt_normalize_cmp_conds(
752 /*====================*/
753 func_node_t* cond, /* in: first in a list of comparison
754 conditions, or NULL */
755 dict_table_t* table) /* in: table */
757 que_node_t* arg1;
758 que_node_t* arg2;
759 sym_node_t* sym_node;
761 while (cond) {
762 arg1 = cond->args;
763 arg2 = que_node_get_next(arg1);
765 if (que_node_get_type(arg2) == QUE_NODE_SYMBOL) {
767 sym_node = arg2;
769 if ((sym_node->token_type == SYM_COLUMN)
770 && (sym_node->table == table)) {
772 /* Switch the order of the arguments */
774 cond->args = arg2;
775 que_node_list_add_last(NULL, arg2);
776 que_node_list_add_last(arg2, arg1);
778 /* Invert the operator */
779 cond->func = opt_invert_cmp_op(cond->func);
783 cond = UT_LIST_GET_NEXT(cond_list, cond);
787 /***********************************************************************
788 Finds out the search condition conjuncts we can, and need, to test as the ith
789 table in a join is accessed. The search tuple can eliminate the need to test
790 some conjuncts. */
791 static
792 void
793 opt_determine_and_normalize_test_conds(
794 /*===================================*/
795 sel_node_t* sel_node, /* in: select node */
796 ulint i) /* in: ith table in the join */
798 plan_t* plan;
800 plan = sel_node_get_nth_plan(sel_node, i);
802 UT_LIST_INIT(plan->end_conds);
803 UT_LIST_INIT(plan->other_conds);
805 /* Recursively go through the conjuncts and classify them */
807 opt_find_test_conds(sel_node, i, sel_node->search_cond);
809 opt_normalize_cmp_conds(UT_LIST_GET_FIRST(plan->end_conds),
810 plan->table);
812 ut_a(UT_LIST_GET_LEN(plan->end_conds) >= plan->n_exact_match);
815 /***********************************************************************
816 Looks for occurrences of the columns of the table in the query subgraph and
817 adds them to the list of columns if an occurrence of the same column does not
818 already exist in the list. If the column is already in the list, puts a value
819 indirection to point to the occurrence in the column list, except if the
820 column occurrence we are looking at is in the column list, in which case
821 nothing is done. */
823 void
824 opt_find_all_cols(
825 /*==============*/
826 ibool copy_val, /* in: if TRUE, new found columns are
827 added as columns to copy */
828 dict_index_t* index, /* in: index of the table to use */
829 sym_node_list_t* col_list, /* in: base node of a list where
830 to add new found columns */
831 plan_t* plan, /* in: plan or NULL */
832 que_node_t* exp) /* in: expression or condition or
833 NULL */
835 func_node_t* func_node;
836 que_node_t* arg;
837 sym_node_t* sym_node;
838 sym_node_t* col_node;
839 ulint col_pos;
841 if (exp == NULL) {
843 return;
846 if (que_node_get_type(exp) == QUE_NODE_FUNC) {
847 func_node = exp;
849 arg = func_node->args;
851 while (arg) {
852 opt_find_all_cols(copy_val, index, col_list, plan,
853 arg);
854 arg = que_node_get_next(arg);
857 return;
860 ut_a(que_node_get_type(exp) == QUE_NODE_SYMBOL);
862 sym_node = exp;
864 if (sym_node->token_type != SYM_COLUMN) {
866 return;
869 if (sym_node->table != index->table) {
871 return;
874 /* Look for an occurrence of the same column in the plan column
875 list */
877 col_node = UT_LIST_GET_FIRST(*col_list);
879 while (col_node) {
880 if (col_node->col_no == sym_node->col_no) {
882 if (col_node == sym_node) {
883 /* sym_node was already in a list: do
884 nothing */
886 return;
889 /* Put an indirection */
890 sym_node->indirection = col_node;
891 sym_node->alias = col_node;
893 return;
896 col_node = UT_LIST_GET_NEXT(col_var_list, col_node);
899 /* The same column did not occur in the list: add it */
901 UT_LIST_ADD_LAST(col_var_list, *col_list, sym_node);
903 sym_node->copy_val = copy_val;
905 /* Fill in the field_no fields in sym_node */
907 sym_node->field_nos[SYM_CLUST_FIELD_NO] = dict_index_get_nth_col_pos(
908 dict_table_get_first_index(index->table), sym_node->col_no);
909 if (!(index->type & DICT_CLUSTERED)) {
911 ut_a(plan);
913 col_pos = dict_index_get_nth_col_pos(index, sym_node->col_no);
915 if (col_pos == ULINT_UNDEFINED) {
917 plan->must_get_clust = TRUE;
920 sym_node->field_nos[SYM_SEC_FIELD_NO] = col_pos;
924 /***********************************************************************
925 Looks for occurrences of the columns of the table in conditions which are
926 not yet determined AFTER the join operation has fetched a row in the ith
927 table. The values for these column must be copied to dynamic memory for
928 later use. */
929 static
930 void
931 opt_find_copy_cols(
932 /*===============*/
933 sel_node_t* sel_node, /* in: select node */
934 ulint i, /* in: ith table in the join */
935 func_node_t* search_cond) /* in: search condition or NULL */
937 func_node_t* new_cond;
938 plan_t* plan;
940 if (search_cond == NULL) {
942 return;
945 ut_ad(que_node_get_type(search_cond) == QUE_NODE_FUNC);
947 if (search_cond->func == PARS_AND_TOKEN) {
948 new_cond = search_cond->args;
950 opt_find_copy_cols(sel_node, i, new_cond);
952 new_cond = que_node_get_next(new_cond);
954 opt_find_copy_cols(sel_node, i, new_cond);
956 return;
959 if (!opt_check_exp_determined_before(search_cond, sel_node, i + 1)) {
961 /* Any ith table columns occurring in search_cond should be
962 copied, as this condition cannot be tested already on the
963 fetch from the ith table */
965 plan = sel_node_get_nth_plan(sel_node, i);
967 opt_find_all_cols(TRUE, plan->index, &(plan->columns), plan,
968 search_cond);
972 /***********************************************************************
973 Classifies the table columns according to whether we use the column only while
974 holding the latch on the page, or whether we have to copy the column value to
975 dynamic memory. Puts the first occurrence of a column to either list in the
976 plan node, and puts indirections to later occurrences of the column. */
977 static
978 void
979 opt_classify_cols(
980 /*==============*/
981 sel_node_t* sel_node, /* in: select node */
982 ulint i) /* in: ith table in the join */
984 plan_t* plan;
985 que_node_t* exp;
987 plan = sel_node_get_nth_plan(sel_node, i);
989 /* The final value of the following field will depend on the
990 environment of the select statement: */
992 plan->must_get_clust = FALSE;
994 UT_LIST_INIT(plan->columns);
996 /* All select list columns should be copied: therefore TRUE as the
997 first argument */
999 exp = sel_node->select_list;
1001 while (exp) {
1002 opt_find_all_cols(TRUE, plan->index, &(plan->columns), plan,
1003 exp);
1004 exp = que_node_get_next(exp);
1007 opt_find_copy_cols(sel_node, i, sel_node->search_cond);
1009 /* All remaining columns in the search condition are temporary
1010 columns: therefore FALSE */
1012 opt_find_all_cols(FALSE, plan->index, &(plan->columns), plan,
1013 sel_node->search_cond);
1016 /***********************************************************************
1017 Fills in the info in plan which is used in accessing a clustered index
1018 record. The columns must already be classified for the plan node. */
1019 static
1020 void
1021 opt_clust_access(
1022 /*=============*/
1023 sel_node_t* sel_node, /* in: select node */
1024 ulint n) /* in: nth table in select */
1026 plan_t* plan;
1027 dict_table_t* table;
1028 dict_index_t* clust_index;
1029 dict_index_t* index;
1030 mem_heap_t* heap;
1031 ulint n_fields;
1032 ulint pos;
1033 ulint i;
1035 plan = sel_node_get_nth_plan(sel_node, n);
1037 index = plan->index;
1039 /* The final value of the following field depends on the environment
1040 of the select statement: */
1042 plan->no_prefetch = FALSE;
1044 if (index->type & DICT_CLUSTERED) {
1045 plan->clust_map = NULL;
1046 plan->clust_ref = NULL;
1048 return;
1051 table = index->table;
1053 clust_index = dict_table_get_first_index(table);
1055 n_fields = dict_index_get_n_unique(clust_index);
1057 heap = pars_sym_tab_global->heap;
1059 plan->clust_ref = dtuple_create(heap, n_fields);
1061 dict_index_copy_types(plan->clust_ref, clust_index, n_fields);
1063 plan->clust_map = mem_heap_alloc(heap, n_fields * sizeof(ulint));
1065 for (i = 0; i < n_fields; i++) {
1066 pos = dict_index_get_nth_field_pos(index, clust_index, i);
1068 ut_a(pos != ULINT_UNDEFINED);
1070 /* We optimize here only queries to InnoDB's internal system
1071 tables, and they should not contain column prefix indexes. */
1073 if (dict_index_get_nth_field(index, pos)->prefix_len != 0
1074 || dict_index_get_nth_field(clust_index, i)
1075 ->prefix_len != 0) {
1076 fprintf(stderr,
1077 "InnoDB: Error in pars0opt.c:"
1078 " table %s has prefix_len != 0\n",
1079 index->table_name);
1082 *(plan->clust_map + i) = pos;
1084 ut_ad(pos != ULINT_UNDEFINED);
1088 /***********************************************************************
1089 Optimizes a select. Decides which indexes to tables to use. The tables
1090 are accessed in the order that they were written to the FROM part in the
1091 select statement. */
1093 void
1094 opt_search_plan(
1095 /*============*/
1096 sel_node_t* sel_node) /* in: parsed select node */
1098 sym_node_t* table_node;
1099 dict_table_t* table;
1100 order_node_t* order_by;
1101 ulint i;
1103 sel_node->plans = mem_heap_alloc(pars_sym_tab_global->heap,
1104 sel_node->n_tables * sizeof(plan_t));
1106 /* Analyze the search condition to find out what we know at each
1107 join stage about the conditions that the columns of a table should
1108 satisfy */
1110 table_node = sel_node->table_list;
1112 if (sel_node->order_by == NULL) {
1113 sel_node->asc = TRUE;
1114 } else {
1115 order_by = sel_node->order_by;
1117 sel_node->asc = order_by->asc;
1120 for (i = 0; i < sel_node->n_tables; i++) {
1122 table = table_node->table;
1124 /* Choose index through which to access the table */
1126 opt_search_plan_for_table(sel_node, i, table);
1128 /* Determine the search condition conjuncts we can test at
1129 this table; normalize the end conditions */
1131 opt_determine_and_normalize_test_conds(sel_node, i);
1133 table_node = que_node_get_next(table_node);
1136 table_node = sel_node->table_list;
1138 for (i = 0; i < sel_node->n_tables; i++) {
1140 /* Classify the table columns into those we only need to access
1141 but not copy, and to those we must copy to dynamic memory */
1143 opt_classify_cols(sel_node, i);
1145 /* Calculate possible info for accessing the clustered index
1146 record */
1148 opt_clust_access(sel_node, i);
1150 table_node = que_node_get_next(table_node);
1153 /* Check that the plan obeys a possible order-by clause: if not,
1154 an assertion error occurs */
1156 opt_check_order_by(sel_node);
1158 #ifdef UNIV_SQL_DEBUG
1159 opt_print_query_plan(sel_node);
1160 #endif
1163 /************************************************************************
1164 Prints info of a query plan. */
1166 void
1167 opt_print_query_plan(
1168 /*=================*/
1169 sel_node_t* sel_node) /* in: select node */
1171 plan_t* plan;
1172 ulint n_fields;
1173 ulint i;
1175 fputs("QUERY PLAN FOR A SELECT NODE\n", stderr);
1177 fputs(sel_node->asc ? "Asc. search; " : "Desc. search; ", stderr);
1179 if (sel_node->set_x_locks) {
1180 fputs("sets row x-locks; ", stderr);
1181 ut_a(sel_node->row_lock_mode == LOCK_X);
1182 ut_a(!sel_node->consistent_read);
1183 } else if (sel_node->consistent_read) {
1184 fputs("consistent read; ", stderr);
1185 } else {
1186 ut_a(sel_node->row_lock_mode == LOCK_S);
1187 fputs("sets row s-locks; ", stderr);
1190 putc('\n', stderr);
1192 for (i = 0; i < sel_node->n_tables; i++) {
1193 plan = sel_node_get_nth_plan(sel_node, i);
1195 if (plan->tuple) {
1196 n_fields = dtuple_get_n_fields(plan->tuple);
1197 } else {
1198 n_fields = 0;
1201 fputs("Table ", stderr);
1202 dict_index_name_print(stderr, NULL, plan->index);
1203 fprintf(stderr,"; exact m. %lu, match %lu, end conds %lu\n",
1204 (unsigned long) plan->n_exact_match,
1205 (unsigned long) n_fields,
1206 (unsigned long) UT_LIST_GET_LEN(plan->end_conds));