opt_range.h 22.8 KB
Newer Older
unknown's avatar
unknown committed
1
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
unknown's avatar
unknown committed
2

unknown's avatar
unknown committed
3 4 5 6
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
unknown's avatar
unknown committed
7

unknown's avatar
unknown committed
8 9 10 11
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
unknown's avatar
unknown committed
12

unknown's avatar
unknown committed
13 14 15 16 17 18 19 20 21 22
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */


/* classes to use when handling where clause */

#ifndef _opt_range_h
#define _opt_range_h

23
#ifdef USE_PRAGMA_INTERFACE
unknown's avatar
unknown committed
24 25 26 27
#pragma interface			/* gcc class implementation */
#endif

typedef struct st_key_part {
unknown's avatar
unknown committed
28
  uint16           key,part, store_length, length;
unknown's avatar
unknown committed
29 30 31
  uint8            null_bit;
  Field            *field;
  Field::imagetype image_type;
unknown's avatar
unknown committed
32 33
} KEY_PART;

34

unknown's avatar
unknown committed
35 36 37 38
class QUICK_RANGE :public Sql_alloc {
 public:
  char *min_key,*max_key;
  uint16 min_length,max_length,flag;
39 40 41
#ifdef HAVE_purify
  uint16 dummy;					/* Avoid warnings on 'flag' */
#endif
unknown's avatar
unknown committed
42 43 44 45 46 47
  QUICK_RANGE();				/* Full range */
  QUICK_RANGE(const char *min_key_arg,uint min_length_arg,
	      const char *max_key_arg,uint max_length_arg,
	      uint flag_arg)
    : min_key((char*) sql_memdup(min_key_arg,min_length_arg+1)),
      max_key((char*) sql_memdup(max_key_arg,max_length_arg+1)),
unknown's avatar
unknown committed
48 49 50
      min_length((uint16) min_length_arg),
      max_length((uint16) max_length_arg),
      flag((uint16) flag_arg)
51 52 53 54 55
    {
#ifdef HAVE_purify
      dummy=0;
#endif
    }
unknown's avatar
unknown committed
56 57
};

unknown's avatar
unknown committed
58

unknown's avatar
unknown committed
59
/*
unknown's avatar
unknown committed
60
  Quick select interface.
61
  This class is a parent for all QUICK_*_SELECT and FT_SELECT classes.
unknown's avatar
unknown committed
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
  
  The usage scenario is as follows:
  1. Create quick select
    quick= new QUICK_XXX_SELECT(...);
    
  2. Perform lightweight initialization. This can be done in 2 ways:
  2.a: Regular initialization
    if (quick->init())
    {
      //the only valid action after failed init() call is delete
      delete quick;
    }
  2.b: Special initialization for quick selects merged by QUICK_ROR_*_SELECT
    if (quick->init_ror_merged_scan())
      delete quick;
        
  3. Perform zero, one, or more scans.
    while (...)
    {
      // initialize quick select for scan. This may allocate
      // buffers and/or prefetch rows. 
      if (quick->reset())
      {
        //the only valid action after failed reset() call is delete
        delete quick;
        //abort query
      }
      
      // perform the scan
      do
      {
        res= quick->get_next();
      } while (res && ...)
    }
    
  4. Delete the select:
    delete quick;
  
unknown's avatar
unknown committed
100 101 102 103
*/

class QUICK_SELECT_I
{
unknown's avatar
unknown committed
104
public:
unknown's avatar
unknown committed
105
  bool sorted;
unknown's avatar
unknown committed
106 107 108 109
  ha_rows records;  /* estimate of # of records to be retrieved */
  double  read_time; /* time to perform this retrieval          */
  TABLE   *head;
  /*
unknown's avatar
unknown committed
110
    Index this quick select uses, or MAX_KEY for quick selects
111
    that use several indexes
unknown's avatar
unknown committed
112
  */
113
  uint index;
unknown's avatar
unknown committed
114 115

  /*
116 117
    Total length of first used_key_parts parts of the key.
    Applicable if index!= MAX_KEY.
unknown's avatar
unknown committed
118
  */
119 120 121 122 123 124 125 126
  uint max_used_key_length;

  /*
    Max. number of (first) key parts this quick select uses for retrieval.
    eg. for "(key1p1=c1 AND key1p2=c2) OR key1p1=c2" used_key_parts == 2.
    Applicable if index!= MAX_KEY.
  */
  uint used_key_parts;
unknown's avatar
unknown committed
127 128 129

  QUICK_SELECT_I();
  virtual ~QUICK_SELECT_I(){};
unknown's avatar
unknown committed
130

131 132 133 134
  /*
    Do post-constructor initialization.
    SYNOPSIS
      init()
unknown's avatar
unknown committed
135 136 137

    init() performs initializations that should have been in constructor if
    it was possible to return errors from constructors. The join optimizer may
138 139 140
    create and then delete quick selects without retrieving any rows so init()
    must not contain any IO or CPU intensive code.

unknown's avatar
unknown committed
141
    If init() call fails the only valid action is to delete this quick select,
142
    reset() and get_next() must not be called.
unknown's avatar
unknown committed
143

144 145 146
    RETURN
      0      OK
      other  Error code
unknown's avatar
unknown committed
147
  */
unknown's avatar
unknown committed
148
  virtual int  init() = 0;
unknown's avatar
unknown committed
149 150

  /*
151 152 153
    Initialize quick select for row retrieval.
    SYNOPSIS
      reset()
unknown's avatar
unknown committed
154 155

    reset() should be called when it is certain that row retrieval will be
156 157
    necessary. This call may do heavyweight initialization like buffering first
    N records etc. If reset() call fails get_next() must not be called.
unknown's avatar
unknown committed
158 159 160 161
    Note that reset() may be called several times if 
     * the quick select is executed in a subselect
     * a JOIN buffer is used
    
162 163 164
    RETURN
      0      OK
      other  Error code
unknown's avatar
unknown committed
165
  */
166
  virtual int  reset(void) = 0;
unknown's avatar
unknown committed
167

unknown's avatar
unknown committed
168 169
  virtual int  get_next() = 0;   /* get next record to retrieve */

unknown's avatar
unknown committed
170 171
  /* Range end should be called when we have looped over the whole index */
  virtual void range_end() {}
unknown's avatar
unknown committed
172

unknown's avatar
unknown committed
173 174 175
  virtual bool reverse_sorted() = 0;
  virtual bool unique_key_range() { return false; }

unknown's avatar
unknown committed
176
  enum {
unknown's avatar
unknown committed
177 178 179
    QS_TYPE_RANGE = 0,
    QS_TYPE_INDEX_MERGE = 1,
    QS_TYPE_RANGE_DESC = 2,
180 181
    QS_TYPE_FULLTEXT   = 3,
    QS_TYPE_ROR_INTERSECT = 4,
182 183
    QS_TYPE_ROR_UNION = 5,
    QS_TYPE_GROUP_MIN_MAX = 6
unknown's avatar
unknown committed
184 185
  };

186 187 188 189
  /* Get type of this quick select - one of the QS_TYPE_* values */
  virtual int get_type() = 0;

  /*
190
    Initialize this quick select as a merged scan inside a ROR-union or a ROR-
unknown's avatar
unknown committed
191
    intersection scan. The caller must not additionally call init() if this
192 193 194
    function is called.
    SYNOPSIS
      init_ror_merged_scan()
195 196 197 198
        reuse_handler If true, the quick select may use table->handler, otherwise
                      it must create and use a separate handler object.
    RETURN
      0     Ok
unknown's avatar
unknown committed
199
      other Error
200
  */
201
  virtual int init_ror_merged_scan(bool reuse_handler)
202
  { DBUG_ASSERT(0); return 1; }
unknown's avatar
unknown committed
203

204 205 206
  /*
    Save ROWID of last retrieved row in file->ref. This used in ROR-merging.
  */
207 208
  virtual void save_last_pos(){};

unknown's avatar
unknown committed
209
  /*
210 211
    Append comma-separated list of keys this quick select uses to key_names;
    append comma-separated list of corresponding used lengths to used_lengths.
212 213
    This is used by select_describe.
  */
unknown's avatar
unknown committed
214
  virtual void add_keys_and_lengths(String *key_names,
215
                                    String *used_lengths)=0;
unknown's avatar
unknown committed
216 217 218

  /*
    Append text representation of quick select structure (what and how is
219 220 221 222 223 224
    merged) to str. The result is added to "Extra" field in EXPLAIN output.
    This function is implemented only by quick selects that merge other quick
    selects output and/or can produce output suitable for merging.
  */
  virtual void add_info_string(String *str) {};
  /*
unknown's avatar
unknown committed
225 226
    Return 1 if any index used by this quick select
     a) uses field that is listed in passed field list or
227 228
     b) is automatically updated (like a timestamp)
  */
229 230 231
  virtual bool check_if_keys_used(List<Item> *fields);

  /*
unknown's avatar
unknown committed
232 233
    rowid of last row retrieved by this quick select. This is used only when
    doing ROR-index_merge selects
234 235
  */
  byte    *last_rowid;
236 237

  /*
unknown's avatar
unknown committed
238
    Table record buffer used by this quick select.
239
  */
240 241 242
  byte    *record;
#ifndef DBUG_OFF
  /*
unknown's avatar
unknown committed
243
    Print quick select information to DBUG_FILE. Caller is responsible
244 245 246
    for locking DBUG_FILE before this call and unlocking it afterwards.
  */
  virtual void dbug_dump(int indent, bool verbose)= 0;
unknown's avatar
unknown committed
247
#endif
unknown's avatar
unknown committed
248 249
};

250

unknown's avatar
unknown committed
251 252 253
struct st_qsel_param;
class SEL_ARG;

254
/*
unknown's avatar
unknown committed
255
  Quick select that does a range scan on a single key. The records are
256 257
  returned in key order.
*/
258
class QUICK_RANGE_SELECT : public QUICK_SELECT_I
unknown's avatar
unknown committed
259 260
{
protected:
unknown's avatar
unknown committed
261
  bool next,dont_free;
unknown's avatar
unknown committed
262
public:
unknown's avatar
unknown committed
263
  int error;
264
protected:
unknown's avatar
unknown committed
265
  handler *file;
266 267 268 269 270
  /*
    If true, this quick select has its "own" handler object which should be
    closed no later then this quick select is deleted.
  */
  bool free_file;
unknown's avatar
unknown committed
271 272 273 274 275 276 277 278
  bool in_range;
  uint multi_range_count; /* copy from thd->variables.multi_range_count */
  uint multi_range_length; /* the allocated length for the array */
  uint multi_range_bufsiz; /* copy from thd->variables.read_rnd_buff_size */
  KEY_MULTI_RANGE *multi_range; /* the multi-range array (allocated and
                                       freed by QUICK_RANGE_SELECT) */
  HANDLER_BUFFER *multi_range_buff; /* the handler buffer (allocated and
                                       freed by QUICK_RANGE_SELECT) */
279

unknown's avatar
unknown committed
280
protected:
unknown's avatar
unknown committed
281
  friend class TRP_ROR_INTERSECT;
282
  friend
unknown's avatar
unknown committed
283
  QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table,
unknown's avatar
unknown committed
284 285
                                               struct st_table_ref *ref,
                                               ha_rows records);
unknown's avatar
unknown committed
286 287
  friend bool get_quick_keys(struct st_qsel_param *param,
                             QUICK_RANGE_SELECT *quick,KEY_PART *key,
288 289
                             SEL_ARG *key_tree,
                             char *min_key, uint min_key_flag,
unknown's avatar
unknown committed
290 291 292 293 294
                             char *max_key, uint max_key_flag);
  friend QUICK_RANGE_SELECT *get_quick_select(struct st_qsel_param*,uint idx,
                                              SEL_ARG *key_tree,
                                              MEM_ROOT *alloc);
  friend class QUICK_SELECT_DESC;
295
  friend class QUICK_INDEX_MERGE_SELECT;
296
  friend class QUICK_ROR_INTERSECT_SELECT;
297 298 299

  DYNAMIC_ARRAY ranges;     /* ordered array of range ptrs */
  QUICK_RANGE **cur_range;  /* current element in ranges  */
unknown's avatar
unknown committed
300

unknown's avatar
unknown committed
301
  QUICK_RANGE *range;
unknown's avatar
unknown committed
302
  KEY_PART *key_parts;
unknown's avatar
unknown committed
303
  KEY_PART_INFO *key_part_info;
unknown's avatar
unknown committed
304
  int cmp_next(QUICK_RANGE *range);
305 306
  int cmp_prev(QUICK_RANGE *range);
  bool row_in_ranges();
unknown's avatar
unknown committed
307
public:
308 309
  MEM_ROOT alloc;

unknown's avatar
unknown committed
310
  QUICK_RANGE_SELECT(THD *thd, TABLE *table,uint index_arg,bool no_alloc=0,
unknown's avatar
unknown committed
311 312
                     MEM_ROOT *parent_alloc=NULL);
  ~QUICK_RANGE_SELECT();
unknown's avatar
unknown committed
313

unknown's avatar
unknown committed
314
  int init();
unknown's avatar
unknown committed
315
  int reset(void);
unknown's avatar
unknown committed
316
  int get_next();
unknown's avatar
unknown committed
317
  void range_end();
318
  int get_next_prefix(uint prefix_length, byte *cur_prefix);
unknown's avatar
unknown committed
319
  bool reverse_sorted() { return 0; }
unknown's avatar
unknown committed
320
  bool unique_key_range();
321
  int init_ror_merged_scan(bool reuse_handler);
322
  void save_last_pos()
323
  { file->position(record); }
unknown's avatar
unknown committed
324
  int get_type() { return QS_TYPE_RANGE; }
325 326
  void add_keys_and_lengths(String *key_names, String *used_lengths);
  void add_info_string(String *str);
327
#ifndef DBUG_OFF
328
  void dbug_dump(int indent, bool verbose);
329
#endif
unknown's avatar
unknown committed
330 331
private:
  /* Used only by QUICK_SELECT_DESC */
unknown's avatar
unknown committed
332 333 334 335 336 337 338
  QUICK_RANGE_SELECT(const QUICK_RANGE_SELECT& org) : QUICK_SELECT_I()
  {
    bcopy(&org, this, sizeof(*this));
    multi_range_length= 0;
    multi_range= NULL;
    multi_range_buff= NULL;
  }
unknown's avatar
unknown committed
339 340
};

341

unknown's avatar
unknown committed
342 343 344 345 346 347 348 349 350 351 352
class QUICK_RANGE_SELECT_GEOM: public QUICK_RANGE_SELECT
{
public:
  QUICK_RANGE_SELECT_GEOM(THD *thd, TABLE *table, uint index_arg,
                          bool no_alloc, MEM_ROOT *parent_alloc)
    :QUICK_RANGE_SELECT(thd, table, index_arg, no_alloc, parent_alloc)
    {};
  virtual int get_next();
};


unknown's avatar
unknown committed
353
/*
354
  QUICK_INDEX_MERGE_SELECT - index_merge access method quick select.
355

unknown's avatar
unknown committed
356
    QUICK_INDEX_MERGE_SELECT uses
357 358
     * QUICK_RANGE_SELECTs to get rows
     * Unique class to remove duplicate rows
359

360
  INDEX MERGE OPTIMIZER
unknown's avatar
unknown committed
361
    Current implementation doesn't detect all cases where index_merge could
362
    be used, in particular:
unknown's avatar
unknown committed
363
     * index_merge will never be used if range scan is possible (even if
364
       range scan is more expensive)
365

unknown's avatar
unknown committed
366
     * index_merge+'using index' is not supported (this the consequence of
367
       the above restriction)
unknown's avatar
unknown committed
368

369
     * If WHERE part contains complex nested AND and OR conditions, some ways
unknown's avatar
unknown committed
370 371
       to retrieve rows using index_merge will not be considered. The choice
       of read plan may depend on the order of conjuncts/disjuncts in WHERE
372 373
       part of the query, see comments near imerge_list_or_list and
       SEL_IMERGE::or_sel_tree_with_checks functions for details.
374

375 376
     * There is no "index_merge_ref" method (but index_merge on non-first
       table in join is possible with 'range checked for each record').
377

unknown's avatar
unknown committed
378
    See comments around SEL_IMERGE class and test_quick_select for more
379
    details.
380

381
  ROW RETRIEVAL ALGORITHM
382

383 384 385
    index_merge uses Unique class for duplicates removal.  index_merge takes
    advantage of Clustered Primary Key (CPK) if the table has one.
    The index_merge algorithm consists of two phases:
386

387 388
    Phase 1 (implemented in QUICK_INDEX_MERGE_SELECT::prepare_unique):
    prepare()
389
    {
390 391 392 393 394 395 396 397 398
      activate 'index only';
      while(retrieve next row for non-CPK scan)
      {
        if (there is a CPK scan and row will be retrieved by it)
          skip this row;
        else
          put its rowid into Unique;
      }
      deactivate 'index only';
399
    }
unknown's avatar
unknown committed
400

401 402
    Phase 2 (implemented as sequence of QUICK_INDEX_MERGE_SELECT::get_next
    calls):
403

404 405 406 407 408 409
    fetch()
    {
      retrieve all rows from row pointers stored in Unique;
      free Unique;
      retrieve all rows for CPK scan;
    }
unknown's avatar
unknown committed
410 411
*/

unknown's avatar
unknown committed
412
class QUICK_INDEX_MERGE_SELECT : public QUICK_SELECT_I
unknown's avatar
unknown committed
413 414 415 416 417 418
{
public:
  QUICK_INDEX_MERGE_SELECT(THD *thd, TABLE *table);
  ~QUICK_INDEX_MERGE_SELECT();

  int  init();
419
  int  reset(void);
unknown's avatar
unknown committed
420 421 422 423
  int  get_next();
  bool reverse_sorted() { return false; }
  bool unique_key_range() { return false; }
  int get_type() { return QS_TYPE_INDEX_MERGE; }
424 425
  void add_keys_and_lengths(String *key_names, String *used_lengths);
  void add_info_string(String *str);
426 427
  bool check_if_keys_used(List<Item> *fields);
#ifndef DBUG_OFF
428
  void dbug_dump(int indent, bool verbose);
429
#endif
unknown's avatar
unknown committed
430 431 432 433 434

  bool push_quick_back(QUICK_RANGE_SELECT *quick_sel_range);

  /* range quick selects this index_merge read consists of */
  List<QUICK_RANGE_SELECT> quick_selects;
unknown's avatar
unknown committed
435

436
  /* quick select that uses clustered primary key (NULL if none) */
437
  QUICK_RANGE_SELECT* pk_quick_select;
unknown's avatar
unknown committed
438

439
  /* true if this select is currently doing a clustered PK scan */
440
  bool  doing_pk_scan;
unknown's avatar
unknown committed
441

442 443
  MEM_ROOT alloc;
  THD *thd;
unknown's avatar
unknown committed
444
  int read_keys_and_merge();
unknown's avatar
unknown committed
445

446 447
  /* used to get rows collected in Unique */
  READ_RECORD read_record;
unknown's avatar
unknown committed
448 449
};

450 451 452

/*
  Rowid-Ordered Retrieval (ROR) index intersection quick select.
unknown's avatar
unknown committed
453
  This quick select produces intersection of row sequences returned
454
  by several QUICK_RANGE_SELECTs it "merges".
unknown's avatar
unknown committed
455 456

  All merged QUICK_RANGE_SELECTs must return rowids in rowid order.
457 458
  QUICK_ROR_INTERSECT_SELECT will return rows in rowid order, too.

unknown's avatar
unknown committed
459
  All merged quick selects retrieve {rowid, covered_fields} tuples (not full
460
  table records).
unknown's avatar
unknown committed
461 462
  QUICK_ROR_INTERSECT_SELECT retrieves full records if it is not being used
  by QUICK_ROR_INTERSECT_SELECT and all merged quick selects together don't
463
  cover needed all fields.
unknown's avatar
unknown committed
464

465 466
  If one of the merged quick selects is a Clustered PK range scan, it is
  used only to filter rowid sequence produced by other merged quick selects.
467
*/
468

unknown's avatar
unknown committed
469
class QUICK_ROR_INTERSECT_SELECT : public QUICK_SELECT_I
470 471
{
public:
unknown's avatar
unknown committed
472
  QUICK_ROR_INTERSECT_SELECT(THD *thd, TABLE *table,
473 474 475 476 477 478 479 480 481 482
                             bool retrieve_full_rows,
                             MEM_ROOT *parent_alloc);
  ~QUICK_ROR_INTERSECT_SELECT();

  int  init();
  int  reset(void);
  int  get_next();
  bool reverse_sorted() { return false; }
  bool unique_key_range() { return false; }
  int get_type() { return QS_TYPE_ROR_INTERSECT; }
483 484
  void add_keys_and_lengths(String *key_names, String *used_lengths);
  void add_info_string(String *str);
485 486
  bool check_if_keys_used(List<Item> *fields);
#ifndef DBUG_OFF
487
  void dbug_dump(int indent, bool verbose);
488
#endif
489
  int init_ror_merged_scan(bool reuse_handler);
490 491
  bool push_quick_back(QUICK_RANGE_SELECT *quick_sel_range);

unknown's avatar
unknown committed
492
  /*
493 494 495
    Range quick selects this intersection consists of, not including
    cpk_quick.
  */
496
  List<QUICK_RANGE_SELECT> quick_selects;
unknown's avatar
unknown committed
497 498 499

  /*
    Merged quick select that uses Clustered PK, if there is one. This quick
500 501
    select is not used for row retrieval, it is used for row retrieval.
  */
502
  QUICK_RANGE_SELECT *cpk_quick;
503 504 505 506

  MEM_ROOT alloc; /* Memory pool for this and merged quick selects data. */
  THD *thd;       /* current thread */
  bool need_to_fetch_row; /* if true, do retrieve full table records. */
unknown's avatar
unknown committed
507 508
  /* in top-level quick select, true if merged scans where initialized */
  bool scans_inited; 
509 510
};

511

512 513
/*
  Rowid-Ordered Retrieval index union select.
514 515
  This quick select produces union of row sequences returned by several
  quick select it "merges".
516

unknown's avatar
unknown committed
517
  All merged quick selects must return rowids in rowid order.
518 519 520 521
  QUICK_ROR_UNION_SELECT will return rows in rowid order, too.

  All merged quick selects are set not to retrieve full table records.
  ROR-union quick select always retrieves full records.
unknown's avatar
unknown committed
522

523
*/
524

unknown's avatar
unknown committed
525
class QUICK_ROR_UNION_SELECT : public QUICK_SELECT_I
526 527 528 529 530 531 532 533 534 535 536
{
public:
  QUICK_ROR_UNION_SELECT(THD *thd, TABLE *table);
  ~QUICK_ROR_UNION_SELECT();

  int  init();
  int  reset(void);
  int  get_next();
  bool reverse_sorted() { return false; }
  bool unique_key_range() { return false; }
  int get_type() { return QS_TYPE_ROR_UNION; }
537 538
  void add_keys_and_lengths(String *key_names, String *used_lengths);
  void add_info_string(String *str);
539 540
  bool check_if_keys_used(List<Item> *fields);
#ifndef DBUG_OFF
541
  void dbug_dump(int indent, bool verbose);
542 543 544 545
#endif

  bool push_quick_back(QUICK_SELECT_I *quick_sel_range);

546
  List<QUICK_SELECT_I> quick_selects; /* Merged quick selects */
unknown's avatar
unknown committed
547

548 549 550 551 552 553 554
  QUEUE queue;    /* Priority queue for merge operation */
  MEM_ROOT alloc; /* Memory pool for this and merged quick selects data. */

  THD *thd;             /* current thread */
  byte *cur_rowid;      /* buffer used in get_next() */
  byte *prev_rowid;     /* rowid of last row returned by get_next() */
  bool have_prev_rowid; /* true if prev_rowid has valid data */
unknown's avatar
unknown committed
555
  uint rowid_length;    /* table rowid length */
556 557
private:
  static int queue_cmp(void *arg, byte *val1, byte *val2);
unknown's avatar
unknown committed
558
  bool scans_inited; 
559 560 561
};


562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658
/*
  Index scan for GROUP-BY queries with MIN/MAX aggregate functions.

  This class provides a specialized index access method for GROUP-BY queries
  of the forms:

       SELECT A_1,...,A_k, [B_1,...,B_m], [MIN(C)], [MAX(C)]
         FROM T
        WHERE [RNG(A_1,...,A_p ; where p <= k)]
         [AND EQ(B_1,...,B_m)]
         [AND PC(C)]
         [AND PA(A_i1,...,A_iq)]
       GROUP BY A_1,...,A_k;

    or

       SELECT DISTINCT A_i1,...,A_ik
         FROM T
        WHERE [RNG(A_1,...,A_p ; where p <= k)]
         [AND PA(A_i1,...,A_iq)];

  where all selected fields are parts of the same index.
  The class of queries that can be processed by this quick select is fully
  specified in the description of get_best_trp_group_min_max() in opt_range.cc.

  The get_next() method directly produces result tuples, thus obviating the
  need to call end_send_group() because all grouping is already done inside
  get_next().

  Since one of the requirements is that all select fields are part of the same
  index, this class produces only index keys, and not complete records.
*/

class QUICK_GROUP_MIN_MAX_SELECT : public QUICK_SELECT_I
{
private:
  handler *file;         /* The handler used to get data. */
  JOIN *join;            /* Descriptor of the current query */
  KEY  *index_info;      /* The index chosen for data access */
  byte *record;          /* Buffer where the next record is returned. */
  byte *tmp_record;      /* Temporary storage for next_min(), next_max(). */
  byte *group_prefix;    /* Key prefix consisting of the GROUP fields. */
  uint group_prefix_len; /* Length of the group prefix. */
  byte *last_prefix;     /* Prefix of the last group for detecting EOF. */
  bool have_min;         /* Specify whether we are computing */
  bool have_max;         /*   a MIN, a MAX, or both.         */
  bool seen_first_key;   /* Denotes whether the first key was retrieved.*/
  KEY_PART_INFO *min_max_arg_part; /* The keypart of the only argument field */
                                   /* of all MIN/MAX functions.              */
  uint min_max_arg_len;  /* The length of the MIN/MAX argument field */
  byte *key_infix;       /* Infix of constants from equality predicates. */
  uint key_infix_len;
  DYNAMIC_ARRAY min_max_ranges; /* Array of range ptrs for the MIN/MAX field. */
  uint real_prefix_len; /* Length of key prefix extended with key_infix. */
  List<Item_sum> *min_functions;
  List<Item_sum> *max_functions;
  List_iterator<Item_sum> *min_functions_it;
  List_iterator<Item_sum> *max_functions_it;
public:
  /*
    The following two members are public to allow easy access from
    TRP_GROUP_MIN_MAX::make_quick()
  */
  MEM_ROOT alloc; /* Memory pool for this and quick_prefix_select data. */
  QUICK_RANGE_SELECT *quick_prefix_select;/* For retrieval of group prefixes. */
private:
  int  next_prefix();
  int  next_min_in_range();
  int  next_max_in_range();
  int  next_min();
  int  next_max();
  void update_min_result();
  void update_max_result();
public:
  QUICK_GROUP_MIN_MAX_SELECT(TABLE *table, JOIN *join, bool have_min,
                             bool have_max, KEY_PART_INFO *min_max_arg_part,
                             uint group_prefix_len, uint used_key_parts,
                             KEY *index_info, uint use_index, double read_cost,
                             ha_rows records, uint key_infix_len,
                             byte *key_infix, MEM_ROOT *parent_alloc);
  ~QUICK_GROUP_MIN_MAX_SELECT();
  bool add_range(SEL_ARG *sel_range);
  void update_key_stat();
  bool alloc_buffers();
  int init();
  int reset();
  int get_next();
  bool reverse_sorted() { return false; }
  bool unique_key_range() { return false; }
  int get_type() { return QS_TYPE_GROUP_MIN_MAX; }
  void add_keys_and_lengths(String *key_names, String *used_lengths);
#ifndef DBUG_OFF
  void dbug_dump(int indent, bool verbose);
#endif
};


unknown's avatar
unknown committed
659
class QUICK_SELECT_DESC: public QUICK_RANGE_SELECT
660 661
{
public:
unknown's avatar
unknown committed
662
  QUICK_SELECT_DESC(QUICK_RANGE_SELECT *q, uint used_key_parts);
663
  int get_next();
664
  bool reverse_sorted() { return 1; }
unknown's avatar
unknown committed
665
  int get_type() { return QS_TYPE_RANGE_DESC; }
666 667
private:
  bool range_reads_after_key(QUICK_RANGE *range);
unknown's avatar
unknown committed
668
#ifdef NOT_USED
unknown's avatar
unknown committed
669
  bool test_if_null_range(QUICK_RANGE *range, uint used_key_parts);
unknown's avatar
unknown committed
670
#endif
671
  int reset(void) { next=0; rev_it.rewind(); return 0; }
672 673 674 675
  List<QUICK_RANGE> rev_ranges;
  List_iterator<QUICK_RANGE> rev_it;
};

676

unknown's avatar
unknown committed
677 678
class SQL_SELECT :public Sql_alloc {
 public:
unknown's avatar
unknown committed
679
  QUICK_SELECT_I *quick;	// If quick-select used
unknown's avatar
unknown committed
680 681 682 683 684 685 686 687 688 689 690 691
  COND		*cond;		// where condition
  TABLE	*head;
  IO_CACHE file;		// Positions to used records
  ha_rows records;		// Records in use if read from file
  double read_time;		// Time to read rows
  key_map quick_keys;		// Possible quick keys
  key_map needed_reg;		// Possible quick keys after prev tables.
  table_map const_tables,read_tables;
  bool	free_cond;

  SQL_SELECT();
  ~SQL_SELECT();
692
  void cleanup();
unknown's avatar
unknown committed
693
  bool check_quick(THD *thd, bool force_quick_range, ha_rows limit)
694 695 696 697 698
  {
    key_map tmp;
    tmp.set_all();
    return test_quick_select(thd, tmp, 0, limit, force_quick_range) < 0;
  }
699
  inline bool skip_record() { return cond ? cond->val_int() == 0 : 0; }
700
  int test_quick_select(THD *thd, key_map keys, table_map prev_tables,
701
			ha_rows limit, bool force_quick_range);
unknown's avatar
unknown committed
702 703
};

unknown's avatar
unknown committed
704

unknown's avatar
unknown committed
705
class FT_SELECT: public QUICK_RANGE_SELECT {
unknown's avatar
unknown committed
706
public:
unknown's avatar
unknown committed
707
  FT_SELECT(THD *thd, TABLE *table, uint key) :
708
      QUICK_RANGE_SELECT (thd, table, key, 1) { VOID(init()); }
709
  ~FT_SELECT() { file->ft_end(); }
unknown's avatar
unknown committed
710
  int init() { return error=file->ft_init(); }
unknown's avatar
unknown committed
711
  int reset() { return 0; }
unknown's avatar
unknown committed
712 713
  int get_next() { return error=file->ft_read(record); }
  int get_type() { return QS_TYPE_FULLTEXT; }
unknown's avatar
unknown committed
714 715
};

unknown's avatar
unknown committed
716
QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table,
unknown's avatar
unknown committed
717 718
                                             struct st_table_ref *ref,
                                             ha_rows records);
719 720
uint get_index_for_order(TABLE *table, ORDER *order, ha_rows limit);

unknown's avatar
unknown committed
721
#endif