~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/opt_range.cc

  • Committer: Brian Aker
  • Date: 2009-06-16 00:53:22 UTC
  • mto: This revision was merged to the branch mainline in revision 1094.
  • Revision ID: brian@gaz-20090616005322-w0ode4jul9z8s2y9
Partial fix for tests for tmp

Show diffs side-by-side

added added

removed removed

Lines of Context:
104
104
*/
105
105
 
106
106
#include <drizzled/server_includes.h>
107
 
#include <drizzled/sql_base.h>
108
107
#include <drizzled/sql_select.h>
109
108
#include <drizzled/error.h>
110
109
#include <drizzled/cost_vect.h>
115
114
#include "drizzled/temporal.h" /* Needed in get_mm_leaf() for timestamp -> datetime comparisons */
116
115
 
117
116
#include <string>
118
 
#include <vector>
119
 
#include <algorithm>
120
117
 
121
118
using namespace std;
122
119
 
123
 
#define HA_END_SPACE_KEY 0
124
 
 
125
120
/*
126
121
  Convert double value to #rows. Currently this does floor(), and we
127
122
  might consider using round() instead.
131
126
    return static_cast<ha_rows>(x);
132
127
}
133
128
 
134
 
extern "C" int refpos_order_cmp(void* arg, const void *a,const void *b)
135
 
{
136
 
  handler *file= (handler*)arg;
137
 
  return file->cmp_ref((const unsigned char*)a, (const unsigned char*)b);
138
 
}
139
 
 
140
129
static int sel_cmp(Field *f,unsigned char *a,unsigned char *b,uint8_t a_flag,uint8_t b_flag);
141
130
 
142
131
static unsigned char is_null_string[2]= {1,0};
645
634
    Possible ways to read rows using index_merge. The list is non-empty only
646
635
    if type==KEY. Currently can be non empty only if keys_map.none().
647
636
  */
648
 
  vector<SEL_IMERGE*> merges;
 
637
  List<SEL_IMERGE> merges;
649
638
 
650
639
  /* The members below are filled/used only after get_mm_tree is done */
651
640
  key_map ror_scans_map;   /* bitmask of ROR scan-able elements in keys */
942
931
 
943
932
 
944
933
/*
945
 
  Perform AND operation on two index_merge lists and store result in im1.
 
934
  Perform AND operation on two index_merge lists and store result in *im1.
946
935
*/
947
936
 
948
 
inline void imerge_list_and_list(vector<SEL_IMERGE*> &im1, vector<SEL_IMERGE*> &im2)
 
937
inline void imerge_list_and_list(List<SEL_IMERGE> *im1, List<SEL_IMERGE> *im2)
949
938
{
950
 
  im1.insert(im1.end(), im2.begin(), im2.end());
951
 
  im2.clear();
 
939
  im1->concat(im2);
952
940
}
953
941
 
954
942
 
975
963
    other Error, both passed lists are unusable
976
964
*/
977
965
 
978
 
static int imerge_list_or_list(RANGE_OPT_PARAM *param,
979
 
                               vector<SEL_IMERGE*> &im1,
980
 
                               vector<SEL_IMERGE*> &im2)
 
966
int imerge_list_or_list(RANGE_OPT_PARAM *param,
 
967
                        List<SEL_IMERGE> *im1,
 
968
                        List<SEL_IMERGE> *im2)
981
969
{
982
 
  SEL_IMERGE *imerge= im1.front();
983
 
  im1.clear();
984
 
  im1.push_back(imerge);
 
970
  SEL_IMERGE *imerge= im1->head();
 
971
  im1->empty();
 
972
  im1->push_back(imerge);
985
973
 
986
 
  return imerge->or_sel_imerge_with_checks(param, im2.front());
 
974
  return imerge->or_sel_imerge_with_checks(param, im2->head());
987
975
}
988
976
 
989
977
 
991
979
  Perform OR operation on index_merge list and key tree.
992
980
 
993
981
  RETURN
994
 
    false   OK, result is stored in im1.
995
 
    true    Error
 
982
    0     OK, result is stored in *im1.
 
983
    other Error
996
984
*/
997
985
 
998
 
static bool imerge_list_or_tree(RANGE_OPT_PARAM *param,
999
 
                                vector<SEL_IMERGE*> &im1,
1000
 
                                SEL_TREE *tree)
 
986
int imerge_list_or_tree(RANGE_OPT_PARAM *param,
 
987
                        List<SEL_IMERGE> *im1,
 
988
                        SEL_TREE *tree)
1001
989
{
1002
 
  vector<SEL_IMERGE*>::iterator imerge= im1.begin();
1003
 
 
1004
 
  while (imerge != im1.end())
 
990
  SEL_IMERGE *imerge;
 
991
  List_iterator<SEL_IMERGE> it(*im1);
 
992
  while ((imerge= it++))
1005
993
  {
1006
 
    if ((*imerge)->or_sel_tree_with_checks(param, tree))
1007
 
      imerge= im1.erase( imerge );
1008
 
    else
1009
 
      ++imerge;
 
994
    if (imerge->or_sel_tree_with_checks(param, tree))
 
995
      it.remove();
1010
996
  }
1011
 
 
1012
 
  return im1.empty();
 
997
  return im1->is_empty();
1013
998
}
1014
999
 
1015
1000
 
1024
1009
           */
1025
1010
 
1026
1011
SQL_SELECT *make_select(Table *head, table_map const_tables,
1027
 
                        table_map read_tables, COND *conds,
 
1012
                        table_map read_tables, COND *conds,
1028
1013
                        bool allow_null_cond,
1029
1014
                        int *error)
1030
1015
{
1188
1173
    free((char*) column_bitmap.bitmap);
1189
1174
  }
1190
1175
  head->column_bitmaps_set(save_read_set, save_write_set);
1191
 
  assert(mrr_buf_desc == NULL);
1192
1176
  if (mrr_buf_desc)
1193
1177
    free(mrr_buf_desc);
 
1178
  return;
1194
1179
}
1195
1180
 
1196
1181
 
1542
1527
 
1543
1528
 
1544
1529
/*
 
1530
  Comparison function to be used QUICK_ROR_UNION_SELECT::queue priority
 
1531
  queue.
 
1532
 
 
1533
  SYNPOSIS
 
1534
    QUICK_ROR_UNION_SELECT::queue_cmp()
 
1535
      arg   Pointer to QUICK_ROR_UNION_SELECT
 
1536
      val1  First merged select
 
1537
      val2  Second merged select
 
1538
*/
 
1539
 
 
1540
int quick_ror_union_select_queue_cmp(void *arg, unsigned char *val1, unsigned char *val2)
 
1541
{
 
1542
  QUICK_ROR_UNION_SELECT *self= (QUICK_ROR_UNION_SELECT*)arg;
 
1543
  return self->head->file->cmp_ref(((QUICK_SELECT_I*)val1)->last_rowid,
 
1544
                                   ((QUICK_SELECT_I*)val2)->last_rowid);
 
1545
}
 
1546
 
 
1547
 
 
1548
/*
1545
1549
  Initialize quick select for row retrieval.
1546
1550
  SYNOPSIS
1547
1551
    reset()
2325
2329
    group_trp= get_best_group_min_max(&param, tree);
2326
2330
    if (group_trp)
2327
2331
    {
2328
 
      param.table->quick_condition_rows= min(group_trp->records,
 
2332
      param.table->quick_condition_rows= cmin(group_trp->records,
2329
2333
                                             head->file->stats.records);
2330
2334
      if (group_trp->read_cost < best_read_time)
2331
2335
      {
2340
2344
        It is possible to use a range-based quick select (but it might be
2341
2345
        slower than 'all' table scan).
2342
2346
      */
2343
 
      if (tree->merges.empty() == true)
 
2347
      if (tree->merges.is_empty())
2344
2348
      {
2345
2349
        TRP_RANGE         *range_trp;
2346
2350
        TRP_ROR_INTERSECT *rori_trp;
2384
2388
      else
2385
2389
      {
2386
2390
        /* Try creating index_merge/ROR-union scan. */
 
2391
        SEL_IMERGE *imerge;
2387
2392
        TABLE_READ_PLAN *best_conj_trp= NULL, *new_conj_trp;
2388
 
        vector<SEL_IMERGE*>::iterator imerge= tree->merges.begin();
2389
 
        while (imerge != tree->merges.end())
 
2393
        List_iterator_fast<SEL_IMERGE> it(tree->merges);
 
2394
        while ((imerge= it++))
2390
2395
        {
2391
 
          new_conj_trp= get_best_disjunct_quick(&param, *imerge, best_read_time);
 
2396
          new_conj_trp= get_best_disjunct_quick(&param, imerge, best_read_time);
2392
2397
          if (new_conj_trp)
2393
2398
            set_if_smaller(param.table->quick_condition_rows,
2394
2399
                           new_conj_trp->records);
2395
 
 
2396
2400
          if (!best_conj_trp || (new_conj_trp && new_conj_trp->read_cost <
2397
2401
                                 best_conj_trp->read_cost))
2398
2402
            best_conj_trp= new_conj_trp;
2399
 
 
2400
 
          ++imerge;
2401
2403
        }
2402
2404
        if (best_conj_trp)
2403
2405
          best_trp= best_conj_trp;
2618
2620
    {
2619
2621
      imerge_trp->read_cost= imerge_cost;
2620
2622
      imerge_trp->records= non_cpk_scan_records + cpk_scan_records;
2621
 
      imerge_trp->records= min(imerge_trp->records,
 
2623
      imerge_trp->records= cmin(imerge_trp->records,
2622
2624
                               param->table->file->stats.records);
2623
2625
      imerge_trp->range_scans= range_scans;
2624
2626
      imerge_trp->range_scans_end= range_scans + n_child_scans;
2919
2921
  return info;
2920
2922
}
2921
2923
 
2922
 
static void ror_intersect_cpy(ROR_INTERSECT_INFO *dst,
2923
 
                              const ROR_INTERSECT_INFO *src)
 
2924
void ror_intersect_cpy(ROR_INTERSECT_INFO *dst, const ROR_INTERSECT_INFO *src)
2924
2925
{
2925
2926
  dst->param= src->param;
2926
2927
  memcpy(dst->covered_fields.bitmap, src->covered_fields.bitmap,
4099
4100
    if (arg != field_item)
4100
4101
      ref_tables|= arg->used_tables();
4101
4102
  }
4102
 
 
4103
4103
  Field *field= field_item->field;
4104
 
  field->setWriteSet();
4105
 
 
4106
4104
  Item_result cmp_type= field->cmp_type();
4107
4105
  if (!((ref_tables | field->table->map) & param_comp))
4108
4106
    ftree= get_func_mm_tree(param, cond_func, field, value, cmp_type, inv);
4114
4112
    while ((item= it++))
4115
4113
    {
4116
4114
      Field *f= item->field;
4117
 
      f->setWriteSet();
4118
 
 
4119
4115
      if (field->eq(f))
4120
4116
        continue;
4121
4117
      if (!((ref_tables | f->table->map) & param_comp))
4266
4262
    while ((field_item= it++))
4267
4263
    {
4268
4264
      Field *field= field_item->field;
4269
 
      field->setWriteSet();
4270
 
 
4271
4265
      Item_result cmp_type= field->cmp_type();
4272
4266
      if (!((ref_tables | field->table->map) & param_comp))
4273
4267
      {
4553
4547
    if (value->real_item()->type() == Item::FIELD_ITEM
4554
4548
        && value->result_type() == STRING_RESULT)
4555
4549
    {
4556
 
      char buff[drizzled::DateTime::MAX_STRING_LENGTH];
 
4550
      char buff[MAX_DATETIME_FULL_WIDTH];
4557
4551
      String tmp(buff, sizeof(buff), &my_charset_bin);
4558
4552
      String *res= value->val_str(&tmp);
4559
4553
 
4583
4577
           * Datetime in right-hand side column is before UNIX epoch, so adjust to
4584
4578
           * lower bound.
4585
4579
           */
4586
 
          char new_value_buff[drizzled::DateTime::MAX_STRING_LENGTH];
4587
 
          int new_value_length;
 
4580
          char new_value_buff[MAX_DATETIME_FULL_WIDTH];
 
4581
          size_t new_value_length;
4588
4582
          String new_value_string(new_value_buff, sizeof(new_value_buff), &my_charset_bin);
4589
4583
 
4590
 
          new_value_length= min_timestamp.to_string(new_value_string.c_ptr(),
4591
 
                                    drizzled::DateTime::MAX_STRING_LENGTH);
4592
 
          assert((new_value_length+1) < drizzled::DateTime::MAX_STRING_LENGTH);
 
4584
          min_timestamp.to_string(new_value_string.c_ptr(), &new_value_length);
4593
4585
          new_value_string.length(new_value_length);
4594
4586
          err= value->save_str_value_in_field(field, &new_value_string);
4595
4587
        }
4599
4591
           * Datetime in right hand side column is after UNIX epoch, so adjust
4600
4592
           * to the higher bound of the epoch.
4601
4593
           */
4602
 
          char new_value_buff[drizzled::DateTime::MAX_STRING_LENGTH];
4603
 
          int new_value_length;
 
4594
          char new_value_buff[MAX_DATETIME_FULL_WIDTH];
 
4595
          size_t new_value_length;
4604
4596
          String new_value_string(new_value_buff, sizeof(new_value_buff), &my_charset_bin);
4605
4597
 
4606
 
          new_value_length= max_timestamp.to_string(new_value_string.c_ptr(),
4607
 
                                        drizzled::DateTime::MAX_STRING_LENGTH);
4608
 
          assert((new_value_length+1) < drizzled::DateTime::MAX_STRING_LENGTH);
 
4598
          max_timestamp.to_string(new_value_string.c_ptr(), &new_value_length);
4609
4599
          new_value_string.length(new_value_length);
4610
4600
          err= value->save_str_value_in_field(field, &new_value_string);
4611
4601
        }
4867
4857
  /* dispose index_merge if there is a "range" option */
4868
4858
  if (result_keys.any())
4869
4859
  {
4870
 
    tree1->merges.clear();
 
4860
    tree1->merges.empty();
4871
4861
    return(tree1);
4872
4862
  }
4873
4863
 
4874
4864
  /* ok, both trees are index_merge trees */
4875
 
  imerge_list_and_list(tree1->merges, tree2->merges);
 
4865
  imerge_list_and_list(&tree1->merges, &tree2->merges);
4876
4866
  return(tree1);
4877
4867
}
4878
4868
 
5026
5016
  else
5027
5017
  {
5028
5018
    /* ok, two trees have KEY type but cannot be used without index merge */
5029
 
    if ((tree1->merges.empty() == true) && (tree2->merges.empty() == true))
 
5019
    if (tree1->merges.is_empty() && tree2->merges.is_empty())
5030
5020
    {
5031
5021
      if (param->remove_jump_scans)
5032
5022
      {
5035
5025
        if (no_trees)
5036
5026
          return(new SEL_TREE(SEL_TREE::ALWAYS));
5037
5027
      }
5038
 
 
5039
 
      /* both trees are "range" trees, produce new index merge structure. */
5040
 
      result= new SEL_TREE();
5041
 
      SEL_IMERGE *merge= new SEL_IMERGE();
5042
 
      result->merges.push_back(merge);
5043
 
 
5044
 
      if( merge->or_sel_tree(param, tree1) || merge->or_sel_tree(param, tree2))
 
5028
      SEL_IMERGE *merge;
 
5029
      /* both trees are "range" trees, produce new index merge structure */
 
5030
      if (!(result= new SEL_TREE()) || !(merge= new SEL_IMERGE()) ||
 
5031
          (result->merges.push_back(merge)) ||
 
5032
          (merge->or_sel_tree(param, tree1)) ||
 
5033
          (merge->or_sel_tree(param, tree2)))
5045
5034
        result= NULL;
5046
5035
      else
5047
5036
        result->type= tree1->type;
5048
5037
    }
5049
 
    else if ((tree1->merges.empty() == false) && (tree2->merges.empty() == false))
 
5038
    else if (!tree1->merges.is_empty() && !tree2->merges.is_empty())
5050
5039
    {
5051
 
      if (imerge_list_or_list(param, tree1->merges, tree2->merges))
 
5040
      if (imerge_list_or_list(param, &tree1->merges, &tree2->merges))
5052
5041
        result= new SEL_TREE(SEL_TREE::ALWAYS);
5053
5042
      else
5054
5043
        result= tree1;
5056
5045
    else
5057
5046
    {
5058
5047
      /* one tree is index merge tree and another is range tree */
5059
 
      if (tree1->merges.empty() == true)
 
5048
      if (tree1->merges.is_empty())
5060
5049
        std::swap(tree1, tree2);
5061
5050
 
5062
5051
      if (param->remove_jump_scans && remove_nonrange_trees(param, tree2))
5063
5052
         return(new SEL_TREE(SEL_TREE::ALWAYS));
5064
 
 
5065
5053
      /* add tree2 to tree1->merges, checking if it collapses to ALWAYS */
5066
 
      if (imerge_list_or_tree(param, tree1->merges, tree2))
 
5054
      if (imerge_list_or_tree(param, &tree1->merges, tree2))
5067
5055
        result= new SEL_TREE(SEL_TREE::ALWAYS);
5068
5056
      else
5069
5057
        result= tree1;
6071
6059
    Value of init_param
6072
6060
*/
6073
6061
 
6074
 
static range_seq_t sel_arg_range_seq_init(void *init_param, uint32_t, uint32_t)
 
6062
range_seq_t sel_arg_range_seq_init(void *init_param, uint32_t, uint32_t)
6075
6063
{
6076
6064
  SEL_ARG_RANGE_SEQ *seq= (SEL_ARG_RANGE_SEQ*)init_param;
6077
6065
  seq->at_start= true;
6138
6126
*/
6139
6127
 
6140
6128
//psergey-merge-todo: support check_quick_keys:max_keypart
6141
 
static uint32_t sel_arg_range_seq_next(range_seq_t rseq, KEY_MULTI_RANGE *range)
 
6129
uint32_t sel_arg_range_seq_next(range_seq_t rseq, KEY_MULTI_RANGE *range)
6142
6130
{
6143
6131
  SEL_ARG *key_tree;
6144
6132
  SEL_ARG_RANGE_SEQ *seq= (SEL_ARG_RANGE_SEQ*)rseq;
6277
6265
    }
6278
6266
  }
6279
6267
  seq->param->range_count++;
6280
 
  seq->param->max_key_part= max(seq->param->max_key_part,(uint32_t)key_tree->part);
 
6268
  seq->param->max_key_part=cmax(seq->param->max_key_part,(uint32_t)key_tree->part);
6281
6269
  return 0;
6282
6270
}
6283
6271
 
6364
6352
      param->table->quick_key_parts[keynr]=param->max_key_part+1;
6365
6353
      param->table->quick_n_ranges[keynr]= param->range_count;
6366
6354
      param->table->quick_condition_rows=
6367
 
        min(param->table->quick_condition_rows, rows);
 
6355
        cmin(param->table->quick_condition_rows, rows);
6368
6356
    }
6369
6357
  }
6370
6358
  /* Figure out if the key scan is ROR (returns rows in ROWID order) or not */
6747
6735
*/
6748
6736
 
6749
6737
QUICK_RANGE_SELECT *get_quick_select_for_ref(Session *session, Table *table,
6750
 
                                             table_reference_st *ref, ha_rows records)
 
6738
                                             TABLE_REF *ref, ha_rows records)
6751
6739
{
6752
6740
  MEM_ROOT *old_root, *alloc;
6753
6741
  QUICK_RANGE_SELECT *quick;
6784
6772
  range->min_keypart_map= range->max_keypart_map=
6785
6773
    make_prev_keypart_map(ref->key_parts);
6786
6774
  range->flag= ((ref->key_length == key_info->key_length &&
6787
 
                 (key_info->flags & HA_END_SPACE_KEY) == 0) ? EQ_RANGE : 0);
6788
 
 
 
6775
                 key_info->flags == 0) ? EQ_RANGE : 0);
6789
6776
 
6790
6777
  if (!(quick->key_parts=key_part=(KEY_PART *)
6791
6778
        alloc_root(&quick->alloc,sizeof(KEY_PART)*ref->key_parts)))
7246
7233
 
7247
7234
 
7248
7235
/*
 
7236
  MRR range sequence interface: array<QUICK_RANGE> impl: utility func for NDB
 
7237
 
 
7238
  SYNOPSIS
 
7239
    mrr_persistent_flag_storage()
 
7240
      seq  Range sequence being traversed
 
7241
      idx  Number of range
 
7242
 
 
7243
  DESCRIPTION
 
7244
    MRR/NDB implementation needs to store some bits for each range. This
 
7245
    function returns a reference to the "range_flag" associated with the
 
7246
    range number idx.
 
7247
 
 
7248
    This function should be removed when we get a proper MRR/NDB
 
7249
    implementation.
 
7250
 
 
7251
  RETURN
 
7252
    Reference to range_flag associated with range number #idx
 
7253
*/
 
7254
 
 
7255
uint16_t &mrr_persistent_flag_storage(range_seq_t seq, uint32_t idx)
 
7256
{
 
7257
  QUICK_RANGE_SEQ_CTX *ctx= (QUICK_RANGE_SEQ_CTX*)seq;
 
7258
  return ctx->first[idx]->flag;
 
7259
}
 
7260
 
 
7261
 
 
7262
/*
 
7263
  MRR range sequence interface: array<QUICK_RANGE> impl: utility func for NDB
 
7264
 
 
7265
  SYNOPSIS
 
7266
    mrr_get_ptr_by_idx()
 
7267
      seq  Range sequence bening traversed
 
7268
      idx  Number of the range
 
7269
 
 
7270
  DESCRIPTION
 
7271
    An extension of MRR range sequence interface needed by NDB: return the
 
7272
    data associated with the given range.
 
7273
 
 
7274
    A proper MRR interface implementer is supposed to store and return
 
7275
    range-associated data. NDB stores number of the range instead. So this
 
7276
    is a helper function that translates range number to range associated
 
7277
    data.
 
7278
 
 
7279
    This function does nothing, as currrently there is only one user of the
 
7280
    MRR interface - the quick range select code, and this user doesn't need
 
7281
    to use range-associated data.
 
7282
 
 
7283
  RETURN
 
7284
    Reference to range-associated data
 
7285
*/
 
7286
 
 
7287
char* &mrr_get_ptr_by_idx(range_seq_t, uint32_t)
 
7288
{
 
7289
  static char *dummy;
 
7290
  return dummy;
 
7291
}
 
7292
 
 
7293
 
 
7294
/*
7249
7295
  Get next possible record using quick-struct.
7250
7296
 
7251
7297
  SYNOPSIS
7339
7385
    last_range= *(cur_range++);
7340
7386
 
7341
7387
    start_key.key=    (const unsigned char*) last_range->min_key;
7342
 
    start_key.length= min(last_range->min_length, (uint16_t)prefix_length);
 
7388
    start_key.length= cmin(last_range->min_length, (uint16_t)prefix_length);
7343
7389
    start_key.keypart_map= last_range->min_keypart_map & keypart_map;
7344
7390
    start_key.flag=   ((last_range->flag & NEAR_MIN) ? HA_READ_AFTER_KEY :
7345
7391
                       (last_range->flag & EQ_RANGE) ?
7346
7392
                       HA_READ_KEY_EXACT : HA_READ_KEY_OR_NEXT);
7347
7393
    end_key.key=      (const unsigned char*) last_range->max_key;
7348
 
    end_key.length=   min(last_range->max_length, (uint16_t)prefix_length);
 
7394
    end_key.length=   cmin(last_range->max_length, (uint16_t)prefix_length);
7349
7395
    end_key.keypart_map= last_range->max_keypart_map & keypart_map;
7350
7396
    /*
7351
7397
      We use READ_AFTER_KEY here because if we are reading on a key
8122
8168
        cur_group_prefix_len+= cur_part->store_length;
8123
8169
        used_key_parts_map.set(key_part_nr);
8124
8170
        ++cur_group_key_parts;
8125
 
        max_key_part= max(max_key_part,key_part_nr);
 
8171
        max_key_part= cmax(max_key_part,key_part_nr);
8126
8172
      }
8127
8173
      /*
8128
8174
        Check that used key parts forms a prefix of the index.
8725
8771
    {
8726
8772
      double blocks_per_group= (double) num_blocks / (double) num_groups;
8727
8773
      p_overlap= (blocks_per_group * (keys_per_subgroup - 1)) / keys_per_group;
8728
 
      p_overlap= min(p_overlap, 1.0);
 
8774
      p_overlap= cmin(p_overlap, 1.0);
8729
8775
    }
8730
 
    io_cost= (double) min(num_groups * (1 + p_overlap), (double)num_blocks);
 
8776
    io_cost= (double) cmin(num_groups * (1 + p_overlap), (double)num_blocks);
8731
8777
  }
8732
8778
  else
8733
8779
    io_cost= (keys_per_group > keys_per_block) ?
9602
9648
      int cmp_res= key_cmp(index_info->key_part,
9603
9649
                           max_key.data(),
9604
9650
                           real_prefix_len + min_max_arg_len);
9605
 
      if (!(((cur_range->flag & NEAR_MAX) && (cmp_res == -1)) ||
9606
 
            (cmp_res <= 0)))
 
9651
      if ((!((cur_range->flag & NEAR_MAX) && (cmp_res == -1)) || (cmp_res <= 0)))
9607
9652
      {
9608
9653
        result= HA_ERR_KEY_NOT_FOUND;
9609
9654
        continue;
9723
9768
      int cmp_res= key_cmp(index_info->key_part,
9724
9769
                           min_key.data(),
9725
9770
                           real_prefix_len + min_max_arg_len);
9726
 
      if (!(((cur_range->flag & NEAR_MIN) && (cmp_res == 1)) ||
 
9771
      if ((!((cur_range->flag & NEAR_MIN) && (cmp_res == 1)) ||
9727
9772
            (cmp_res >= 0)))
9728
9773
        continue;
9729
9774
    }