~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/optimizer/key_field.cc

  • Committer: Monty Taylor
  • Date: 2008-09-16 00:00:48 UTC
  • mto: This revision was merged to the branch mainline in revision 391.
  • Revision ID: monty@inaugust.com-20080916000048-3rvrv3gv9l0ad3gs
Fixed copyright headers in drizzled/

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* - mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
 
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3
 
 *
4
 
 *  Copyright (C) 2008-2009 Sun Microsystems, Inc.
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; either version 2 of the License, or
9
 
 *  (at your option) any later version.
10
 
 *
11
 
 *  This program is distributed in the hope that it will be useful,
12
 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 
 *  GNU General Public License for more details.
15
 
 *
16
 
 *  You should have received a copy of the GNU General Public License
17
 
 *  along with this program; if not, write to the Free Software
18
 
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19
 
 */
20
 
 
21
 
#include "config.h"
22
 
#include <drizzled/sql_select.h>
23
 
#include <drizzled/nested_join.h>
24
 
#include <drizzled/item/cmpfunc.h>
25
 
#include "drizzled/optimizer/key_field.h"
26
 
#include "drizzled/optimizer/key_use.h"
27
 
 
28
 
#include <vector>
29
 
 
30
 
using namespace std;
31
 
 
32
 
namespace drizzled
33
 
{
34
 
 
35
 
void optimizer::add_key_part(DYNAMIC_ARRAY *keyuse_array,
36
 
                             optimizer::KeyField *key_field)
37
 
{
38
 
  Field *field= key_field->getField();
39
 
  Table *form= field->getTable();
40
 
 
41
 
  if (key_field->isEqualityCondition() &&
42
 
      ! (key_field->getOptimizeFlags() & KEY_OPTIMIZE_EXISTS))
43
 
  {
44
 
    for (uint32_t key= 0; key < form->sizeKeys(); key++)
45
 
    {
46
 
      if (! (form->keys_in_use_for_query.test(key)))
47
 
        continue;
48
 
 
49
 
      uint32_t key_parts= (uint32_t) form->key_info[key].key_parts;
50
 
      for (uint32_t part= 0; part < key_parts; part++)
51
 
      {
52
 
        if (field->eq(form->key_info[key].key_part[part].field))
53
 
        {
54
 
          optimizer::KeyUse keyuse(field->getTable(),
55
 
                                   key_field->getValue(),
56
 
                                   key_field->getValue()->used_tables(),
57
 
                                   key,
58
 
                                   part,
59
 
                                   key_field->getOptimizeFlags() & KEY_OPTIMIZE_REF_OR_NULL,
60
 
                                   1 << part,
61
 
                                   0,
62
 
                                   key_field->rejectNullValues(),
63
 
                                   key_field->getConditionalGuard());
64
 
          insert_dynamic(keyuse_array, (unsigned char*) &keyuse);
65
 
        }
66
 
      }
67
 
    }
68
 
  }
69
 
}
70
 
 
71
 
void optimizer::add_key_fields_for_nj(Join *join,
72
 
                                      TableList *nested_join_table,
73
 
                                      optimizer::KeyField **end,
74
 
                                      uint32_t *and_level,
75
 
                                      vector<optimizer::SargableParam> &sargables)
76
 
{
77
 
  List_iterator<TableList> li(nested_join_table->getNestedJoin()->join_list);
78
 
  List_iterator<TableList> li2(nested_join_table->getNestedJoin()->join_list);
79
 
  bool have_another= false;
80
 
  table_map tables= 0;
81
 
  TableList *table;
82
 
  assert(nested_join_table->getNestedJoin());
83
 
 
84
 
  while ((table= li++) || (have_another && (li=li2, have_another=false,
85
 
                                            (table= li++))))
86
 
  {
87
 
    if (table->getNestedJoin())
88
 
    {
89
 
      if (! table->on_expr)
90
 
      {
91
 
        /* It's a semi-join nest. Walk into it as if it wasn't a nest */
92
 
        have_another= true;
93
 
        li2= li;
94
 
        li= List_iterator<TableList>(table->getNestedJoin()->join_list);
95
 
      }
96
 
      else
97
 
        add_key_fields_for_nj(join, table, end, and_level, sargables);
98
 
    }
99
 
    else
100
 
      if (! table->on_expr)
101
 
        tables|= table->table->map;
102
 
  }
103
 
  if (nested_join_table->on_expr)
104
 
  {
105
 
    add_key_fields(join,
106
 
                   end,
107
 
                   and_level,
108
 
                   nested_join_table->on_expr,
109
 
                   tables,
110
 
                   sargables);
111
 
  }
112
 
}
113
 
 
114
 
optimizer::KeyField *optimizer::merge_key_fields(optimizer::KeyField *start,
115
 
                                                 optimizer::KeyField *new_fields,
116
 
                                                 optimizer::KeyField *end,
117
 
                                                 uint32_t and_level)
118
 
{
119
 
  if (start == new_fields)
120
 
    return start;                               // Impossible or
121
 
  if (new_fields == end)
122
 
    return start;                               // No new fields, skip all
123
 
 
124
 
  optimizer::KeyField *first_free= new_fields;
125
 
 
126
 
  /* Mark all found fields in old array */
127
 
  for (; new_fields != end; new_fields++)
128
 
  {
129
 
    for (optimizer::KeyField *old= start; old != first_free; old++)
130
 
    {
131
 
      if (old->getField() == new_fields->getField())
132
 
      {
133
 
        /*
134
 
          NOTE: below const_item() call really works as "!used_tables()", i.e.
135
 
          it can return false where it is feasible to make it return true.
136
 
 
137
 
          The cause is as follows: Some of the tables are already known to be
138
 
          const tables (the detection code is in make_join_statistics(),
139
 
          above the update_ref_and_keys() call), but we didn't propagate
140
 
          information about this: Table::const_table is not set to true, and
141
 
          Item::update_used_tables() hasn't been called for each item.
142
 
          The result of this is that we're missing some 'ref' accesses.
143
 
          TODO: OptimizerTeam: Fix this
144
 
        */
145
 
        if (! new_fields->getValue()->const_item())
146
 
        {
147
 
          /*
148
 
            If the value matches, we can use the key reference.
149
 
            If not, we keep it until we have examined all new values
150
 
          */
151
 
          if (old->getValue()->eq(new_fields->getValue(), old->getField()->binary()))
152
 
          {
153
 
            old->setLevel(and_level);
154
 
            old->setOptimizeFlags(((old->getOptimizeFlags() &
155
 
                                    new_fields->getOptimizeFlags() &
156
 
                                    KEY_OPTIMIZE_EXISTS) |
157
 
                                   ((old->getOptimizeFlags() |
158
 
                                     new_fields->getOptimizeFlags()) &
159
 
                                    KEY_OPTIMIZE_REF_OR_NULL)));
160
 
            old->setRejectNullValues(old->rejectNullValues() &&
161
 
                                     new_fields->rejectNullValues());
162
 
          }
163
 
        }
164
 
        else if (old->isEqualityCondition() &&
165
 
                 new_fields->isEqualityCondition() &&
166
 
                 old->getValue()->eq_by_collation(new_fields->getValue(),
167
 
                                                  old->getField()->binary(),
168
 
                                                  old->getField()->charset()))
169
 
 
170
 
        {
171
 
          old->setLevel(and_level);
172
 
          old->setOptimizeFlags(((old->getOptimizeFlags() &
173
 
                                  new_fields->getOptimizeFlags() &
174
 
                                  KEY_OPTIMIZE_EXISTS) |
175
 
                                 ((old->getOptimizeFlags() |
176
 
                                   new_fields->getOptimizeFlags()) &
177
 
                                 KEY_OPTIMIZE_REF_OR_NULL)));
178
 
          old->setRejectNullValues(old->rejectNullValues() &&
179
 
                                   new_fields->rejectNullValues());
180
 
        }
181
 
        else if (old->isEqualityCondition() &&
182
 
                 new_fields->isEqualityCondition() &&
183
 
                 ((old->getValue()->const_item() &&
184
 
                   old->getValue()->is_null()) ||
185
 
                   new_fields->getValue()->is_null()))
186
 
        {
187
 
          /* field = expression OR field IS NULL */
188
 
          old->setLevel(and_level);
189
 
          old->setOptimizeFlags(KEY_OPTIMIZE_REF_OR_NULL);
190
 
          /*
191
 
            Remember the NOT NULL value unless the value does not depend
192
 
            on other tables.
193
 
           */
194
 
          if (! old->getValue()->used_tables() &&
195
 
              old->getValue()->is_null())
196
 
          {
197
 
            old->setValue(new_fields->getValue());
198
 
          }
199
 
          /* The referred expression can be NULL: */
200
 
          old->setRejectNullValues(false);
201
 
        }
202
 
        else
203
 
        {
204
 
          /*
205
 
            We are comparing two different const.  In this case we can't
206
 
            use a key-lookup on this so it's better to remove the value
207
 
            and let the range optimzier handle it
208
 
          */
209
 
          if (old == --first_free)              // If last item
210
 
            break;
211
 
          *old= *first_free;                    // Remove old value
212
 
          old--;                                // Retry this value
213
 
        }
214
 
      }
215
 
    }
216
 
  }
217
 
  /* Remove all not used items */
218
 
  for (optimizer::KeyField *old= start; old != first_free;)
219
 
  {
220
 
    if (old->getLevel() != and_level)
221
 
    {                                           // Not used in all levels
222
 
      if (old == --first_free)
223
 
        break;
224
 
      *old= *first_free;                        // Remove old value
225
 
      continue;
226
 
    }
227
 
    old++;
228
 
  }
229
 
  return first_free;
230
 
}
231
 
 
232
 
void optimizer::add_key_field(optimizer::KeyField **key_fields,
233
 
                              uint32_t and_level,
234
 
                              Item_func *cond,
235
 
                              Field *field,
236
 
                              bool eq_func,
237
 
                              Item **value,
238
 
                              uint32_t num_values,
239
 
                              table_map usable_tables,
240
 
                              vector<optimizer::SargableParam> &sargables)
241
 
{
242
 
  uint32_t exists_optimize= 0;
243
 
  if (! (field->flags & PART_KEY_FLAG))
244
 
  {
245
 
    // Don't remove column IS NULL on a LEFT JOIN table
246
 
    if (! eq_func || (*value)->type() != Item::NULL_ITEM ||
247
 
        ! field->getTable()->maybe_null || field->null_ptr)
248
 
      return;                                   // Not a key. Skip it
249
 
    exists_optimize= KEY_OPTIMIZE_EXISTS;
250
 
    assert(num_values == 1);
251
 
  }
252
 
  else
253
 
  {
254
 
    table_map used_tables= 0;
255
 
    bool optimizable= 0;
256
 
    for (uint32_t i= 0; i < num_values; i++)
257
 
    {
258
 
      used_tables|= (value[i])->used_tables();
259
 
      if (! ((value[i])->used_tables() & (field->getTable()->map | RAND_TABLE_BIT)))
260
 
        optimizable= 1;
261
 
    }
262
 
    if (! optimizable)
263
 
      return;
264
 
    if (! (usable_tables & field->getTable()->map))
265
 
    {
266
 
      if (! eq_func || (*value)->type() != Item::NULL_ITEM ||
267
 
          ! field->getTable()->maybe_null || field->null_ptr)
268
 
        return;                                 // Can't use left join optimize
269
 
      exists_optimize= KEY_OPTIMIZE_EXISTS;
270
 
    }
271
 
    else
272
 
    {
273
 
      JoinTable *stat= field->getTable()->reginfo.join_tab;
274
 
      key_map possible_keys= field->key_start;
275
 
      possible_keys&= field->getTable()->keys_in_use_for_query;
276
 
      stat[0].keys|= possible_keys;             // Add possible keys
277
 
 
278
 
      /*
279
 
        Save the following cases:
280
 
        Field op constant
281
 
        Field LIKE constant where constant doesn't start with a wildcard
282
 
        Field = field2 where field2 is in a different table
283
 
        Field op formula
284
 
        Field IS NULL
285
 
        Field IS NOT NULL
286
 
        Field BETWEEN ...
287
 
        Field IN ...
288
 
      */
289
 
      stat[0].key_dependent|= used_tables;
290
 
 
291
 
      bool is_const= 1;
292
 
      for (uint32_t i= 0; i < num_values; i++)
293
 
      {
294
 
        if (! (is_const&= value[i]->const_item()))
295
 
          break;
296
 
      }
297
 
      if (is_const)
298
 
        stat[0].const_keys|= possible_keys;
299
 
      else if (! eq_func)
300
 
      {
301
 
        /*
302
 
          Save info to be able check whether this predicate can be
303
 
          considered as sargable for range analisis after reading const tables.
304
 
          We do not save info about equalities as update_const_equal_items
305
 
          will take care of updating info on keys from sargable equalities.
306
 
        */
307
 
        optimizer::SargableParam tmp(field, value, num_values);
308
 
        sargables.push_back(tmp);
309
 
      }
310
 
      /*
311
 
        We can't always use indexes when comparing a string index to a
312
 
        number. cmp_type() is checked to allow compare of dates to numbers.
313
 
        eq_func is NEVER true when num_values > 1
314
 
       */
315
 
      if (! eq_func)
316
 
      {
317
 
        /*
318
 
          Additional optimization: if we're processing
319
 
          "t.key BETWEEN c1 AND c1" then proceed as if we were processing
320
 
          "t.key = c1".
321
 
          TODO: This is a very limited fix. A more generic fix is possible.
322
 
          There are 2 options:
323
 
          A) Make equality propagation code be able to handle BETWEEN
324
 
             (including cases like t1.key BETWEEN t2.key AND t3.key)
325
 
          B) Make range optimizer to infer additional "t.key = c" equalities
326
 
             and use them in equality propagation process (see details in
327
 
             OptimizerKBAndTodo)
328
 
        */
329
 
        if ((cond->functype() != Item_func::BETWEEN) ||
330
 
            ((Item_func_between*) cond)->negated ||
331
 
            ! value[0]->eq(value[1], field->binary()))
332
 
          return;
333
 
        eq_func= true;
334
 
      }
335
 
 
336
 
      if (field->result_type() == STRING_RESULT)
337
 
      {
338
 
        if ((*value)->result_type() != STRING_RESULT)
339
 
        {
340
 
          if (field->cmp_type() != (*value)->result_type())
341
 
            return;
342
 
        }
343
 
        else
344
 
        {
345
 
          /*
346
 
            We can't use indexes if the effective collation
347
 
            of the operation differ from the field collation.
348
 
          */
349
 
          if (field->cmp_type() == STRING_RESULT &&
350
 
              ((Field_str*)field)->charset() != cond->compare_collation())
351
 
            return;
352
 
        }
353
 
      }
354
 
    }
355
 
  }
356
 
  /*
357
 
    For the moment eq_func is always true. This slot is reserved for future
358
 
    extensions where we want to remembers other things than just eq comparisons
359
 
  */
360
 
  assert(eq_func);
361
 
  /* Store possible eq field */
362
 
  (*key_fields)->setField(field);
363
 
  (*key_fields)->setEqualityConditionUsed(eq_func);
364
 
  (*key_fields)->setValue(*value);
365
 
  (*key_fields)->setLevel(and_level);
366
 
  (*key_fields)->setOptimizeFlags(exists_optimize);
367
 
  /*
368
 
    If the condition has form "tbl.keypart = othertbl.field" and
369
 
    othertbl.field can be NULL, there will be no matches if othertbl.field
370
 
    has NULL value.
371
 
    We use null_rejecting in add_not_null_conds() to add
372
 
    'othertbl.field IS NOT NULL' to tab->select_cond.
373
 
  */
374
 
  (*key_fields)->setRejectNullValues((cond->functype() == Item_func::EQ_FUNC ||
375
 
                                      cond->functype() == Item_func::MULT_EQUAL_FUNC) &&
376
 
                                     ((*value)->type() == Item::FIELD_ITEM) &&
377
 
                                     ((Item_field*)*value)->field->maybe_null());
378
 
  (*key_fields)->setConditionalGuard(NULL);
379
 
  (*key_fields)++;
380
 
}
381
 
 
382
 
void optimizer::add_key_equal_fields(optimizer::KeyField **key_fields,
383
 
                                     uint32_t and_level,
384
 
                                     Item_func *cond,
385
 
                                     Item_field *field_item,
386
 
                                     bool eq_func,
387
 
                                     Item **val,
388
 
                                     uint32_t num_values,
389
 
                                     table_map usable_tables,
390
 
                                     vector<optimizer::SargableParam> &sargables)
391
 
{
392
 
  Field *field= field_item->field;
393
 
  add_key_field(key_fields, and_level, cond, field,
394
 
                eq_func, val, num_values, usable_tables, sargables);
395
 
  Item_equal *item_equal= field_item->item_equal;
396
 
  if (item_equal)
397
 
  {
398
 
    /*
399
 
      Add to the set of possible key values every substitution of
400
 
      the field for an equal field included into item_equal
401
 
    */
402
 
    Item_equal_iterator it(*item_equal);
403
 
    Item_field *item;
404
 
    while ((item= it++))
405
 
    {
406
 
      if (! field->eq(item->field))
407
 
      {
408
 
        add_key_field(key_fields, and_level, cond, item->field,
409
 
                      eq_func, val, num_values, usable_tables,
410
 
                      sargables);
411
 
      }
412
 
    }
413
 
  }
414
 
}
415
 
 
416
 
void optimizer::add_key_fields(Join *join,
417
 
                               optimizer::KeyField **key_fields,
418
 
                               uint32_t *and_level,
419
 
                               COND *cond,
420
 
                               table_map usable_tables,
421
 
                               vector<optimizer::SargableParam> &sargables)
422
 
{
423
 
  if (cond->type() == Item_func::COND_ITEM)
424
 
  {
425
 
    List_iterator_fast<Item> li(*((Item_cond*) cond)->argument_list());
426
 
    optimizer::KeyField *org_key_fields= *key_fields;
427
 
 
428
 
    if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)
429
 
    {
430
 
      Item *item;
431
 
      while ((item= li++))
432
 
      {
433
 
        add_key_fields(join,
434
 
                       key_fields,
435
 
                       and_level,
436
 
                       item,
437
 
                       usable_tables,
438
 
                       sargables);
439
 
      }
440
 
      for (; org_key_fields != *key_fields; org_key_fields++)
441
 
        org_key_fields->setLevel(*and_level);
442
 
    }
443
 
    else
444
 
    {
445
 
      (*and_level)++;
446
 
      add_key_fields(join,
447
 
                     key_fields,
448
 
                     and_level,
449
 
                     li++,
450
 
                     usable_tables,
451
 
                     sargables);
452
 
      Item *item;
453
 
      while ((item= li++))
454
 
      {
455
 
        optimizer::KeyField *start_key_fields= *key_fields;
456
 
        (*and_level)++;
457
 
        add_key_fields(join,
458
 
                       key_fields,
459
 
                       and_level,
460
 
                       item,
461
 
                       usable_tables,
462
 
                       sargables);
463
 
        *key_fields= merge_key_fields(org_key_fields, start_key_fields,
464
 
                                      *key_fields, ++(*and_level));
465
 
      }
466
 
    }
467
 
    return;
468
 
  }
469
 
 
470
 
  /*
471
 
    Subquery optimization: Conditions that are pushed down into subqueries
472
 
    are wrapped into Item_func_trig_cond. We process the wrapped condition
473
 
    but need to set cond_guard for KeyUse elements generated from it.
474
 
  */
475
 
  {
476
 
    if (cond->type() == Item::FUNC_ITEM &&
477
 
        ((Item_func*)cond)->functype() == Item_func::TRIG_COND_FUNC)
478
 
    {
479
 
      Item *cond_arg= ((Item_func*)cond)->arguments()[0];
480
 
      if (! join->group_list &&
481
 
          ! join->order &&
482
 
          join->unit->item &&
483
 
          join->unit->item->substype() == Item_subselect::IN_SUBS &&
484
 
          ! join->unit->is_union())
485
 
      {
486
 
        optimizer::KeyField *save= *key_fields;
487
 
        add_key_fields(join,
488
 
                       key_fields,
489
 
                       and_level,
490
 
                       cond_arg,
491
 
                       usable_tables,
492
 
                       sargables);
493
 
        /* Indicate that this ref access candidate is for subquery lookup */
494
 
        for (; save != *key_fields; save++)
495
 
          save->setConditionalGuard(((Item_func_trig_cond*)cond)->get_trig_var());
496
 
      }
497
 
      return;
498
 
    }
499
 
  }
500
 
 
501
 
  /* If item is of type 'field op field/constant' add it to key_fields */
502
 
  if (cond->type() != Item::FUNC_ITEM)
503
 
    return;
504
 
  Item_func *cond_func= (Item_func*) cond;
505
 
  switch (cond_func->select_optimize())
506
 
  {
507
 
  case Item_func::OPTIMIZE_NONE:
508
 
    break;
509
 
  case Item_func::OPTIMIZE_KEY:
510
 
  {
511
 
    Item **values;
512
 
    // BETWEEN, IN, NE
513
 
    if (cond_func->key_item()->real_item()->type() == Item::FIELD_ITEM &&
514
 
        ! (cond_func->used_tables() & OUTER_REF_TABLE_BIT))
515
 
    {
516
 
      values= cond_func->arguments() + 1;
517
 
      if (cond_func->functype() == Item_func::NE_FUNC &&
518
 
          cond_func->arguments()[1]->real_item()->type() == Item::FIELD_ITEM &&
519
 
          ! (cond_func->arguments()[0]->used_tables() & OUTER_REF_TABLE_BIT))
520
 
        values--;
521
 
      assert(cond_func->functype() != Item_func::IN_FUNC ||
522
 
             cond_func->argument_count() != 2);
523
 
      add_key_equal_fields(key_fields, *and_level, cond_func,
524
 
                           (Item_field*) (cond_func->key_item()->real_item()),
525
 
                           0, values,
526
 
                           cond_func->argument_count()-1,
527
 
                           usable_tables, sargables);
528
 
    }
529
 
    if (cond_func->functype() == Item_func::BETWEEN)
530
 
    {
531
 
      values= cond_func->arguments();
532
 
      for (uint32_t i= 1 ; i < cond_func->argument_count(); i++)
533
 
      {
534
 
        Item_field *field_item;
535
 
        if (cond_func->arguments()[i]->real_item()->type() == Item::FIELD_ITEM
536
 
            &&
537
 
            ! (cond_func->arguments()[i]->used_tables() & OUTER_REF_TABLE_BIT))
538
 
        {
539
 
          field_item= (Item_field *) (cond_func->arguments()[i]->real_item());
540
 
          add_key_equal_fields(key_fields, *and_level, cond_func,
541
 
                               field_item, 0, values, 1, usable_tables,
542
 
                               sargables);
543
 
        }
544
 
      }
545
 
    }
546
 
    break;
547
 
  }
548
 
  case Item_func::OPTIMIZE_OP:
549
 
  {
550
 
    bool equal_func= (cond_func->functype() == Item_func::EQ_FUNC ||
551
 
                                  cond_func->functype() == Item_func::EQUAL_FUNC);
552
 
 
553
 
    if (cond_func->arguments()[0]->real_item()->type() == Item::FIELD_ITEM &&
554
 
        ! (cond_func->arguments()[0]->used_tables() & OUTER_REF_TABLE_BIT))
555
 
    {
556
 
      add_key_equal_fields(key_fields, *and_level, cond_func,
557
 
                           (Item_field*) (cond_func->arguments()[0])->real_item(),
558
 
                           equal_func,
559
 
                           cond_func->arguments()+1, 1, usable_tables,
560
 
                           sargables);
561
 
    }
562
 
    if (cond_func->arguments()[1]->real_item()->type() == Item::FIELD_ITEM &&
563
 
        cond_func->functype() != Item_func::LIKE_FUNC &&
564
 
        ! (cond_func->arguments()[1]->used_tables() & OUTER_REF_TABLE_BIT))
565
 
    {
566
 
      add_key_equal_fields(key_fields, *and_level, cond_func,
567
 
                           (Item_field*) (cond_func->arguments()[1])->real_item(), equal_func,
568
 
                           cond_func->arguments(),1,usable_tables,
569
 
                           sargables);
570
 
    }
571
 
    break;
572
 
  }
573
 
  case Item_func::OPTIMIZE_NULL:
574
 
    /* column_name IS [NOT] NULL */
575
 
    if (cond_func->arguments()[0]->real_item()->type() == Item::FIELD_ITEM &&
576
 
        ! (cond_func->used_tables() & OUTER_REF_TABLE_BIT))
577
 
    {
578
 
      Item *tmp= new Item_null;
579
 
      if (unlikely(! tmp))                       // Should never be true
580
 
        return;
581
 
      add_key_equal_fields(key_fields, *and_level, cond_func,
582
 
                           (Item_field*) (cond_func->arguments()[0])->real_item(),
583
 
                           cond_func->functype() == Item_func::ISNULL_FUNC,
584
 
                           &tmp, 1, usable_tables, sargables);
585
 
    }
586
 
    break;
587
 
  case Item_func::OPTIMIZE_EQUAL:
588
 
    Item_equal *item_equal= (Item_equal *) cond;
589
 
    Item *const_item= item_equal->get_const();
590
 
    Item_equal_iterator it(*item_equal);
591
 
    Item_field *item;
592
 
    if (const_item)
593
 
    {
594
 
      /*
595
 
        For each field field1 from item_equal consider the equality
596
 
        field1=const_item as a condition allowing an index access of the table
597
 
        with field1 by the keys value of field1.
598
 
      */
599
 
      while ((item= it++))
600
 
      {
601
 
        add_key_field(key_fields, *and_level, cond_func, item->field,
602
 
                      true, &const_item, 1, usable_tables, sargables);
603
 
      }
604
 
    }
605
 
    else
606
 
    {
607
 
      /*
608
 
        Consider all pairs of different fields included into item_equal.
609
 
        For each of them (field1, field1) consider the equality
610
 
        field1=field2 as a condition allowing an index access of the table
611
 
        with field1 by the keys value of field2.
612
 
      */
613
 
      Item_equal_iterator fi(*item_equal);
614
 
      while ((item= fi++))
615
 
      {
616
 
        Field *field= item->field;
617
 
        while ((item= it++))
618
 
        {
619
 
          if (! field->eq(item->field))
620
 
          {
621
 
            add_key_field(key_fields, *and_level, cond_func, field,
622
 
                          true, (Item **) &item, 1, usable_tables,
623
 
                          sargables);
624
 
          }
625
 
        }
626
 
        it.rewind();
627
 
      }
628
 
    }
629
 
    break;
630
 
  }
631
 
}
632
 
 
633
 
} /* namespace drizzled */