~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/optimizer/quick_index_merge_select.cc

  • Committer: Brian Aker
  • Date: 2009-12-09 01:09:43 UTC
  • mfrom: (1240.1.8 build)
  • Revision ID: brian@gaz-20091209010943-n5iq2b9ins7mx73j
MergeĀ build

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
extern "C"
 
29
int refpos_order_cmp(void *arg, const void *a, const void *b);
 
30
 
 
31
extern "C"
 
32
int refpos_order_cmp(void *arg, const void *a, const void *b)
 
33
{
 
34
  Cursor *cursor= (Cursor*)arg;
 
35
  return cursor->cmp_ref((const unsigned char *) a, (const unsigned char *) b);
 
36
}
 
37
 
 
38
optimizer::QuickIndexMergeSelect::QuickIndexMergeSelect(Session *session_param,
 
39
                                                        Table *table)
 
40
  :
 
41
    pk_quick_select(NULL),
 
42
    session(session_param)
 
43
{
 
44
  index= MAX_KEY;
 
45
  head= table;
 
46
  memset(&read_record, 0, sizeof(read_record));
 
47
  init_sql_alloc(&alloc, session->variables.range_alloc_block_size, 0);
 
48
  return;
 
49
}
 
50
 
 
51
int optimizer::QuickIndexMergeSelect::init()
 
52
{
 
53
  return 0;
 
54
}
 
55
 
 
56
int optimizer::QuickIndexMergeSelect::reset()
 
57
{
 
58
  return (read_keys_and_merge());
 
59
}
 
60
 
 
61
bool
 
62
optimizer::QuickIndexMergeSelect::push_quick_back(optimizer::QuickRangeSelect *quick_sel_range)
 
63
{
 
64
  /*
 
65
    Save quick_select that does scan on clustered primary key as it will be
 
66
    processed separately.
 
67
  */
 
68
  if (head->cursor->primary_key_is_clustered() &&
 
69
      quick_sel_range->index == head->s->primary_key)
 
70
  {
 
71
    pk_quick_select= quick_sel_range;
 
72
  }
 
73
  else
 
74
  {
 
75
    return quick_selects.push_back(quick_sel_range);
 
76
  }
 
77
  return 0;
 
78
}
 
79
 
 
80
optimizer::QuickIndexMergeSelect::~QuickIndexMergeSelect()
 
81
{
 
82
  List_iterator_fast<optimizer::QuickRangeSelect> quick_it(quick_selects);
 
83
  optimizer::QuickRangeSelect* quick;
 
84
  quick_it.rewind();
 
85
  while ((quick= quick_it++))
 
86
  {
 
87
    quick->cursor= NULL;
 
88
  }
 
89
  quick_selects.delete_elements();
 
90
  delete pk_quick_select;
 
91
  free_root(&alloc,MYF(0));
 
92
  return;
 
93
}
 
94
 
 
95
 
 
96
int optimizer::QuickIndexMergeSelect::read_keys_and_merge()
 
97
{
 
98
  List_iterator_fast<optimizer::QuickRangeSelect> cur_quick_it(quick_selects);
 
99
  optimizer::QuickRangeSelect* cur_quick;
 
100
  int result;
 
101
  Unique *unique;
 
102
  Cursor *cursor= head->cursor;
 
103
 
 
104
  cursor->extra(HA_EXTRA_KEYREAD);
 
105
  head->prepare_for_position();
 
106
 
 
107
  cur_quick_it.rewind();
 
108
  cur_quick= cur_quick_it++;
 
109
  assert(cur_quick != 0);
 
110
 
 
111
  /*
 
112
    We reuse the same instance of Cursor so we need to call both init and
 
113
    reset here.
 
114
  */
 
115
  if (cur_quick->init() || cur_quick->reset())
 
116
    return 0;
 
117
 
 
118
  unique= new Unique(refpos_order_cmp,
 
119
                     (void *)cursor,
 
120
                     cursor->ref_length,
 
121
                     session->variables.sortbuff_size);
 
122
  if (!unique)
 
123
    return 0;
 
124
  for (;;)
 
125
  {
 
126
    while ((result= cur_quick->get_next()) == HA_ERR_END_OF_FILE)
 
127
    {
 
128
      cur_quick->range_end();
 
129
      cur_quick= cur_quick_it++;
 
130
      if (!cur_quick)
 
131
        break;
 
132
 
 
133
      if (cur_quick->cursor->inited != Cursor::NONE)
 
134
        cur_quick->cursor->ha_index_end();
 
135
      if (cur_quick->init() || cur_quick->reset())
 
136
        return 0;
 
137
    }
 
138
 
 
139
    if (result)
 
140
    {
 
141
      if (result != HA_ERR_END_OF_FILE)
 
142
      {
 
143
        cur_quick->range_end();
 
144
        return result;
 
145
      }
 
146
      break;
 
147
    }
 
148
 
 
149
    if (session->killed)
 
150
      return 0;
 
151
 
 
152
    /* skip row if it will be retrieved by clustered PK scan */
 
153
    if (pk_quick_select && pk_quick_select->row_in_ranges())
 
154
      continue;
 
155
 
 
156
    cur_quick->cursor->position(cur_quick->record);
 
157
    result= unique->unique_add((char*)cur_quick->cursor->ref);
 
158
    if (result)
 
159
      return 0;
 
160
 
 
161
  }
 
162
 
 
163
  /* ok, all row ids are in Unique */
 
164
  result= unique->get(head);
 
165
  delete unique;
 
166
  doing_pk_scan= false;
 
167
  /* index_merge currently doesn't support "using index" at all */
 
168
  cursor->extra(HA_EXTRA_NO_KEYREAD);
 
169
  /* start table scan */
 
170
  init_read_record(&read_record, session, head, (optimizer::SqlSelect*) 0, 1, 1);
 
171
  return result;
 
172
}
 
173
 
 
174
 
 
175
int optimizer::QuickIndexMergeSelect::get_next()
 
176
{
 
177
  int result;
 
178
 
 
179
  if (doing_pk_scan)
 
180
    return(pk_quick_select->get_next());
 
181
 
 
182
  if ((result= read_record.read_record(&read_record)) == -1)
 
183
  {
 
184
    result= HA_ERR_END_OF_FILE;
 
185
    end_read_record(&read_record);
 
186
    /* All rows from Unique have been retrieved, do a clustered PK scan */
 
187
    if (pk_quick_select)
 
188
    {
 
189
      doing_pk_scan= true;
 
190
      if ((result= pk_quick_select->init()) ||
 
191
          (result= pk_quick_select->reset()))
 
192
        return result;
 
193
      return(pk_quick_select->get_next());
 
194
    }
 
195
  }
 
196
 
 
197
  return result;
 
198
}
 
199
 
 
200
bool optimizer::QuickIndexMergeSelect::is_keys_used(const MyBitmap *fields)
 
201
{
 
202
  optimizer::QuickRangeSelect *quick= NULL;
 
203
  List_iterator_fast<QuickRangeSelect> it(quick_selects);
 
204
  while ((quick= it++))
 
205
  {
 
206
    if (is_key_used(head, quick->index, fields))
 
207
      return 1;
 
208
  }
 
209
  return 0;
 
210
}
 
211
 
 
212
 
 
213
void optimizer::QuickIndexMergeSelect::add_info_string(String *str)
 
214
{
 
215
  optimizer::QuickRangeSelect *quick= NULL;
 
216
  bool first= true;
 
217
  List_iterator_fast<optimizer::QuickRangeSelect> it(quick_selects);
 
218
  str->append(STRING_WITH_LEN("sort_union("));
 
219
  while ((quick= it++))
 
220
  {
 
221
    if (! first)
 
222
      str->append(',');
 
223
    else
 
224
      first= false;
 
225
    quick->add_info_string(str);
 
226
  }
 
227
  if (pk_quick_select)
 
228
  {
 
229
    str->append(',');
 
230
    pk_quick_select->add_info_string(str);
 
231
  }
 
232
  str->append(')');
 
233
}
 
234
 
 
235
 
 
236
void optimizer::QuickIndexMergeSelect::add_keys_and_lengths(String *key_names,
 
237
                                                            String *used_lengths)
 
238
{
 
239
  char buf[64];
 
240
  uint32_t length;
 
241
  bool first= true;
 
242
  optimizer::QuickRangeSelect *quick= NULL;
 
243
 
 
244
  List_iterator_fast<optimizer::QuickRangeSelect> it(quick_selects);
 
245
  while ((quick= it++))
 
246
  {
 
247
    if (first)
 
248
      first= false;
 
249
    else
 
250
    {
 
251
      key_names->append(',');
 
252
      used_lengths->append(',');
 
253
    }
 
254
 
 
255
    KEY *key_info= head->key_info + quick->index;
 
256
    key_names->append(key_info->name);
 
257
    length= int64_t2str(quick->max_used_key_length, buf, 10) - buf;
 
258
    used_lengths->append(buf, length);
 
259
  }
 
260
  if (pk_quick_select)
 
261
  {
 
262
    KEY *key_info= head->key_info + pk_quick_select->index;
 
263
    key_names->append(',');
 
264
    key_names->append(key_info->name);
 
265
    length= int64_t2str(pk_quick_select->max_used_key_length, buf, 10) - buf;
 
266
    used_lengths->append(',');
 
267
    used_lengths->append(buf, length);
 
268
  }
 
269
}
 
270
 
 
271