~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/optimizer/quick_index_merge_select.cc

Big merge.

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