~drizzle-trunk/drizzle/development

1237.13.44 by Padraig O'Sullivan
Moved the SEL_TREE and SEL_IMERGE classes out into their own header and implementation files.
1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3
 *
1999.6.1 by kalebral at gmail
update Copyright strings to a more common format to help with creating the master debian copyright file
4
 *  Copyright (C) 2008-2009 Sun Microsystems, Inc.
1237.13.44 by Padraig O'Sullivan
Moved the SEL_TREE and SEL_IMERGE classes out into their own header and implementation files.
5
 *
6
 *  This program is free software; you can redistribute it and/or modify
7
 *  it under the terms of the GNU General Public License as published by
8
 *  the Free Software Foundation; version 2 of the License.
9
 *
10
 *  This program is distributed in the hope that it will be useful,
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 *  GNU General Public License for more details.
14
 *
15
 *  You should have received a copy of the GNU General Public License
16
 *  along with this program; if not, write to the Free Software
17
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
 */
19
2173.2.1 by Monty Taylor
Fixes incorrect usage of include
20
#include <config.h>
1237.13.44 by Padraig O'Sullivan
Moved the SEL_TREE and SEL_IMERGE classes out into their own header and implementation files.
21
2173.2.1 by Monty Taylor
Fixes incorrect usage of include
22
#include <drizzled/sql_base.h>
23
#include <drizzled/sql_select.h>
24
#include <drizzled/memory/sql_alloc.h>
25
#include <drizzled/optimizer/range.h>
26
#include <drizzled/optimizer/range_param.h>
27
#include <drizzled/optimizer/sel_arg.h>
28
#include <drizzled/optimizer/sel_tree.h>
29
#include <drizzled/optimizer/sel_imerge.h>
1237.13.44 by Padraig O'Sullivan
Moved the SEL_TREE and SEL_IMERGE classes out into their own header and implementation files.
30
31
using namespace std;
32
using namespace drizzled;
33
34
static optimizer::SEL_ARG *key_or(optimizer::RangeParameter *param, optimizer::SEL_ARG *key1, optimizer::SEL_ARG *key2);
35
static bool eq_tree(optimizer::SEL_ARG* a, optimizer::SEL_ARG *b);
36
2318.6.47 by Olaf van der Spek
Refactor
37
bool optimizer::sel_trees_can_be_ored(const SEL_TREE& tree1, const SEL_TREE& tree2, const RangeParameter& param)
1237.13.44 by Padraig O'Sullivan
Moved the SEL_TREE and SEL_IMERGE classes out into their own header and implementation files.
38
{
2318.6.47 by Olaf van der Spek
Refactor
39
  key_map common_keys= tree1.keys_map;
40
  common_keys&= tree2.keys_map;
1237.13.44 by Padraig O'Sullivan
Moved the SEL_TREE and SEL_IMERGE classes out into their own header and implementation files.
41
42
  if (common_keys.none())
43
    return false;
44
45
  /* trees have a common key, check if they refer to same key part */
2318.6.47 by Olaf van der Spek
Refactor
46
  for (uint32_t key_no= 0; key_no < param.keys; key_no++)
1237.13.44 by Padraig O'Sullivan
Moved the SEL_TREE and SEL_IMERGE classes out into their own header and implementation files.
47
  {
2318.6.47 by Olaf van der Spek
Refactor
48
    if (common_keys.test(key_no) && tree1.keys[key_no]->part == tree2.keys[key_no]->part)
49
      return true;
1237.13.44 by Padraig O'Sullivan
Moved the SEL_TREE and SEL_IMERGE classes out into their own header and implementation files.
50
  }
51
  return false;
52
}
53
54
55
/*
56
  Perform OR operation on 2 index_merge lists, storing result in first list.
57
58
  NOTES
59
    The following conversion is implemented:
60
     (a_1 &&...&& a_N)||(b_1 &&...&& b_K) = AND_i,j(a_i || b_j) =>
61
      => (a_1||b_1).
62
63
    i.e. all conjuncts except the first one are currently dropped.
64
    This is done to avoid producing N*K ways to do index_merge.
65
66
    If (a_1||b_1) produce a condition that is always true, NULL is returned
67
    and index_merge is discarded (while it is actually possible to try
68
    harder).
69
70
    As a consequence of this, choice of keys to do index_merge read may depend
71
    on the order of conditions in WHERE part of the query.
72
73
  RETURN
74
    0     OK, result is stored in *im1
75
    other Error, both passed lists are unusable
76
*/
77
2318.6.49 by Olaf van der Spek
Refactor
78
static int imerge_list_or_list(optimizer::RangeParameter *param, List<optimizer::SEL_IMERGE> *im1, List<optimizer::SEL_IMERGE> *im2)
1237.13.44 by Padraig O'Sullivan
Moved the SEL_TREE and SEL_IMERGE classes out into their own header and implementation files.
79
{
2183.2.21 by Olaf van der Spek
Use List::front()
80
  optimizer::SEL_IMERGE *imerge= &im1->front();
2179.2.1 by Olaf van der Spek
Rename List::empty to clear (std::list uses clear)
81
  im1->clear();
1237.13.44 by Padraig O'Sullivan
Moved the SEL_TREE and SEL_IMERGE classes out into their own header and implementation files.
82
  im1->push_back(imerge);
83
2318.6.49 by Olaf van der Spek
Refactor
84
  return imerge->or_sel_imerge_with_checks(*param, im2->front());
1237.13.44 by Padraig O'Sullivan
Moved the SEL_TREE and SEL_IMERGE classes out into their own header and implementation files.
85
}
86
87
88
/*
89
  Perform OR operation on index_merge list and key tree.
90
91
  RETURN
92
     0     OK, result is stored in *im1.
93
     other Error
94
 */
95
2318.6.50 by Olaf van der Spek
Refactir
96
static int imerge_list_or_tree(optimizer::RangeParameter& param, List<optimizer::SEL_IMERGE>& im1, optimizer::SEL_TREE& tree)
1237.13.44 by Padraig O'Sullivan
Moved the SEL_TREE and SEL_IMERGE classes out into their own header and implementation files.
97
{
2318.6.50 by Olaf van der Spek
Refactir
98
  List_iterator<optimizer::SEL_IMERGE> it(im1.begin());
2318.6.48 by Olaf van der Spek
Refactor
99
  while (optimizer::SEL_IMERGE* imerge= it++)
1237.13.44 by Padraig O'Sullivan
Moved the SEL_TREE and SEL_IMERGE classes out into their own header and implementation files.
100
  {
2318.6.50 by Olaf van der Spek
Refactir
101
    if (imerge->or_sel_tree_with_checks(param, tree))
1237.13.44 by Padraig O'Sullivan
Moved the SEL_TREE and SEL_IMERGE classes out into their own header and implementation files.
102
      it.remove();
103
  }
2318.6.50 by Olaf van der Spek
Refactir
104
  return im1.is_empty();
1237.13.44 by Padraig O'Sullivan
Moved the SEL_TREE and SEL_IMERGE classes out into their own header and implementation files.
105
}
106
107
2318.6.51 by Olaf van der Spek
Refactor
108
optimizer::SEL_TREE* optimizer::tree_or(optimizer::RangeParameter *param, optimizer::SEL_TREE *tree1, optimizer::SEL_TREE *tree2)
1237.13.44 by Padraig O'Sullivan
Moved the SEL_TREE and SEL_IMERGE classes out into their own header and implementation files.
109
{
110
  if (! tree1 || ! tree2)
111
    return 0;
112
2318.6.51 by Olaf van der Spek
Refactor
113
  if (tree1->type == SEL_TREE::IMPOSSIBLE || tree2->type == SEL_TREE::ALWAYS)
1237.13.44 by Padraig O'Sullivan
Moved the SEL_TREE and SEL_IMERGE classes out into their own header and implementation files.
114
    return tree2;
115
2318.6.51 by Olaf van der Spek
Refactor
116
  if (tree2->type == SEL_TREE::IMPOSSIBLE || tree1->type == SEL_TREE::ALWAYS)
1237.13.44 by Padraig O'Sullivan
Moved the SEL_TREE and SEL_IMERGE classes out into their own header and implementation files.
117
    return tree1;
118
2318.6.51 by Olaf van der Spek
Refactor
119
  if (tree1->type == SEL_TREE::MAYBE)
1237.13.44 by Padraig O'Sullivan
Moved the SEL_TREE and SEL_IMERGE classes out into their own header and implementation files.
120
    return tree1; // Can't use this
121
2318.6.51 by Olaf van der Spek
Refactor
122
  if (tree2->type == SEL_TREE::MAYBE)
1237.13.44 by Padraig O'Sullivan
Moved the SEL_TREE and SEL_IMERGE classes out into their own header and implementation files.
123
    return tree2;
124
2318.6.51 by Olaf van der Spek
Refactor
125
  SEL_TREE *result= NULL;
1237.13.44 by Padraig O'Sullivan
Moved the SEL_TREE and SEL_IMERGE classes out into their own header and implementation files.
126
  key_map  result_keys;
127
  result_keys.reset();
2318.6.47 by Olaf van der Spek
Refactor
128
  if (sel_trees_can_be_ored(*tree1, *tree2, *param))
1237.13.44 by Padraig O'Sullivan
Moved the SEL_TREE and SEL_IMERGE classes out into their own header and implementation files.
129
  {
130
    /* Join the trees key per key */
2318.6.51 by Olaf van der Spek
Refactor
131
    SEL_ARG** key1= tree1->keys;
132
    SEL_ARG** key2= tree2->keys;
133
    SEL_ARG** end= key1+param->keys;
134
    for (; key1 != end;  key1++, key2++)
1237.13.44 by Padraig O'Sullivan
Moved the SEL_TREE and SEL_IMERGE classes out into their own header and implementation files.
135
    {
136
      *key1= key_or(param, *key1, *key2);
137
      if (*key1)
138
      {
139
        result= tree1; // Added to tree1
140
        result_keys.set(key1 - tree1->keys);
141
      }
142
    }
143
    if (result)
144
      result->keys_map= result_keys;
145
  }
146
  else
147
  {
148
    /* ok, two trees have KEY type but cannot be used without index merge */
149
    if (tree1->merges.is_empty() && tree2->merges.is_empty())
150
    {
2318.6.51 by Olaf van der Spek
Refactor
151
      if (param->remove_jump_scans && (remove_nonrange_trees(param, tree1) || remove_nonrange_trees(param, tree2)))
152
        return new SEL_TREE(SEL_TREE::ALWAYS);
1237.13.44 by Padraig O'Sullivan
Moved the SEL_TREE and SEL_IMERGE classes out into their own header and implementation files.
153
      /* both trees are "range" trees, produce new index merge structure */
2318.6.51 by Olaf van der Spek
Refactor
154
			result= new SEL_TREE();
155
			SEL_IMERGE* merge= new SEL_IMERGE();
2241.2.11 by Olaf van der Spek
Refactor
156
			result->merges.push_back(merge);
2318.6.46 by Olaf van der Spek
Refactor
157
      merge->or_sel_tree(param, tree1);
158
      merge->or_sel_tree(param, tree2);
159
      result->type= tree1->type;
1237.13.44 by Padraig O'Sullivan
Moved the SEL_TREE and SEL_IMERGE classes out into their own header and implementation files.
160
    }
161
    else if (!tree1->merges.is_empty() && !tree2->merges.is_empty())
162
    {
2318.6.51 by Olaf van der Spek
Refactor
163
      result= imerge_list_or_list(param, &tree1->merges, &tree2->merges)
164
        ? new SEL_TREE(SEL_TREE::ALWAYS)
165
        : tree1;
1237.13.44 by Padraig O'Sullivan
Moved the SEL_TREE and SEL_IMERGE classes out into their own header and implementation files.
166
    }
167
    else
168
    {
169
      /* one tree is index merge tree and another is range tree */
170
      if (tree1->merges.is_empty())
171
        std::swap(tree1, tree2);
172
2318.6.51 by Olaf van der Spek
Refactor
173
      if (param->remove_jump_scans && remove_nonrange_trees(param, tree2))
174
         return new SEL_TREE(SEL_TREE::ALWAYS);
1237.13.44 by Padraig O'Sullivan
Moved the SEL_TREE and SEL_IMERGE classes out into their own header and implementation files.
175
      /* add tree2 to tree1->merges, checking if it collapses to ALWAYS */
2318.6.51 by Olaf van der Spek
Refactor
176
      result= imerge_list_or_tree(*param, tree1->merges, *tree2)
177
        ? new SEL_TREE(SEL_TREE::ALWAYS)
178
        : tree1;
1237.13.44 by Padraig O'Sullivan
Moved the SEL_TREE and SEL_IMERGE classes out into their own header and implementation files.
179
    }
180
  }
181
  return result;
182
}
183
184
185
static optimizer::SEL_ARG *
186
key_or(optimizer::RangeParameter *param, optimizer::SEL_ARG *key1, optimizer::SEL_ARG *key2)
187
{
188
  if (! key1)
189
  {
190
    if (key2)
191
    {
192
      key2->use_count--;
193
      key2->free_tree();
194
    }
195
    return 0;
196
  }
197
  if (! key2)
198
  {
199
    key1->use_count--;
200
    key1->free_tree();
201
    return 0;
202
  }
203
  key1->use_count--;
204
  key2->use_count--;
205
206
  if (key1->part != key2->part)
207
  {
208
    key1->free_tree();
209
    key2->free_tree();
210
    return 0;					// Can't optimize this
211
  }
212
213
  // If one of the key is MAYBE_KEY then the found region may be bigger
214
  if (key1->type == optimizer::SEL_ARG::MAYBE_KEY)
215
  {
216
    key2->free_tree();
217
    key1->use_count++;
218
    return key1;
219
  }
220
  if (key2->type == optimizer::SEL_ARG::MAYBE_KEY)
221
  {
222
    key1->free_tree();
223
    key2->use_count++;
224
    return key2;
225
  }
226
227
  if (key1->use_count > 0)
228
  {
229
    if (key2->use_count == 0 || key1->elements > key2->elements)
230
    {
231
      std::swap(key1,key2);
232
    }
233
    if (key1->use_count > 0 || !(key1=key1->clone_tree(param)))
234
      return 0;					// OOM
235
  }
236
237
  // Add tree at key2 to tree at key1
238
  bool key2_shared= key2->use_count != 0;
239
  key1->maybe_flag|= key2->maybe_flag;
240
241
  for (key2=key2->first(); key2; )
242
  {
243
    optimizer::SEL_ARG *tmp= key1->find_range(key2); // Find key1.min <= key2.min
244
    int cmp;
245
246
    if (! tmp)
247
    {
248
      tmp=key1->first(); // tmp.min > key2.min
249
      cmp= -1;
250
    }
251
    else if ((cmp=tmp->cmp_max_to_min(key2)) < 0)
252
    {						// Found tmp.max < key2.min
253
      optimizer::SEL_ARG *next= tmp->next;
254
      if (cmp == -2 && eq_tree(tmp->next_key_part,key2->next_key_part))
255
      {
256
        // Join near ranges like tmp.max < 0 and key2.min >= 0
257
        optimizer::SEL_ARG *key2_next=key2->next;
258
        if (key2_shared)
259
        {
260
          if (! (key2=new optimizer::SEL_ARG(*key2)))
261
            return 0;		// out of memory
262
          key2->increment_use_count(key1->use_count+1);
263
          key2->next= key2_next; // New copy of key2
264
        }
265
        key2->copy_min(tmp);
266
        if (! (key1=key1->tree_delete(tmp)))
267
        {					// Only one key in tree
268
          key1= key2;
269
          key1->make_root();
270
          key2= key2_next;
271
          break;
272
        }
273
      }
274
      if (! (tmp= next)) // tmp.min > key2.min
275
        break; // Copy rest of key2
276
    }
277
    if (cmp < 0)
278
    {						// tmp.min > key2.min
279
      int tmp_cmp;
280
      if ((tmp_cmp= tmp->cmp_min_to_max(key2)) > 0) // if tmp.min > key2.max
281
      {
282
        if (tmp_cmp == 2 && eq_tree(tmp->next_key_part,key2->next_key_part))
283
        {					// ranges are connected
284
          tmp->copy_min_to_min(key2);
285
          key1->merge_flags(key2);
286
          if (tmp->min_flag & NO_MIN_RANGE &&
287
              tmp->max_flag & NO_MAX_RANGE)
288
          {
289
            if (key1->maybe_flag)
290
              return new optimizer::SEL_ARG(optimizer::SEL_ARG::MAYBE_KEY);
291
            return 0;
292
          }
293
          key2->increment_use_count(-1);	// Free not used tree
294
          key2= key2->next;
295
          continue;
296
        }
297
        else
298
        {
299
          optimizer::SEL_ARG *next= key2->next; // Keys are not overlapping
300
          if (key2_shared)
301
          {
302
            optimizer::SEL_ARG *cpy= new optimizer::SEL_ARG(*key2); // Must make copy
303
            if (! cpy)
304
              return 0; // OOM
305
            key1= key1->insert(cpy);
306
            key2->increment_use_count(key1->use_count+1);
307
          }
308
          else
309
            key1= key1->insert(key2);		// Will destroy key2_root
310
          key2= next;
311
          continue;
312
        }
313
      }
314
    }
315
316
    // tmp.max >= key2.min && tmp.min <= key.cmax(overlapping ranges)
317
    if (eq_tree(tmp->next_key_part,key2->next_key_part))
318
    {
319
      if (tmp->is_same(key2))
320
      {
321
        tmp->merge_flags(key2);			// Copy maybe flags
322
        key2->increment_use_count(-1);		// Free not used tree
323
      }
324
      else
325
      {
326
        optimizer::SEL_ARG *last= tmp;
327
        while (last->next && last->next->cmp_min_to_max(key2) <= 0 &&
328
               eq_tree(last->next->next_key_part,key2->next_key_part))
329
        {
330
          optimizer::SEL_ARG *save= last;
331
          last= last->next;
332
          key1= key1->tree_delete(save);
333
        }
334
        last->copy_min(tmp);
335
        if (last->copy_min(key2) || last->copy_max(key2))
336
        {					// Full range
337
          key1->free_tree();
338
          for (; key2; key2= key2->next)
339
            key2->increment_use_count(-1);	// Free not used tree
340
          if (key1->maybe_flag)
341
            return new optimizer::SEL_ARG(optimizer::SEL_ARG::MAYBE_KEY);
342
          return 0;
343
        }
344
      }
345
      key2= key2->next;
346
      continue;
347
    }
348
349
    if (cmp >= 0 && tmp->cmp_min_to_min(key2) < 0)
350
    {						// tmp.min <= x < key2.min
351
      optimizer::SEL_ARG *new_arg= tmp->clone_first(key2);
352
      if (! new_arg)
353
        return 0;				// OOM
354
      if ((new_arg->next_key_part= key1->next_key_part))
355
        new_arg->increment_use_count(key1->use_count+1);
356
      tmp->copy_min_to_min(key2);
357
      key1= key1->insert(new_arg);
358
    }
359
360
    // tmp.min >= key2.min && tmp.min <= key2.max
361
    optimizer::SEL_ARG key(*key2); // Get copy we can modify
362
    for (;;)
363
    {
364
      if (tmp->cmp_min_to_min(&key) > 0)
365
      {						// key.min <= x < tmp.min
366
        optimizer::SEL_ARG *new_arg= key.clone_first(tmp);
367
        if (! new_arg)
368
          return 0;				// OOM
369
        if ((new_arg->next_key_part=key.next_key_part))
370
          new_arg->increment_use_count(key1->use_count+1);
371
        key1= key1->insert(new_arg);
372
      }
373
      if ((cmp=tmp->cmp_max_to_max(&key)) <= 0)
374
      {						// tmp.min. <= x <= tmp.max
375
        tmp->maybe_flag|= key.maybe_flag;
376
        key.increment_use_count(key1->use_count+1);
377
        tmp->next_key_part= key_or(param, tmp->next_key_part, key.next_key_part);
378
        if (! cmp)				// Key2 is ready
379
          break;
380
        key.copy_max_to_min(tmp);
381
        if (! (tmp= tmp->next))
382
        {
383
          optimizer::SEL_ARG *tmp2= new optimizer::SEL_ARG(key);
384
          if (! tmp2)
385
            return 0;				// OOM
386
          key1= key1->insert(tmp2);
387
          key2= key2->next;
388
          goto end;
389
        }
390
        if (tmp->cmp_min_to_max(&key) > 0)
391
        {
392
          optimizer::SEL_ARG *tmp2= new optimizer::SEL_ARG(key);
393
          if (! tmp2)
394
            return 0;				// OOM
395
          key1= key1->insert(tmp2);
396
          break;
397
        }
398
      }
399
      else
400
      {
401
        optimizer::SEL_ARG *new_arg= tmp->clone_last(&key); // tmp.min <= x <= key.max
402
        if (! new_arg)
403
          return 0;				// OOM
404
        tmp->copy_max_to_min(&key);
405
        tmp->increment_use_count(key1->use_count+1);
406
        /* Increment key count as it may be used for next loop */
407
        key.increment_use_count(1);
408
        new_arg->next_key_part= key_or(param, tmp->next_key_part, key.next_key_part);
409
        key1= key1->insert(new_arg);
410
        break;
411
      }
412
    }
413
    key2= key2->next;
414
  }
415
416
end:
417
  while (key2)
418
  {
419
    optimizer::SEL_ARG *next= key2->next;
420
    if (key2_shared)
421
    {
422
      optimizer::SEL_ARG *tmp= new optimizer::SEL_ARG(*key2);		// Must make copy
423
      if (! tmp)
424
        return 0;
425
      key2->increment_use_count(key1->use_count+1);
426
      key1= key1->insert(tmp);
427
    }
428
    else
429
      key1= key1->insert(key2);			// Will destroy key2_root
430
    key2= next;
431
  }
432
  key1->use_count++;
433
  return key1;
434
}
435
436
437
/*
438
  Remove the trees that are not suitable for record retrieval.
439
  SYNOPSIS
440
    param  Range analysis parameter
441
    tree   Tree to be processed, tree->type is KEY or KEY_SMALLER
442
443
  DESCRIPTION
444
    This function walks through tree->keys[] and removes the SEL_ARG* trees
445
    that are not "maybe" trees (*) and cannot be used to construct quick range
446
    selects.
447
    (*) - have type MAYBE or MAYBE_KEY. Perhaps we should remove trees of
448
          these types here as well.
449
450
    A SEL_ARG* tree cannot be used to construct quick select if it has
451
    tree->part != 0. (e.g. it could represent "keypart2 < const").
452
453
    WHY THIS FUNCTION IS NEEDED
454
455
    Normally we allow construction of optimizer::SEL_TREE objects that have SEL_ARG
456
    trees that do not allow quick range select construction. For example for
457
    " keypart1=1 AND keypart2=2 " the execution will proceed as follows:
458
    tree1= optimizer::SEL_TREE { SEL_ARG{keypart1=1} }
459
    tree2= optimizer::SEL_TREE { SEL_ARG{keypart2=2} } -- can't make quick range select
460
                                               from this
461
    call tree_and(tree1, tree2) -- this joins SEL_ARGs into a usable SEL_ARG
462
                                   tree.
463
464
    There is an exception though: when we construct index_merge optimizer::SEL_TREE,
465
    any SEL_ARG* tree that cannot be used to construct quick range select can
466
    be removed, because current range analysis code doesn't provide any way
467
    that tree could be later combined with another tree.
468
    Consider an example: we should not construct
469
    st1 = optimizer::SEL_TREE {
470
      merges = SEL_IMERGE {
471
                            optimizer::SEL_TREE(t.key1part1 = 1),
472
                            optimizer::SEL_TREE(t.key2part2 = 2)   -- (*)
473
                          }
474
                   };
475
    because
476
     - (*) cannot be used to construct quick range select,
477
     - There is no execution path that would cause (*) to be converted to
478
       a tree that could be used.
479
480
    The latter is easy to verify: first, notice that the only way to convert
481
    (*) into a usable tree is to call tree_and(something, (*)).
482
483
    Second look at what tree_and/tree_or function would do when passed a
484
    optimizer::SEL_TREE that has the structure like st1 tree has, and conlcude that
485
    tree_and(something, (*)) will not be called.
486
487
  RETURN
488
    0  Ok, some suitable trees left
489
    1  No tree->keys[] left.
490
*/
491
bool optimizer::remove_nonrange_trees(optimizer::RangeParameter *param, optimizer::SEL_TREE *tree)
492
{
2318.6.51 by Olaf van der Spek
Refactor
493
  bool res= true;
1237.13.44 by Padraig O'Sullivan
Moved the SEL_TREE and SEL_IMERGE classes out into their own header and implementation files.
494
  for (uint32_t i= 0; i < param->keys; i++)
495
  {
496
    if (tree->keys[i])
497
    {
498
      if (tree->keys[i]->part)
499
      {
500
        tree->keys[i]= NULL;
501
        tree->keys_map.reset(i);
502
      }
503
      else
2318.6.51 by Olaf van der Spek
Refactor
504
        res= false;
1237.13.44 by Padraig O'Sullivan
Moved the SEL_TREE and SEL_IMERGE classes out into their own header and implementation files.
505
    }
506
  }
2318.6.51 by Olaf van der Spek
Refactor
507
  return res;
1237.13.44 by Padraig O'Sullivan
Moved the SEL_TREE and SEL_IMERGE classes out into their own header and implementation files.
508
}
509
510
511
/* Compare if two trees are equal */
512
static bool eq_tree(optimizer::SEL_ARG *a, optimizer::SEL_ARG *b)
513
{
514
  if (a == b)
515
    return true;
516
517
  if (! a || ! b || ! a->is_same(b))
518
  {
519
    return false;
520
  }
521
522
  if (a->left != &optimizer::null_element && b->left != &optimizer::null_element)
523
  {
524
    if (! eq_tree(a->left,b->left))
525
      return false;
526
  }
527
  else if (a->left != &optimizer::null_element || b->left != &optimizer::null_element)
528
  {
529
    return false;
530
  }
531
532
  if (a->right != &optimizer::null_element && b->right != &optimizer::null_element)
533
  {
534
    if (! eq_tree(a->right,b->right))
535
      return false;
536
  }
537
  else if (a->right != &optimizer::null_element || b->right != &optimizer::null_element)
538
  {
539
    return false;
540
  }
541
542
  if (a->next_key_part != b->next_key_part)
543
  {						// Sub range
544
    if (! a->next_key_part != ! b->next_key_part ||
545
	      ! eq_tree(a->next_key_part, b->next_key_part))
546
      return false;
547
  }
548
549
  return true;
550
}