1
/******************************************************
6
Created 12/21/1997 Heikki Tuuri
7
*******************************************************/
12
#include "pars0opt.ic"
18
#include "dict0dict.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. */
40
/* out: the equivalent operator when the order of
41
the arguments is switched */
42
int op) /* in: operator */
46
} else if (op == '>') {
48
} else if (op == '=') {
50
} else if (op == PARS_LE_TOKEN) {
51
return(PARS_GE_TOKEN);
52
} else if (op == PARS_GE_TOKEN) {
53
return(PARS_LE_TOKEN);
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. */
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;
80
ut_ad(exp && sel_node);
82
if (que_node_get_type(exp) == QUE_NODE_FUNC) {
85
arg = func_node->args;
88
if (!opt_check_exp_determined_before(arg, sel_node,
93
arg = que_node_get_next(arg);
99
ut_a(que_node_get_type(exp) == QUE_NODE_SYMBOL);
103
if (sym_node->token_type != SYM_COLUMN) {
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) {
121
/***********************************************************************
122
Looks in a comparison condition if a column value is already restricted by
123
it BEFORE the nth table is accessed. */
126
opt_look_for_col_in_comparison_before(
127
/*==================================*/
128
/* out: expression restricting the
129
value of the column, or NULL if not
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
138
ulint* op) /* out: comparison operator ('=',
139
PARS_GE_TOKEN, ... ); this is inverted
140
if the column appears on the right
143
sym_node_t* sym_node;
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 != '=')) {
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)) {
171
arg = search_cond->args;
173
if (que_node_get_type(arg) == QUE_NODE_SYMBOL) {
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,
189
*op = search_cond->func;
196
exp = search_cond->args;
197
arg = que_node_get_next(arg);
199
if (que_node_get_type(arg) == QUE_NODE_SYMBOL) {
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,
208
*op = opt_invert_cmp_op(search_cond->func);
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. */
225
opt_look_for_col_in_cond_before(
226
/*============================*/
227
/* out: expression restricting the
228
value of the column, or NULL if not
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
237
ulint* op) /* out: comparison operator ('=',
238
PARS_GE_TOKEN, ... ) */
240
func_node_t* new_cond;
243
if (search_cond == 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,
263
new_cond = que_node_get_next(new_cond);
265
exp = opt_look_for_col_in_cond_before(cmp_type, col_no,
271
exp = opt_look_for_col_in_comparison_before(cmp_type, col_no,
272
search_cond, sel_node,
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
283
if (sel_node->asc && ((*op == '<') || (*op == PARS_LE_TOKEN))) {
287
} else if (!sel_node->asc
288
&& ((*op == '>') || (*op == PARS_GE_TOKEN))) {
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
305
opt_calc_index_goodness(
306
/*====================*/
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
313
ulint* last_op) /* out: last comparison operator, if
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);
340
/* The value for this column is exactly known already
341
at this stage of the join */
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);
362
if (goodness >= 4 * dict_index_get_n_unique(index)) {
365
if (index->type & DICT_CLUSTERED) {
371
/* We have to test for goodness here, as last_op may note be set */
372
if (goodness && index->type & DICT_CLUSTERED) {
380
/***********************************************************************
381
Calculates the number of matched fields based on an index goodness. */
384
opt_calc_n_fields_from_goodness(
385
/*============================*/
386
/* out: number of excatly or partially matched
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,
398
opt_op_to_search_mode(
399
/*==================*/
400
/* out: search mode */
401
ibool asc, /* in: TRUE if the rows should be fetched in an
403
ulint op) /* in: operator '=', PARS_GE_TOKEN, ... */
411
} else if (op == '<') {
414
} else if (op == '>') {
417
} else if (op == PARS_GE_TOKEN) {
420
} else if (op == PARS_LE_TOKEN) {
430
/***********************************************************************
431
Determines if a node is an argument node of a function node. */
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 */
442
arg = func_node->args;
445
if (arg == arg_node) {
450
arg = que_node_get_next(arg);
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
464
sel_node_t* sel_node) /* in: select node; asserts an error
465
if the plan does not agree with the
468
order_node_t* order_node;
469
dict_table_t* order_table;
474
if (!sel_node->order_by) {
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);
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,
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
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 */
522
dict_index_t* best_index;
525
ulint last_op = 75946965; /* Eliminate a Purify
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);
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 */
545
/* should be do ... until ? comment by Jani */
547
goodness = opt_calc_index_goodness(index, sel_node, i,
548
index_plan, &last_op);
549
if (goodness > best_goodness) {
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);
569
plan->n_exact_match = 0;
571
plan->tuple = dtuple_create(pars_sym_tab_global->heap,
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;
583
plan->n_exact_match = n_fields - 1;
586
plan->mode = opt_op_to_search_mode(sel_node->asc,
590
if ((best_index->type & DICT_CLUSTERED)
591
&& (plan->n_exact_match >= dict_index_get_n_unique(best_index))) {
593
plan->unique_search = TRUE;
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. */
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 */
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 */
647
n_fields = dtuple_get_n_fields(plan->tuple);
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(
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. */
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;
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);
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. */
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 */
759
sym_node_t* sym_node;
763
arg2 = que_node_get_next(arg1);
765
if (que_node_get_type(arg2) == QUE_NODE_SYMBOL) {
769
if ((sym_node->token_type == SYM_COLUMN)
770
&& (sym_node->table == table)) {
772
/* Switch the order of the arguments */
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
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 */
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),
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
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
835
func_node_t* func_node;
837
sym_node_t* sym_node;
838
sym_node_t* col_node;
846
if (que_node_get_type(exp) == QUE_NODE_FUNC) {
849
arg = func_node->args;
852
opt_find_all_cols(copy_val, index, col_list, plan,
854
arg = que_node_get_next(arg);
860
ut_a(que_node_get_type(exp) == QUE_NODE_SYMBOL);
864
if (sym_node->token_type != SYM_COLUMN) {
869
if (sym_node->table != index->table) {
874
/* Look for an occurrence of the same column in the plan column
877
col_node = UT_LIST_GET_FIRST(*col_list);
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
889
/* Put an indirection */
890
sym_node->indirection = col_node;
891
sym_node->alias = col_node;
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)) {
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
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;
940
if (search_cond == NULL) {
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);
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,
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. */
981
sel_node_t* sel_node, /* in: select node */
982
ulint i) /* in: ith table in the join */
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
999
exp = sel_node->select_list;
1002
opt_find_all_cols(TRUE, plan->index, &(plan->columns), plan,
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. */
1023
sel_node_t* sel_node, /* in: select node */
1024
ulint n) /* in: nth table in select */
1027
dict_table_t* table;
1028
dict_index_t* clust_index;
1029
dict_index_t* index;
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;
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) {
1077
"InnoDB: Error in pars0opt.c:"
1078
" table %s has prefix_len != 0\n",
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. */
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;
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
1110
table_node = sel_node->table_list;
1112
if (sel_node->order_by == NULL) {
1113
sel_node->asc = TRUE;
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
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);
1163
/************************************************************************
1164
Prints info of a query plan. */
1167
opt_print_query_plan(
1168
/*=================*/
1169
sel_node_t* sel_node) /* in: select node */
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);
1186
ut_a(sel_node->row_lock_mode == LOCK_S);
1187
fputs("sets row s-locks; ", stderr);
1192
for (i = 0; i < sel_node->n_tables; i++) {
1193
plan = sel_node_get_nth_plan(sel_node, i);
1196
n_fields = dtuple_get_n_fields(plan->tuple);
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));