22
22
@defgroup Query_Optimizer Query Optimizer
28
28
#include <iostream>
29
29
#include <algorithm>
32
#include "drizzled/sql_select.h" /* include join.h */
34
#include "drizzled/error.h"
35
#include "drizzled/gettext.h"
36
#include "drizzled/util/test.h"
37
#include "drizzled/name_resolution_context_state.h"
38
#include "drizzled/nested_join.h"
39
#include "drizzled/probes.h"
40
#include "drizzled/show.h"
41
#include "drizzled/item/cache.h"
42
#include "drizzled/item/cmpfunc.h"
43
#include "drizzled/item/copy_string.h"
44
#include "drizzled/item/uint.h"
45
#include "drizzled/cached_item.h"
46
#include "drizzled/sql_base.h"
47
#include "drizzled/field/blob.h"
48
#include "drizzled/check_stack_overrun.h"
49
#include "drizzled/lock.h"
50
#include "drizzled/item/outer_ref.h"
51
#include "drizzled/index_hint.h"
52
#include "drizzled/records.h"
53
#include "drizzled/internal/iocache.h"
54
#include "drizzled/drizzled.h"
55
#include "drizzled/plugin/storage_engine.h"
57
#include "drizzled/sql_union.h"
58
#include "drizzled/optimizer/key_field.h"
59
#include "drizzled/optimizer/position.h"
60
#include "drizzled/optimizer/sargable_param.h"
61
#include "drizzled/optimizer/key_use.h"
62
#include "drizzled/optimizer/range.h"
63
#include "drizzled/optimizer/quick_range_select.h"
64
#include "drizzled/optimizer/quick_ror_intersect_select.h"
66
#include "drizzled/filesort.h"
32
#include <drizzled/sql_select.h> /* include join.h */
34
#include <drizzled/error.h>
35
#include <drizzled/gettext.h>
36
#include <drizzled/util/test.h>
37
#include <drizzled/name_resolution_context_state.h>
38
#include <drizzled/nested_join.h>
39
#include <drizzled/probes.h>
40
#include <drizzled/show.h>
41
#include <drizzled/item/cache.h>
42
#include <drizzled/item/cmpfunc.h>
43
#include <drizzled/item/copy_string.h>
44
#include <drizzled/item/uint.h>
45
#include <drizzled/cached_item.h>
46
#include <drizzled/sql_base.h>
47
#include <drizzled/field/blob.h>
48
#include <drizzled/check_stack_overrun.h>
49
#include <drizzled/lock.h>
50
#include <drizzled/item/outer_ref.h>
51
#include <drizzled/index_hint.h>
52
#include <drizzled/records.h>
53
#include <drizzled/internal/iocache.h>
54
#include <drizzled/drizzled.h>
55
#include <drizzled/plugin/storage_engine.h>
56
#include <drizzled/sql_union.h>
57
#include <drizzled/optimizer/key_field.h>
58
#include <drizzled/optimizer/position.h>
59
#include <drizzled/optimizer/sargable_param.h>
60
#include <drizzled/optimizer/key_use.h>
61
#include <drizzled/optimizer/range.h>
62
#include <drizzled/optimizer/quick_range_select.h>
63
#include <drizzled/optimizer/quick_ror_intersect_select.h>
64
#include <drizzled/filesort.h>
65
#include <drizzled/sql_lex.h>
66
#include <drizzled/session.h>
67
#include <drizzled/sort_field.h>
68
#include <drizzled/select_result.h>
69
#include <drizzled/key.h>
70
#include <drizzled/my_hash.h>
68
72
using namespace std;
73
76
static int sort_keyuse(optimizer::KeyUse *a, optimizer::KeyUse *b);
74
77
static COND *build_equal_items(Session *session, COND *cond,
199
202
true an error occured
202
bool fix_inner_refs(Session *session,
203
List<Item> &all_fields,
205
bool fix_inner_refs(Session *session,
206
List<Item> &all_fields,
205
208
Item **ref_pointer_array)
207
210
Item_outer_ref *ref;
209
212
bool direct_ref= false;
211
List_iterator<Item_outer_ref> ref_it(select->inner_refs_list);
214
List<Item_outer_ref>::iterator ref_it(select->inner_refs_list.begin());
212
215
while ((ref= ref_it++))
214
217
Item *item= ref->outer_ref;
215
218
Item **item_ref= ref->ref;
216
219
Item_ref *new_ref;
218
TODO: this field item already might be present in the select list.
221
@todo this field item already might be present in the select list.
219
222
In this case instead of adding new field item we could use an
220
223
existing one. The change will lead to less operations for copying fields,
221
224
smaller temporary tables and less data passed through filesort.
223
226
if (ref_pointer_array && !ref->found_in_select_list)
225
int el= all_fields.elements;
228
int el= all_fields.size();
226
229
ref_pointer_array[el]= item;
227
230
/* Add the field item to the select list of the current select. */
228
231
all_fields.push_front(item);
637
640
(e.g. if there is a key(a,b,c) but only b < 5 (or a=2 and c < 3) is
638
641
used in the query, we drop the partial key parts from consideration).
640
if (keyuse->elements)
642
645
optimizer::KeyUse key_end,*prev,*save_pos,*use;
644
internal::my_qsort(keyuse->buffer,keyuse->elements,sizeof(optimizer::KeyUse),
647
internal::my_qsort(keyuse->buffer,keyuse->size(),sizeof(optimizer::KeyUse),
645
648
(qsort_cmp) sort_keyuse);
647
650
memset(&key_end, 0, sizeof(key_end)); /* Add for easy testing */
648
insert_dynamic(keyuse,(unsigned char*) &key_end);
651
keyuse->push_back(&key_end);
650
use= save_pos= dynamic_element(keyuse, 0, optimizer::KeyUse*);
653
use= save_pos= (optimizer::KeyUse*)keyuse->buffer;
652
655
found_eq_constant= 0;
656
for (i= 0; i < keyuse->elements-1; i++, use++)
659
for (i= 0; i < keyuse->size()-1; i++, use++)
658
661
if (! use->getUsedTables() && use->getOptimizeFlags() != KEY_OPTIMIZE_REF_OR_NULL)
659
662
use->getTable()->const_key_parts[use->getKey()]|= use->getKeypartMap();
660
663
if (use->getKey() == prev->getKey() && use->getTable() == prev->getTable())
662
if (prev->getKeypart() + 1 < use->getKeypart() ||
665
if (prev->getKeypart() + 1 < use->getKeypart() ||
663
666
((prev->getKeypart() == use->getKeypart()) && found_eq_constant))
664
667
continue; /* remove */
1902
1898
Item_cond_and *and_cond= new Item_cond_and(eq_list);
1903
1899
and_cond->quick_fix_field();
1904
1900
List<Item> *args= and_cond->argument_list();
1905
List_iterator_fast<Item_equal> it(cond_equal.current_level);
1901
List<Item_equal>::iterator it(cond_equal.current_level.begin());
1906
1902
while ((item_equal= it++))
1908
1904
item_equal->fix_length_and_dec();
1909
1905
item_equal->update_used_tables();
1910
set_if_bigger(session->lex->current_select->max_equal_elems,
1906
set_if_bigger(session->lex().current_select->max_equal_elems,
1911
1907
item_equal->members());
1913
1909
and_cond->cond_equal= cond_equal;
2759
2755
if (should_fix_fields)
2760
2756
cond->update_used_tables();
2762
if (! ((Item_cond*) cond)->argument_list()->elements || *cond_value != Item::COND_OK)
2758
if (! ((Item_cond*) cond)->argument_list()->size() || *cond_value != Item::COND_OK)
2763
2759
return (COND*) NULL;
2765
if (((Item_cond*) cond)->argument_list()->elements == 1)
2761
if (((Item_cond*) cond)->argument_list()->size() == 1)
2767
2763
/* Argument list contains only one element, so reduce it so a single item, then remove list */
2768
item= ((Item_cond*) cond)->argument_list()->head();
2769
((Item_cond*) cond)->argument_list()->empty();
2764
item= &((Item_cond*) cond)->argument_list()->front();
2765
((Item_cond*) cond)->argument_list()->clear();
5144
5136
extra_length= ALIGN_SIZE(key_length)-key_length;
5147
if (hash_init(&hash, &my_charset_bin, (uint32_t) cursor->stats.records, 0,
5148
key_length, (hash_get_key) 0, 0, 0))
5139
if (hash_init(&hash, &my_charset_bin, (uint32_t) cursor.stats.records, 0, key_length, (hash_get_key) 0, 0, 0))
5153
if ((error= cursor->startTableScan(1)))
5142
if ((error= cursor.startTableScan(1)))
5156
5145
key_pos= &key_buffer[0];
5159
unsigned char *org_key_pos;
5160
5148
if (session->getKilled())
5162
5150
session->send_kill_message();
5166
if ((error=cursor->rnd_next(record)))
5154
if ((error=cursor.rnd_next(record)))
5168
5156
if (error == HA_ERR_RECORD_DELETED)
5794
5781
List<Item> &all_fields)
5797
List_iterator_fast<Item> li(all_fields);
5784
List<Item>::iterator li(all_fields.begin());
5798
5785
CopyField *copy= NULL;
5799
res_selected_fields.empty();
5800
res_all_fields.empty();
5801
List_iterator_fast<Item> itr(res_all_fields);
5786
res_selected_fields.clear();
5787
res_all_fields.clear();
5788
List<Item>::iterator itr(res_all_fields.begin());
5802
5789
List<Item> extra_funcs;
5803
uint32_t i, border= all_fields.elements - elements;
5790
uint32_t i, border= all_fields.size() - elements;
5805
5792
if (param->field_count &&
5806
!(copy=param->copy_field= new CopyField[param->field_count]))
5793
!(copy= param->copy_field= new CopyField[param->field_count]))
5809
param->copy_funcs.empty();
5796
param->copy_funcs.clear();
5810
5797
for (i= 0; (pos= li++); i++)
5875
5861
!real_pos->with_sum_func)
5876
5862
{ // Save for send fields
5879
In most cases this result will be sent to the user.
5865
@todo In most cases this result will be sent to the user.
5880
5866
This should be changed to use copy_int or copy_real depending
5881
5867
on how the value is to be used: In some cases this may be an
5882
5868
argument in a group function, like: IF(ISNULL(col),0,COUNT(*))
5884
if (!(pos=new Item_copy_string(pos)))
5870
pos=new Item_copy_string(pos);
5886
5871
if (i < border) // HAVING, order_st and GROUP BY
5888
if (extra_funcs.push_back(pos))
5891
else if (param->copy_funcs.push_back(pos))
5872
extra_funcs.push_back(pos);
5874
param->copy_funcs.push_back(pos);
5894
5876
res_all_fields.push_back(pos);
5895
ref_pointer_array[((i < border)? all_fields.elements-i-1 : i-border)]=
5877
ref_pointer_array[((i < border)? all_fields.size()-i-1 : i-border)]=
5898
5880
param->copy_field_end= copy;
6038
6019
uint32_t elements,
6039
6020
List<Item> &all_fields)
6041
List_iterator_fast<Item> it(all_fields);
6022
List<Item>::iterator it(all_fields.begin());
6042
6023
Item *item, *new_item;
6043
res_selected_fields.empty();
6044
res_all_fields.empty();
6024
res_selected_fields.clear();
6025
res_all_fields.clear();
6046
uint32_t i, border= all_fields.elements - elements;
6027
uint32_t i, border= all_fields.size() - elements;
6047
6028
for (i= 0; (item= it++); i++)
6049
6030
res_all_fields.push_back(new_item= item->get_tmp_table_item(session));
6050
ref_pointer_array[((i < border)? all_fields.elements-i-1 : i-border)]=
6031
ref_pointer_array[((i < border)? all_fields.size()-i-1 : i-border)]=
6054
List_iterator_fast<Item> itr(res_all_fields);
6035
List<Item>::iterator itr(res_all_fields.begin());
6055
6036
for (i= 0; i < border; i++)
6057
6038
itr.sublist(res_selected_fields, elements);
6285
6266
@param session thread Cursor
6286
6267
@param str string where table should be printed
6287
6268
@param tables list of tables in join
6288
@query_type type of the query is being generated
6290
6270
void print_join(Session *session, String *str,
6291
List<TableList> *tables, enum_query_type)
6271
List<TableList> *tables)
6293
6273
/* List is reversed => we should reverse it before using */
6294
List_iterator_fast<TableList> ti(*tables);
6274
List<TableList>::iterator ti(tables->begin());
6295
6275
TableList **table= (TableList **)session->getMemRoot()->allocate(sizeof(TableList*) *
6297
6277
if (table == 0)
6298
6278
return; // out of memory
6300
for (TableList **t= table + (tables->elements - 1); t >= table; t--)
6280
for (TableList **t= table + (tables->size() - 1); t >= table; t--)
6302
assert(tables->elements >= 1);
6303
print_table_array(session, str, table, table + tables->elements);
6282
assert(tables->size() >= 1);
6283
print_table_array(session, str, table, table + tables->size());
6306
void Select_Lex::print(Session *session, String *str, enum_query_type query_type)
6286
void Select_Lex::print(Session *session, String *str)
6308
6288
/* QQ: session may not be set for sub queries, but this should be fixed */
6309
6289
if(not session)
6399
6379
str->append(STRING_WITH_LEN(" having "));
6400
6380
if (cur_having)
6401
cur_having->print(str, query_type);
6381
cur_having->print(str);
6403
6383
str->append(having_value != Item::COND_FALSE ? "1" : "0");
6406
if (order_list.elements)
6386
if (order_list.size())
6408
6388
str->append(STRING_WITH_LEN(" order by "));
6409
print_order(str, (Order *) order_list.first, query_type);
6389
print_order(str, (Order *) order_list.first);
6413
print_limit(session, str, query_type);
6393
print_limit(session, str);
6415
6395
// PROCEDURE unsupported here