~drizzle-trunk/drizzle/development

1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
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
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
 */
1 by brian
clean slate
20
21
/**
22
  @file
23
24
  Optimising of MIN(), MAX() and COUNT(*) queries without 'group by' clause
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
25
  by replacing the aggregate expression with a constant.
1 by brian
clean slate
26
27
  Given a table with a compound key on columns (a,b,c), the following
28
  types of queries are optimised (assuming the table handler supports
29
  the required methods)
30
31
  @verbatim
32
  SELECT COUNT(*) FROM t1[,t2,t3,...]
33
  SELECT MIN(b) FROM t1 WHERE a=const
34
  SELECT MAX(c) FROM t1 WHERE a=const AND b=const
35
  SELECT MAX(b) FROM t1 WHERE a=const AND b<const
36
  SELECT MIN(b) FROM t1 WHERE a=const AND b>const
37
  SELECT MIN(b) FROM t1 WHERE a=const AND b BETWEEN const AND const
38
  SELECT MAX(b) FROM t1 WHERE a=const AND b BETWEEN const AND const
39
  @endverbatim
40
41
  Instead of '<' one can use '<=', '>', '>=' and '=' as well.
42
  Instead of 'a=const' the condition 'a IS NULL' can be used.
43
44
  If all selected fields are replaced then we will also remove all
45
  involved tables and return the answer without any join. Thus, the
46
  following query will be replaced with a row of two constants:
47
  @verbatim
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
48
  SELECT MAX(b), MIN(d) FROM t1,t2
1 by brian
clean slate
49
    WHERE a=const AND b<const AND d>const
50
  @endverbatim
51
  (assuming a index for column d of table t2 is defined)
52
*/
53
1241.9.36 by Monty Taylor
ZOMG. I deleted drizzled/server_includes.h.
54
#include "config.h"
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
55
#include "drizzled/sql_select.h"
56
#include "drizzled/item/sum.h"
57
#include "drizzled/item/cmpfunc.h"
58
#include "drizzled/optimizer/sum.h"
59
60
namespace drizzled
61
{
62
1240.3.1 by Brian Aker
Merge Padraig.
63
static bool find_key_for_maxmin(bool max_fl,
64
                                table_reference_st *ref,
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
65
                                Field* field,
1240.3.1 by Brian Aker
Merge Padraig.
66
                                COND *cond,
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
67
                                uint32_t *range_fl,
482 by Brian Aker
Remove uint.
68
                                uint32_t *key_prefix_length);
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
69
1240.3.1 by Brian Aker
Merge Padraig.
70
static int reckey_in_range(bool max_fl,
71
                           table_reference_st *ref,
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
72
                           Field* field,
1240.3.1 by Brian Aker
Merge Padraig.
73
                           COND *cond,
74
                           uint32_t range_fl,
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
75
                           uint32_t prefix_len);
76
1237.13.5 by Padraig O'Sullivan
Split some classes from the range optimizer out in to their own header and implementation files.
77
static int maxmin_in_range(bool max_fl, Field *field, COND *cond);
1 by brian
clean slate
78
79
80
/*
81
  Get exact count of rows in all tables
82
83
  SYNOPSIS
84
    get_exact_records()
85
    tables		List of tables
86
87
  NOTES
88
    When this is called, we know all table handlers supports HA_HAS_RECORDS
89
    or HA_STATS_RECORDS_IS_EXACT
90
91
  RETURN
163 by Brian Aker
Merge Monty's code.
92
    UINT64_MAX	Error: Could not calculate number of rows
1 by brian
clean slate
93
    #			Multiplication of number of rows in all tables
94
*/
327.2.4 by Brian Aker
Refactoring table.h
95
static uint64_t get_exact_record_count(TableList *tables)
1 by brian
clean slate
96
{
151 by Brian Aker
Ulonglong to uint64_t
97
  uint64_t count= 1;
327.2.4 by Brian Aker
Refactoring table.h
98
  for (TableList *tl= tables; tl; tl= tl->next_leaf)
1 by brian
clean slate
99
  {
1208.3.2 by brian
Update for Cursor renaming.
100
    ha_rows tmp= tl->table->cursor->records();
1 by brian
clean slate
101
    if ((tmp == HA_POS_ERROR))
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
102
    {
163 by Brian Aker
Merge Monty's code.
103
      return UINT64_MAX;
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
104
    }
1 by brian
clean slate
105
    count*= tmp;
106
  }
107
  return count;
108
}
109
110
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
111
int optimizer::sum_query(TableList *tables, List<Item> &all_fields, COND *conds)
1 by brian
clean slate
112
{
113
  List_iterator_fast<Item> it(all_fields);
114
  int const_result= 1;
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
115
  bool recalc_const_item= false;
151 by Brian Aker
Ulonglong to uint64_t
116
  uint64_t count= 1;
1240.3.1 by Brian Aker
Merge Padraig.
117
  bool is_exact_count= true;
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
118
  bool maybe_exact_count= true;
119
  table_map removed_tables= 0;
120
  table_map outer_tables= 0;
121
  table_map used_tables= 0;
1 by brian
clean slate
122
  table_map where_tables= 0;
1237.13.5 by Padraig O'Sullivan
Split some classes from the range optimizer out in to their own header and implementation files.
123
  Item *item= NULL;
1 by brian
clean slate
124
  int error;
125
126
  if (conds)
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
127
  {
1 by brian
clean slate
128
    where_tables= conds->used_tables();
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
129
  }
1 by brian
clean slate
130
131
  /*
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
132
     Analyze outer join dependencies, and, if possible, compute the number
133
     of returned rows.
134
   */
327.2.4 by Brian Aker
Refactoring table.h
135
  for (TableList *tl= tables; tl; tl= tl->next_leaf)
1 by brian
clean slate
136
  {
1237.13.5 by Padraig O'Sullivan
Split some classes from the range optimizer out in to their own header and implementation files.
137
    TableList *embedded= NULL;
1637.2.7 by Vijay Samuel
Merge encapsulate TableList-2.
138
    for (embedded= tl; embedded; embedded= embedded->getEmbedding())
1 by brian
clean slate
139
    {
140
      if (embedded->on_expr)
141
        break;
142
    }
143
    if (embedded)
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
144
      /* Don't replace expression on a table that is part of an outer join */
1 by brian
clean slate
145
    {
146
      outer_tables|= tl->table->map;
147
148
      /*
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
149
         We can't optimise LEFT JOIN in cases where the WHERE condition
150
         restricts the table that is used, like in:
151
         SELECT MAX(t1.a) FROM t1 LEFT JOIN t2 join-condition
152
         WHERE t2.field IS NULL;
153
       */
1 by brian
clean slate
154
      if (tl->table->map & where_tables)
155
        return 0;
156
    }
157
    else
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
158
    {
1 by brian
clean slate
159
      used_tables|= tl->table->map;
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
160
    }
1 by brian
clean slate
161
162
    /*
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
163
       If the storage manager of 'tl' gives exact row count as part of
164
       statistics (cheap), compute the total number of rows. If there are
165
       no outer table dependencies, this count may be used as the real count.
166
       Schema tables are filled after this function is invoked, so we can't
167
       get row count
168
     */
169
    if (! (tl->table->cursor->getEngine()->check_flag(HTON_BIT_STATS_RECORDS_IS_EXACT)))
1 by brian
clean slate
170
    {
1234.1.3 by Brian Aker
Merge in removal of table_flags.
171
      maybe_exact_count&= test(tl->table->cursor->getEngine()->check_flag(HTON_BIT_HAS_RECORDS));
51.1.35 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
172
      is_exact_count= false;
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
173
      count= 1; // ensure count != 0
1 by brian
clean slate
174
    }
175
    else
176
    {
1208.3.2 by brian
Update for Cursor renaming.
177
      error= tl->table->cursor->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
1 by brian
clean slate
178
      if(error)
179
      {
1216.1.1 by Brian Aker
Move print_error up to Engine.
180
        tl->table->print_error(error, MYF(ME_FATALERROR));
1 by brian
clean slate
181
        return error;
182
      }
1208.3.2 by brian
Update for Cursor renaming.
183
      count*= tl->table->cursor->stats.records;
1 by brian
clean slate
184
    }
185
  }
186
187
  /*
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
188
     Iterate through all items in the SELECT clause and replace
189
     COUNT(), MIN() and MAX() with constants (if possible).
190
   */
1 by brian
clean slate
191
192
  while ((item= it++))
193
  {
194
    if (item->type() == Item::SUM_FUNC_ITEM)
195
    {
196
      Item_sum *item_sum= (((Item_sum*) item));
1240.3.1 by Brian Aker
Merge Padraig.
197
      switch (item_sum->sum_func())
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
198
      {
199
        case Item_sum::COUNT_FUNC:
200
          /*
201
             If the expr in COUNT(expr) can never be null we can change this
202
             to the number of rows in the tables if this number is exact and
203
             there are no outer joins.
204
           */
205
          if (! conds && ! ((Item_sum_count*) item)->args[0]->maybe_null &&
206
              ! outer_tables && maybe_exact_count)
207
          {
208
            if (! is_exact_count)
209
            {
210
              if ((count= get_exact_record_count(tables)) == UINT64_MAX)
211
              {
212
                /* Error from handler in counting rows. Don't optimize count() */
213
                const_result= 0;
214
                continue;
215
              }
216
              is_exact_count= 1;                  // count is now exact
217
            }
218
            ((Item_sum_count*) item)->make_const_count((int64_t) count);
219
            recalc_const_item= 1;
220
          }
221
          else
222
          {
223
            const_result= 0;
224
          }
225
          break;
226
        case Item_sum::MIN_FUNC:
227
          {
228
            /*
229
               If MIN(expr) is the first part of a key or if all previous
230
               parts of the key is found in the COND, then we can use
231
               indexes to find the key.
232
             */
233
            Item *expr=item_sum->args[0];
234
            if (expr->real_item()->type() == Item::FIELD_ITEM)
235
            {
236
              unsigned char key_buff[MAX_KEY_LENGTH];
237
              table_reference_st ref;
238
              uint32_t range_fl, prefix_len;
239
240
              ref.key_buff= key_buff;
241
              Item_field *item_field= (Item_field*) (expr->real_item());
1660.1.3 by Brian Aker
Encapsulate Table in field
242
              Table *table= item_field->field->getTable();
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
243
244
              /*
245
                 Look for a partial key that can be used for optimization.
246
                 If we succeed, ref.key_length will contain the length of
247
                 this key, while prefix_len will contain the length of
248
                 the beginning of this key without field used in MIN().
249
                 Type of range for the key part for this field will be
250
                 returned in range_fl.
251
               */
1240.3.1 by Brian Aker
Merge Padraig.
252
              if (table->cursor->inited ||
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
253
                  (outer_tables & table->map) ||
1240.3.1 by Brian Aker
Merge Padraig.
254
                  ! find_key_for_maxmin(0,
255
                                        &ref,
256
                                        item_field->field,
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
257
                                        conds,
1240.3.1 by Brian Aker
Merge Padraig.
258
                                        &range_fl,
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
259
                                        &prefix_len))
260
              {
261
                const_result= 0;
262
                break;
263
              }
1491.1.6 by Jay Pipes
Cursor::ha_index_init() -> Cursor::startIndexScan(). Cursor::ha_index_end() -> Cursor::endIndexScan()
264
              error= table->cursor->startIndexScan(static_cast<uint32_t>(ref.key), 1);
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
265
266
              if (! ref.key_length)
267
              {
268
                error= table->cursor->index_first(table->record[0]);
269
              }
270
              else
271
              {
272
                /*
273
                   Use index to replace MIN/MAX functions with their values
274
                   according to the following rules:
275
276
                   1) Insert the minimum non-null values where the WHERE clause still
277
                   matches, or
278
                   2) a NULL value if there are only NULL values for key_part_k.
279
                   3) Fail, producing a row of nulls
280
281
                   Implementation: Read the smallest value using the search key. If
282
                   the interval is open, read the next value after the search
283
                   key. If read fails, and we're looking for a MIN() value for a
284
                   nullable column, test if there is an exact match for the key.
285
                 */
286
                if (! (range_fl & NEAR_MIN))
1237.13.5 by Padraig O'Sullivan
Split some classes from the range optimizer out in to their own header and implementation files.
287
                {
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
288
                  /*
289
                     Closed interval: Either The MIN argument is non-nullable, or
290
                     we have a >= predicate for the MIN argument.
291
                   */
292
                  error= table->cursor->index_read_map(table->record[0],
293
                                                       ref.key_buff,
294
                                                       make_prev_keypart_map(ref.key_parts),
295
                                                       HA_READ_KEY_OR_NEXT);
1237.13.5 by Padraig O'Sullivan
Split some classes from the range optimizer out in to their own header and implementation files.
296
                }
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
297
                else
298
                {
299
                  /*
300
                     Open interval: There are two cases:
301
                     1) We have only MIN() and the argument column is nullable, or
302
                     2) there is a > predicate on it, nullability is irrelevant.
303
                     We need to scan the next bigger record first.
304
                   */
305
                  error= table->cursor->index_read_map(table->record[0],
306
                                                       ref.key_buff,
307
                                                       make_prev_keypart_map(ref.key_parts),
308
                                                       HA_READ_AFTER_KEY);
309
                  /*
310
                     If the found record is outside the group formed by the search
311
                     prefix, or there is no such record at all, check if all
312
                     records in that group have NULL in the MIN argument
313
                     column. If that is the case return that NULL.
314
315
                     Check if case 1 from above holds. If it does, we should read
316
                     the skipped tuple.
317
                   */
318
                  if (item_field->field->real_maybe_null() &&
319
                      ref.key_buff[prefix_len] == 1 &&
320
                      /*
321
                         Last keypart (i.e. the argument to MIN) is set to NULL by
322
                         find_key_for_maxmin only if all other keyparts are bound
323
                         to constants in a conjunction of equalities. Hence, we
324
                         can detect this by checking only if the last keypart is
325
                         NULL.
326
                       */
327
                      (error == HA_ERR_KEY_NOT_FOUND ||
328
                       key_cmp_if_same(table, ref.key_buff, ref.key, prefix_len)))
329
                  {
330
                    assert(item_field->field->real_maybe_null());
331
                    error= table->cursor->index_read_map(table->record[0],
332
                                                         ref.key_buff,
333
                                                         make_prev_keypart_map(ref.key_parts),
334
                                                         HA_READ_KEY_EXACT);
335
                  }
336
                }
337
              }
338
              /* Verify that the read tuple indeed matches the search key */
1240.3.1 by Brian Aker
Merge Padraig.
339
              if (! error &&
340
                  reckey_in_range(0,
341
                                  &ref,
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
342
                                  item_field->field,
1240.3.1 by Brian Aker
Merge Padraig.
343
                                  conds,
344
                                  range_fl,
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
345
                                  prefix_len))
346
              {
347
                error= HA_ERR_KEY_NOT_FOUND;
348
              }
349
              if (table->key_read)
350
              {
351
                table->key_read= 0;
352
                table->cursor->extra(HA_EXTRA_NO_KEYREAD);
353
              }
1491.1.6 by Jay Pipes
Cursor::ha_index_init() -> Cursor::startIndexScan(). Cursor::ha_index_end() -> Cursor::endIndexScan()
354
              table->cursor->endIndexScan();
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
355
              if (error)
356
              {
357
                if (error == HA_ERR_KEY_NOT_FOUND || error == HA_ERR_END_OF_FILE)
358
                {
359
                  return HA_ERR_KEY_NOT_FOUND;	      // No rows matching WHERE
360
                }
361
                /* HA_ERR_LOCK_DEADLOCK or some other error */
362
                table->print_error(error, MYF(0));
363
                return error;
364
              }
365
              removed_tables|= table->map;
366
            }
367
            else if (! expr->const_item() || ! is_exact_count)
368
            {
369
              /*
370
                 The optimization is not applicable in both cases:
371
                 (a) 'expr' is a non-constant expression. Then we can't
372
                 replace 'expr' by a constant.
373
                 (b) 'expr' is a costant. According to ANSI, MIN/MAX must return
374
                 NULL if the query does not return any rows. Thus, if we are not
375
                 able to determine if the query returns any rows, we can't apply
376
                 the optimization and replace MIN/MAX with a constant.
377
               */
378
              const_result= 0;
379
              break;
380
            }
381
            if (! count)
382
            {
383
              /* If count == 0, then we know that is_exact_count == true. */
384
              ((Item_sum_min*) item_sum)->clear(); /* Set to NULL. */
385
            }
386
            else
387
            {
388
              ((Item_sum_min*) item_sum)->reset(); /* Set to the constant value. */
389
            }
390
            ((Item_sum_min*) item_sum)->make_const();
391
            recalc_const_item= 1;
392
            break;
393
          }
394
        case Item_sum::MAX_FUNC:
395
          {
396
            /*
397
               If MAX(expr) is the first part of a key or if all previous
398
               parts of the key is found in the COND, then we can use
399
               indexes to find the key.
400
             */
401
            Item *expr= item_sum->args[0];
402
            if (expr->real_item()->type() == Item::FIELD_ITEM)
403
            {
404
              unsigned char key_buff[MAX_KEY_LENGTH];
405
              table_reference_st ref;
406
              uint32_t range_fl, prefix_len;
407
408
              ref.key_buff= key_buff;
409
              Item_field *item_field= (Item_field*) (expr->real_item());
1660.1.3 by Brian Aker
Encapsulate Table in field
410
              Table *table= item_field->field->getTable();
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
411
412
              /*
413
                 Look for a partial key that can be used for optimization.
414
                 If we succeed, ref.key_length will contain the length of
415
                 this key, while prefix_len will contain the length of
416
                 the beginning of this key without field used in MAX().
417
                 Type of range for the key part for this field will be
418
                 returned in range_fl.
419
               */
1240.3.1 by Brian Aker
Merge Padraig.
420
              if (table->cursor->inited ||
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
421
                  (outer_tables & table->map) ||
1240.3.1 by Brian Aker
Merge Padraig.
422
                  ! find_key_for_maxmin(1,
423
                                        &ref,
424
                                        item_field->field,
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
425
                                        conds,
1240.3.1 by Brian Aker
Merge Padraig.
426
                                        &range_fl,
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
427
                                        &prefix_len))
428
              {
429
                const_result= 0;
430
                break;
431
              }
1491.1.6 by Jay Pipes
Cursor::ha_index_init() -> Cursor::startIndexScan(). Cursor::ha_index_end() -> Cursor::endIndexScan()
432
              error= table->cursor->startIndexScan(static_cast<uint32_t>(ref.key), 1);
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
433
434
              if (! ref.key_length)
435
              {
436
                error= table->cursor->index_last(table->record[0]);
437
              }
438
              else
439
              {
1240.3.1 by Brian Aker
Merge Padraig.
440
                error= table->cursor->index_read_map(table->record[0],
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
441
                                                     key_buff,
442
                                                     make_prev_keypart_map(ref.key_parts),
443
                                                     range_fl & NEAR_MAX ?
444
                                                     HA_READ_BEFORE_KEY :
445
                                                     HA_READ_PREFIX_LAST_OR_PREV);
446
              }
1240.3.1 by Brian Aker
Merge Padraig.
447
              if (! error &&
448
                  reckey_in_range(1,
449
                                  &ref,
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
450
                                  item_field->field,
1240.3.1 by Brian Aker
Merge Padraig.
451
                                  conds,
452
                                  range_fl,
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
453
                                  prefix_len))
454
              {
455
                error= HA_ERR_KEY_NOT_FOUND;
456
              }
457
              if (table->key_read)
458
              {
459
                table->key_read= 0;
460
                table->cursor->extra(HA_EXTRA_NO_KEYREAD);
461
              }
1491.1.6 by Jay Pipes
Cursor::ha_index_init() -> Cursor::startIndexScan(). Cursor::ha_index_end() -> Cursor::endIndexScan()
462
              table->cursor->endIndexScan();
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
463
              if (error)
464
              {
465
                if (error == HA_ERR_KEY_NOT_FOUND || error == HA_ERR_END_OF_FILE)
466
                {
467
                  return HA_ERR_KEY_NOT_FOUND;	     // No rows matching WHERE
468
                }
469
                /* HA_ERR_LOCK_DEADLOCK or some other error */
470
                table->print_error(error, MYF(ME_FATALERROR));
471
                return error;
472
              }
473
              removed_tables|= table->map;
474
            }
475
            else if (! expr->const_item() || ! is_exact_count)
476
            {
477
              /*
478
                 The optimization is not applicable in both cases:
479
                 (a) 'expr' is a non-constant expression. Then we can't
480
                 replace 'expr' by a constant.
481
                 (b) 'expr' is a costant. According to ANSI, MIN/MAX must return
482
                 NULL if the query does not return any rows. Thus, if we are not
483
                 able to determine if the query returns any rows, we can't apply
484
                 the optimization and replace MIN/MAX with a constant.
485
               */
486
              const_result= 0;
487
              break;
488
            }
489
            if (! count)
490
            {
491
              /* If count != 1, then we know that is_exact_count == true. */
492
              ((Item_sum_max*) item_sum)->clear(); /* Set to NULL. */
493
            }
494
            else
495
            {
496
              ((Item_sum_max*) item_sum)->reset(); /* Set to the constant value. */
497
            }
498
            ((Item_sum_max*) item_sum)->make_const();
499
            recalc_const_item= 1;
500
            break;
501
          }
502
        default:
503
          const_result= 0;
504
          break;
1 by brian
clean slate
505
      }
506
    }
507
    else if (const_result)
508
    {
509
      if (recalc_const_item)
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
510
      {
1 by brian
clean slate
511
        item->update_used_tables();
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
512
      }
513
      if (! item->const_item())
514
      {
1 by brian
clean slate
515
        const_result= 0;
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
516
      }
1 by brian
clean slate
517
    }
518
  }
519
  /*
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
520
     If we have a where clause, we can only ignore searching in the
521
     tables if MIN/MAX optimisation replaced all used tables
522
     We do not use replaced values in case of:
523
     SELECT MIN(key) FROM table_1, empty_table
524
     removed_tables is != 0 if we have used MIN() or MAX().
525
   */
1 by brian
clean slate
526
  if (removed_tables && used_tables != removed_tables)
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
527
  {
1 by brian
clean slate
528
    const_result= 0;                            // We didn't remove all tables
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
529
  }
1 by brian
clean slate
530
  return const_result;
531
}
532
533
1237.13.5 by Padraig O'Sullivan
Split some classes from the range optimizer out in to their own header and implementation files.
534
bool optimizer::simple_pred(Item_func *func_item, Item **args, bool &inv_order)
1 by brian
clean slate
535
{
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
536
  Item *item= NULL;
1237.13.5 by Padraig O'Sullivan
Split some classes from the range optimizer out in to their own header and implementation files.
537
  inv_order= false;
1240.3.1 by Brian Aker
Merge Padraig.
538
  switch (func_item->argument_count())
1237.13.5 by Padraig O'Sullivan
Split some classes from the range optimizer out in to their own header and implementation files.
539
  {
1 by brian
clean slate
540
  case 0:
541
    /* MULT_EQUAL_FUNC */
542
    {
543
      Item_equal *item_equal= (Item_equal *) func_item;
544
      Item_equal_iterator it(*item_equal);
545
      args[0]= it++;
546
      if (it++)
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
547
      {
548
        return 0;
549
      }
550
      if (! (args[1]= item_equal->get_const()))
551
      {
552
        return 0;
553
      }
1 by brian
clean slate
554
    }
555
    break;
556
  case 1:
557
    /* field IS NULL */
558
    item= func_item->arguments()[0];
559
    if (item->type() != Item::FIELD_ITEM)
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
560
    {
1 by brian
clean slate
561
      return 0;
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
562
    }
1 by brian
clean slate
563
    args[0]= item;
564
    break;
565
  case 2:
566
    /* 'field op const' or 'const op field' */
567
    item= func_item->arguments()[0];
568
    if (item->type() == Item::FIELD_ITEM)
569
    {
570
      args[0]= item;
571
      item= func_item->arguments()[1];
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
572
      if (! item->const_item())
573
      {
1 by brian
clean slate
574
        return 0;
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
575
      }
1 by brian
clean slate
576
      args[1]= item;
577
    }
578
    else if (item->const_item())
579
    {
580
      args[1]= item;
581
      item= func_item->arguments()[1];
582
      if (item->type() != Item::FIELD_ITEM)
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
583
      {
1 by brian
clean slate
584
        return 0;
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
585
      }
1 by brian
clean slate
586
      args[0]= item;
1237.13.5 by Padraig O'Sullivan
Split some classes from the range optimizer out in to their own header and implementation files.
587
      inv_order= true;
1 by brian
clean slate
588
    }
589
    else
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
590
    {
1 by brian
clean slate
591
      return 0;
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
592
    }
1 by brian
clean slate
593
    break;
594
  case 3:
595
    /* field BETWEEN const AND const */
596
    item= func_item->arguments()[0];
597
    if (item->type() == Item::FIELD_ITEM)
598
    {
599
      args[0]= item;
600
      for (int i= 1 ; i <= 2; i++)
601
      {
602
        item= func_item->arguments()[i];
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
603
        if (! item->const_item())
604
        {
1 by brian
clean slate
605
          return 0;
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
606
        }
1 by brian
clean slate
607
        args[i]= item;
608
      }
609
    }
610
    else
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
611
    {
1 by brian
clean slate
612
      return 0;
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
613
    }
1 by brian
clean slate
614
  }
615
  return 1;
616
}
617
618
619
/**
620
  Check whether a condition matches a key to get {MAX|MIN}(field):.
621
622
     For the index specified by the keyinfo parameter, index that
623
     contains field as its component (field_part), the function
624
     checks whether the condition cond is a conjunction and all its
625
     conjuncts referring to the columns of the same table as column
626
     field are one of the following forms:
627
     - f_i= const_i or const_i= f_i or f_i is null,
628
     where f_i is part of the index
629
     - field {<|<=|>=|>|=} const or const {<|<=|>=|>|=} field
630
     - field between const1 and const2
631
632
  @param[in]     max_fl         Set to 1 if we are optimising MAX()
633
  @param[in,out] ref            Reference to the structure we store the key
634
    value
635
  @param[in]     keyinfo        Reference to the key info
636
  @param[in]     field_part     Pointer to the key part for the field
637
  @param[in]     cond           WHERE condition
638
  @param[in,out] key_part_used  Map of matchings parts
639
  @param[in,out] range_fl       Says whether including key will be used
640
  @param[out]    prefix_len     Length of common key part for the range
641
    where MAX/MIN is searched for
642
643
  @retval
644
    0        Index can't be used.
645
  @retval
646
    1        We can use index to get MIN/MAX value
647
*/
1240.3.1 by Brian Aker
Merge Padraig.
648
static bool matching_cond(bool max_fl,
649
                          table_reference_st *ref,
1535 by Brian Aker
Rename of KEY to KeyInfo
650
                          KeyInfo *keyinfo,
1534 by Brian Aker
Remove of KeyPartInfo
651
                          KeyPartInfo *field_part,
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
652
                          COND *cond,
1240.3.1 by Brian Aker
Merge Padraig.
653
                          key_part_map *key_part_used,
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
654
                          uint32_t *range_fl,
482 by Brian Aker
Remove uint.
655
                          uint32_t *prefix_len)
1 by brian
clean slate
656
{
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
657
  if (! cond)
658
  {
1 by brian
clean slate
659
    return 1;
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
660
  }
1 by brian
clean slate
661
  Field *field= field_part->field;
1089.1.3 by Brian Aker
Fix protobuf to release memory. Add in assert() for wrong column usage. Fix
662
663
  field->setWriteSet();
664
1660.1.3 by Brian Aker
Encapsulate Table in field
665
  if (! (cond->used_tables() & field->getTable()->map))
1 by brian
clean slate
666
  {
667
    /* Condition doesn't restrict the used table */
668
    return 1;
669
  }
670
  if (cond->type() == Item::COND_ITEM)
671
  {
672
    if (((Item_cond*) cond)->functype() == Item_func::COND_OR_FUNC)
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
673
    {
1 by brian
clean slate
674
      return 0;
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
675
    }
1 by brian
clean slate
676
677
    /* AND */
678
    List_iterator_fast<Item> li(*((Item_cond*) cond)->argument_list());
679
    Item *item;
680
    while ((item= li++))
681
    {
1240.3.1 by Brian Aker
Merge Padraig.
682
      if (! matching_cond(max_fl,
683
                          ref,
684
                          keyinfo,
685
                          field_part,
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
686
                          item,
1240.3.1 by Brian Aker
Merge Padraig.
687
                          key_part_used,
688
                          range_fl,
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
689
                          prefix_len))
690
      {
1 by brian
clean slate
691
        return 0;
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
692
      }
1 by brian
clean slate
693
    }
694
    return 1;
695
  }
696
697
  if (cond->type() != Item::FUNC_ITEM)
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
698
  {
699
    return 0; // Not operator, can't optimize
700
  }
701
702
  bool eq_type= false; // =, <=> or IS NULL
703
  bool noeq_type= false; // < or >
704
  bool less_fl= false; // < or <=
705
  bool is_null= false;
706
  bool between= false;
707
1240.3.1 by Brian Aker
Merge Padraig.
708
  switch (((Item_func*) cond)->functype())
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
709
  {
1 by brian
clean slate
710
  case Item_func::ISNULL_FUNC:
711
    is_null= 1;     /* fall through */
712
  case Item_func::EQ_FUNC:
713
  case Item_func::EQUAL_FUNC:
714
    eq_type= 1;
715
    break;
716
  case Item_func::LT_FUNC:
717
    noeq_type= 1;   /* fall through */
718
  case Item_func::LE_FUNC:
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
719
    less_fl= 1;
1 by brian
clean slate
720
    break;
721
  case Item_func::GT_FUNC:
722
    noeq_type= 1;   /* fall through */
723
  case Item_func::GE_FUNC:
724
    break;
725
  case Item_func::BETWEEN:
726
    between= 1;
727
    break;
728
  case Item_func::MULT_EQUAL_FUNC:
729
    eq_type= 1;
730
    break;
731
  default:
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
732
    return 0; // Can't optimize function
1 by brian
clean slate
733
  }
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
734
1 by brian
clean slate
735
  Item *args[3];
736
  bool inv;
737
738
  /* Test if this is a comparison of a field and constant */
1237.13.5 by Padraig O'Sullivan
Split some classes from the range optimizer out in to their own header and implementation files.
739
  if (! optimizer::simple_pred((Item_func*) cond, args, inv))
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
740
  {
1 by brian
clean slate
741
    return 0;
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
742
  }
1 by brian
clean slate
743
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
744
  if (inv && ! eq_type)
745
  {
746
    less_fl= 1 - less_fl; // Convert '<' -> '>' (etc)
747
  }
1 by brian
clean slate
748
749
  /* Check if field is part of the tested partial key */
481 by Brian Aker
Remove all of uchar.
750
  unsigned char *key_ptr= ref->key_buff;
1534 by Brian Aker
Remove of KeyPartInfo
751
  KeyPartInfo *part= NULL;
1 by brian
clean slate
752
  for (part= keyinfo->key_part; ; key_ptr+= part++->store_length)
753
754
  {
755
    if (part > field_part)
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
756
    {
1 by brian
clean slate
757
      return 0;                     // Field is beyond the tested parts
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
758
    }
1 by brian
clean slate
759
    if (part->field->eq(((Item_field*) args[0])->field))
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
760
    {
1 by brian
clean slate
761
      break;                        // Found a part of the key for the field
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
762
    }
1 by brian
clean slate
763
  }
764
765
  bool is_field_part= part == field_part;
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
766
  if (! (is_field_part || eq_type))
767
  {
1 by brian
clean slate
768
    return 0;
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
769
  }
1 by brian
clean slate
770
771
  key_part_map org_key_part_used= *key_part_used;
772
  if (eq_type || between || max_fl == less_fl)
773
  {
482 by Brian Aker
Remove uint.
774
    uint32_t length= (key_ptr-ref->key_buff)+part->store_length;
1 by brian
clean slate
775
    if (ref->key_length < length)
776
    {
777
    /* Ultimately ref->key_length will contain the length of the search key */
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
778
      ref->key_length= length;
1 by brian
clean slate
779
      ref->key_parts= (part - keyinfo->key_part) + 1;
780
    }
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
781
    if (! *prefix_len && part + 1 == field_part)
782
    {
1 by brian
clean slate
783
      *prefix_len= length;
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
784
    }
1 by brian
clean slate
785
    if (is_field_part && eq_type)
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
786
    {
1 by brian
clean slate
787
      *prefix_len= ref->key_length;
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
788
    }
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
789
1 by brian
clean slate
790
    *key_part_used|= (key_part_map) 1 << (part - keyinfo->key_part);
791
  }
792
793
  if (org_key_part_used != *key_part_used ||
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
794
      (is_field_part &&
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
795
       (between || eq_type || max_fl == less_fl) && ! cond->val_int()))
1 by brian
clean slate
796
  {
797
    /*
798
      It's the first predicate for this part or a predicate of the
799
      following form  that moves upper/lower bounds for max/min values:
800
      - field BETWEEN const AND const
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
801
      - field = const
1 by brian
clean slate
802
      - field {<|<=} const, when searching for MAX
803
      - field {>|>=} const, when searching for MIN
804
    */
805
806
    if (is_null)
807
    {
808
      part->field->set_null();
481 by Brian Aker
Remove all of uchar.
809
      *key_ptr= (unsigned char) 1;
1 by brian
clean slate
810
    }
811
    else
812
    {
813
      store_val_in_field(part->field, args[between && max_fl ? 2 : 1],
814
                         CHECK_FIELD_IGNORE);
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
815
      if (part->null_bit)
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
816
      {
481 by Brian Aker
Remove all of uchar.
817
        *key_ptr++= (unsigned char) test(part->field->is_null());
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
818
      }
1055.2.5 by Jay Pipes
Removal of dead Field::image_type and st_key_part::image_type member variables. Legacy from geometry MyISAM types...
819
      part->field->get_key_image(key_ptr, part->length);
1 by brian
clean slate
820
    }
821
    if (is_field_part)
822
    {
823
      if (between || eq_type)
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
824
      {
1 by brian
clean slate
825
        *range_fl&= ~(NO_MAX_RANGE | NO_MIN_RANGE);
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
826
      }
1 by brian
clean slate
827
      else
828
      {
829
        *range_fl&= ~(max_fl ? NO_MAX_RANGE : NO_MIN_RANGE);
830
        if (noeq_type)
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
831
        {
1 by brian
clean slate
832
          *range_fl|=  (max_fl ? NEAR_MAX : NEAR_MIN);
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
833
        }
1 by brian
clean slate
834
        else
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
835
        {
1 by brian
clean slate
836
          *range_fl&= ~(max_fl ? NEAR_MAX : NEAR_MIN);
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
837
        }
1 by brian
clean slate
838
      }
839
    }
840
  }
841
  else if (eq_type)
842
  {
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
843
    if ((! is_null && !cond->val_int()) ||
1 by brian
clean slate
844
        (is_null && !test(part->field->is_null())))
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
845
    {
1 by brian
clean slate
846
     return 0;                       // Impossible test
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
847
    }
1 by brian
clean slate
848
  }
849
  else if (is_field_part)
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
850
  {
1 by brian
clean slate
851
    *range_fl&= ~(max_fl ? NO_MIN_RANGE : NO_MAX_RANGE);
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
852
  }
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
853
  return 1;
1 by brian
clean slate
854
}
855
856
857
/**
858
  Check whether we can get value for {max|min}(field) by using a key.
859
860
     If where-condition is not a conjunction of 0 or more conjuct the
861
     function returns false, otherwise it checks whether there is an
862
     index including field as its k-th component/part such that:
863
864
     -# for each previous component f_i there is one and only one conjunct
865
        of the form: f_i= const_i or const_i= f_i or f_i is null
866
     -# references to field occur only in conjucts of the form:
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
867
        field {<|<=|>=|>|=} const or const {<|<=|>=|>|=} field or
1 by brian
clean slate
868
        field BETWEEN const1 AND const2
869
     -# all references to the columns from the same table as column field
870
        occur only in conjucts mentioned above.
871
     -# each of k first components the index is not partial, i.e. is not
872
        defined on a fixed length proper prefix of the field.
873
874
     If such an index exists the function through the ref parameter
875
     returns the key value to find max/min for the field using the index,
876
     the length of first (k-1) components of the key and flags saying
877
     how to apply the key for the search max/min value.
878
     (if we have a condition field = const, prefix_len contains the length
879
     of the whole search key)
880
881
  @param[in]     max_fl      0 for MIN(field) / 1 for MAX(field)
882
  @param[in,out] ref         Reference to the structure we store the key value
883
  @param[in]     field       Field used inside MIN() / MAX()
884
  @param[in]     cond        WHERE condition
885
  @param[out]    range_fl    Bit flags for how to search if key is ok
886
  @param[out]    prefix_len  Length of prefix for the search range
887
888
  @note
889
    This function may set table->key_read to 1, which must be reset after
890
    index is used! (This can only happen when function returns 1)
891
892
  @retval
893
    0   Index can not be used to optimize MIN(field)/MAX(field)
894
  @retval
895
    1   Can use key to optimize MIN()/MAX().
896
    In this case ref, range_fl and prefix_len are updated
897
*/
1240.3.1 by Brian Aker
Merge Padraig.
898
static bool find_key_for_maxmin(bool max_fl,
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
899
                                table_reference_st *ref,
1240.3.1 by Brian Aker
Merge Padraig.
900
                                Field* field,
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
901
                                COND *cond,
1240.3.1 by Brian Aker
Merge Padraig.
902
                                uint32_t *range_fl,
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
903
                                uint32_t *prefix_len)
1 by brian
clean slate
904
{
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
905
  if (! (field->flags & PART_KEY_FLAG))
906
  {
907
    return 0; // Not key field
908
  }
1 by brian
clean slate
909
1660.1.3 by Brian Aker
Encapsulate Table in field
910
  Table *table= field->getTable();
482 by Brian Aker
Remove uint.
911
  uint32_t idx= 0;
1 by brian
clean slate
912
1535 by Brian Aker
Rename of KEY to KeyInfo
913
  KeyInfo *keyinfo,*keyinfo_end= NULL;
1578.2.10 by Brian Aker
keys and fields partial encapsulation.
914
  for (keyinfo= table->key_info, keyinfo_end= keyinfo+table->getShare()->sizeKeys();
1 by brian
clean slate
915
       keyinfo != keyinfo_end;
916
       keyinfo++,idx++)
917
  {
1534 by Brian Aker
Remove of KeyPartInfo
918
    KeyPartInfo *part= NULL;
919
    KeyPartInfo *part_end= NULL;
1 by brian
clean slate
920
    key_part_map key_part_to_use= 0;
921
    /*
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
922
      Perform a check if index is not disabled by ALTER Table
1 by brian
clean slate
923
      or IGNORE INDEX.
924
    */
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
925
    if (! table->keys_in_use_for_query.test(idx))
926
    {
1 by brian
clean slate
927
      continue;
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
928
    }
482 by Brian Aker
Remove uint.
929
    uint32_t jdx= 0;
1 by brian
clean slate
930
    *prefix_len= 0;
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
931
    for (part= keyinfo->key_part, part_end= part+keyinfo->key_parts;
932
         part != part_end;
1 by brian
clean slate
933
         part++, jdx++, key_part_to_use= (key_part_to_use << 1) | 1)
934
    {
1235.1.14 by Brian Aker
Final move of index flags up to Engine (new interface still needed).
935
      if (! (table->index_flags(idx) & HA_READ_ORDER))
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
936
      {
1 by brian
clean slate
937
        return 0;
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
938
      }
1 by brian
clean slate
939
940
      /* Check whether the index component is partial */
1578.2.16 by Brian Aker
Merge in change to getTable() to private the field objects.
941
      Field *part_field= table->getField(part->fieldnr-1);
1089.1.3 by Brian Aker
Fix protobuf to release memory. Add in assert() for wrong column usage. Fix
942
      part_field->setWriteSet();
943
1 by brian
clean slate
944
      if ((part_field->flags & BLOB_FLAG) ||
945
          part->length < part_field->key_length())
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
946
      {
1 by brian
clean slate
947
        break;
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
948
      }
1 by brian
clean slate
949
950
      if (field->eq(part->field))
951
      {
952
        ref->key= idx;
953
        ref->key_length= 0;
954
        ref->key_parts= 0;
955
        key_part_map key_part_used= 0;
956
        *range_fl= NO_MIN_RANGE | NO_MAX_RANGE;
1240.3.1 by Brian Aker
Merge Padraig.
957
        if (matching_cond(max_fl,
958
                          ref,
959
                          keyinfo,
960
                          part,
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
961
                          cond,
1240.3.1 by Brian Aker
Merge Padraig.
962
                          &key_part_used,
963
                          range_fl,
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
964
                          prefix_len) &&
965
            ! (key_part_to_use & ~key_part_used))
1 by brian
clean slate
966
        {
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
967
          if (! max_fl && key_part_used == key_part_to_use && part->null_bit)
1 by brian
clean slate
968
          {
969
            /*
970
              The query is on this form:
971
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
972
              SELECT MIN(key_part_k)
973
              FROM t1
1 by brian
clean slate
974
              WHERE key_part_1 = const and ... and key_part_k-1 = const
975
976
              If key_part_k is nullable, we want to find the first matching row
977
              where key_part_k is not null. The key buffer is now {const, ...,
978
              NULL}. This will be passed to the handler along with a flag
979
              indicating open interval. If a tuple is read that does not match
980
              these search criteria, an attempt will be made to read an exact
981
              match for the key buffer.
982
            */
983
            /* Set the first byte of key_part_k to 1, that means NULL */
984
            ref->key_buff[ref->key_length]= 1;
985
            ref->key_length+= part->store_length;
986
            ref->key_parts++;
51.1.35 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
987
            assert(ref->key_parts == jdx+1);
1 by brian
clean slate
988
            *range_fl&= ~NO_MIN_RANGE;
989
            *range_fl|= NEAR_MIN; // Open interval
990
          }
991
          /*
992
            The following test is false when the key in the key tree is
993
            converted (for example to upper case)
994
          */
1005.2.6 by Monty Taylor
Re-added bitset<> as a replacement for Bitmap<>
995
          if (field->part_of_key.test(idx))
1 by brian
clean slate
996
          {
997
            table->key_read= 1;
1208.3.2 by brian
Update for Cursor renaming.
998
            table->cursor->extra(HA_EXTRA_KEYREAD);
1 by brian
clean slate
999
          }
1000
          return 1;
1001
        }
1002
      }
1003
    }
1004
  }
1005
  return 0;
1006
}
1007
1008
1009
/**
1010
  Check whether found key is in range specified by conditions.
1011
1012
  @param[in] max_fl         0 for MIN(field) / 1 for MAX(field)
1013
  @param[in] ref            Reference to the key value and info
1014
  @param[in] field          Field used the MIN/MAX expression
1015
  @param[in] cond           WHERE condition
1016
  @param[in] range_fl       Says whether there is a condition to to be checked
1017
  @param[in] prefix_len     Length of the constant part of the key
1018
1019
  @retval
1020
    0        ok
1021
  @retval
1022
    1        WHERE was not true for the found row
1023
*/
1240.3.1 by Brian Aker
Merge Padraig.
1024
static int reckey_in_range(bool max_fl,
1025
                           table_reference_st *ref,
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
1026
                           Field* field,
1240.3.1 by Brian Aker
Merge Padraig.
1027
                           COND *cond,
1028
                           uint32_t range_fl,
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
1029
                           uint32_t prefix_len)
1 by brian
clean slate
1030
{
1660.1.3 by Brian Aker
Encapsulate Table in field
1031
  if (key_cmp_if_same(field->getTable(), ref->key_buff, ref->key, prefix_len))
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
1032
  {
1 by brian
clean slate
1033
    return 1;
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
1034
  }
1035
  if (! cond || (range_fl & (max_fl ? NO_MIN_RANGE : NO_MAX_RANGE)))
1036
  {
1 by brian
clean slate
1037
    return 0;
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
1038
  }
1 by brian
clean slate
1039
  return maxmin_in_range(max_fl, field, cond);
1040
}
1041
1042
1043
/**
1044
  Check whether {MAX|MIN}(field) is in range specified by conditions.
1045
1046
  @param[in] max_fl          0 for MIN(field) / 1 for MAX(field)
1047
  @param[in] field           Field used the MIN/MAX expression
1048
  @param[in] cond            WHERE condition
1049
1050
  @retval
1051
    0        ok
1052
  @retval
1053
    1        WHERE was not true for the found row
1054
*/
1055
static int maxmin_in_range(bool max_fl, Field* field, COND *cond)
1056
{
1057
  /* If AND/OR condition */
1058
  if (cond->type() == Item::COND_ITEM)
1059
  {
1060
    List_iterator_fast<Item> li(*((Item_cond*) cond)->argument_list());
1061
    Item *item;
1062
    while ((item= li++))
1063
    {
1064
      if (maxmin_in_range(max_fl, field, item))
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
1065
      {
1 by brian
clean slate
1066
        return 1;
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
1067
      }
1 by brian
clean slate
1068
    }
1069
    return 0;
1070
  }
1071
1660.1.3 by Brian Aker
Encapsulate Table in field
1072
  if (cond->used_tables() != field->getTable()->map)
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
1073
  {
1 by brian
clean slate
1074
    return 0;
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
1075
  }
1076
  bool less_fl= false;
1240.3.1 by Brian Aker
Merge Padraig.
1077
  switch (((Item_func*) cond)->functype())
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
1078
  {
1 by brian
clean slate
1079
  case Item_func::BETWEEN:
1080
    return cond->val_int() == 0;                // Return 1 if WHERE is false
1081
  case Item_func::LT_FUNC:
1082
  case Item_func::LE_FUNC:
1083
    less_fl= 1;
1084
  case Item_func::GT_FUNC:
1085
  case Item_func::GE_FUNC:
1086
  {
1087
    Item *item= ((Item_func*) cond)->arguments()[1];
1088
    /* In case of 'const op item' we have to swap the operator */
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
1089
    if (! item->const_item())
1090
    {
1 by brian
clean slate
1091
      less_fl= 1-less_fl;
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
1092
    }
1 by brian
clean slate
1093
    /*
1094
      We only have to check the expression if we are using an expression like
1095
      SELECT MAX(b) FROM t1 WHERE a=const AND b>const
1096
      not for
1097
      SELECT MAX(b) FROM t1 WHERE a=const AND b<const
1098
    */
1099
    if (max_fl != less_fl)
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
1100
    {
1 by brian
clean slate
1101
      return cond->val_int() == 0;                // Return 1 if WHERE is false
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
1102
    }
1 by brian
clean slate
1103
    return 0;
1104
  }
1105
  case Item_func::EQ_FUNC:
1106
  case Item_func::EQUAL_FUNC:
1107
    break;
1108
  default:                                        // Keep compiler happy
51.1.35 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
1109
    assert(1);                               // Impossible
1 by brian
clean slate
1110
    break;
1111
  }
1112
  return 0;
1113
}
1114
1237.9.1 by Padraig O'Sullivan
Moved the opt_sum.cc file into the optimizer directory and renamed it to sum.cc. Added a header file
1115
} /* namespace drizzled */
1116