~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/optimizer/quick_ror_intersect_select.cc

Merged with trunk.

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/util/functors.h"
 
23
#include "drizzled/optimizer/range.h"
 
24
#include "drizzled/optimizer/quick_range_select.h"
 
25
#include "drizzled/optimizer/quick_ror_intersect_select.h"
 
26
 
 
27
#include <vector>
 
28
 
 
29
using namespace std;
 
30
using namespace drizzled;
 
31
 
 
32
 
 
33
optimizer::QuickRorIntersectSelect::QuickRorIntersectSelect(Session *session_param,
 
34
                                                            Table *table,
 
35
                                                            bool retrieve_full_rows,
 
36
                                                            MEM_ROOT *parent_alloc)
 
37
  :
 
38
    cpk_quick(NULL),
 
39
    session(session_param),
 
40
    need_to_fetch_row(retrieve_full_rows),
 
41
    scans_inited(false)
 
42
{
 
43
  index= MAX_KEY;
 
44
  head= table;
 
45
  record= head->record[0];
 
46
  if (! parent_alloc)
 
47
  {
 
48
    init_sql_alloc(&alloc, session->variables.range_alloc_block_size, 0);
 
49
  }
 
50
  else
 
51
  {
 
52
    memset(&alloc, 0, sizeof(MEM_ROOT));
 
53
  }
 
54
  last_rowid= (unsigned char*) alloc_root(parent_alloc ? parent_alloc : &alloc,
 
55
                                          head->cursor->ref_length);
 
56
}
 
57
 
 
58
 
 
59
optimizer::QuickRorIntersectSelect::~QuickRorIntersectSelect()
 
60
{
 
61
  for_each(quick_selects.begin(),
 
62
           quick_selects.end(),
 
63
           DeletePtr());
 
64
  quick_selects.clear();
 
65
  delete cpk_quick;
 
66
  free_root(&alloc,MYF(0));
 
67
  if (need_to_fetch_row && head->cursor->inited != Cursor::NONE)
 
68
  {
 
69
    head->cursor->ha_rnd_end();
 
70
  }
 
71
  return;
 
72
}
 
73
 
 
74
 
 
75
int optimizer::QuickRorIntersectSelect::init()
 
76
{
 
77
 /* Check if last_rowid was successfully allocated in ctor */
 
78
  return (! last_rowid);
 
79
}
 
80
 
 
81
 
 
82
int optimizer::QuickRorIntersectSelect::init_ror_merged_scan(bool reuse_handler)
 
83
{
 
84
  vector<optimizer::QuickRangeSelect *>::iterator it= quick_selects.begin();
 
85
 
 
86
  /* Initialize all merged "children" quick selects */
 
87
  assert(! need_to_fetch_row || reuse_handler);
 
88
  if (! need_to_fetch_row && reuse_handler)
 
89
  {
 
90
    optimizer::QuickRangeSelect *quick= *it;
 
91
    ++it;
 
92
    /*
 
93
      There is no use of this->cursor. Use it for the first of merged range
 
94
      selects.
 
95
    */
 
96
    if (quick->init_ror_merged_scan(true))
 
97
      return 0;
 
98
    quick->cursor->extra(HA_EXTRA_KEYREAD_PRESERVE_FIELDS);
 
99
  }
 
100
  while (it != quick_selects.end())
 
101
  {
 
102
    if ((*it)->init_ror_merged_scan(false))
 
103
    {
 
104
      return 0;
 
105
    }
 
106
    (*it)->cursor->extra(HA_EXTRA_KEYREAD_PRESERVE_FIELDS);
 
107
    /* All merged scans share the same record buffer in intersection. */
 
108
    (*it)->record= head->record[0];
 
109
    ++it;
 
110
  }
 
111
 
 
112
  if (need_to_fetch_row && head->cursor->ha_rnd_init(1))
 
113
  {
 
114
    return 0;
 
115
  }
 
116
  return 0;
 
117
}
 
118
 
 
119
 
 
120
int optimizer::QuickRorIntersectSelect::reset()
 
121
{
 
122
  if (! scans_inited && init_ror_merged_scan(true))
 
123
  {
 
124
    return 0;
 
125
  }
 
126
  scans_inited= true;
 
127
  for (vector<optimizer::QuickRangeSelect *>::iterator it= quick_selects.begin();
 
128
       it != quick_selects.end();
 
129
       ++it)
 
130
  {
 
131
    (*it)->reset();
 
132
  }
 
133
  return 0;
 
134
}
 
135
 
 
136
 
 
137
bool
 
138
optimizer::QuickRorIntersectSelect::push_quick_back(optimizer::QuickRangeSelect *quick)
 
139
{
 
140
  quick_selects.push_back(quick);
 
141
  return false;
 
142
}
 
143
 
 
144
 
 
145
bool optimizer::QuickRorIntersectSelect::is_keys_used(const MyBitmap *fields)
 
146
{
 
147
  for (vector<optimizer::QuickRangeSelect *>::iterator it= quick_selects.begin();
 
148
       it != quick_selects.end();
 
149
       ++it)
 
150
  {
 
151
    if (is_key_used(head, (*it)->index, fields))
 
152
    {
 
153
      return 1;
 
154
    }
 
155
  }
 
156
  return 0;
 
157
}
 
158
 
 
159
 
 
160
int optimizer::QuickRorIntersectSelect::get_next()
 
161
{
 
162
  optimizer::QuickRangeSelect *quick= NULL;
 
163
  vector<optimizer::QuickRangeSelect *>::iterator it= quick_selects.begin();
 
164
  int error;
 
165
  int cmp;
 
166
  uint32_t last_rowid_count= 0;
 
167
 
 
168
  do
 
169
  {
 
170
    /* Get a rowid for first quick and save it as a 'candidate' */
 
171
    quick= *it;
 
172
    ++it;
 
173
    error= quick->get_next();
 
174
    if (cpk_quick)
 
175
    {
 
176
      while (! error && ! cpk_quick->row_in_ranges())
 
177
        error= quick->get_next();
 
178
    }
 
179
    if (error)
 
180
      return error;
 
181
 
 
182
    quick->cursor->position(quick->record);
 
183
    memcpy(last_rowid, quick->cursor->ref, head->cursor->ref_length);
 
184
    last_rowid_count= 1;
 
185
 
 
186
    while (last_rowid_count < quick_selects.size())
 
187
    {
 
188
      /** @todo: fix this madness!!!! */
 
189
      if (it != quick_selects.end())
 
190
      {
 
191
        quick= *it;
 
192
        ++it;
 
193
      }
 
194
      else
 
195
      {
 
196
        it= quick_selects.begin();
 
197
        quick= *it;
 
198
        ++it;
 
199
      }
 
200
 
 
201
      do
 
202
      {
 
203
        if ((error= quick->get_next()))
 
204
          return error;
 
205
        quick->cursor->position(quick->record);
 
206
        cmp= head->cursor->cmp_ref(quick->cursor->ref, last_rowid);
 
207
      } while (cmp < 0);
 
208
 
 
209
      /* Ok, current select 'caught up' and returned ref >= cur_ref */
 
210
      if (cmp > 0)
 
211
      {
 
212
        /* Found a row with ref > cur_ref. Make it a new 'candidate' */
 
213
        if (cpk_quick)
 
214
        {
 
215
          while (! cpk_quick->row_in_ranges())
 
216
          {
 
217
            if ((error= quick->get_next()))
 
218
              return error;
 
219
          }
 
220
        }
 
221
        memcpy(last_rowid, quick->cursor->ref, head->cursor->ref_length);
 
222
        last_rowid_count= 1;
 
223
      }
 
224
      else
 
225
      {
 
226
        /* current 'candidate' row confirmed by this select */
 
227
        last_rowid_count++;
 
228
      }
 
229
    }
 
230
 
 
231
    /* We get here if we got the same row ref in all scans. */
 
232
    if (need_to_fetch_row)
 
233
      error= head->cursor->rnd_pos(head->record[0], last_rowid);
 
234
  } while (error == HA_ERR_RECORD_DELETED);
 
235
  return error;
 
236
}
 
237
 
 
238
 
 
239
void optimizer::QuickRorIntersectSelect::add_info_string(String *str)
 
240
{
 
241
  bool first= true;
 
242
  str->append(STRING_WITH_LEN("intersect("));
 
243
  for (vector<optimizer::QuickRangeSelect *>::iterator it= quick_selects.begin();
 
244
       it != quick_selects.end();
 
245
       ++it)
 
246
  {
 
247
    KEY *key_info= head->key_info + (*it)->index;
 
248
    if (! first)
 
249
      str->append(',');
 
250
    else
 
251
      first= false;
 
252
    str->append(key_info->name);
 
253
  }
 
254
  if (cpk_quick)
 
255
  {
 
256
    KEY *key_info= head->key_info + cpk_quick->index;
 
257
    str->append(',');
 
258
    str->append(key_info->name);
 
259
  }
 
260
  str->append(')');
 
261
}
 
262
 
 
263
 
 
264
void optimizer::QuickRorIntersectSelect::add_keys_and_lengths(String *key_names,
 
265
                                                              String *used_lengths)
 
266
{
 
267
  char buf[64];
 
268
  uint32_t length;
 
269
  bool first= true;
 
270
  for (vector<optimizer::QuickRangeSelect *>::iterator it= quick_selects.begin();
 
271
       it != quick_selects.end();
 
272
       ++it)
 
273
  {
 
274
    KEY *key_info= head->key_info + (*it)->index;
 
275
    if (first)
 
276
    {
 
277
      first= false;
 
278
    }
 
279
    else
 
280
    {
 
281
      key_names->append(',');
 
282
      used_lengths->append(',');
 
283
    }
 
284
    key_names->append(key_info->name);
 
285
    length= int64_t2str((*it)->max_used_key_length, buf, 10) - buf;
 
286
    used_lengths->append(buf, length);
 
287
  }
 
288
 
 
289
  if (cpk_quick)
 
290
  {
 
291
    KEY *key_info= head->key_info + cpk_quick->index;
 
292
    key_names->append(',');
 
293
    key_names->append(key_info->name);
 
294
    length= int64_t2str(cpk_quick->max_used_key_length, buf, 10) - buf;
 
295
    used_lengths->append(',');
 
296
    used_lengths->append(buf, length);
 
297
  }
 
298
}
 
299