~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/optimizer/quick_index_merge_select.cc

Split some classes from the range optimizer out in to their own header and implementation files.
Corrected the case on these classes also to adhere to the coding standards. Cleaned up any style
issues in any code I came across while moving code.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
 
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 
3
 *
 
4
 *  Copyright (C) 2008-2009 Sun Microsystems
 
5
 *
 
6
 *  This program is free software; you can redistribute it and/or modify
 
7
 *  it under the terms of the GNU General Public License as published by
 
8
 *  the Free Software Foundation; version 2 of the License.
 
9
 *
 
10
 *  This program is distributed in the hope that it will be useful,
 
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 *  GNU General Public License for more details.
 
14
 *
 
15
 *  You should have received a copy of the GNU General Public License
 
16
 *  along with this program; if not, write to the Free Software
 
17
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
18
 */
 
19
 
 
20
#include "drizzled/server_includes.h"
 
21
#include "drizzled/session.h"
 
22
#include "drizzled/records.h"
 
23
#include "drizzled/optimizer/quick_range_select.h"
 
24
#include "drizzled/optimizer/quick_index_merge_select.h"
 
25
 
 
26
using namespace drizzled;
 
27
 
 
28
static int refpos_order_cmp(void *arg, const void *a, const void *b)
 
29
{
 
30
  Cursor *cursor= (Cursor*)arg;
 
31
  return cursor->cmp_ref((const unsigned char *) a, (const unsigned char *) b);
 
32
}
 
33
 
 
34
optimizer::QuickIndexMergeSelect::QuickIndexMergeSelect(Session *session_param,
 
35
                                                        Table *table)
 
36
  :
 
37
    pk_quick_select(NULL), 
 
38
    session(session_param)
 
39
{
 
40
  index= MAX_KEY;
 
41
  head= table;
 
42
  memset(&read_record, 0, sizeof(read_record));
 
43
  init_sql_alloc(&alloc, session->variables.range_alloc_block_size, 0);
 
44
  return;
 
45
}
 
46
 
 
47
int optimizer::QuickIndexMergeSelect::init()
 
48
{
 
49
  return 0;
 
50
}
 
51
 
 
52
int optimizer::QuickIndexMergeSelect::reset()
 
53
{
 
54
  return (read_keys_and_merge());
 
55
}
 
56
 
 
57
bool
 
58
optimizer::QuickIndexMergeSelect::push_quick_back(optimizer::QuickRangeSelect *quick_sel_range)
 
59
{
 
60
  /*
 
61
    Save quick_select that does scan on clustered primary key as it will be
 
62
    processed separately.
 
63
  */
 
64
  if (head->cursor->primary_key_is_clustered() &&
 
65
      quick_sel_range->index == head->s->primary_key)
 
66
  {
 
67
    pk_quick_select= quick_sel_range;
 
68
  }
 
69
  else
 
70
  {
 
71
    return quick_selects.push_back(quick_sel_range);
 
72
  }
 
73
  return 0;
 
74
}
 
75
 
 
76
optimizer::QuickIndexMergeSelect::~QuickIndexMergeSelect()
 
77
{
 
78
  List_iterator_fast<optimizer::QuickRangeSelect> quick_it(quick_selects);
 
79
  optimizer::QuickRangeSelect* quick;
 
80
  quick_it.rewind();
 
81
  while ((quick= quick_it++))
 
82
  {
 
83
    quick->cursor= NULL;
 
84
  }
 
85
  quick_selects.delete_elements();
 
86
  delete pk_quick_select;
 
87
  free_root(&alloc,MYF(0));
 
88
  return;
 
89
}
 
90
 
 
91
 
 
92
int optimizer::QuickIndexMergeSelect::read_keys_and_merge()
 
93
{
 
94
  List_iterator_fast<optimizer::QuickRangeSelect> cur_quick_it(quick_selects);
 
95
  optimizer::QuickRangeSelect* cur_quick;
 
96
  int result;
 
97
  Unique *unique;
 
98
  Cursor *cursor= head->cursor;
 
99
 
 
100
  cursor->extra(HA_EXTRA_KEYREAD);
 
101
  head->prepare_for_position();
 
102
 
 
103
  cur_quick_it.rewind();
 
104
  cur_quick= cur_quick_it++;
 
105
  assert(cur_quick != 0);
 
106
 
 
107
  /*
 
108
    We reuse the same instance of Cursor so we need to call both init and
 
109
    reset here.
 
110
  */
 
111
  if (cur_quick->init() || cur_quick->reset())
 
112
    return 0;
 
113
 
 
114
  unique= new Unique(refpos_order_cmp, 
 
115
                     (void *)cursor,
 
116
                     cursor->ref_length,
 
117
                     session->variables.sortbuff_size);
 
118
  if (!unique)
 
119
    return 0;
 
120
  for (;;)
 
121
  {
 
122
    while ((result= cur_quick->get_next()) == HA_ERR_END_OF_FILE)
 
123
    {
 
124
      cur_quick->range_end();
 
125
      cur_quick= cur_quick_it++;
 
126
      if (!cur_quick)
 
127
        break;
 
128
 
 
129
      if (cur_quick->cursor->inited != Cursor::NONE)
 
130
        cur_quick->cursor->ha_index_end();
 
131
      if (cur_quick->init() || cur_quick->reset())
 
132
        return 0;
 
133
    }
 
134
 
 
135
    if (result)
 
136
    {
 
137
      if (result != HA_ERR_END_OF_FILE)
 
138
      {
 
139
        cur_quick->range_end();
 
140
        return result;
 
141
      }
 
142
      break;
 
143
    }
 
144
 
 
145
    if (session->killed)
 
146
      return 0;
 
147
 
 
148
    /* skip row if it will be retrieved by clustered PK scan */
 
149
    if (pk_quick_select && pk_quick_select->row_in_ranges())
 
150
      continue;
 
151
 
 
152
    cur_quick->cursor->position(cur_quick->record);
 
153
    result= unique->unique_add((char*)cur_quick->cursor->ref);
 
154
    if (result)
 
155
      return 0;
 
156
 
 
157
  }
 
158
 
 
159
  /* ok, all row ids are in Unique */
 
160
  result= unique->get(head);
 
161
  delete unique;
 
162
  doing_pk_scan= false;
 
163
  /* index_merge currently doesn't support "using index" at all */
 
164
  cursor->extra(HA_EXTRA_NO_KEYREAD);
 
165
  /* start table scan */
 
166
  init_read_record(&read_record, session, head, (optimizer::SqlSelect*) 0, 1, 1);
 
167
  return result;
 
168
}
 
169
 
 
170
 
 
171
int optimizer::QuickIndexMergeSelect::get_next()
 
172
{
 
173
  int result;
 
174
 
 
175
  if (doing_pk_scan)
 
176
    return(pk_quick_select->get_next());
 
177
 
 
178
  if ((result= read_record.read_record(&read_record)) == -1)
 
179
  {
 
180
    result= HA_ERR_END_OF_FILE;
 
181
    end_read_record(&read_record);
 
182
    /* All rows from Unique have been retrieved, do a clustered PK scan */
 
183
    if (pk_quick_select)
 
184
    {
 
185
      doing_pk_scan= true;
 
186
      if ((result= pk_quick_select->init()) ||
 
187
          (result= pk_quick_select->reset()))
 
188
        return result;
 
189
      return(pk_quick_select->get_next());
 
190
    }
 
191
  }
 
192
 
 
193
  return result;
 
194
}
 
195
 
 
196
bool optimizer::QuickIndexMergeSelect::is_keys_used(const MyBitmap *fields)
 
197
{
 
198
  optimizer::QuickRangeSelect *quick= NULL;
 
199
  List_iterator_fast<QuickRangeSelect> it(quick_selects);
 
200
  while ((quick= it++))
 
201
  {
 
202
    if (is_key_used(head, quick->index, fields))
 
203
      return 1;
 
204
  }
 
205
  return 0;
 
206
}
 
207
 
 
208
 
 
209
void optimizer::QuickIndexMergeSelect::add_info_string(String *str)
 
210
{
 
211
  optimizer::QuickRangeSelect *quick= NULL;
 
212
  bool first= true;
 
213
  List_iterator_fast<optimizer::QuickRangeSelect> it(quick_selects);
 
214
  str->append(STRING_WITH_LEN("sort_union("));
 
215
  while ((quick= it++))
 
216
  {
 
217
    if (! first)
 
218
      str->append(',');
 
219
    else
 
220
      first= false;
 
221
    quick->add_info_string(str);
 
222
  }
 
223
  if (pk_quick_select)
 
224
  {
 
225
    str->append(',');
 
226
    pk_quick_select->add_info_string(str);
 
227
  }
 
228
  str->append(')');
 
229
}
 
230
 
 
231
 
 
232
void optimizer::QuickIndexMergeSelect::add_keys_and_lengths(String *key_names,
 
233
                                                            String *used_lengths)
 
234
{
 
235
  char buf[64];
 
236
  uint32_t length;
 
237
  bool first= true;
 
238
  optimizer::QuickRangeSelect *quick= NULL;
 
239
 
 
240
  List_iterator_fast<optimizer::QuickRangeSelect> it(quick_selects);
 
241
  while ((quick= it++))
 
242
  {
 
243
    if (first)
 
244
      first= false;
 
245
    else
 
246
    {
 
247
      key_names->append(',');
 
248
      used_lengths->append(',');
 
249
    }
 
250
 
 
251
    KEY *key_info= head->key_info + quick->index;
 
252
    key_names->append(key_info->name);
 
253
    length= int64_t2str(quick->max_used_key_length, buf, 10) - buf;
 
254
    used_lengths->append(buf, length);
 
255
  }
 
256
  if (pk_quick_select)
 
257
  {
 
258
    KEY *key_info= head->key_info + pk_quick_select->index;
 
259
    key_names->append(',');
 
260
    key_names->append(key_info->name);
 
261
    length= int64_t2str(pk_quick_select->max_used_key_length, buf, 10) - buf;
 
262
    used_lengths->append(',');
 
263
    used_lengths->append(buf, length);
 
264
  }
 
265
}
 
266
 
 
267