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., 51 Franklin
15
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));