Merge lp:~posulliv/drizzle/optimizer-style-cleanup into lp:~drizzle-trunk/drizzle/development

Proposed by Padraig O'Sullivan
Status: Merged
Merged at revision: not available
Proposed branch: lp:~posulliv/drizzle/optimizer-style-cleanup
Merge into: lp:~drizzle-trunk/drizzle/development
Diff against target: 2727 lines (+1105/-960)
7 files modified
drizzled/include.am (+4/-0)
drizzled/optimizer/range.cc (+116/-958)
drizzled/optimizer/sel_imerge.cc (+98/-0)
drizzled/optimizer/sel_imerge.h (+122/-0)
drizzled/optimizer/sel_tree.cc (+600/-0)
drizzled/optimizer/sel_tree.h (+155/-0)
drizzled/optimizer/table_read_plan.h (+10/-2)
To merge this branch: bzr merge lp:~posulliv/drizzle/optimizer-style-cleanup
Reviewer Review Type Date Requested Status
Drizzle Developers Pending
Review via email: mp+21420@code.launchpad.net

Description of the change

Continues the work of cleaning up some of the optimizer code. Moved some classes into their own header and implementation files. Cleaned up some style issues also.

-Padraig

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'drizzled/include.am'
2--- drizzled/include.am 2010-03-05 03:12:24 +0000
3+++ drizzled/include.am 2010-03-16 01:44:16 +0000
4@@ -283,6 +283,8 @@
5 drizzled/optimizer/range_param.h \
6 drizzled/optimizer/sargable_param.h \
7 drizzled/optimizer/sel_arg.h \
8+ drizzled/optimizer/sel_imerge.h \
9+ drizzled/optimizer/sel_tree.h \
10 drizzled/optimizer/sum.h \
11 drizzled/optimizer/table_read_plan.h \
12 drizzled/order.h \
13@@ -647,6 +649,8 @@
14 drizzled/optimizer/quick_ror_union_select.cc \
15 drizzled/optimizer/range.cc \
16 drizzled/optimizer/sel_arg.cc \
17+ drizzled/optimizer/sel_imerge.cc \
18+ drizzled/optimizer/sel_tree.cc \
19 drizzled/optimizer/sum.cc \
20 drizzled/plugin/authentication.cc \
21 drizzled/plugin/authorization.cc \
22
23=== modified file 'drizzled/optimizer/range.cc'
24--- drizzled/optimizer/range.cc 2010-02-10 20:00:52 +0000
25+++ drizzled/optimizer/range.cc 2010-03-16 01:44:16 +0000
26@@ -37,19 +37,12 @@
27 The entry point for the range analysis module is get_mm_tree() function.
28
29 The lists are returned in form of complicated structure of interlinked
30- SEL_TREE/SEL_IMERGE/SEL_ARG objects.
31+ optimizer::SEL_TREE/optimizer::SEL_IMERGE/SEL_ARG objects.
32 See quick_range_seq_next, find_used_partitions for examples of how to walk
33 this structure.
34 All direct "users" of this module are located within this cursor, too.
35
36
37- PartitionPruningModule
38- A module that accepts a partitioned table, condition, and finds which
39- partitions we will need to use in query execution. Search down for
40- "PartitionPruningModule" for description.
41- The module has single entry point - prune_partitions() function.
42-
43-
44 Range/index_merge/groupby-minmax optimizer module
45 A module that accepts a table, condition, and returns
46 - a QUICK_*_SELECT object that can be used to retrieve rows that match
47@@ -133,6 +126,8 @@
48 #include "drizzled/optimizer/quick_ror_union_select.h"
49 #include "drizzled/optimizer/table_read_plan.h"
50 #include "drizzled/optimizer/sel_arg.h"
51+#include "drizzled/optimizer/sel_imerge.h"
52+#include "drizzled/optimizer/sel_tree.h"
53 #include "drizzled/optimizer/range_param.h"
54 #include "drizzled/records.h"
55 #include "drizzled/internal/my_sys.h"
56@@ -235,59 +230,9 @@
57 }
58 }
59
60-class SEL_IMERGE;
61-
62-
63-class SEL_TREE :public memory::SqlAlloc
64-{
65-public:
66- /*
67- Starting an effort to document this field:
68- (for some i, keys[i]->type == optimizer::SEL_ARG::IMPOSSIBLE) =>
69- (type == SEL_TREE::IMPOSSIBLE)
70- */
71- enum Type
72- {
73- IMPOSSIBLE,
74- ALWAYS,
75- MAYBE,
76- KEY,
77- KEY_SMALLER
78- } type;
79-
80- SEL_TREE(enum Type type_arg) :type(type_arg) {}
81- SEL_TREE() :type(KEY)
82- {
83- keys_map.reset();
84- memset(keys, 0, sizeof(keys));
85- }
86- /*
87- Note: there may exist SEL_TREE objects with sel_tree->type=KEY and
88- keys[i]=0 for all i. (SergeyP: it is not clear whether there is any
89- merit in range analyzer functions (e.g. get_mm_parts) returning a
90- pointer to such SEL_TREE instead of NULL)
91- */
92- optimizer::SEL_ARG *keys[MAX_KEY];
93- key_map keys_map; /* bitmask of non-NULL elements in keys */
94-
95- /*
96- Possible ways to read rows using index_merge. The list is non-empty only
97- if type==KEY. Currently can be non empty only if keys_map.none().
98- */
99- List<SEL_IMERGE> merges;
100-
101- /* The members below are filled/used only after get_mm_tree is done */
102- key_map ror_scans_map; /* bitmask of ROR scan-able elements in keys */
103- uint32_t n_ror_scans; /* number of set bits in ror_scans_map */
104-
105- struct st_ror_scan_info **ror_scans; /* list of ROR key scans */
106- struct st_ror_scan_info **ror_scans_end; /* last ROR scan */
107- /* Note that #records for each key scan is stored in table->quick_rows */
108-};
109-
110 struct st_ror_scan_info;
111
112-static SEL_TREE * get_mm_parts(optimizer::RangeParameter *param,
113+static optimizer::SEL_TREE * get_mm_parts(optimizer::RangeParameter *param,
114 COND *cond_func,
115 Field *field,
116 Item_func::Functype type,
117@@ -301,7 +246,7 @@
118 Item_func::Functype type,
119 Item *value);
120
121-static SEL_TREE *get_mm_tree(optimizer::RangeParameter *param, COND *cond);
122+static optimizer::SEL_TREE *get_mm_tree(optimizer::RangeParameter *param, COND *cond);
123
124 static bool is_key_scan_ror(optimizer::Parameter *param, uint32_t keynr, uint8_t nparts);
125
126@@ -315,51 +260,36 @@
127 COST_VECT *cost);
128
129 static optimizer::RangeReadPlan *get_key_scans_params(optimizer::Parameter *param,
130- SEL_TREE *tree,
131+ optimizer::SEL_TREE *tree,
132 bool index_read_must_be_used,
133 bool update_tbl_stats,
134 double read_time);
135
136 static
137 optimizer::RorIntersectReadPlan *get_best_ror_intersect(const optimizer::Parameter *param,
138- SEL_TREE *tree,
139+ optimizer::SEL_TREE *tree,
140 double read_time,
141 bool *are_all_covering);
142
143 static
144 optimizer::RorIntersectReadPlan *get_best_covering_ror_intersect(optimizer::Parameter *param,
145- SEL_TREE *tree,
146+ optimizer::SEL_TREE *tree,
147 double read_time);
148
149 static
150 optimizer::TableReadPlan *get_best_disjunct_quick(optimizer::Parameter *param,
151- SEL_IMERGE *imerge,
152+ optimizer::SEL_IMERGE *imerge,
153 double read_time);
154
155 static
156-optimizer::GroupMinMaxReadPlan *get_best_group_min_max(optimizer::Parameter *param, SEL_TREE *tree);
157-
158-static void print_sel_tree(optimizer::Parameter *param,
159- SEL_TREE *tree,
160- key_map *tree_map,
161- const char *msg);
162-
163-static void print_ror_scans_arr(Table *table,
164- const char *msg,
165- struct st_ror_scan_info **start,
166- struct st_ror_scan_info **end);
167-static void print_ror_scans_vector(Table *table,
168- const char *msg,
169- vector<struct st_ror_scan_info *> &vec);
170-
171-static SEL_TREE *tree_and(optimizer::RangeParameter *param, SEL_TREE *tree1, SEL_TREE *tree2);
172-
173-static SEL_TREE *tree_or(optimizer::RangeParameter *param, SEL_TREE *tree1, SEL_TREE *tree2);
174+optimizer::GroupMinMaxReadPlan *get_best_group_min_max(optimizer::Parameter *param, optimizer::SEL_TREE *tree);
175+
176+static optimizer::SEL_TREE *tree_and(optimizer::RangeParameter *param,
177+ optimizer::SEL_TREE *tree1,
178+ optimizer::SEL_TREE *tree2);
179
180 static optimizer::SEL_ARG *sel_add(optimizer::SEL_ARG *key1, optimizer::SEL_ARG *key2);
181
182-static optimizer::SEL_ARG *key_or(optimizer::RangeParameter *param, optimizer::SEL_ARG *key1, optimizer::SEL_ARG *key2);
183-
184 static optimizer::SEL_ARG *key_and(optimizer::RangeParameter *param,
185 optimizer::SEL_ARG *key1,
186 optimizer::SEL_ARG *key2,
187@@ -367,228 +297,31 @@
188
189 static bool get_range(optimizer::SEL_ARG **e1, optimizer::SEL_ARG **e2, optimizer::SEL_ARG *root1);
190
191-static bool eq_tree(optimizer::SEL_ARG* a, optimizer::SEL_ARG *b);
192-
193 optimizer::SEL_ARG optimizer::null_element(optimizer::SEL_ARG::IMPOSSIBLE);
194
195 static bool null_part_in_key(KEY_PART *key_part,
196 const unsigned char *key,
197 uint32_t length);
198
199-bool sel_trees_can_be_ored(SEL_TREE *tree1, SEL_TREE *tree2, optimizer::RangeParameter *param);
200-
201-
202-/*
203- SEL_IMERGE is a list of possible ways to do index merge, i.e. it is
204- a condition in the following form:
205- (t_1||t_2||...||t_N) && (next)
206-
207- where all t_i are SEL_TREEs, next is another SEL_IMERGE and no pair
208- (t_i,t_j) contains SEL_ARGS for the same index.
209-
210- SEL_TREE contained in SEL_IMERGE always has merges=NULL.
211-
212- This class relies on memory manager to do the cleanup.
213-*/
214-
215-class SEL_IMERGE : public memory::SqlAlloc
216-{
217- enum { PREALLOCED_TREES= 10};
218-public:
219- SEL_TREE *trees_prealloced[PREALLOCED_TREES];
220- SEL_TREE **trees; /* trees used to do index_merge */
221- SEL_TREE **trees_next; /* last of these trees */
222- SEL_TREE **trees_end; /* end of allocated space */
223-
224- optimizer::SEL_ARG ***best_keys; /* best keys to read in SEL_TREEs */
225-
226- SEL_IMERGE() :
227- trees(&trees_prealloced[0]),
228- trees_next(trees),
229- trees_end(trees + PREALLOCED_TREES)
230- {}
231- int or_sel_tree(optimizer::RangeParameter *param, SEL_TREE *tree);
232- int or_sel_tree_with_checks(optimizer::RangeParameter *param, SEL_TREE *new_tree);
233- int or_sel_imerge_with_checks(optimizer::RangeParameter *param, SEL_IMERGE* imerge);
234-};
235-
236-
237-/*
238- Add SEL_TREE to this index_merge without any checks,
239-
240- NOTES
241- This function implements the following:
242- (x_1||...||x_N) || t = (x_1||...||x_N||t), where x_i, t are SEL_TREEs
243-
244- RETURN
245- 0 - OK
246- -1 - Out of memory.
247-*/
248-int SEL_IMERGE::or_sel_tree(optimizer::RangeParameter *param, SEL_TREE *tree)
249-{
250- if (trees_next == trees_end)
251- {
252- const int realloc_ratio= 2; /* Double size for next round */
253- uint32_t old_elements= (trees_end - trees);
254- uint32_t old_size= sizeof(SEL_TREE**) * old_elements;
255- uint32_t new_size= old_size * realloc_ratio;
256- SEL_TREE **new_trees;
257- if (!(new_trees= (SEL_TREE**)alloc_root(param->mem_root, new_size)))
258- return -1;
259- memcpy(new_trees, trees, old_size);
260- trees= new_trees;
261- trees_next= trees + old_elements;
262- trees_end= trees + old_elements * realloc_ratio;
263- }
264- *(trees_next++)= tree;
265- return 0;
266-}
267-
268-
269-/*
270- Perform OR operation on this SEL_IMERGE and supplied SEL_TREE new_tree,
271- combining new_tree with one of the trees in this SEL_IMERGE if they both
272- have SEL_ARGs for the same key.
273-
274- SYNOPSIS
275- or_sel_tree_with_checks()
276- param Parameter from SqlSelect::test_quick_select
277- new_tree SEL_TREE with type KEY or KEY_SMALLER.
278-
279- NOTES
280- This does the following:
281- (t_1||...||t_k)||new_tree =
282- either
283- = (t_1||...||t_k||new_tree)
284- or
285- = (t_1||....||(t_j|| new_tree)||...||t_k),
286-
287- where t_i, y are SEL_TREEs.
288- new_tree is combined with the first t_j it has a SEL_ARG on common
289- key with. As a consequence of this, choice of keys to do index_merge
290- read may depend on the order of conditions in WHERE part of the query.
291-
292- RETURN
293- 0 OK
294- 1 One of the trees was combined with new_tree to SEL_TREE::ALWAYS,
295- and (*this) should be discarded.
296- -1 An error occurred.
297-*/
298-int SEL_IMERGE::or_sel_tree_with_checks(optimizer::RangeParameter *param, SEL_TREE *new_tree)
299-{
300- for (SEL_TREE** tree = trees;
301- tree != trees_next;
302- tree++)
303- {
304- if (sel_trees_can_be_ored(*tree, new_tree, param))
305- {
306- *tree = tree_or(param, *tree, new_tree);
307- if (!*tree)
308- return 1;
309- if (((*tree)->type == SEL_TREE::MAYBE) ||
310- ((*tree)->type == SEL_TREE::ALWAYS))
311- return 1;
312- /* SEL_TREE::IMPOSSIBLE is impossible here */
313- return 0;
314- }
315- }
316-
317- /* New tree cannot be combined with any of existing trees. */
318- return or_sel_tree(param, new_tree);
319-}
320-
321-
322-/*
323- Perform OR operation on this index_merge and supplied index_merge list.
324-
325- RETURN
326- 0 - OK
327- 1 - One of conditions in result is always true and this SEL_IMERGE
328- should be discarded.
329- -1 - An error occurred
330-*/
331-
332-int SEL_IMERGE::or_sel_imerge_with_checks(optimizer::RangeParameter *param, SEL_IMERGE* imerge)
333-{
334- for (SEL_TREE** tree= imerge->trees;
335- tree != imerge->trees_next;
336- tree++)
337- {
338- if (or_sel_tree_with_checks(param, *tree))
339- return 1;
340- }
341- return 0;
342-}
343+bool sel_trees_can_be_ored(optimizer::SEL_TREE *tree1,
344+ optimizer::SEL_TREE *tree2,
345+ optimizer::RangeParameter *param);
346+
347+
348+
349+
350
351
352 /*
353 Perform AND operation on two index_merge lists and store result in *im1.
354 */
355
356-inline void imerge_list_and_list(List<SEL_IMERGE> *im1, List<SEL_IMERGE> *im2)
357+inline void imerge_list_and_list(List<optimizer::SEL_IMERGE> *im1, List<optimizer::SEL_IMERGE> *im2)
358 {
359 im1->concat(im2);
360 }
361
362
363-/*
364- Perform OR operation on 2 index_merge lists, storing result in first list.
365-
366- NOTES
367- The following conversion is implemented:
368- (a_1 &&...&& a_N)||(b_1 &&...&& b_K) = AND_i,j(a_i || b_j) =>
369- => (a_1||b_1).
370-
371- i.e. all conjuncts except the first one are currently dropped.
372- This is done to avoid producing N*K ways to do index_merge.
373-
374- If (a_1||b_1) produce a condition that is always true, NULL is returned
375- and index_merge is discarded (while it is actually possible to try
376- harder).
377-
378- As a consequence of this, choice of keys to do index_merge read may depend
379- on the order of conditions in WHERE part of the query.
380-
381- RETURN
382- 0 OK, result is stored in *im1
383- other Error, both passed lists are unusable
384-*/
385-
386-static int imerge_list_or_list(optimizer::RangeParameter *param,
387- List<SEL_IMERGE> *im1,
388- List<SEL_IMERGE> *im2)
389-{
390- SEL_IMERGE *imerge= im1->head();
391- im1->empty();
392- im1->push_back(imerge);
393-
394- return imerge->or_sel_imerge_with_checks(param, im2->head());
395-}
396-
397-
398-/*
399- Perform OR operation on index_merge list and key tree.
400-
401- RETURN
402- 0 OK, result is stored in *im1.
403- other Error
404- */
405-
406-static int imerge_list_or_tree(optimizer::RangeParameter *param,
407- List<SEL_IMERGE> *im1,
408- SEL_TREE *tree)
409-{
410- SEL_IMERGE *imerge;
411- List_iterator<SEL_IMERGE> it(*im1);
412- while ((imerge= it++))
413- {
414- if (imerge->or_sel_tree_with_checks(param, tree))
415- it.remove();
416- }
417- return im1->is_empty();
418-}
419-
420-
421 /***************************************************************************
422 ** Basic functions for SqlSelect and QuickRangeSelect
423 ***************************************************************************/
424@@ -928,7 +661,7 @@
425 if (keys_to_use.any())
426 {
427 memory::Root alloc;
428- SEL_TREE *tree= NULL;
429+ optimizer::SEL_TREE *tree= NULL;
430 KEY_PART *key_parts;
431 KEY *key_info;
432 optimizer::Parameter param;
433@@ -1016,7 +749,7 @@
434 {
435 if ((tree= get_mm_tree(&param,cond)))
436 {
437- if (tree->type == SEL_TREE::IMPOSSIBLE)
438+ if (tree->type == optimizer::SEL_TREE::IMPOSSIBLE)
439 {
440 records=0L; /* Return -1 from this function. */
441 read_time= (double) HA_POS_ERROR;
442@@ -1026,7 +759,7 @@
443 If the tree can't be used for range scans, proceed anyway, as we
444 can construct a group-min-max quick select
445 */
446- if (tree->type != SEL_TREE::KEY && tree->type != SEL_TREE::KEY_SMALLER)
447+ if (tree->type != optimizer::SEL_TREE::KEY && tree->type != optimizer::SEL_TREE::KEY_SMALLER)
448 tree= NULL;
449 }
450 }
451@@ -1097,10 +830,10 @@
452 else
453 {
454 /* Try creating index_merge/ROR-union scan. */
455- SEL_IMERGE *imerge= NULL;
456+ optimizer::SEL_IMERGE *imerge= NULL;
457 optimizer::TableReadPlan *best_conj_trp= NULL;
458 optimizer::TableReadPlan *new_conj_trp= NULL;
459- List_iterator_fast<SEL_IMERGE> it(tree->merges);
460+ List_iterator_fast<optimizer::SEL_IMERGE> it(tree->merges);
461 while ((imerge= it++))
462 {
463 new_conj_trp= get_best_disjunct_quick(&param, imerge, best_read_time);
464@@ -1143,7 +876,7 @@
465 }
466
467 /*
468- Get best plan for a SEL_IMERGE disjunctive expression.
469+ Get best plan for a optimizer::SEL_IMERGE disjunctive expression.
470 SYNOPSIS
471 get_best_disjunct_quick()
472 param Parameter from check_quick_select function
473@@ -1209,10 +942,10 @@
474
475 static
476 optimizer::TableReadPlan *get_best_disjunct_quick(optimizer::Parameter *param,
477- SEL_IMERGE *imerge,
478+ optimizer::SEL_IMERGE *imerge,
479 double read_time)
480 {
481- SEL_TREE **ptree;
482+ optimizer::SEL_TREE **ptree= NULL;
483 optimizer::IndexMergeReadPlan *imerge_trp= NULL;
484 uint32_t n_child_scans= imerge->trees_next - imerge->trees;
485 optimizer::RangeReadPlan **range_scans= NULL;
486@@ -1245,7 +978,6 @@
487 ptree != imerge->trees_next;
488 ptree++, cur_child++)
489 {
490- print_sel_tree(param, *ptree, &(*ptree)->keys_map, "tree in SEL_IMERGE");
491 if (!(*cur_child= get_key_scans_params(param, *ptree, true, false, read_time)))
492 {
493 /*
494@@ -1960,28 +1692,28 @@
495
496 static
497 optimizer::RorIntersectReadPlan *get_best_ror_intersect(const optimizer::Parameter *param,
498- SEL_TREE *tree,
499+ optimizer::SEL_TREE *tree,
500 double read_time,
501 bool *are_all_covering)
502 {
503- uint32_t idx;
504+ uint32_t idx= 0;
505 double min_cost= DBL_MAX;
506
507- if ((tree->n_ror_scans < 2) || !param->table->cursor->stats.records)
508+ if ((tree->n_ror_scans < 2) || ! param->table->cursor->stats.records)
509 return NULL;
510
511 /*
512 Step1: Collect ROR-able SEL_ARGs and create ROR_SCAN_INFO for each of
513 them. Also find and save clustered PK scan if there is one.
514 */
515- ROR_SCAN_INFO **cur_ror_scan;
516+ ROR_SCAN_INFO **cur_ror_scan= NULL;
517 ROR_SCAN_INFO *cpk_scan= NULL;
518- uint32_t cpk_no;
519+ uint32_t cpk_no= 0;
520 bool cpk_scan_used= false;
521
522- if (!(tree->ror_scans= (ROR_SCAN_INFO**)alloc_root(param->mem_root,
523- sizeof(ROR_SCAN_INFO*)*
524- param->keys)))
525+ if (! (tree->ror_scans= (ROR_SCAN_INFO**)alloc_root(param->mem_root,
526+ sizeof(ROR_SCAN_INFO*)*
527+ param->keys)))
528 return NULL;
529 cpk_no= ((param->table->cursor->primary_key_is_clustered()) ?
530 param->table->s->primary_key : MAX_KEY);
531@@ -2003,9 +1735,6 @@
532 }
533
534 tree->ror_scans_end= cur_ror_scan;
535- print_ror_scans_arr(param->table, "original",
536- tree->ror_scans,
537- tree->ror_scans_end);
538 /*
539 Ok, [ror_scans, ror_scans_end) is array of ptrs to initialized
540 ROR_SCAN_INFO's.
541@@ -2013,26 +1742,24 @@
542 */
543 internal::my_qsort(tree->ror_scans, tree->n_ror_scans, sizeof(ROR_SCAN_INFO*),
544 (qsort_cmp)cmp_ror_scan_info);
545- print_ror_scans_arr(param->table, "ordered",
546- tree->ror_scans,
547- tree->ror_scans_end);
548
549- ROR_SCAN_INFO **intersect_scans; /* ROR scans used in index intersection */
550- ROR_SCAN_INFO **intersect_scans_end;
551- if (!(intersect_scans= (ROR_SCAN_INFO**)alloc_root(param->mem_root,
552- sizeof(ROR_SCAN_INFO*)*
553- tree->n_ror_scans)))
554+ ROR_SCAN_INFO **intersect_scans= NULL; /* ROR scans used in index intersection */
555+ ROR_SCAN_INFO **intersect_scans_end= NULL;
556+ if (! (intersect_scans= (ROR_SCAN_INFO**)alloc_root(param->mem_root,
557+ sizeof(ROR_SCAN_INFO*)*
558+ tree->n_ror_scans)))
559 return NULL;
560 intersect_scans_end= intersect_scans;
561
562 /* Create and incrementally update ROR intersection. */
563- ROR_INTERSECT_INFO *intersect, *intersect_best;
564- if (!(intersect= ror_intersect_init(param)) ||
565- !(intersect_best= ror_intersect_init(param)))
566+ ROR_INTERSECT_INFO *intersect= NULL;
567+ ROR_INTERSECT_INFO *intersect_best= NULL;
568+ if (! (intersect= ror_intersect_init(param)) ||
569+ ! (intersect_best= ror_intersect_init(param)))
570 return NULL;
571
572 /* [intersect_scans,intersect_scans_best) will hold the best intersection */
573- ROR_SCAN_INFO **intersect_scans_best;
574+ ROR_SCAN_INFO **intersect_scans_best= NULL;
575 cur_ror_scan= tree->ror_scans;
576 intersect_scans_best= intersect_scans;
577 while (cur_ror_scan != tree->ror_scans_end && !intersect->is_covering)
578@@ -2060,11 +1787,6 @@
579 return NULL;
580 }
581
582- print_ror_scans_arr(param->table,
583- "best ROR-intersection",
584- intersect_scans,
585- intersect_scans_best);
586-
587 *are_all_covering= intersect->is_covering;
588 uint32_t best_num= intersect_scans_best - intersect_scans;
589 ror_intersect_cpy(intersect, intersect_best);
590@@ -2096,14 +1818,14 @@
591 trp->read_cost= intersect_best->total_cost;
592 /* Prevent divisons by zero */
593 ha_rows best_rows = double2rows(intersect_best->out_rows);
594- if (!best_rows)
595+ if (! best_rows)
596 best_rows= 1;
597 set_if_smaller(param->table->quick_condition_rows, best_rows);
598 trp->records= best_rows;
599 trp->setCostOfIndexScans(intersect_best->index_scan_costs);
600 trp->cpk_scan= cpk_scan_used? cpk_scan: NULL;
601 }
602- return(trp);
603+ return trp;
604 }
605
606
607@@ -2112,7 +1834,7 @@
608 SYNOPSIS
609 get_best_covering_ror_intersect()
610 param Parameter from test_quick_select function.
611- tree SEL_TREE with sets of intervals for different keys.
612+ tree optimizer::SEL_TREE with sets of intervals for different keys.
613 read_time Don't return table read plans with cost > read_time.
614
615 RETURN
616@@ -2142,7 +1864,7 @@
617
618 static
619 optimizer::RorIntersectReadPlan *get_best_covering_ror_intersect(optimizer::Parameter *param,
620- SEL_TREE *tree,
621+ optimizer::SEL_TREE *tree,
622 double read_time)
623 {
624 ROR_SCAN_INFO **ror_scan_mark;
625@@ -2177,9 +1899,6 @@
626 ha_rows records=0;
627 bool all_covered;
628
629- print_ror_scans_arr(param->table,
630- "building covering ROR-I",
631- ror_scan_mark, ror_scans_end);
632 do
633 {
634 /*
635@@ -2201,10 +1920,6 @@
636 sizeof(ROR_SCAN_INFO*),
637 (qsort_cmp)cmp_ror_scan_info_covering);
638
639- print_ror_scans_arr(param->table,
640- "remaining scans",
641- ror_scan_mark, ror_scans_end);
642-
643 /* I=I-first(I) */
644 total_cost += (*ror_scan_mark)->index_read_cost;
645 records += (*ror_scan_mark)->records;
646@@ -2222,10 +1937,6 @@
647 Ok, [tree->ror_scans .. ror_scan) holds covering index_intersection with
648 cost total_cost.
649 */
650- print_ror_scans_arr(param->table,
651- "creating covering ROR-intersect",
652- tree->ror_scans, ror_scan_mark);
653-
654 /* Add priority queue use cost. */
655 total_cost += rows2double(records)*
656 log((double)(ror_scan_mark - tree->ror_scans)) /
657@@ -2253,12 +1964,12 @@
658
659
660 /*
661- Get best "range" table read plan for given SEL_TREE, also update some info
662+ Get best "range" table read plan for given optimizer::SEL_TREE, also update some info
663
664 SYNOPSIS
665 get_key_scans_params()
666 param Parameters from test_quick_select
667- tree Make range select for this SEL_TREE
668+ tree Make range select for this optimizer::SEL_TREE
669 index_read_must_be_used true <=> assume 'index only' option will be set
670 (except for clustered PK indexes)
671 update_tbl_stats true <=> update table->quick_* with information
672@@ -2267,7 +1978,7 @@
673 cost > read_time.
674
675 DESCRIPTION
676- Find the best "range" table read plan for given SEL_TREE.
677+ Find the best "range" table read plan for given optimizer::SEL_TREE.
678 The side effects are
679 - tree->ror_scans is updated to indicate which scans are ROR scans.
680 - if update_tbl_stats=true then table->quick_* is updated with info
681@@ -2279,7 +1990,7 @@
682 */
683
684 static optimizer::RangeReadPlan *get_key_scans_params(optimizer::Parameter *param,
685- SEL_TREE *tree,
686+ optimizer::SEL_TREE *tree,
687 bool index_read_must_be_used,
688 bool update_tbl_stats,
689 double read_time)
690@@ -2293,11 +2004,10 @@
691 uint32_t best_buf_size= 0;
692 optimizer::RangeReadPlan *read_plan= NULL;
693 /*
694- Note that there may be trees that have type SEL_TREE::KEY but contain no
695+ Note that there may be trees that have type optimizer::SEL_TREE::KEY but contain no
696 key reads at all, e.g. tree for expression "key1 is not null" where key1
697 is defined as "not null".
698 */
699- print_sel_tree(param, tree, &tree->keys_map, "tree scans");
700 tree->ror_scans_map.reset();
701 tree->n_ror_scans= 0;
702 for (idx= 0,key=tree->keys, end=key+param->keys; key != end; key++,idx++)
703@@ -2336,7 +2046,6 @@
704 }
705 }
706
707- print_sel_tree(param, tree, &tree->ror_scans_map, "ROR scans");
708 if (key_to_read)
709 {
710 idx= key_to_read - tree->keys;
711@@ -2396,9 +2105,6 @@
712 (retrieve_full_rows? (! is_covering) : false),
713 parent_alloc)))
714 {
715- print_ror_scans_vector(param->table,
716- "creating ROR-intersect",
717- ror_range_scans);
718 alloc= parent_alloc ? parent_alloc : &quick_intersect->alloc;
719 for (vector<struct st_ror_scan_info *>::iterator it= ror_range_scans.begin();
720 it != ror_range_scans.end();
721@@ -2466,7 +2172,7 @@
722
723
724 /*
725- Build a SEL_TREE for <> or NOT BETWEEN predicate
726+ Build a optimizer::SEL_TREE for <> or NOT BETWEEN predicate
727
728 SYNOPSIS
729 get_ne_mm_tree()
730@@ -2481,13 +2187,13 @@
731 # Pointer to tree built tree
732 0 on error
733 */
734-static SEL_TREE *get_ne_mm_tree(optimizer::RangeParameter *param,
735+static optimizer::SEL_TREE *get_ne_mm_tree(optimizer::RangeParameter *param,
736 Item_func *cond_func,
737 Field *field,
738 Item *lt_value, Item *gt_value,
739 Item_result cmp_type)
740 {
741- SEL_TREE *tree;
742+ optimizer::SEL_TREE *tree= NULL;
743 tree= get_mm_parts(param, cond_func, field, Item_func::LT_FUNC,
744 lt_value, cmp_type);
745 if (tree)
746@@ -2504,7 +2210,7 @@
747
748
749 /*
750- Build a SEL_TREE for a simple predicate
751+ Build a optimizer::SEL_TREE for a simple predicate
752
753 SYNOPSIS
754 get_func_mm_tree()
755@@ -2519,14 +2225,14 @@
756 RETURN
757 Pointer to the tree built tree
758 */
759-static SEL_TREE *get_func_mm_tree(optimizer::RangeParameter *param,
760+static optimizer::SEL_TREE *get_func_mm_tree(optimizer::RangeParameter *param,
761 Item_func *cond_func,
762 Field *field,
763 Item *value,
764 Item_result cmp_type,
765 bool inv)
766 {
767- SEL_TREE *tree= NULL;
768+ optimizer::SEL_TREE *tree= NULL;
769
770 switch (cond_func->functype())
771 {
772@@ -2598,7 +2304,7 @@
773 {
774 /*
775 We get here for conditions in form "t.key NOT IN (c1, c2, ...)",
776- where c{i} are constants. Our goal is to produce a SEL_TREE that
777+ where c{i} are constants. Our goal is to produce a optimizer::SEL_TREE that
778 represents intervals:
779
780 ($MIN<t.key<c1) OR (c1<t.key<c2) OR (c2<t.key<c3) OR ... (*)
781@@ -2607,7 +2313,7 @@
782
783 The most straightforward way to produce it is to convert NOT IN
784 into "(t.key != c1) AND (t.key != c2) AND ... " and let the range
785- analyzer to build SEL_TREE from that. The problem is that the
786+ analyzer to build optimizer::SEL_TREE from that. The problem is that the
787 range analyzer will use O(N^2) memory (which is probably a bug),
788 and people do use big NOT IN lists (e.g. see BUG#15872, BUG#21282),
789 will run out of memory.
790@@ -2620,8 +2326,8 @@
791
792 Considering the above, we'll handle NOT IN as follows:
793 * if the number of entries in the NOT IN list is less than
794- NOT_IN_IGNORE_THRESHOLD, construct the SEL_TREE (*) manually.
795- * Otherwise, don't produce a SEL_TREE.
796+ NOT_IN_IGNORE_THRESHOLD, construct the optimizer::SEL_TREE (*) manually.
797+ * Otherwise, don't produce a optimizer::SEL_TREE.
798 */
799 #define NOT_IN_IGNORE_THRESHOLD 1000
800 memory::Root *tmp_root= param->mem_root;
801@@ -2640,7 +2346,7 @@
802 if (func->array->count > NOT_IN_IGNORE_THRESHOLD || ! value_item)
803 break;
804
805- /* Get a SEL_TREE for "(-inf|NULL) < X < c_0" interval. */
806+ /* Get a optimizer::SEL_TREE for "(-inf|NULL) < X < c_0" interval. */
807 uint32_t i=0;
808 do
809 {
810@@ -2653,20 +2359,20 @@
811 if (! tree)
812 break;
813 i++;
814- } while (i < func->array->count && tree->type == SEL_TREE::IMPOSSIBLE);
815+ } while (i < func->array->count && tree->type == optimizer::SEL_TREE::IMPOSSIBLE);
816
817- if (!tree || tree->type == SEL_TREE::IMPOSSIBLE)
818+ if (!tree || tree->type == optimizer::SEL_TREE::IMPOSSIBLE)
819 {
820 /* We get here in cases like "t.unsigned NOT IN (-1,-2,-3) */
821 tree= NULL;
822 break;
823 }
824- SEL_TREE *tree2;
825+ optimizer::SEL_TREE *tree2= NULL;
826 for (; i < func->array->count; i++)
827 {
828 if (func->array->compare_elems(i, i-1))
829 {
830- /* Get a SEL_TREE for "-inf < X < c_i" interval */
831+ /* Get a optimizer::SEL_TREE for "-inf < X < c_i" interval */
832 func->array->value_to_item(i, value_item);
833 tree2= get_mm_parts(param, cond_func, field, Item_func::LT_FUNC,
834 value_item, cmp_type);
835@@ -2696,10 +2402,10 @@
836 }
837 }
838
839- if (tree && tree->type != SEL_TREE::IMPOSSIBLE)
840+ if (tree && tree->type != optimizer::SEL_TREE::IMPOSSIBLE)
841 {
842 /*
843- Get the SEL_TREE for the last "c_last < X < +inf" interval
844+ Get the optimizer::SEL_TREE for the last "c_last < X < +inf" interval
845 (value_item cotains c_last already)
846 */
847 tree2= get_mm_parts(param, cond_func, field, Item_func::GT_FUNC,
848@@ -2763,7 +2469,7 @@
849
850
851 /*
852- Build conjunction of all SEL_TREEs for a simple predicate applying equalities
853+ Build conjunction of all optimizer::SEL_TREEs for a simple predicate applying equalities
854
855 SYNOPSIS
856 get_full_func_mm_tree()
857@@ -2778,7 +2484,7 @@
858
859 DESCRIPTION
860 For a simple SARGable predicate of the form (f op c), where f is a field and
861- c is a constant, the function builds a conjunction of all SEL_TREES that can
862+ c is a constant, the function builds a conjunction of all optimizer::SEL_TREES that can
863 be obtained by the substitution of f for all different fields equal to f.
864
865 NOTES
866@@ -2788,9 +2494,9 @@
867 each fj belonging to the same multiple equality as fi
868 are built as well.
869 E.g. for WHERE t1.a=t2.a AND t2.a > 10
870- a SEL_TREE for t2.a > 10 will be built for quick select from t2
871+ a optimizer::SEL_TREE for t2.a > 10 will be built for quick select from t2
872 and
873- a SEL_TREE for t1.a > 10 will be built for quick select from t1.
874+ a optimizer::SEL_TREE for t1.a > 10 will be built for quick select from t1.
875
876 A BETWEEN predicate of the form (fi [NOT] BETWEEN c1 AND c2) is treated
877 in a similar way: we build a conjuction of trees for the results
878@@ -2829,16 +2535,16 @@
879 the form (c IN (c1,...,f,...,cn)).
880
881 RETURN
882- Pointer to the tree representing the built conjunction of SEL_TREEs
883+ Pointer to the tree representing the built conjunction of optimizer::SEL_TREEs
884 */
885
886-static SEL_TREE *get_full_func_mm_tree(optimizer::RangeParameter *param,
887+static optimizer::SEL_TREE *get_full_func_mm_tree(optimizer::RangeParameter *param,
888 Item_func *cond_func,
889 Item_field *field_item, Item *value,
890 bool inv)
891 {
892- SEL_TREE *tree= 0;
893- SEL_TREE *ftree= 0;
894+ optimizer::SEL_TREE *tree= 0;
895+ optimizer::SEL_TREE *ftree= 0;
896 table_map ref_tables= 0;
897 table_map param_comp= ~(param->prev_tables | param->read_tables |
898 param->current_table);
899@@ -2880,10 +2586,10 @@
900
901 /* make a select tree of all keys in condition */
902
903-static SEL_TREE *get_mm_tree(optimizer::RangeParameter *param, COND *cond)
904+static optimizer::SEL_TREE *get_mm_tree(optimizer::RangeParameter *param, COND *cond)
905 {
906- SEL_TREE *tree=0;
907- SEL_TREE *ftree= 0;
908+ optimizer::SEL_TREE *tree=0;
909+ optimizer::SEL_TREE *ftree= 0;
910 Item_field *field_item= 0;
911 bool inv= false;
912 Item *value= 0;
913@@ -2898,12 +2604,12 @@
914 Item *item;
915 while ((item=li++))
916 {
917- SEL_TREE *new_tree= get_mm_tree(param,item);
918+ optimizer::SEL_TREE *new_tree= get_mm_tree(param,item);
919 if (param->session->is_fatal_error ||
920 param->alloced_sel_args > optimizer::SEL_ARG::MAX_SEL_ARGS)
921 return 0; // out of memory
922 tree=tree_and(param,tree,new_tree);
923- if (tree && tree->type == SEL_TREE::IMPOSSIBLE)
924+ if (tree && tree->type == optimizer::SEL_TREE::IMPOSSIBLE)
925 break;
926 }
927 }
928@@ -2915,11 +2621,11 @@
929 Item *item;
930 while ((item=li++))
931 {
932- SEL_TREE *new_tree= get_mm_tree(param,item);
933+ optimizer::SEL_TREE *new_tree= get_mm_tree(param,item);
934 if (!new_tree)
935 return 0; // out of memory
936 tree=tree_or(param,tree,new_tree);
937- if (!tree || tree->type == SEL_TREE::ALWAYS)
938+ if (!tree || tree->type == optimizer::SEL_TREE::ALWAYS)
939 break;
940 }
941 }
942@@ -2937,8 +2643,8 @@
943 */
944 memory::Root *tmp_root= param->mem_root;
945 param->session->mem_root= param->old_root;
946- tree= cond->val_int() ? new(tmp_root) SEL_TREE(SEL_TREE::ALWAYS) :
947- new(tmp_root) SEL_TREE(SEL_TREE::IMPOSSIBLE);
948+ tree= cond->val_int() ? new(tmp_root) optimizer::SEL_TREE(optimizer::SEL_TREE::ALWAYS) :
949+ new(tmp_root) optimizer::SEL_TREE(optimizer::SEL_TREE::IMPOSSIBLE);
950 param->session->mem_root= tmp_root;
951 return(tree);
952 }
953@@ -2952,7 +2658,7 @@
954 if ((ref_tables & param->current_table) ||
955 (ref_tables & ~(param->prev_tables | param->read_tables)))
956 return 0;
957- return(new SEL_TREE(SEL_TREE::MAYBE));
958+ return(new optimizer::SEL_TREE(optimizer::SEL_TREE::MAYBE));
959 }
960
961 Item_func *cond_func= (Item_func*) cond;
962@@ -2981,7 +2687,7 @@
963 if (cond_func->arguments()[i]->real_item()->type() == Item::FIELD_ITEM)
964 {
965 field_item= (Item_field*) (cond_func->arguments()[i]->real_item());
966- SEL_TREE *tmp= get_full_func_mm_tree(param, cond_func,
967+ optimizer::SEL_TREE *tmp= get_full_func_mm_tree(param, cond_func,
968 field_item, (Item*)(intptr_t)i, inv);
969 if (inv)
970 tree= !tree ? tmp : tree_or(param, tree, tmp);
971@@ -3051,7 +2757,7 @@
972 }
973
974
975-static SEL_TREE *
976+static optimizer::SEL_TREE *
977 get_mm_parts(optimizer::RangeParameter *param,
978 COND *cond_func,
979 Field *field,
980@@ -3063,7 +2769,7 @@
981
982 KEY_PART *key_part = param->key_parts;
983 KEY_PART *end = param->key_parts_end;
984- SEL_TREE *tree=0;
985+ optimizer::SEL_TREE *tree=0;
986 if (value &&
987 value->used_tables() & ~(param->prev_tables | param->read_tables))
988 return 0;
989@@ -3072,7 +2778,7 @@
990 if (field->eq(key_part->field))
991 {
992 optimizer::SEL_ARG *sel_arg=0;
993- if (!tree && !(tree=new SEL_TREE()))
994+ if (!tree && !(tree=new optimizer::SEL_TREE()))
995 return 0; // OOM
996 if (!value || !(value->used_tables() & ~param->read_tables))
997 {
998@@ -3082,7 +2788,7 @@
999 continue;
1000 if (sel_arg->type == optimizer::SEL_ARG::IMPOSSIBLE)
1001 {
1002- tree->type=SEL_TREE::IMPOSSIBLE;
1003+ tree->type=optimizer::SEL_TREE::IMPOSSIBLE;
1004 return(tree);
1005 }
1006 }
1007@@ -3569,26 +3275,26 @@
1008 #define swap_clone_flag(A) ((A & 1) << 1) | ((A & 2) >> 1)
1009
1010
1011-static SEL_TREE *
1012-tree_and(optimizer::RangeParameter *param, SEL_TREE *tree1, SEL_TREE *tree2)
1013+static optimizer::SEL_TREE *
1014+tree_and(optimizer::RangeParameter *param, optimizer::SEL_TREE *tree1, optimizer::SEL_TREE *tree2)
1015 {
1016 if (!tree1)
1017 return(tree2);
1018 if (!tree2)
1019 return(tree1);
1020- if (tree1->type == SEL_TREE::IMPOSSIBLE || tree2->type == SEL_TREE::ALWAYS)
1021+ if (tree1->type == optimizer::SEL_TREE::IMPOSSIBLE || tree2->type == optimizer::SEL_TREE::ALWAYS)
1022 return(tree1);
1023- if (tree2->type == SEL_TREE::IMPOSSIBLE || tree1->type == SEL_TREE::ALWAYS)
1024+ if (tree2->type == optimizer::SEL_TREE::IMPOSSIBLE || tree1->type == optimizer::SEL_TREE::ALWAYS)
1025 return(tree2);
1026- if (tree1->type == SEL_TREE::MAYBE)
1027+ if (tree1->type == optimizer::SEL_TREE::MAYBE)
1028 {
1029- if (tree2->type == SEL_TREE::KEY)
1030- tree2->type=SEL_TREE::KEY_SMALLER;
1031+ if (tree2->type == optimizer::SEL_TREE::KEY)
1032+ tree2->type=optimizer::SEL_TREE::KEY_SMALLER;
1033 return(tree2);
1034 }
1035- if (tree2->type == SEL_TREE::MAYBE)
1036+ if (tree2->type == optimizer::SEL_TREE::MAYBE)
1037 {
1038- tree1->type=SEL_TREE::KEY_SMALLER;
1039+ tree1->type=optimizer::SEL_TREE::KEY_SMALLER;
1040 return(tree1);
1041 }
1042 key_map result_keys;
1043@@ -3609,7 +3315,7 @@
1044 *key1=key_and(param, *key1, *key2, flag);
1045 if (*key1 && (*key1)->type == optimizer::SEL_ARG::IMPOSSIBLE)
1046 {
1047- tree1->type= SEL_TREE::IMPOSSIBLE;
1048+ tree1->type= optimizer::SEL_TREE::IMPOSSIBLE;
1049 return(tree1);
1050 }
1051 result_keys.set(key1 - tree1->keys);
1052@@ -3629,195 +3335,6 @@
1053 }
1054
1055
1056-/*
1057- Check if two SEL_TREES can be combined into one (i.e. a single key range
1058- read can be constructed for "cond_of_tree1 OR cond_of_tree2" ) without
1059- using index_merge.
1060-*/
1061-
1062-bool sel_trees_can_be_ored(SEL_TREE *tree1, SEL_TREE *tree2,
1063- optimizer::RangeParameter* param)
1064-{
1065- key_map common_keys= tree1->keys_map;
1066- common_keys&= tree2->keys_map;
1067-
1068- if (common_keys.none())
1069- return false;
1070-
1071- /* trees have a common key, check if they refer to same key part */
1072- optimizer::SEL_ARG **key1,**key2;
1073- for (uint32_t key_no=0; key_no < param->keys; key_no++)
1074- {
1075- if (common_keys.test(key_no))
1076- {
1077- key1= tree1->keys + key_no;
1078- key2= tree2->keys + key_no;
1079- if ((*key1)->part == (*key2)->part)
1080- {
1081- return true;
1082- }
1083- }
1084- }
1085- return false;
1086-}
1087-
1088-
1089-/*
1090- Remove the trees that are not suitable for record retrieval.
1091- SYNOPSIS
1092- param Range analysis parameter
1093- tree Tree to be processed, tree->type is KEY or KEY_SMALLER
1094-
1095- DESCRIPTION
1096- This function walks through tree->keys[] and removes the SEL_ARG* trees
1097- that are not "maybe" trees (*) and cannot be used to construct quick range
1098- selects.
1099- (*) - have type MAYBE or MAYBE_KEY. Perhaps we should remove trees of
1100- these types here as well.
1101-
1102- A SEL_ARG* tree cannot be used to construct quick select if it has
1103- tree->part != 0. (e.g. it could represent "keypart2 < const").
1104-
1105- WHY THIS FUNCTION IS NEEDED
1106-
1107- Normally we allow construction of SEL_TREE objects that have SEL_ARG
1108- trees that do not allow quick range select construction. For example for
1109- " keypart1=1 AND keypart2=2 " the execution will proceed as follows:
1110- tree1= SEL_TREE { SEL_ARG{keypart1=1} }
1111- tree2= SEL_TREE { SEL_ARG{keypart2=2} } -- can't make quick range select
1112- from this
1113- call tree_and(tree1, tree2) -- this joins SEL_ARGs into a usable SEL_ARG
1114- tree.
1115-
1116- There is an exception though: when we construct index_merge SEL_TREE,
1117- any SEL_ARG* tree that cannot be used to construct quick range select can
1118- be removed, because current range analysis code doesn't provide any way
1119- that tree could be later combined with another tree.
1120- Consider an example: we should not construct
1121- st1 = SEL_TREE {
1122- merges = SEL_IMERGE {
1123- SEL_TREE(t.key1part1 = 1),
1124- SEL_TREE(t.key2part2 = 2) -- (*)
1125- }
1126- };
1127- because
1128- - (*) cannot be used to construct quick range select,
1129- - There is no execution path that would cause (*) to be converted to
1130- a tree that could be used.
1131-
1132- The latter is easy to verify: first, notice that the only way to convert
1133- (*) into a usable tree is to call tree_and(something, (*)).
1134-
1135- Second look at what tree_and/tree_or function would do when passed a
1136- SEL_TREE that has the structure like st1 tree has, and conlcude that
1137- tree_and(something, (*)) will not be called.
1138-
1139- RETURN
1140- 0 Ok, some suitable trees left
1141- 1 No tree->keys[] left.
1142-*/
1143-
1144-static bool remove_nonrange_trees(optimizer::RangeParameter *param, SEL_TREE *tree)
1145-{
1146- bool res= false;
1147- for (uint32_t i=0; i < param->keys; i++)
1148- {
1149- if (tree->keys[i])
1150- {
1151- if (tree->keys[i]->part)
1152- {
1153- tree->keys[i]= NULL;
1154- tree->keys_map.reset(i);
1155- }
1156- else
1157- res= true;
1158- }
1159- }
1160- return !res;
1161-}
1162-
1163-
1164-static SEL_TREE *
1165-tree_or(optimizer::RangeParameter *param,SEL_TREE *tree1,SEL_TREE *tree2)
1166-{
1167- if (!tree1 || !tree2)
1168- return 0;
1169- if (tree1->type == SEL_TREE::IMPOSSIBLE || tree2->type == SEL_TREE::ALWAYS)
1170- return(tree2);
1171- if (tree2->type == SEL_TREE::IMPOSSIBLE || tree1->type == SEL_TREE::ALWAYS)
1172- return(tree1);
1173- if (tree1->type == SEL_TREE::MAYBE)
1174- return(tree1); // Can't use this
1175- if (tree2->type == SEL_TREE::MAYBE)
1176- return(tree2);
1177-
1178- SEL_TREE *result= 0;
1179- key_map result_keys;
1180- result_keys.reset();
1181- if (sel_trees_can_be_ored(tree1, tree2, param))
1182- {
1183- /* Join the trees key per key */
1184- optimizer::SEL_ARG **key1,**key2,**end;
1185- for (key1= tree1->keys,key2= tree2->keys,end= key1+param->keys ;
1186- key1 != end ; key1++,key2++)
1187- {
1188- *key1=key_or(param, *key1, *key2);
1189- if (*key1)
1190- {
1191- result=tree1; // Added to tree1
1192- result_keys.set(key1 - tree1->keys);
1193- }
1194- }
1195- if (result)
1196- result->keys_map= result_keys;
1197- }
1198- else
1199- {
1200- /* ok, two trees have KEY type but cannot be used without index merge */
1201- if (tree1->merges.is_empty() && tree2->merges.is_empty())
1202- {
1203- if (param->remove_jump_scans)
1204- {
1205- bool no_trees= remove_nonrange_trees(param, tree1);
1206- no_trees= no_trees || remove_nonrange_trees(param, tree2);
1207- if (no_trees)
1208- return(new SEL_TREE(SEL_TREE::ALWAYS));
1209- }
1210- SEL_IMERGE *merge;
1211- /* both trees are "range" trees, produce new index merge structure */
1212- if (!(result= new SEL_TREE()) || !(merge= new SEL_IMERGE()) ||
1213- (result->merges.push_back(merge)) ||
1214- (merge->or_sel_tree(param, tree1)) ||
1215- (merge->or_sel_tree(param, tree2)))
1216- result= NULL;
1217- else
1218- result->type= tree1->type;
1219- }
1220- else if (!tree1->merges.is_empty() && !tree2->merges.is_empty())
1221- {
1222- if (imerge_list_or_list(param, &tree1->merges, &tree2->merges))
1223- result= new SEL_TREE(SEL_TREE::ALWAYS);
1224- else
1225- result= tree1;
1226- }
1227- else
1228- {
1229- /* one tree is index merge tree and another is range tree */
1230- if (tree1->merges.is_empty())
1231- std::swap(tree1, tree2);
1232-
1233- if (param->remove_jump_scans && remove_nonrange_trees(param, tree2))
1234- return(new SEL_TREE(SEL_TREE::ALWAYS));
1235- /* add tree2 to tree1->merges, checking if it collapses to ALWAYS */
1236- if (imerge_list_or_tree(param, &tree1->merges, tree2))
1237- result= new SEL_TREE(SEL_TREE::ALWAYS);
1238- else
1239- result= tree1;
1240- }
1241- }
1242- return result;
1243-}
1244-
1245
1246 /* And key trees where key1->part < key2 -> part */
1247
1248@@ -4014,302 +3531,6 @@
1249 }
1250
1251
1252-static optimizer::SEL_ARG *
1253-key_or(optimizer::RangeParameter *param, optimizer::SEL_ARG *key1, optimizer::SEL_ARG *key2)
1254-{
1255- if (! key1)
1256- {
1257- if (key2)
1258- {
1259- key2->use_count--;
1260- key2->free_tree();
1261- }
1262- return 0;
1263- }
1264- if (! key2)
1265- {
1266- key1->use_count--;
1267- key1->free_tree();
1268- return 0;
1269- }
1270- key1->use_count--;
1271- key2->use_count--;
1272-
1273- if (key1->part != key2->part)
1274- {
1275- key1->free_tree();
1276- key2->free_tree();
1277- return 0; // Can't optimize this
1278- }
1279-
1280- // If one of the key is MAYBE_KEY then the found region may be bigger
1281- if (key1->type == optimizer::SEL_ARG::MAYBE_KEY)
1282- {
1283- key2->free_tree();
1284- key1->use_count++;
1285- return key1;
1286- }
1287- if (key2->type == optimizer::SEL_ARG::MAYBE_KEY)
1288- {
1289- key1->free_tree();
1290- key2->use_count++;
1291- return key2;
1292- }
1293-
1294- if (key1->use_count > 0)
1295- {
1296- if (key2->use_count == 0 || key1->elements > key2->elements)
1297- {
1298- std::swap(key1,key2);
1299- }
1300- if (key1->use_count > 0 || !(key1=key1->clone_tree(param)))
1301- return 0; // OOM
1302- }
1303-
1304- // Add tree at key2 to tree at key1
1305- bool key2_shared= key2->use_count != 0;
1306- key1->maybe_flag|= key2->maybe_flag;
1307-
1308- for (key2=key2->first(); key2; )
1309- {
1310- optimizer::SEL_ARG *tmp= key1->find_range(key2); // Find key1.min <= key2.min
1311- int cmp;
1312-
1313- if (! tmp)
1314- {
1315- tmp=key1->first(); // tmp.min > key2.min
1316- cmp= -1;
1317- }
1318- else if ((cmp=tmp->cmp_max_to_min(key2)) < 0)
1319- { // Found tmp.max < key2.min
1320- optimizer::SEL_ARG *next= tmp->next;
1321- if (cmp == -2 && eq_tree(tmp->next_key_part,key2->next_key_part))
1322- {
1323- // Join near ranges like tmp.max < 0 and key2.min >= 0
1324- optimizer::SEL_ARG *key2_next=key2->next;
1325- if (key2_shared)
1326- {
1327- if (! (key2=new optimizer::SEL_ARG(*key2)))
1328- return 0; // out of memory
1329- key2->increment_use_count(key1->use_count+1);
1330- key2->next= key2_next; // New copy of key2
1331- }
1332- key2->copy_min(tmp);
1333- if (! (key1=key1->tree_delete(tmp)))
1334- { // Only one key in tree
1335- key1= key2;
1336- key1->make_root();
1337- key2= key2_next;
1338- break;
1339- }
1340- }
1341- if (! (tmp= next)) // tmp.min > key2.min
1342- break; // Copy rest of key2
1343- }
1344- if (cmp < 0)
1345- { // tmp.min > key2.min
1346- int tmp_cmp;
1347- if ((tmp_cmp= tmp->cmp_min_to_max(key2)) > 0) // if tmp.min > key2.max
1348- {
1349- if (tmp_cmp == 2 && eq_tree(tmp->next_key_part,key2->next_key_part))
1350- { // ranges are connected
1351- tmp->copy_min_to_min(key2);
1352- key1->merge_flags(key2);
1353- if (tmp->min_flag & NO_MIN_RANGE &&
1354- tmp->max_flag & NO_MAX_RANGE)
1355- {
1356- if (key1->maybe_flag)
1357- return new optimizer::SEL_ARG(optimizer::SEL_ARG::MAYBE_KEY);
1358- return 0;
1359- }
1360- key2->increment_use_count(-1); // Free not used tree
1361- key2= key2->next;
1362- continue;
1363- }
1364- else
1365- {
1366- optimizer::SEL_ARG *next= key2->next; // Keys are not overlapping
1367- if (key2_shared)
1368- {
1369- optimizer::SEL_ARG *cpy= new optimizer::SEL_ARG(*key2); // Must make copy
1370- if (! cpy)
1371- return 0; // OOM
1372- key1= key1->insert(cpy);
1373- key2->increment_use_count(key1->use_count+1);
1374- }
1375- else
1376- key1= key1->insert(key2); // Will destroy key2_root
1377- key2= next;
1378- continue;
1379- }
1380- }
1381- }
1382-
1383- // tmp.max >= key2.min && tmp.min <= key.cmax(overlapping ranges)
1384- if (eq_tree(tmp->next_key_part,key2->next_key_part))
1385- {
1386- if (tmp->is_same(key2))
1387- {
1388- tmp->merge_flags(key2); // Copy maybe flags
1389- key2->increment_use_count(-1); // Free not used tree
1390- }
1391- else
1392- {
1393- optimizer::SEL_ARG *last= tmp;
1394- while (last->next && last->next->cmp_min_to_max(key2) <= 0 &&
1395- eq_tree(last->next->next_key_part,key2->next_key_part))
1396- {
1397- optimizer::SEL_ARG *save= last;
1398- last= last->next;
1399- key1= key1->tree_delete(save);
1400- }
1401- last->copy_min(tmp);
1402- if (last->copy_min(key2) || last->copy_max(key2))
1403- { // Full range
1404- key1->free_tree();
1405- for (; key2; key2= key2->next)
1406- key2->increment_use_count(-1); // Free not used tree
1407- if (key1->maybe_flag)
1408- return new optimizer::SEL_ARG(optimizer::SEL_ARG::MAYBE_KEY);
1409- return 0;
1410- }
1411- }
1412- key2= key2->next;
1413- continue;
1414- }
1415-
1416- if (cmp >= 0 && tmp->cmp_min_to_min(key2) < 0)
1417- { // tmp.min <= x < key2.min
1418- optimizer::SEL_ARG *new_arg= tmp->clone_first(key2);
1419- if (! new_arg)
1420- return 0; // OOM
1421- if ((new_arg->next_key_part= key1->next_key_part))
1422- new_arg->increment_use_count(key1->use_count+1);
1423- tmp->copy_min_to_min(key2);
1424- key1= key1->insert(new_arg);
1425- }
1426-
1427- // tmp.min >= key2.min && tmp.min <= key2.max
1428- optimizer::SEL_ARG key(*key2); // Get copy we can modify
1429- for (;;)
1430- {
1431- if (tmp->cmp_min_to_min(&key) > 0)
1432- { // key.min <= x < tmp.min
1433- optimizer::SEL_ARG *new_arg= key.clone_first(tmp);
1434- if (! new_arg)
1435- return 0; // OOM
1436- if ((new_arg->next_key_part=key.next_key_part))
1437- new_arg->increment_use_count(key1->use_count+1);
1438- key1= key1->insert(new_arg);
1439- }
1440- if ((cmp=tmp->cmp_max_to_max(&key)) <= 0)
1441- { // tmp.min. <= x <= tmp.max
1442- tmp->maybe_flag|= key.maybe_flag;
1443- key.increment_use_count(key1->use_count+1);
1444- tmp->next_key_part= key_or(param, tmp->next_key_part, key.next_key_part);
1445- if (! cmp) // Key2 is ready
1446- break;
1447- key.copy_max_to_min(tmp);
1448- if (! (tmp= tmp->next))
1449- {
1450- optimizer::SEL_ARG *tmp2= new optimizer::SEL_ARG(key);
1451- if (! tmp2)
1452- return 0; // OOM
1453- key1= key1->insert(tmp2);
1454- key2= key2->next;
1455- goto end;
1456- }
1457- if (tmp->cmp_min_to_max(&key) > 0)
1458- {
1459- optimizer::SEL_ARG *tmp2= new optimizer::SEL_ARG(key);
1460- if (! tmp2)
1461- return 0; // OOM
1462- key1= key1->insert(tmp2);
1463- break;
1464- }
1465- }
1466- else
1467- {
1468- optimizer::SEL_ARG *new_arg= tmp->clone_last(&key); // tmp.min <= x <= key.max
1469- if (! new_arg)
1470- return 0; // OOM
1471- tmp->copy_max_to_min(&key);
1472- tmp->increment_use_count(key1->use_count+1);
1473- /* Increment key count as it may be used for next loop */
1474- key.increment_use_count(1);
1475- new_arg->next_key_part= key_or(param, tmp->next_key_part, key.next_key_part);
1476- key1= key1->insert(new_arg);
1477- break;
1478- }
1479- }
1480- key2= key2->next;
1481- }
1482-
1483-end:
1484- while (key2)
1485- {
1486- optimizer::SEL_ARG *next= key2->next;
1487- if (key2_shared)
1488- {
1489- optimizer::SEL_ARG *tmp= new optimizer::SEL_ARG(*key2); // Must make copy
1490- if (! tmp)
1491- return 0;
1492- key2->increment_use_count(key1->use_count+1);
1493- key1= key1->insert(tmp);
1494- }
1495- else
1496- key1= key1->insert(key2); // Will destroy key2_root
1497- key2= next;
1498- }
1499- key1->use_count++;
1500- return key1;
1501-}
1502-
1503-
1504-/* Compare if two trees are equal */
1505-static bool eq_tree(optimizer::SEL_ARG *a, optimizer::SEL_ARG *b)
1506-{
1507- if (a == b)
1508- {
1509- return true;
1510- }
1511-
1512- if (! a || ! b || ! a->is_same(b))
1513- {
1514- return false;
1515- }
1516-
1517- if (a->left != &optimizer::null_element && b->left != &optimizer::null_element)
1518- {
1519- if (! eq_tree(a->left,b->left))
1520- return false;
1521- }
1522- else if (a->left != &optimizer::null_element || b->left != &optimizer::null_element)
1523- {
1524- return false;
1525- }
1526-
1527- if (a->right != &optimizer::null_element && b->right != &optimizer::null_element)
1528- {
1529- if (! eq_tree(a->right,b->right))
1530- return false;
1531- }
1532- else if (a->right != &optimizer::null_element || b->right != &optimizer::null_element)
1533- {
1534- return false;
1535- }
1536-
1537- if (a->next_key_part != b->next_key_part)
1538- { // Sub range
1539- if (! a->next_key_part != ! b->next_key_part ||
1540- ! eq_tree(a->next_key_part, b->next_key_part))
1541- return false;
1542- }
1543-
1544- return true;
1545-}
1546-
1547-
1548 /****************************************************************************
1549 MRR Range Sequence Interface implementation that walks a SEL_ARG* tree.
1550 ****************************************************************************/
1551@@ -4340,7 +3561,7 @@
1552 */
1553 typedef struct st_sel_arg_range_seq
1554 {
1555- uint32_t keyno; /* index of used tree in SEL_TREE structure */
1556+ uint32_t keyno; /* index of used tree in optimizer::SEL_TREE structure */
1557 uint32_t real_keyno; /* Number of the index in tables */
1558 optimizer::Parameter *param;
1559 optimizer::SEL_ARG *start; /* Root node of the traversed SEL_ARG* graph */
1560@@ -4582,7 +3803,7 @@
1561 SYNOPSIS
1562 check_quick_select()
1563 param Parameter from test_quick_select
1564- idx Number of index to use in Parameter::key SEL_TREE::key
1565+ idx Number of index to use in Parameter::key optimizer::SEL_TREE::key
1566 index_only true - assume only index tuples will be accessed
1567 false - assume full table rows will be read
1568 tree Transformed selection condition, tree->key[idx] holds
1569@@ -5196,7 +4417,7 @@
1570 static inline uint32_t get_field_keypart(KEY *index, Field *field);
1571
1572 static inline optimizer::SEL_ARG * get_index_range_tree(uint32_t index,
1573- SEL_TREE *range_tree,
1574+ optimizer::SEL_TREE *range_tree,
1575 optimizer::Parameter *param,
1576 uint32_t *param_idx);
1577
1578@@ -5217,7 +4438,7 @@
1579 KEY *index_info,
1580 uint32_t used_key_parts,
1581 uint32_t group_key_parts,
1582- SEL_TREE *range_tree,
1583+ optimizer::SEL_TREE *range_tree,
1584 optimizer::SEL_ARG *index_tree,
1585 ha_rows quick_prefix_records,
1586 bool have_min,
1587@@ -5354,7 +4575,7 @@
1588 - NULL
1589 */
1590 static optimizer::GroupMinMaxReadPlan *
1591-get_best_group_min_max(optimizer::Parameter *param, SEL_TREE *tree)
1592+get_best_group_min_max(optimizer::Parameter *param, optimizer::SEL_TREE *tree)
1593 {
1594 Session *session= param->session;
1595 JOIN *join= session->lex->current_select->join;
1596@@ -6068,8 +5289,8 @@
1597
1598 DESCRIPTION
1599
1600- A SEL_TREE contains range trees for all usable indexes. This procedure
1601- finds the SEL_ARG sub-tree for 'index'. The members of a SEL_TREE are
1602+ A optimizer::SEL_TREE contains range trees for all usable indexes. This procedure
1603+ finds the SEL_ARG sub-tree for 'index'. The members of a optimizer::SEL_TREE are
1604 ordered in the same way as the members of Parameter::key, thus we first find
1605 the corresponding index in the array Parameter::key. This index is returned
1606 through the variable param_idx, to be used later as argument of
1607@@ -6079,7 +5300,7 @@
1608 Pointer to the SEL_ARG subtree that corresponds to index.
1609 */
1610 optimizer::SEL_ARG *get_index_range_tree(uint32_t index,
1611- SEL_TREE* range_tree,
1612+ optimizer::SEL_TREE* range_tree,
1613 optimizer::Parameter *param,
1614 uint32_t *param_idx)
1615 {
1616@@ -6158,7 +5379,7 @@
1617 KEY *index_info,
1618 uint32_t used_key_parts,
1619 uint32_t group_key_parts,
1620- SEL_TREE *range_tree,
1621+ optimizer::SEL_TREE *range_tree,
1622 optimizer::SEL_ARG *,
1623 ha_rows quick_prefix_records,
1624 bool have_min,
1625@@ -6360,67 +5581,4 @@
1626 }
1627
1628
1629-static void print_sel_tree(optimizer::Parameter *param, SEL_TREE *tree, key_map *tree_map, const char *)
1630-{
1631- optimizer::SEL_ARG **key= NULL;
1632- optimizer::SEL_ARG **end= NULL;
1633- int idx= 0;
1634- char buff[1024];
1635-
1636- String tmp(buff,sizeof(buff),&my_charset_bin);
1637- tmp.length(0);
1638- for (idx= 0, key=tree->keys, end= key + param->keys;
1639- key != end;
1640- key++, idx++)
1641- {
1642- if (tree_map->test(idx))
1643- {
1644- uint32_t keynr= param->real_keynr[idx];
1645- if (tmp.length())
1646- tmp.append(',');
1647- tmp.append(param->table->key_info[keynr].name);
1648- }
1649- }
1650- if (! tmp.length())
1651- tmp.append(STRING_WITH_LEN("(empty)"));
1652-}
1653-
1654-
1655-static void print_ror_scans_arr(Table *table,
1656- const char *,
1657- struct st_ror_scan_info **start,
1658- struct st_ror_scan_info **end)
1659-{
1660- char buff[1024];
1661- String tmp(buff,sizeof(buff),&my_charset_bin);
1662- tmp.length(0);
1663- for (; start != end; start++)
1664- {
1665- if (tmp.length())
1666- tmp.append(',');
1667- tmp.append(table->key_info[(*start)->keynr].name);
1668- }
1669- if (! tmp.length())
1670- tmp.append(STRING_WITH_LEN("(empty)"));
1671-}
1672-
1673-static void print_ror_scans_vector(Table *table,
1674- const char *,
1675- vector<struct st_ror_scan_info *> &vec)
1676-{
1677- char buff[1024];
1678- String tmp(buff,sizeof(buff),&my_charset_bin);
1679- tmp.length(0);
1680- for (vector<struct st_ror_scan_info *>::iterator it= vec.begin();
1681- it != vec.end();
1682- ++it)
1683- {
1684- if (tmp.length())
1685- tmp.append(',');
1686- tmp.append(table->key_info[(*it)->keynr].name);
1687- }
1688- if (! tmp.length())
1689- tmp.append(STRING_WITH_LEN("(empty)"));
1690-}
1691-
1692 } /* namespace drizzled */
1693
1694=== added file 'drizzled/optimizer/sel_imerge.cc'
1695--- drizzled/optimizer/sel_imerge.cc 1970-01-01 00:00:00 +0000
1696+++ drizzled/optimizer/sel_imerge.cc 2010-03-16 01:44:16 +0000
1697@@ -0,0 +1,98 @@
1698+/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
1699+ * vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
1700+ *
1701+ * Copyright (C) 2008-2009 Sun Microsystems
1702+ *
1703+ * This program is free software; you can redistribute it and/or modify
1704+ * it under the terms of the GNU General Public License as published by
1705+ * the Free Software Foundation; version 2 of the License.
1706+ *
1707+ * This program is distributed in the hope that it will be useful,
1708+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1709+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1710+ * GNU General Public License for more details.
1711+ *
1712+ * You should have received a copy of the GNU General Public License
1713+ * along with this program; if not, write to the Free Software
1714+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
1715+ */
1716+
1717+#include "config.h"
1718+
1719+#include "drizzled/sql_base.h"
1720+#include "drizzled/sql_select.h"
1721+#include "drizzled/memory/sql_alloc.h"
1722+#include "drizzled/optimizer/range.h"
1723+#include "drizzled/optimizer/range_param.h"
1724+#include "drizzled/optimizer/sel_arg.h"
1725+#include "drizzled/optimizer/sel_tree.h"
1726+#include "drizzled/optimizer/sel_imerge.h"
1727+
1728+using namespace std;
1729+using namespace drizzled;
1730+
1731+optimizer::SEL_IMERGE::SEL_IMERGE()
1732+ :
1733+ trees(&trees_prealloced[0]),
1734+ trees_next(trees),
1735+ trees_end(trees + PREALLOCED_TREES)
1736+{}
1737+
1738+
1739+int optimizer::SEL_IMERGE::or_sel_tree(optimizer::RangeParameter *param, optimizer::SEL_TREE *tree)
1740+{
1741+ if (trees_next == trees_end)
1742+ {
1743+ const int realloc_ratio= 2; /* Double size for next round */
1744+ uint32_t old_elements= (trees_end - trees);
1745+ uint32_t old_size= sizeof(optimizer::SEL_TREE**) * old_elements;
1746+ uint32_t new_size= old_size * realloc_ratio;
1747+ optimizer::SEL_TREE **new_trees= NULL;
1748+ if (! (new_trees= (optimizer::SEL_TREE**) alloc_root(param->mem_root, new_size)))
1749+ return -1;
1750+ memcpy(new_trees, trees, old_size);
1751+ trees= new_trees;
1752+ trees_next= trees + old_elements;
1753+ trees_end= trees + old_elements * realloc_ratio;
1754+ }
1755+ *(trees_next++)= tree;
1756+ return 0;
1757+}
1758+
1759+
1760+int optimizer::SEL_IMERGE::or_sel_tree_with_checks(optimizer::RangeParameter *param, optimizer::SEL_TREE *new_tree)
1761+{
1762+ for (optimizer::SEL_TREE** tree = trees;
1763+ tree != trees_next;
1764+ tree++)
1765+ {
1766+ if (sel_trees_can_be_ored(*tree, new_tree, param))
1767+ {
1768+ *tree = tree_or(param, *tree, new_tree);
1769+ if (!*tree)
1770+ return 1;
1771+ if (((*tree)->type == optimizer::SEL_TREE::MAYBE) ||
1772+ ((*tree)->type == optimizer::SEL_TREE::ALWAYS))
1773+ return 1;
1774+ /* optimizer::SEL_TREE::IMPOSSIBLE is impossible here */
1775+ return 0;
1776+ }
1777+ }
1778+
1779+ /* New tree cannot be combined with any of existing trees. */
1780+ return or_sel_tree(param, new_tree);
1781+}
1782+
1783+
1784+int optimizer::SEL_IMERGE::or_sel_imerge_with_checks(optimizer::RangeParameter *param, optimizer::SEL_IMERGE* imerge)
1785+{
1786+ for (optimizer::SEL_TREE** tree= imerge->trees;
1787+ tree != imerge->trees_next;
1788+ tree++)
1789+ {
1790+ if (or_sel_tree_with_checks(param, *tree))
1791+ return 1;
1792+ }
1793+ return 0;
1794+}
1795+
1796
1797=== added file 'drizzled/optimizer/sel_imerge.h'
1798--- drizzled/optimizer/sel_imerge.h 1970-01-01 00:00:00 +0000
1799+++ drizzled/optimizer/sel_imerge.h 2010-03-16 01:44:16 +0000
1800@@ -0,0 +1,122 @@
1801+/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
1802+ * vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
1803+ *
1804+ * Copyright (C) 2008-2009 Sun Microsystems
1805+ *
1806+ * This program is free software; you can redistribute it and/or modify
1807+ * it under the terms of the GNU General Public License as published by
1808+ * the Free Software Foundation; version 2 of the License.
1809+ *
1810+ * This program is distributed in the hope that it will be useful,
1811+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1812+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1813+ * GNU General Public License for more details.
1814+ *
1815+ * You should have received a copy of the GNU General Public License
1816+ * along with this program; if not, write to the Free Software
1817+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
1818+ */
1819+
1820+#ifndef DRIZZLED_OPTIMIZER_SEL_IMERGE_H
1821+#define DRIZZLED_OPTIMIZER_SEL_IMERGE_H
1822+
1823+#include "drizzled/memory/sql_alloc.h"
1824+
1825+namespace drizzled
1826+{
1827+
1828+namespace optimizer
1829+{
1830+
1831+class RangeParameter;
1832+class SEL_TREE;
1833+class SEL_ARG;
1834+
1835+/*
1836+ SEL_IMERGE is a list of possible ways to do index merge, i.e. it is
1837+ a condition in the following form:
1838+ (t_1||t_2||...||t_N) && (next)
1839+
1840+ where all t_i are optimizer::SEL_TREEs, next is another SEL_IMERGE and no pair
1841+ (t_i,t_j) contains SEL_ARGS for the same index.
1842+
1843+ optimizer::SEL_TREE contained in SEL_IMERGE always has merges=NULL.
1844+
1845+ This class relies on memory manager to do the cleanup.
1846+*/
1847+class SEL_IMERGE : public memory::SqlAlloc
1848+{
1849+ enum { PREALLOCED_TREES= 10};
1850+public:
1851+ SEL_TREE *trees_prealloced[PREALLOCED_TREES];
1852+ SEL_TREE **trees; /* trees used to do index_merge */
1853+ SEL_TREE **trees_next; /* last of these trees */
1854+ SEL_TREE **trees_end; /* end of allocated space */
1855+
1856+ SEL_ARG ***best_keys; /* best keys to read in optimizer::SEL_TREEs */
1857+
1858+ SEL_IMERGE();
1859+
1860+ /*
1861+ Add optimizer::SEL_TREE to this index_merge without any checks,
1862+
1863+ NOTES
1864+ This function implements the following:
1865+ (x_1||...||x_N) || t = (x_1||...||x_N||t), where x_i, t are optimizer::SEL_TREEs
1866+
1867+ RETURN
1868+ 0 - OK
1869+ -1 - Out of memory.
1870+ */
1871+ int or_sel_tree(RangeParameter *param, SEL_TREE *tree);
1872+
1873+ /*
1874+ Perform OR operation on this SEL_IMERGE and supplied optimizer::SEL_TREE new_tree,
1875+ combining new_tree with one of the trees in this SEL_IMERGE if they both
1876+ have SEL_ARGs for the same key.
1877+
1878+ SYNOPSIS
1879+ or_sel_tree_with_checks()
1880+ param Parameter from SqlSelect::test_quick_select
1881+ new_tree optimizer::SEL_TREE with type KEY or KEY_SMALLER.
1882+
1883+ NOTES
1884+ This does the following:
1885+ (t_1||...||t_k)||new_tree =
1886+ either
1887+ = (t_1||...||t_k||new_tree)
1888+ or
1889+ = (t_1||....||(t_j|| new_tree)||...||t_k),
1890+
1891+ where t_i, y are optimizer::SEL_TREEs.
1892+ new_tree is combined with the first t_j it has a SEL_ARG on common
1893+ key with. As a consequence of this, choice of keys to do index_merge
1894+ read may depend on the order of conditions in WHERE part of the query.
1895+
1896+ RETURN
1897+ 0 OK
1898+ 1 One of the trees was combined with new_tree to optimizer::SEL_TREE::ALWAYS,
1899+ and (*this) should be discarded.
1900+ -1 An error occurred.
1901+ */
1902+ int or_sel_tree_with_checks(optimizer::RangeParameter *param, optimizer::SEL_TREE *new_tree);
1903+
1904+ /*
1905+ Perform OR operation on this index_merge and supplied index_merge list.
1906+
1907+ RETURN
1908+ 0 - OK
1909+ 1 - One of conditions in result is always true and this SEL_IMERGE
1910+ should be discarded.
1911+ -1 - An error occurred
1912+ */
1913+ int or_sel_imerge_with_checks(optimizer::RangeParameter *param, SEL_IMERGE* imerge);
1914+
1915+};
1916+
1917+
1918+} /* namespace optimizer */
1919+
1920+} /* namespace drizzled */
1921+
1922+#endif /* DRIZZLED_OPTIMIZER_SEL_IMERGE_H */
1923
1924=== added file 'drizzled/optimizer/sel_tree.cc'
1925--- drizzled/optimizer/sel_tree.cc 1970-01-01 00:00:00 +0000
1926+++ drizzled/optimizer/sel_tree.cc 2010-03-16 01:44:16 +0000
1927@@ -0,0 +1,600 @@
1928+/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
1929+ * vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
1930+ *
1931+ * Copyright (C) 2008-2009 Sun Microsystems
1932+ *
1933+ * This program is free software; you can redistribute it and/or modify
1934+ * it under the terms of the GNU General Public License as published by
1935+ * the Free Software Foundation; version 2 of the License.
1936+ *
1937+ * This program is distributed in the hope that it will be useful,
1938+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1939+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1940+ * GNU General Public License for more details.
1941+ *
1942+ * You should have received a copy of the GNU General Public License
1943+ * along with this program; if not, write to the Free Software
1944+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
1945+ */
1946+
1947+#include "config.h"
1948+
1949+#include "drizzled/sql_base.h"
1950+#include "drizzled/sql_select.h"
1951+#include "drizzled/memory/sql_alloc.h"
1952+#include "drizzled/optimizer/range.h"
1953+#include "drizzled/optimizer/range_param.h"
1954+#include "drizzled/optimizer/sel_arg.h"
1955+#include "drizzled/optimizer/sel_tree.h"
1956+#include "drizzled/optimizer/sel_imerge.h"
1957+
1958+using namespace std;
1959+using namespace drizzled;
1960+
1961+static optimizer::SEL_ARG *key_or(optimizer::RangeParameter *param, optimizer::SEL_ARG *key1, optimizer::SEL_ARG *key2);
1962+static bool eq_tree(optimizer::SEL_ARG* a, optimizer::SEL_ARG *b);
1963+
1964+bool optimizer::sel_trees_can_be_ored(optimizer::SEL_TREE *tree1,
1965+ optimizer::SEL_TREE *tree2,
1966+ optimizer::RangeParameter* param)
1967+{
1968+ key_map common_keys= tree1->keys_map;
1969+ common_keys&= tree2->keys_map;
1970+
1971+ if (common_keys.none())
1972+ {
1973+ return false;
1974+ }
1975+
1976+ /* trees have a common key, check if they refer to same key part */
1977+ optimizer::SEL_ARG **key1,**key2;
1978+ for (uint32_t key_no=0; key_no < param->keys; key_no++)
1979+ {
1980+ if (common_keys.test(key_no))
1981+ {
1982+ key1= tree1->keys + key_no;
1983+ key2= tree2->keys + key_no;
1984+ if ((*key1)->part == (*key2)->part)
1985+ {
1986+ return true;
1987+ }
1988+ }
1989+ }
1990+ return false;
1991+}
1992+
1993+
1994+/*
1995+ Perform OR operation on 2 index_merge lists, storing result in first list.
1996+
1997+ NOTES
1998+ The following conversion is implemented:
1999+ (a_1 &&...&& a_N)||(b_1 &&...&& b_K) = AND_i,j(a_i || b_j) =>
2000+ => (a_1||b_1).
2001+
2002+ i.e. all conjuncts except the first one are currently dropped.
2003+ This is done to avoid producing N*K ways to do index_merge.
2004+
2005+ If (a_1||b_1) produce a condition that is always true, NULL is returned
2006+ and index_merge is discarded (while it is actually possible to try
2007+ harder).
2008+
2009+ As a consequence of this, choice of keys to do index_merge read may depend
2010+ on the order of conditions in WHERE part of the query.
2011+
2012+ RETURN
2013+ 0 OK, result is stored in *im1
2014+ other Error, both passed lists are unusable
2015+*/
2016+
2017+static int imerge_list_or_list(optimizer::RangeParameter *param,
2018+ List<optimizer::SEL_IMERGE> *im1,
2019+ List<optimizer::SEL_IMERGE> *im2)
2020+{
2021+ optimizer::SEL_IMERGE *imerge= im1->head();
2022+ im1->empty();
2023+ im1->push_back(imerge);
2024+
2025+ return imerge->or_sel_imerge_with_checks(param, im2->head());
2026+}
2027+
2028+
2029+/*
2030+ Perform OR operation on index_merge list and key tree.
2031+
2032+ RETURN
2033+ 0 OK, result is stored in *im1.
2034+ other Error
2035+ */
2036+
2037+static int imerge_list_or_tree(optimizer::RangeParameter *param,
2038+ List<optimizer::SEL_IMERGE> *im1,
2039+ optimizer::SEL_TREE *tree)
2040+{
2041+ optimizer::SEL_IMERGE *imerge= NULL;
2042+ List_iterator<optimizer::SEL_IMERGE> it(*im1);
2043+ while ((imerge= it++))
2044+ {
2045+ if (imerge->or_sel_tree_with_checks(param, tree))
2046+ it.remove();
2047+ }
2048+ return im1->is_empty();
2049+}
2050+
2051+
2052+optimizer::SEL_TREE *
2053+optimizer::tree_or(optimizer::RangeParameter *param,
2054+ optimizer::SEL_TREE *tree1,
2055+ optimizer::SEL_TREE *tree2)
2056+{
2057+ if (! tree1 || ! tree2)
2058+ {
2059+ return 0;
2060+ }
2061+
2062+ if (tree1->type == optimizer::SEL_TREE::IMPOSSIBLE || tree2->type == optimizer::SEL_TREE::ALWAYS)
2063+ {
2064+ return tree2;
2065+ }
2066+
2067+ if (tree2->type == optimizer::SEL_TREE::IMPOSSIBLE || tree1->type == optimizer::SEL_TREE::ALWAYS)
2068+ {
2069+ return tree1;
2070+ }
2071+
2072+ if (tree1->type == optimizer::SEL_TREE::MAYBE)
2073+ {
2074+ return tree1; // Can't use this
2075+ }
2076+
2077+ if (tree2->type == optimizer::SEL_TREE::MAYBE)
2078+ {
2079+ return tree2;
2080+ }
2081+
2082+ optimizer::SEL_TREE *result= NULL;
2083+ key_map result_keys;
2084+ result_keys.reset();
2085+ if (sel_trees_can_be_ored(tree1, tree2, param))
2086+ {
2087+ /* Join the trees key per key */
2088+ optimizer::SEL_ARG **key1= NULL;
2089+ optimizer::SEL_ARG **key2= NULL;
2090+ optimizer::SEL_ARG **end= NULL;
2091+ for (key1= tree1->keys,key2= tree2->keys,end= key1+param->keys;
2092+ key1 != end;
2093+ key1++, key2++)
2094+ {
2095+ *key1= key_or(param, *key1, *key2);
2096+ if (*key1)
2097+ {
2098+ result= tree1; // Added to tree1
2099+ result_keys.set(key1 - tree1->keys);
2100+ }
2101+ }
2102+ if (result)
2103+ result->keys_map= result_keys;
2104+ }
2105+ else
2106+ {
2107+ /* ok, two trees have KEY type but cannot be used without index merge */
2108+ if (tree1->merges.is_empty() && tree2->merges.is_empty())
2109+ {
2110+ if (param->remove_jump_scans)
2111+ {
2112+ bool no_trees= optimizer::remove_nonrange_trees(param, tree1);
2113+ no_trees= no_trees || optimizer::remove_nonrange_trees(param, tree2);
2114+ if (no_trees)
2115+ {
2116+ return (new optimizer::SEL_TREE(optimizer::SEL_TREE::ALWAYS));
2117+ }
2118+ }
2119+ optimizer::SEL_IMERGE *merge= NULL;
2120+ /* both trees are "range" trees, produce new index merge structure */
2121+ if (! (result= new optimizer::SEL_TREE()) ||
2122+ ! (merge= new optimizer::SEL_IMERGE()) ||
2123+ (result->merges.push_back(merge)) ||
2124+ (merge->or_sel_tree(param, tree1)) ||
2125+ (merge->or_sel_tree(param, tree2)))
2126+ {
2127+ result= NULL;
2128+ }
2129+ else
2130+ {
2131+ result->type= tree1->type;
2132+ }
2133+ }
2134+ else if (!tree1->merges.is_empty() && !tree2->merges.is_empty())
2135+ {
2136+ if (imerge_list_or_list(param, &tree1->merges, &tree2->merges))
2137+ result= new optimizer::SEL_TREE(optimizer::SEL_TREE::ALWAYS);
2138+ else
2139+ result= tree1;
2140+ }
2141+ else
2142+ {
2143+ /* one tree is index merge tree and another is range tree */
2144+ if (tree1->merges.is_empty())
2145+ std::swap(tree1, tree2);
2146+
2147+ if (param->remove_jump_scans && optimizer::remove_nonrange_trees(param, tree2))
2148+ return(new optimizer::SEL_TREE(optimizer::SEL_TREE::ALWAYS));
2149+ /* add tree2 to tree1->merges, checking if it collapses to ALWAYS */
2150+ if (imerge_list_or_tree(param, &tree1->merges, tree2))
2151+ result= new optimizer::SEL_TREE(optimizer::SEL_TREE::ALWAYS);
2152+ else
2153+ result= tree1;
2154+ }
2155+ }
2156+ return result;
2157+}
2158+
2159+
2160+static optimizer::SEL_ARG *
2161+key_or(optimizer::RangeParameter *param, optimizer::SEL_ARG *key1, optimizer::SEL_ARG *key2)
2162+{
2163+ if (! key1)
2164+ {
2165+ if (key2)
2166+ {
2167+ key2->use_count--;
2168+ key2->free_tree();
2169+ }
2170+ return 0;
2171+ }
2172+ if (! key2)
2173+ {
2174+ key1->use_count--;
2175+ key1->free_tree();
2176+ return 0;
2177+ }
2178+ key1->use_count--;
2179+ key2->use_count--;
2180+
2181+ if (key1->part != key2->part)
2182+ {
2183+ key1->free_tree();
2184+ key2->free_tree();
2185+ return 0; // Can't optimize this
2186+ }
2187+
2188+ // If one of the key is MAYBE_KEY then the found region may be bigger
2189+ if (key1->type == optimizer::SEL_ARG::MAYBE_KEY)
2190+ {
2191+ key2->free_tree();
2192+ key1->use_count++;
2193+ return key1;
2194+ }
2195+ if (key2->type == optimizer::SEL_ARG::MAYBE_KEY)
2196+ {
2197+ key1->free_tree();
2198+ key2->use_count++;
2199+ return key2;
2200+ }
2201+
2202+ if (key1->use_count > 0)
2203+ {
2204+ if (key2->use_count == 0 || key1->elements > key2->elements)
2205+ {
2206+ std::swap(key1,key2);
2207+ }
2208+ if (key1->use_count > 0 || !(key1=key1->clone_tree(param)))
2209+ return 0; // OOM
2210+ }
2211+
2212+ // Add tree at key2 to tree at key1
2213+ bool key2_shared= key2->use_count != 0;
2214+ key1->maybe_flag|= key2->maybe_flag;
2215+
2216+ for (key2=key2->first(); key2; )
2217+ {
2218+ optimizer::SEL_ARG *tmp= key1->find_range(key2); // Find key1.min <= key2.min
2219+ int cmp;
2220+
2221+ if (! tmp)
2222+ {
2223+ tmp=key1->first(); // tmp.min > key2.min
2224+ cmp= -1;
2225+ }
2226+ else if ((cmp=tmp->cmp_max_to_min(key2)) < 0)
2227+ { // Found tmp.max < key2.min
2228+ optimizer::SEL_ARG *next= tmp->next;
2229+ if (cmp == -2 && eq_tree(tmp->next_key_part,key2->next_key_part))
2230+ {
2231+ // Join near ranges like tmp.max < 0 and key2.min >= 0
2232+ optimizer::SEL_ARG *key2_next=key2->next;
2233+ if (key2_shared)
2234+ {
2235+ if (! (key2=new optimizer::SEL_ARG(*key2)))
2236+ return 0; // out of memory
2237+ key2->increment_use_count(key1->use_count+1);
2238+ key2->next= key2_next; // New copy of key2
2239+ }
2240+ key2->copy_min(tmp);
2241+ if (! (key1=key1->tree_delete(tmp)))
2242+ { // Only one key in tree
2243+ key1= key2;
2244+ key1->make_root();
2245+ key2= key2_next;
2246+ break;
2247+ }
2248+ }
2249+ if (! (tmp= next)) // tmp.min > key2.min
2250+ break; // Copy rest of key2
2251+ }
2252+ if (cmp < 0)
2253+ { // tmp.min > key2.min
2254+ int tmp_cmp;
2255+ if ((tmp_cmp= tmp->cmp_min_to_max(key2)) > 0) // if tmp.min > key2.max
2256+ {
2257+ if (tmp_cmp == 2 && eq_tree(tmp->next_key_part,key2->next_key_part))
2258+ { // ranges are connected
2259+ tmp->copy_min_to_min(key2);
2260+ key1->merge_flags(key2);
2261+ if (tmp->min_flag & NO_MIN_RANGE &&
2262+ tmp->max_flag & NO_MAX_RANGE)
2263+ {
2264+ if (key1->maybe_flag)
2265+ return new optimizer::SEL_ARG(optimizer::SEL_ARG::MAYBE_KEY);
2266+ return 0;
2267+ }
2268+ key2->increment_use_count(-1); // Free not used tree
2269+ key2= key2->next;
2270+ continue;
2271+ }
2272+ else
2273+ {
2274+ optimizer::SEL_ARG *next= key2->next; // Keys are not overlapping
2275+ if (key2_shared)
2276+ {
2277+ optimizer::SEL_ARG *cpy= new optimizer::SEL_ARG(*key2); // Must make copy
2278+ if (! cpy)
2279+ return 0; // OOM
2280+ key1= key1->insert(cpy);
2281+ key2->increment_use_count(key1->use_count+1);
2282+ }
2283+ else
2284+ key1= key1->insert(key2); // Will destroy key2_root
2285+ key2= next;
2286+ continue;
2287+ }
2288+ }
2289+ }
2290+
2291+ // tmp.max >= key2.min && tmp.min <= key.cmax(overlapping ranges)
2292+ if (eq_tree(tmp->next_key_part,key2->next_key_part))
2293+ {
2294+ if (tmp->is_same(key2))
2295+ {
2296+ tmp->merge_flags(key2); // Copy maybe flags
2297+ key2->increment_use_count(-1); // Free not used tree
2298+ }
2299+ else
2300+ {
2301+ optimizer::SEL_ARG *last= tmp;
2302+ while (last->next && last->next->cmp_min_to_max(key2) <= 0 &&
2303+ eq_tree(last->next->next_key_part,key2->next_key_part))
2304+ {
2305+ optimizer::SEL_ARG *save= last;
2306+ last= last->next;
2307+ key1= key1->tree_delete(save);
2308+ }
2309+ last->copy_min(tmp);
2310+ if (last->copy_min(key2) || last->copy_max(key2))
2311+ { // Full range
2312+ key1->free_tree();
2313+ for (; key2; key2= key2->next)
2314+ key2->increment_use_count(-1); // Free not used tree
2315+ if (key1->maybe_flag)
2316+ return new optimizer::SEL_ARG(optimizer::SEL_ARG::MAYBE_KEY);
2317+ return 0;
2318+ }
2319+ }
2320+ key2= key2->next;
2321+ continue;
2322+ }
2323+
2324+ if (cmp >= 0 && tmp->cmp_min_to_min(key2) < 0)
2325+ { // tmp.min <= x < key2.min
2326+ optimizer::SEL_ARG *new_arg= tmp->clone_first(key2);
2327+ if (! new_arg)
2328+ return 0; // OOM
2329+ if ((new_arg->next_key_part= key1->next_key_part))
2330+ new_arg->increment_use_count(key1->use_count+1);
2331+ tmp->copy_min_to_min(key2);
2332+ key1= key1->insert(new_arg);
2333+ }
2334+
2335+ // tmp.min >= key2.min && tmp.min <= key2.max
2336+ optimizer::SEL_ARG key(*key2); // Get copy we can modify
2337+ for (;;)
2338+ {
2339+ if (tmp->cmp_min_to_min(&key) > 0)
2340+ { // key.min <= x < tmp.min
2341+ optimizer::SEL_ARG *new_arg= key.clone_first(tmp);
2342+ if (! new_arg)
2343+ return 0; // OOM
2344+ if ((new_arg->next_key_part=key.next_key_part))
2345+ new_arg->increment_use_count(key1->use_count+1);
2346+ key1= key1->insert(new_arg);
2347+ }
2348+ if ((cmp=tmp->cmp_max_to_max(&key)) <= 0)
2349+ { // tmp.min. <= x <= tmp.max
2350+ tmp->maybe_flag|= key.maybe_flag;
2351+ key.increment_use_count(key1->use_count+1);
2352+ tmp->next_key_part= key_or(param, tmp->next_key_part, key.next_key_part);
2353+ if (! cmp) // Key2 is ready
2354+ break;
2355+ key.copy_max_to_min(tmp);
2356+ if (! (tmp= tmp->next))
2357+ {
2358+ optimizer::SEL_ARG *tmp2= new optimizer::SEL_ARG(key);
2359+ if (! tmp2)
2360+ return 0; // OOM
2361+ key1= key1->insert(tmp2);
2362+ key2= key2->next;
2363+ goto end;
2364+ }
2365+ if (tmp->cmp_min_to_max(&key) > 0)
2366+ {
2367+ optimizer::SEL_ARG *tmp2= new optimizer::SEL_ARG(key);
2368+ if (! tmp2)
2369+ return 0; // OOM
2370+ key1= key1->insert(tmp2);
2371+ break;
2372+ }
2373+ }
2374+ else
2375+ {
2376+ optimizer::SEL_ARG *new_arg= tmp->clone_last(&key); // tmp.min <= x <= key.max
2377+ if (! new_arg)
2378+ return 0; // OOM
2379+ tmp->copy_max_to_min(&key);
2380+ tmp->increment_use_count(key1->use_count+1);
2381+ /* Increment key count as it may be used for next loop */
2382+ key.increment_use_count(1);
2383+ new_arg->next_key_part= key_or(param, tmp->next_key_part, key.next_key_part);
2384+ key1= key1->insert(new_arg);
2385+ break;
2386+ }
2387+ }
2388+ key2= key2->next;
2389+ }
2390+
2391+end:
2392+ while (key2)
2393+ {
2394+ optimizer::SEL_ARG *next= key2->next;
2395+ if (key2_shared)
2396+ {
2397+ optimizer::SEL_ARG *tmp= new optimizer::SEL_ARG(*key2); // Must make copy
2398+ if (! tmp)
2399+ return 0;
2400+ key2->increment_use_count(key1->use_count+1);
2401+ key1= key1->insert(tmp);
2402+ }
2403+ else
2404+ key1= key1->insert(key2); // Will destroy key2_root
2405+ key2= next;
2406+ }
2407+ key1->use_count++;
2408+ return key1;
2409+}
2410+
2411+
2412+/*
2413+ Remove the trees that are not suitable for record retrieval.
2414+ SYNOPSIS
2415+ param Range analysis parameter
2416+ tree Tree to be processed, tree->type is KEY or KEY_SMALLER
2417+
2418+ DESCRIPTION
2419+ This function walks through tree->keys[] and removes the SEL_ARG* trees
2420+ that are not "maybe" trees (*) and cannot be used to construct quick range
2421+ selects.
2422+ (*) - have type MAYBE or MAYBE_KEY. Perhaps we should remove trees of
2423+ these types here as well.
2424+
2425+ A SEL_ARG* tree cannot be used to construct quick select if it has
2426+ tree->part != 0. (e.g. it could represent "keypart2 < const").
2427+
2428+ WHY THIS FUNCTION IS NEEDED
2429+
2430+ Normally we allow construction of optimizer::SEL_TREE objects that have SEL_ARG
2431+ trees that do not allow quick range select construction. For example for
2432+ " keypart1=1 AND keypart2=2 " the execution will proceed as follows:
2433+ tree1= optimizer::SEL_TREE { SEL_ARG{keypart1=1} }
2434+ tree2= optimizer::SEL_TREE { SEL_ARG{keypart2=2} } -- can't make quick range select
2435+ from this
2436+ call tree_and(tree1, tree2) -- this joins SEL_ARGs into a usable SEL_ARG
2437+ tree.
2438+
2439+ There is an exception though: when we construct index_merge optimizer::SEL_TREE,
2440+ any SEL_ARG* tree that cannot be used to construct quick range select can
2441+ be removed, because current range analysis code doesn't provide any way
2442+ that tree could be later combined with another tree.
2443+ Consider an example: we should not construct
2444+ st1 = optimizer::SEL_TREE {
2445+ merges = SEL_IMERGE {
2446+ optimizer::SEL_TREE(t.key1part1 = 1),
2447+ optimizer::SEL_TREE(t.key2part2 = 2) -- (*)
2448+ }
2449+ };
2450+ because
2451+ - (*) cannot be used to construct quick range select,
2452+ - There is no execution path that would cause (*) to be converted to
2453+ a tree that could be used.
2454+
2455+ The latter is easy to verify: first, notice that the only way to convert
2456+ (*) into a usable tree is to call tree_and(something, (*)).
2457+
2458+ Second look at what tree_and/tree_or function would do when passed a
2459+ optimizer::SEL_TREE that has the structure like st1 tree has, and conlcude that
2460+ tree_and(something, (*)) will not be called.
2461+
2462+ RETURN
2463+ 0 Ok, some suitable trees left
2464+ 1 No tree->keys[] left.
2465+*/
2466+bool optimizer::remove_nonrange_trees(optimizer::RangeParameter *param, optimizer::SEL_TREE *tree)
2467+{
2468+ bool res= false;
2469+ for (uint32_t i= 0; i < param->keys; i++)
2470+ {
2471+ if (tree->keys[i])
2472+ {
2473+ if (tree->keys[i]->part)
2474+ {
2475+ tree->keys[i]= NULL;
2476+ tree->keys_map.reset(i);
2477+ }
2478+ else
2479+ res= true;
2480+ }
2481+ }
2482+ return ! res;
2483+}
2484+
2485+
2486+/* Compare if two trees are equal */
2487+static bool eq_tree(optimizer::SEL_ARG *a, optimizer::SEL_ARG *b)
2488+{
2489+ if (a == b)
2490+ {
2491+ return true;
2492+ }
2493+
2494+ if (! a || ! b || ! a->is_same(b))
2495+ {
2496+ return false;
2497+ }
2498+
2499+ if (a->left != &optimizer::null_element && b->left != &optimizer::null_element)
2500+ {
2501+ if (! eq_tree(a->left,b->left))
2502+ return false;
2503+ }
2504+ else if (a->left != &optimizer::null_element || b->left != &optimizer::null_element)
2505+ {
2506+ return false;
2507+ }
2508+
2509+ if (a->right != &optimizer::null_element && b->right != &optimizer::null_element)
2510+ {
2511+ if (! eq_tree(a->right,b->right))
2512+ return false;
2513+ }
2514+ else if (a->right != &optimizer::null_element || b->right != &optimizer::null_element)
2515+ {
2516+ return false;
2517+ }
2518+
2519+ if (a->next_key_part != b->next_key_part)
2520+ { // Sub range
2521+ if (! a->next_key_part != ! b->next_key_part ||
2522+ ! eq_tree(a->next_key_part, b->next_key_part))
2523+ return false;
2524+ }
2525+
2526+ return true;
2527+}
2528
2529=== added file 'drizzled/optimizer/sel_tree.h'
2530--- drizzled/optimizer/sel_tree.h 1970-01-01 00:00:00 +0000
2531+++ drizzled/optimizer/sel_tree.h 2010-03-16 01:44:16 +0000
2532@@ -0,0 +1,155 @@
2533+/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2534+ * vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
2535+ *
2536+ * Copyright (C) 2008-2009 Sun Microsystems
2537+ *
2538+ * This program is free software; you can redistribute it and/or modify
2539+ * it under the terms of the GNU General Public License as published by
2540+ * the Free Software Foundation; version 2 of the License.
2541+ *
2542+ * This program is distributed in the hope that it will be useful,
2543+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2544+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2545+ * GNU General Public License for more details.
2546+ *
2547+ * You should have received a copy of the GNU General Public License
2548+ * along with this program; if not, write to the Free Software
2549+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2550+ */
2551+
2552+#ifndef DRIZZLED_OPTIMIZER_SEL_TREE_H
2553+#define DRIZZLED_OPTIMIZER_SEL_TREE_H
2554+
2555+#include "drizzled/memory/sql_alloc.h"
2556+
2557+namespace drizzled
2558+{
2559+
2560+namespace optimizer
2561+{
2562+
2563+class RangeParameter;
2564+class SEL_IMERGE;
2565+class SEL_ARG;
2566+
2567+class SEL_TREE : public drizzled::memory::SqlAlloc
2568+{
2569+public:
2570+ /*
2571+ Starting an effort to document this field:
2572+ (for some i, keys[i]->type == optimizer::SEL_ARG::IMPOSSIBLE) =>
2573+ (type == SEL_TREE::IMPOSSIBLE)
2574+ */
2575+ enum Type
2576+ {
2577+ IMPOSSIBLE,
2578+ ALWAYS,
2579+ MAYBE,
2580+ KEY,
2581+ KEY_SMALLER
2582+ } type;
2583+
2584+ SEL_TREE(enum Type type_arg) :type(type_arg) {}
2585+ SEL_TREE() :type(KEY)
2586+ {
2587+ keys_map.reset();
2588+ memset(keys, 0, sizeof(keys));
2589+ }
2590+ /*
2591+ Note: there may exist SEL_TREE objects with sel_tree->type=KEY and
2592+ keys[i]=0 for all i. (SergeyP: it is not clear whether there is any
2593+ merit in range analyzer functions (e.g. get_mm_parts) returning a
2594+ pointer to such SEL_TREE instead of NULL)
2595+ */
2596+ SEL_ARG *keys[MAX_KEY];
2597+ key_map keys_map; /* bitmask of non-NULL elements in keys */
2598+
2599+ /*
2600+ Possible ways to read rows using index_merge. The list is non-empty only
2601+ if type==KEY. Currently can be non empty only if keys_map.none().
2602+ */
2603+ List<SEL_IMERGE> merges;
2604+
2605+ /* The members below are filled/used only after get_mm_tree is done */
2606+ key_map ror_scans_map; /* bitmask of ROR scan-able elements in keys */
2607+ uint32_t n_ror_scans; /* number of set bits in ror_scans_map */
2608+
2609+ struct st_ror_scan_info **ror_scans; /* list of ROR key scans */
2610+ struct st_ror_scan_info **ror_scans_end; /* last ROR scan */
2611+ /* Note that #records for each key scan is stored in table->quick_rows */
2612+
2613+};
2614+
2615+/*
2616+ Check if two optimizer::SEL_TREES can be combined into one (i.e. a single key range
2617+ read can be constructed for "cond_of_tree1 OR cond_of_tree2" ) without
2618+ using index_merge.
2619+*/
2620+bool sel_trees_can_be_ored(SEL_TREE *tree1,
2621+ SEL_TREE *tree2,
2622+ RangeParameter* param);
2623+
2624+SEL_TREE *
2625+tree_or(RangeParameter *param, SEL_TREE *tree1, SEL_TREE *tree2);
2626+
2627+/*
2628+ Remove the trees that are not suitable for record retrieval.
2629+ SYNOPSIS
2630+ param Range analysis parameter
2631+ tree Tree to be processed, tree->type is KEY or KEY_SMALLER
2632+
2633+ DESCRIPTION
2634+ This function walks through tree->keys[] and removes the SEL_ARG* trees
2635+ that are not "maybe" trees (*) and cannot be used to construct quick range
2636+ selects.
2637+ (*) - have type MAYBE or MAYBE_KEY. Perhaps we should remove trees of
2638+ these types here as well.
2639+
2640+ A SEL_ARG* tree cannot be used to construct quick select if it has
2641+ tree->part != 0. (e.g. it could represent "keypart2 < const").
2642+
2643+ WHY THIS FUNCTION IS NEEDED
2644+
2645+ Normally we allow construction of optimizer::SEL_TREE objects that have SEL_ARG
2646+ trees that do not allow quick range select construction. For example for
2647+ " keypart1=1 AND keypart2=2 " the execution will proceed as follows:
2648+ tree1= optimizer::SEL_TREE { SEL_ARG{keypart1=1} }
2649+ tree2= optimizer::SEL_TREE { SEL_ARG{keypart2=2} } -- can't make quick range select
2650+ from this
2651+ call tree_and(tree1, tree2) -- this joins SEL_ARGs into a usable SEL_ARG
2652+ tree.
2653+
2654+ There is an exception though: when we construct index_merge optimizer::SEL_TREE,
2655+ any SEL_ARG* tree that cannot be used to construct quick range select can
2656+ be removed, because current range analysis code doesn't provide any way
2657+ that tree could be later combined with another tree.
2658+ Consider an example: we should not construct
2659+ st1 = optimizer::SEL_TREE {
2660+ merges = SEL_IMERGE {
2661+ optimizer::SEL_TREE(t.key1part1 = 1),
2662+ optimizer::SEL_TREE(t.key2part2 = 2) -- (*)
2663+ }
2664+ };
2665+ because
2666+ - (*) cannot be used to construct quick range select,
2667+ - There is no execution path that would cause (*) to be converted to
2668+ a tree that could be used.
2669+
2670+ The latter is easy to verify: first, notice that the only way to convert
2671+ (*) into a usable tree is to call tree_and(something, (*)).
2672+
2673+ Second look at what tree_and/tree_or function would do when passed a
2674+ optimizer::SEL_TREE that has the structure like st1 tree has, and conlcude that
2675+ tree_and(something, (*)) will not be called.
2676+
2677+ RETURN
2678+ 0 Ok, some suitable trees left
2679+ 1 No tree->keys[] left.
2680+ */
2681+bool remove_nonrange_trees(RangeParameter *param, SEL_TREE *tree);
2682+
2683+} /* namespace optimizer */
2684+
2685+} /* namespace drizzled */
2686+
2687+#endif /* DRIZZLED_OPTIMIZER_SEL_TREE_H */
2688
2689=== modified file 'drizzled/optimizer/table_read_plan.h'
2690--- drizzled/optimizer/table_read_plan.h 2010-02-10 20:00:52 +0000
2691+++ drizzled/optimizer/table_read_plan.h 2010-03-16 01:44:16 +0000
2692@@ -20,10 +20,11 @@
2693 #ifndef DRIZZLED_OPTIMIZER_TABLE_READ_PLAN_H
2694 #define DRIZZLED_OPTIMIZER_TABLE_READ_PLAN_H
2695
2696+#include "drizzled/util/functors.h"
2697+
2698 namespace drizzled
2699 {
2700
2701-class SEL_TREE;
2702 struct st_ror_scan_info;
2703
2704 namespace optimizer
2705@@ -31,6 +32,7 @@
2706
2707 class Parameter;
2708 class SEL_ARG;
2709+class SEL_TREE;
2710
2711 /*
2712 Table rows retrieval plan. Range optimizer creates QuickSelectInterface-derived
2713@@ -152,7 +154,13 @@
2714 index_scan_costs(0.0)
2715 {}
2716
2717- virtual ~RorIntersectReadPlan() {} /* Remove gcc warning */
2718+ virtual ~RorIntersectReadPlan()
2719+ {
2720+ for_each(ror_range_scans.begin(),
2721+ ror_range_scans.end(),
2722+ DeletePtr());
2723+ ror_range_scans.clear();
2724+ }
2725
2726 QuickSelectInterface *make_quick(Parameter *param,
2727 bool retrieve_full_rows,