1 /*****************************************************************************
3 Copyright (c) 1997, 2009, Innobase Oy. All Rights Reserved.
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.
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.
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 St, Fifth Floor, Boston, MA 02110-1301 USA
17 *****************************************************************************/
19 /**************************************************//**
23 Created 12/21/1997 Heikki Tuuri
24 *******************************************************/
29 #include "pars0opt.ic"
35 #include "dict0dict.h"
39 #include "pars0pars.h"
40 #include "lock0lock.h"
42 #define OPT_EQUAL 1 /* comparison by = */
43 #define OPT_COMPARISON 2 /* comparison by <, >, <=, or >= */
45 #define OPT_NOT_COND 1
46 #define OPT_END_COND 2
47 #define OPT_TEST_COND 3
48 #define OPT_SCROLL_COND 4
51 /*******************************************************************//**
52 Inverts a comparison operator.
53 @return the equivalent operator when the order of the arguments is switched */
58 int op
) /*!< in: operator */
62 } else if (op
== '>') {
64 } else if (op
== '=') {
66 } else if (op
== PARS_LE_TOKEN
) {
67 return(PARS_GE_TOKEN
);
68 } else if (op
== PARS_GE_TOKEN
) {
69 return(PARS_LE_TOKEN
);
77 /*******************************************************************//**
78 Checks if the value of an expression can be calculated BEFORE the nth table
79 in a join is accessed. If this is the case, it can possibly be used in an
80 index search for the nth table.
81 @return TRUE if already determined */
84 opt_check_exp_determined_before(
85 /*============================*/
86 que_node_t
* exp
, /*!< in: expression */
87 sel_node_t
* sel_node
, /*!< in: select node */
88 ulint nth_table
) /*!< in: nth table will be accessed */
90 func_node_t
* func_node
;
96 ut_ad(exp
&& sel_node
);
98 if (que_node_get_type(exp
) == QUE_NODE_FUNC
) {
101 arg
= func_node
->args
;
104 if (!opt_check_exp_determined_before(arg
, sel_node
,
109 arg
= que_node_get_next(arg
);
115 ut_a(que_node_get_type(exp
) == QUE_NODE_SYMBOL
);
119 if (sym_node
->token_type
!= SYM_COLUMN
) {
124 for (i
= 0; i
< nth_table
; i
++) {
126 table
= sel_node_get_nth_plan(sel_node
, i
)->table
;
128 if (sym_node
->table
== table
) {
137 /*******************************************************************//**
138 Looks in a comparison condition if a column value is already restricted by
139 it BEFORE the nth table is accessed.
140 @return expression restricting the value of the column, or NULL if not known */
143 opt_look_for_col_in_comparison_before(
144 /*==================================*/
145 ulint cmp_type
, /*!< in: OPT_EQUAL, OPT_COMPARISON */
146 ulint col_no
, /*!< in: column number */
147 func_node_t
* search_cond
, /*!< in: comparison condition */
148 sel_node_t
* sel_node
, /*!< in: select node */
149 ulint nth_table
, /*!< in: nth table in a join (a query
150 from a single table is considered a
152 ulint
* op
) /*!< out: comparison operator ('=',
153 PARS_GE_TOKEN, ... ); this is inverted
154 if the column appears on the right
157 sym_node_t
* sym_node
;
164 ut_a((search_cond
->func
== '<')
165 || (search_cond
->func
== '>')
166 || (search_cond
->func
== '=')
167 || (search_cond
->func
== PARS_GE_TOKEN
)
168 || (search_cond
->func
== PARS_LE_TOKEN
));
170 table
= sel_node_get_nth_plan(sel_node
, nth_table
)->table
;
172 if ((cmp_type
== OPT_EQUAL
) && (search_cond
->func
!= '=')) {
176 } else if ((cmp_type
== OPT_COMPARISON
)
177 && (search_cond
->func
!= '<')
178 && (search_cond
->func
!= '>')
179 && (search_cond
->func
!= PARS_GE_TOKEN
)
180 && (search_cond
->func
!= PARS_LE_TOKEN
)) {
185 arg
= search_cond
->args
;
187 if (que_node_get_type(arg
) == QUE_NODE_SYMBOL
) {
190 if ((sym_node
->token_type
== SYM_COLUMN
)
191 && (sym_node
->table
== table
)
192 && (sym_node
->col_no
== col_no
)) {
194 /* sym_node contains the desired column id */
196 /* Check if the expression on the right side of the
197 operator is already determined */
199 exp
= que_node_get_next(arg
);
201 if (opt_check_exp_determined_before(exp
, sel_node
,
203 *op
= search_cond
->func
;
210 exp
= search_cond
->args
;
211 arg
= que_node_get_next(arg
);
213 if (que_node_get_type(arg
) == QUE_NODE_SYMBOL
) {
216 if ((sym_node
->token_type
== SYM_COLUMN
)
217 && (sym_node
->table
== table
)
218 && (sym_node
->col_no
== col_no
)) {
220 if (opt_check_exp_determined_before(exp
, sel_node
,
222 *op
= opt_invert_cmp_op(search_cond
->func
);
232 /*******************************************************************//**
233 Looks in a search condition if a column value is already restricted by the
234 search condition BEFORE the nth table is accessed. Takes into account that
235 if we will fetch in an ascending order, we cannot utilize an upper limit for
236 a column value; in a descending order, respectively, a lower limit.
237 @return expression restricting the value of the column, or NULL if not known */
240 opt_look_for_col_in_cond_before(
241 /*============================*/
242 ulint cmp_type
, /*!< in: OPT_EQUAL, OPT_COMPARISON */
243 ulint col_no
, /*!< in: column number */
244 func_node_t
* search_cond
, /*!< in: search condition or NULL */
245 sel_node_t
* sel_node
, /*!< in: select node */
246 ulint nth_table
, /*!< in: nth table in a join (a query
247 from a single table is considered a
249 ulint
* op
) /*!< out: comparison operator ('=',
250 PARS_GE_TOKEN, ... ) */
252 func_node_t
* new_cond
;
255 if (search_cond
== NULL
) {
260 ut_a(que_node_get_type(search_cond
) == QUE_NODE_FUNC
);
261 ut_a(search_cond
->func
!= PARS_OR_TOKEN
);
262 ut_a(search_cond
->func
!= PARS_NOT_TOKEN
);
264 if (search_cond
->func
== PARS_AND_TOKEN
) {
265 new_cond
= search_cond
->args
;
267 exp
= opt_look_for_col_in_cond_before(cmp_type
, col_no
,
275 new_cond
= que_node_get_next(new_cond
);
277 exp
= opt_look_for_col_in_cond_before(cmp_type
, col_no
,
283 exp
= opt_look_for_col_in_comparison_before(cmp_type
, col_no
,
284 search_cond
, sel_node
,
291 /* If we will fetch in an ascending order, we cannot utilize an upper
292 limit for a column value; in a descending order, respectively, a lower
295 if (sel_node
->asc
&& ((*op
== '<') || (*op
== PARS_LE_TOKEN
))) {
299 } else if (!sel_node
->asc
300 && ((*op
== '>') || (*op
== PARS_GE_TOKEN
))) {
308 /*******************************************************************//**
309 Calculates the goodness for an index according to a select node. The
310 goodness is 4 times the number of first fields in index whose values we
311 already know exactly in the query. If we have a comparison condition for
312 an additional field, 2 point are added. If the index is unique, and we know
313 all the unique fields for the index we add 1024 points. For a clustered index
318 opt_calc_index_goodness(
319 /*====================*/
320 dict_index_t
* index
, /*!< in: index */
321 sel_node_t
* sel_node
, /*!< in: parsed select node */
322 ulint nth_table
, /*!< in: nth table in a join */
323 que_node_t
** index_plan
, /*!< in/out: comparison expressions for
325 ulint
* last_op
) /*!< out: last comparison operator, if
337 /* Note that as higher level node pointers in the B-tree contain
338 page addresses as the last field, we must not put more fields in
339 the search tuple than dict_index_get_n_unique_in_tree(index); see
340 the note in btr_cur_search_to_nth_level. */
342 n_fields
= dict_index_get_n_unique_in_tree(index
);
344 for (j
= 0; j
< n_fields
; j
++) {
346 col_no
= dict_index_get_nth_col_no(index
, j
);
348 exp
= opt_look_for_col_in_cond_before(
349 OPT_EQUAL
, col_no
, sel_node
->search_cond
,
350 sel_node
, nth_table
, &op
);
352 /* The value for this column is exactly known already
353 at this stage of the join */
359 /* Look for non-equality comparisons */
361 exp
= opt_look_for_col_in_cond_before(
362 OPT_COMPARISON
, col_no
, sel_node
->search_cond
,
363 sel_node
, nth_table
, &op
);
374 if (goodness
>= 4 * dict_index_get_n_unique(index
)) {
377 if (dict_index_is_clust(index
)) {
383 /* We have to test for goodness here, as last_op may note be set */
384 if (goodness
&& dict_index_is_clust(index
)) {
392 /*******************************************************************//**
393 Calculates the number of matched fields based on an index goodness.
394 @return number of excatly or partially matched fields */
397 opt_calc_n_fields_from_goodness(
398 /*============================*/
399 ulint goodness
) /*!< in: goodness */
401 return(((goodness
% 1024) + 2) / 4);
404 /*******************************************************************//**
405 Converts a comparison operator to the corresponding search mode PAGE_CUR_GE,
407 @return search mode */
410 opt_op_to_search_mode(
411 /*==================*/
412 ibool asc
, /*!< in: TRUE if the rows should be fetched in an
414 ulint op
) /*!< in: operator '=', PARS_GE_TOKEN, ... */
422 } else if (op
== '<') {
425 } else if (op
== '>') {
428 } else if (op
== PARS_GE_TOKEN
) {
431 } else if (op
== PARS_LE_TOKEN
) {
441 /*******************************************************************//**
442 Determines if a node is an argument node of a function node.
443 @return TRUE if is an argument */
448 que_node_t
* arg_node
, /*!< in: possible argument node */
449 func_node_t
* func_node
) /*!< in: function node */
453 arg
= func_node
->args
;
456 if (arg
== arg_node
) {
461 arg
= que_node_get_next(arg
);
467 /*******************************************************************//**
468 Decides if the fetching of rows should be made in a descending order, and
469 also checks that the chosen query plan produces a result which satisfies
475 sel_node_t
* sel_node
) /*!< in: select node; asserts an error
476 if the plan does not agree with the
479 order_node_t
* order_node
;
480 dict_table_t
* order_table
;
485 if (!sel_node
->order_by
) {
490 order_node
= sel_node
->order_by
;
491 order_col_no
= order_node
->column
->col_no
;
492 order_table
= order_node
->column
->table
;
494 /* If there is an order-by clause, the first non-exactly matched field
495 in the index used for the last table in the table list should be the
496 column defined in the order-by clause, and for all the other tables
497 we should get only at most a single row, otherwise we cannot presently
498 calculate the order-by, as we have no sort utility */
500 for (i
= 0; i
< sel_node
->n_tables
; i
++) {
502 plan
= sel_node_get_nth_plan(sel_node
, i
);
504 if (i
< sel_node
->n_tables
- 1) {
505 ut_a(dict_index_get_n_unique(plan
->index
)
506 <= plan
->n_exact_match
);
508 ut_a(plan
->table
== order_table
);
510 ut_a((dict_index_get_n_unique(plan
->index
)
511 <= plan
->n_exact_match
)
512 || (dict_index_get_nth_col_no(plan
->index
,
519 /*******************************************************************//**
520 Optimizes a select. Decides which indexes to tables to use. The tables
521 are accessed in the order that they were written to the FROM part in the
525 opt_search_plan_for_table(
526 /*======================*/
527 sel_node_t
* sel_node
, /*!< in: parsed select node */
528 ulint i
, /*!< in: this is the ith table */
529 dict_table_t
* table
) /*!< in: table */
533 dict_index_t
* best_index
;
536 ulint last_op
= 75946965; /* Eliminate a Purify
539 ulint best_last_op
= 0; /* remove warning */
540 que_node_t
* index_plan
[256];
541 que_node_t
* best_index_plan
[256];
543 plan
= sel_node_get_nth_plan(sel_node
, i
);
546 plan
->asc
= sel_node
->asc
;
547 plan
->pcur_is_open
= FALSE
;
548 plan
->cursor_at_end
= FALSE
;
550 /* Calculate goodness for each index of the table */
552 index
= dict_table_get_first_index(table
);
553 best_index
= index
; /* Eliminate compiler warning */
556 /* should be do ... until ? comment by Jani */
558 goodness
= opt_calc_index_goodness(index
, sel_node
, i
,
559 index_plan
, &last_op
);
560 if (goodness
> best_goodness
) {
563 best_goodness
= goodness
;
564 n_fields
= opt_calc_n_fields_from_goodness(goodness
);
566 ut_memcpy(best_index_plan
, index_plan
,
567 n_fields
* sizeof(void*));
568 best_last_op
= last_op
;
571 index
= dict_table_get_next_index(index
);
574 plan
->index
= best_index
;
576 n_fields
= opt_calc_n_fields_from_goodness(best_goodness
);
580 plan
->n_exact_match
= 0;
582 plan
->tuple
= dtuple_create(pars_sym_tab_global
->heap
,
584 dict_index_copy_types(plan
->tuple
, plan
->index
, n_fields
);
586 plan
->tuple_exps
= mem_heap_alloc(pars_sym_tab_global
->heap
,
587 n_fields
* sizeof(void*));
589 ut_memcpy(plan
->tuple_exps
, best_index_plan
,
590 n_fields
* sizeof(void*));
591 if (best_last_op
== '=') {
592 plan
->n_exact_match
= n_fields
;
594 plan
->n_exact_match
= n_fields
- 1;
597 plan
->mode
= opt_op_to_search_mode(sel_node
->asc
,
601 if (dict_index_is_clust(best_index
)
602 && (plan
->n_exact_match
>= dict_index_get_n_unique(best_index
))) {
604 plan
->unique_search
= TRUE
;
606 plan
->unique_search
= FALSE
;
609 plan
->old_vers_heap
= NULL
;
611 btr_pcur_init(&(plan
->pcur
));
612 btr_pcur_init(&(plan
->clust_pcur
));
615 /*******************************************************************//**
616 Looks at a comparison condition and decides if it can, and need, be tested for
617 a table AFTER the table has been accessed.
618 @return OPT_NOT_COND if not for this table, else OPT_END_COND,
619 OPT_TEST_COND, or OPT_SCROLL_COND, where the last means that the
620 condition need not be tested, except when scroll cursors are used */
623 opt_classify_comparison(
624 /*====================*/
625 sel_node_t
* sel_node
, /*!< in: select node */
626 ulint i
, /*!< in: ith table in the join */
627 func_node_t
* cond
) /*!< in: comparison condition */
634 ut_ad(cond
&& sel_node
);
636 plan
= sel_node_get_nth_plan(sel_node
, i
);
638 /* Check if the condition is determined after the ith table has been
639 accessed, but not after the i - 1:th */
641 if (!opt_check_exp_determined_before(cond
, sel_node
, i
+ 1)) {
643 return(OPT_NOT_COND
);
646 if ((i
> 0) && opt_check_exp_determined_before(cond
, sel_node
, i
)) {
648 return(OPT_NOT_COND
);
651 /* If the condition is an exact match condition used in constructing
652 the search tuple, it is classified as OPT_END_COND */
655 n_fields
= dtuple_get_n_fields(plan
->tuple
);
660 for (j
= 0; j
< plan
->n_exact_match
; j
++) {
662 if (opt_is_arg(plan
->tuple_exps
[j
], cond
)) {
664 return(OPT_END_COND
);
668 /* If the condition is an non-exact match condition used in
669 constructing the search tuple, it is classified as OPT_SCROLL_COND.
670 When the cursor is positioned, and if a non-scroll cursor is used,
671 there is no need to test this condition; if a scroll cursor is used
672 the testing is necessary when the cursor is reversed. */
674 if ((n_fields
> plan
->n_exact_match
)
675 && opt_is_arg(plan
->tuple_exps
[n_fields
- 1], cond
)) {
677 return(OPT_SCROLL_COND
);
680 /* If the condition is a non-exact match condition on the first field
681 in index for which there is no exact match, and it limits the search
682 range from the opposite side of the search tuple already BEFORE we
683 access the table, it is classified as OPT_END_COND */
685 if ((dict_index_get_n_fields(plan
->index
) > plan
->n_exact_match
)
686 && opt_look_for_col_in_comparison_before(
688 dict_index_get_nth_col_no(plan
->index
,
689 plan
->n_exact_match
),
690 cond
, sel_node
, i
, &op
)) {
692 if (sel_node
->asc
&& ((op
== '<') || (op
== PARS_LE_TOKEN
))) {
694 return(OPT_END_COND
);
697 if (!sel_node
->asc
&& ((op
== '>') || (op
== PARS_GE_TOKEN
))) {
699 return(OPT_END_COND
);
703 /* Otherwise, cond is classified as OPT_TEST_COND */
705 return(OPT_TEST_COND
);
708 /*******************************************************************//**
709 Recursively looks for test conditions for a table in a join. */
714 sel_node_t
* sel_node
, /*!< in: select node */
715 ulint i
, /*!< in: ith table in the join */
716 func_node_t
* cond
) /*!< in: conjunction of search
717 conditions or NULL */
719 func_node_t
* new_cond
;
728 if (cond
->func
== PARS_AND_TOKEN
) {
729 new_cond
= cond
->args
;
731 opt_find_test_conds(sel_node
, i
, new_cond
);
733 new_cond
= que_node_get_next(new_cond
);
735 opt_find_test_conds(sel_node
, i
, new_cond
);
740 plan
= sel_node_get_nth_plan(sel_node
, i
);
742 class = opt_classify_comparison(sel_node
, i
, cond
);
744 if (class == OPT_END_COND
) {
745 UT_LIST_ADD_LAST(cond_list
, plan
->end_conds
, cond
);
747 } else if (class == OPT_TEST_COND
) {
748 UT_LIST_ADD_LAST(cond_list
, plan
->other_conds
, cond
);
753 /*******************************************************************//**
754 Normalizes a list of comparison conditions so that a column of the table
755 appears on the left side of the comparison if possible. This is accomplished
756 by switching the arguments of the operator. */
759 opt_normalize_cmp_conds(
760 /*====================*/
761 func_node_t
* cond
, /*!< in: first in a list of comparison
762 conditions, or NULL */
763 dict_table_t
* table
) /*!< in: table */
767 sym_node_t
* sym_node
;
771 arg2
= que_node_get_next(arg1
);
773 if (que_node_get_type(arg2
) == QUE_NODE_SYMBOL
) {
777 if ((sym_node
->token_type
== SYM_COLUMN
)
778 && (sym_node
->table
== table
)) {
780 /* Switch the order of the arguments */
783 que_node_list_add_last(NULL
, arg2
);
784 que_node_list_add_last(arg2
, arg1
);
786 /* Invert the operator */
787 cond
->func
= opt_invert_cmp_op(cond
->func
);
791 cond
= UT_LIST_GET_NEXT(cond_list
, cond
);
795 /*******************************************************************//**
796 Finds out the search condition conjuncts we can, and need, to test as the ith
797 table in a join is accessed. The search tuple can eliminate the need to test
801 opt_determine_and_normalize_test_conds(
802 /*===================================*/
803 sel_node_t
* sel_node
, /*!< in: select node */
804 ulint i
) /*!< in: ith table in the join */
808 plan
= sel_node_get_nth_plan(sel_node
, i
);
810 UT_LIST_INIT(plan
->end_conds
);
811 UT_LIST_INIT(plan
->other_conds
);
813 /* Recursively go through the conjuncts and classify them */
815 opt_find_test_conds(sel_node
, i
, sel_node
->search_cond
);
817 opt_normalize_cmp_conds(UT_LIST_GET_FIRST(plan
->end_conds
),
820 ut_a(UT_LIST_GET_LEN(plan
->end_conds
) >= plan
->n_exact_match
);
823 /*******************************************************************//**
824 Looks for occurrences of the columns of the table in the query subgraph and
825 adds them to the list of columns if an occurrence of the same column does not
826 already exist in the list. If the column is already in the list, puts a value
827 indirection to point to the occurrence in the column list, except if the
828 column occurrence we are looking at is in the column list, in which case
834 ibool copy_val
, /*!< in: if TRUE, new found columns are
835 added as columns to copy */
836 dict_index_t
* index
, /*!< in: index of the table to use */
837 sym_node_list_t
* col_list
, /*!< in: base node of a list where
838 to add new found columns */
839 plan_t
* plan
, /*!< in: plan or NULL */
840 que_node_t
* exp
) /*!< in: expression or condition or
843 func_node_t
* func_node
;
845 sym_node_t
* sym_node
;
846 sym_node_t
* col_node
;
854 if (que_node_get_type(exp
) == QUE_NODE_FUNC
) {
857 arg
= func_node
->args
;
860 opt_find_all_cols(copy_val
, index
, col_list
, plan
,
862 arg
= que_node_get_next(arg
);
868 ut_a(que_node_get_type(exp
) == QUE_NODE_SYMBOL
);
872 if (sym_node
->token_type
!= SYM_COLUMN
) {
877 if (sym_node
->table
!= index
->table
) {
882 /* Look for an occurrence of the same column in the plan column
885 col_node
= UT_LIST_GET_FIRST(*col_list
);
888 if (col_node
->col_no
== sym_node
->col_no
) {
890 if (col_node
== sym_node
) {
891 /* sym_node was already in a list: do
897 /* Put an indirection */
898 sym_node
->indirection
= col_node
;
899 sym_node
->alias
= col_node
;
904 col_node
= UT_LIST_GET_NEXT(col_var_list
, col_node
);
907 /* The same column did not occur in the list: add it */
909 UT_LIST_ADD_LAST(col_var_list
, *col_list
, sym_node
);
911 sym_node
->copy_val
= copy_val
;
913 /* Fill in the field_no fields in sym_node */
915 sym_node
->field_nos
[SYM_CLUST_FIELD_NO
] = dict_index_get_nth_col_pos(
916 dict_table_get_first_index(index
->table
), sym_node
->col_no
);
917 if (!dict_index_is_clust(index
)) {
921 col_pos
= dict_index_get_nth_col_pos(index
, sym_node
->col_no
);
923 if (col_pos
== ULINT_UNDEFINED
) {
925 plan
->must_get_clust
= TRUE
;
928 sym_node
->field_nos
[SYM_SEC_FIELD_NO
] = col_pos
;
932 /*******************************************************************//**
933 Looks for occurrences of the columns of the table in conditions which are
934 not yet determined AFTER the join operation has fetched a row in the ith
935 table. The values for these column must be copied to dynamic memory for
941 sel_node_t
* sel_node
, /*!< in: select node */
942 ulint i
, /*!< in: ith table in the join */
943 func_node_t
* search_cond
) /*!< in: search condition or NULL */
945 func_node_t
* new_cond
;
948 if (search_cond
== NULL
) {
953 ut_ad(que_node_get_type(search_cond
) == QUE_NODE_FUNC
);
955 if (search_cond
->func
== PARS_AND_TOKEN
) {
956 new_cond
= search_cond
->args
;
958 opt_find_copy_cols(sel_node
, i
, new_cond
);
960 new_cond
= que_node_get_next(new_cond
);
962 opt_find_copy_cols(sel_node
, i
, new_cond
);
967 if (!opt_check_exp_determined_before(search_cond
, sel_node
, i
+ 1)) {
969 /* Any ith table columns occurring in search_cond should be
970 copied, as this condition cannot be tested already on the
971 fetch from the ith table */
973 plan
= sel_node_get_nth_plan(sel_node
, i
);
975 opt_find_all_cols(TRUE
, plan
->index
, &(plan
->columns
), plan
,
980 /*******************************************************************//**
981 Classifies the table columns according to whether we use the column only while
982 holding the latch on the page, or whether we have to copy the column value to
983 dynamic memory. Puts the first occurrence of a column to either list in the
984 plan node, and puts indirections to later occurrences of the column. */
989 sel_node_t
* sel_node
, /*!< in: select node */
990 ulint i
) /*!< in: ith table in the join */
995 plan
= sel_node_get_nth_plan(sel_node
, i
);
997 /* The final value of the following field will depend on the
998 environment of the select statement: */
1000 plan
->must_get_clust
= FALSE
;
1002 UT_LIST_INIT(plan
->columns
);
1004 /* All select list columns should be copied: therefore TRUE as the
1007 exp
= sel_node
->select_list
;
1010 opt_find_all_cols(TRUE
, plan
->index
, &(plan
->columns
), plan
,
1012 exp
= que_node_get_next(exp
);
1015 opt_find_copy_cols(sel_node
, i
, sel_node
->search_cond
);
1017 /* All remaining columns in the search condition are temporary
1018 columns: therefore FALSE */
1020 opt_find_all_cols(FALSE
, plan
->index
, &(plan
->columns
), plan
,
1021 sel_node
->search_cond
);
1024 /*******************************************************************//**
1025 Fills in the info in plan which is used in accessing a clustered index
1026 record. The columns must already be classified for the plan node. */
1031 sel_node_t
* sel_node
, /*!< in: select node */
1032 ulint n
) /*!< in: nth table in select */
1035 dict_table_t
* table
;
1036 dict_index_t
* clust_index
;
1037 dict_index_t
* index
;
1043 plan
= sel_node_get_nth_plan(sel_node
, n
);
1045 index
= plan
->index
;
1047 /* The final value of the following field depends on the environment
1048 of the select statement: */
1050 plan
->no_prefetch
= FALSE
;
1052 if (dict_index_is_clust(index
)) {
1053 plan
->clust_map
= NULL
;
1054 plan
->clust_ref
= NULL
;
1059 table
= index
->table
;
1061 clust_index
= dict_table_get_first_index(table
);
1063 n_fields
= dict_index_get_n_unique(clust_index
);
1065 heap
= pars_sym_tab_global
->heap
;
1067 plan
->clust_ref
= dtuple_create(heap
, n_fields
);
1069 dict_index_copy_types(plan
->clust_ref
, clust_index
, n_fields
);
1071 plan
->clust_map
= mem_heap_alloc(heap
, n_fields
* sizeof(ulint
));
1073 for (i
= 0; i
< n_fields
; i
++) {
1074 pos
= dict_index_get_nth_field_pos(index
, clust_index
, i
);
1076 ut_a(pos
!= ULINT_UNDEFINED
);
1078 /* We optimize here only queries to InnoDB's internal system
1079 tables, and they should not contain column prefix indexes. */
1081 if (dict_index_get_nth_field(index
, pos
)->prefix_len
!= 0
1082 || dict_index_get_nth_field(clust_index
, i
)
1083 ->prefix_len
!= 0) {
1085 "InnoDB: Error in pars0opt.c:"
1086 " table %s has prefix_len != 0\n",
1090 *(plan
->clust_map
+ i
) = pos
;
1092 ut_ad(pos
!= ULINT_UNDEFINED
);
1096 /*******************************************************************//**
1097 Optimizes a select. Decides which indexes to tables to use. The tables
1098 are accessed in the order that they were written to the FROM part in the
1099 select statement. */
1104 sel_node_t
* sel_node
) /*!< in: parsed select node */
1106 sym_node_t
* table_node
;
1107 dict_table_t
* table
;
1108 order_node_t
* order_by
;
1111 sel_node
->plans
= mem_heap_alloc(pars_sym_tab_global
->heap
,
1112 sel_node
->n_tables
* sizeof(plan_t
));
1114 /* Analyze the search condition to find out what we know at each
1115 join stage about the conditions that the columns of a table should
1118 table_node
= sel_node
->table_list
;
1120 if (sel_node
->order_by
== NULL
) {
1121 sel_node
->asc
= TRUE
;
1123 order_by
= sel_node
->order_by
;
1125 sel_node
->asc
= order_by
->asc
;
1128 for (i
= 0; i
< sel_node
->n_tables
; i
++) {
1130 table
= table_node
->table
;
1132 /* Choose index through which to access the table */
1134 opt_search_plan_for_table(sel_node
, i
, table
);
1136 /* Determine the search condition conjuncts we can test at
1137 this table; normalize the end conditions */
1139 opt_determine_and_normalize_test_conds(sel_node
, i
);
1141 table_node
= que_node_get_next(table_node
);
1144 table_node
= sel_node
->table_list
;
1146 for (i
= 0; i
< sel_node
->n_tables
; i
++) {
1148 /* Classify the table columns into those we only need to access
1149 but not copy, and to those we must copy to dynamic memory */
1151 opt_classify_cols(sel_node
, i
);
1153 /* Calculate possible info for accessing the clustered index
1156 opt_clust_access(sel_node
, i
);
1158 table_node
= que_node_get_next(table_node
);
1161 /* Check that the plan obeys a possible order-by clause: if not,
1162 an assertion error occurs */
1164 opt_check_order_by(sel_node
);
1166 #ifdef UNIV_SQL_DEBUG
1167 opt_print_query_plan(sel_node
);
1171 /********************************************************************//**
1172 Prints info of a query plan. */
1175 opt_print_query_plan(
1176 /*=================*/
1177 sel_node_t
* sel_node
) /*!< in: select node */
1183 fputs("QUERY PLAN FOR A SELECT NODE\n", stderr
);
1185 fputs(sel_node
->asc
? "Asc. search; " : "Desc. search; ", stderr
);
1187 if (sel_node
->set_x_locks
) {
1188 fputs("sets row x-locks; ", stderr
);
1189 ut_a(sel_node
->row_lock_mode
== LOCK_X
);
1190 ut_a(!sel_node
->consistent_read
);
1191 } else if (sel_node
->consistent_read
) {
1192 fputs("consistent read; ", stderr
);
1194 ut_a(sel_node
->row_lock_mode
== LOCK_S
);
1195 fputs("sets row s-locks; ", stderr
);
1200 for (i
= 0; i
< sel_node
->n_tables
; i
++) {
1201 plan
= sel_node_get_nth_plan(sel_node
, i
);
1204 n_fields
= dtuple_get_n_fields(plan
->tuple
);
1209 fputs("Table ", stderr
);
1210 dict_index_name_print(stderr
, NULL
, plan
->index
);
1211 fprintf(stderr
,"; exact m. %lu, match %lu, end conds %lu\n",
1212 (unsigned long) plan
->n_exact_match
,
1213 (unsigned long) n_fields
,
1214 (unsigned long) UT_LIST_GET_LEN(plan
->end_conds
));