1237.13.20
by Padraig O'Sullivan
Forgot to include a copyright header in one of the new files I created. |
1 |
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
|
2 |
* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
|
|
3 |
*
|
|
1999.6.1
by kalebral at gmail
update Copyright strings to a more common format to help with creating the master debian copyright file |
4 |
* Copyright (C) 2008-2009 Sun Microsystems, Inc.
|
1237.13.20
by Padraig O'Sullivan
Forgot to include a copyright header in one of the new files I created. |
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 |
*/
|
|
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
19 |
|
2173.2.1
by Monty Taylor
Fixes incorrect usage of include |
20 |
#include <config.h> |
21 |
#include <drizzled/session.h> |
|
22 |
#include <drizzled/sql_select.h> |
|
23 |
#include <drizzled/join.h> |
|
24 |
#include <drizzled/optimizer/range.h> |
|
25 |
#include <drizzled/optimizer/quick_group_min_max_select.h> |
|
26 |
#include <drizzled/optimizer/quick_range.h> |
|
27 |
#include <drizzled/optimizer/quick_range_select.h> |
|
28 |
#include <drizzled/optimizer/sel_arg.h> |
|
29 |
#include <drizzled/internal/m_string.h> |
|
30 |
#include <drizzled/util/functors.h> |
|
2198.1.1
by Olaf van der Spek
Remove unnecessary alter* includes |
31 |
#include <drizzled/key.h> |
2234.1.4
by Olaf van der Spek
Refactor includes |
32 |
#include <drizzled/table.h> |
2241.3.2
by Olaf van der Spek
Refactor Session::variables |
33 |
#include <drizzled/system_variables.h> |
1237.13.29
by Padraig O'Sullivan
Replaced a DYNAMIC_ARRAY with std::vector in the range optimizer. |
34 |
|
35 |
#include <vector> |
|
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
36 |
|
37 |
using namespace std; |
|
38 |
||
2241.3.2
by Olaf van der Spek
Refactor Session::variables |
39 |
namespace drizzled { |
2318.6.54
by Olaf van der Spek
Refactor |
40 |
namespace optimizer { |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
41 |
|
2318.6.54
by Olaf van der Spek
Refactor |
42 |
QuickGroupMinMaxSelect::QuickGroupMinMaxSelect(Table *table, |
1541.1.1
by Brian Aker
JOIN -> Join rename |
43 |
Join *join_arg, |
1237.13.21
by Padraig O'Sullivan
Corrected some style issues in the QuickGroupMinMaxSelect class. |
44 |
bool have_min_arg, |
45 |
bool have_max_arg, |
|
1534
by Brian Aker
Remove of KeyPartInfo |
46 |
KeyPartInfo *min_max_arg_part_arg, |
1237.13.21
by Padraig O'Sullivan
Corrected some style issues in the QuickGroupMinMaxSelect class. |
47 |
uint32_t group_prefix_len_arg, |
48 |
uint32_t group_key_parts_arg, |
|
49 |
uint32_t used_key_parts_arg, |
|
1535
by Brian Aker
Rename of KEY to KeyInfo |
50 |
KeyInfo *index_info_arg, |
1237.13.21
by Padraig O'Sullivan
Corrected some style issues in the QuickGroupMinMaxSelect class. |
51 |
uint32_t use_index, |
52 |
double read_cost_arg, |
|
53 |
ha_rows records_arg, |
|
54 |
uint32_t key_infix_len_arg, |
|
55 |
unsigned char *key_infix_arg, |
|
1253.1.3
by Monty Taylor
MEM_ROOT == memory::Root |
56 |
memory::Root *parent_alloc) |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
57 |
:
|
58 |
join(join_arg), |
|
59 |
index_info(index_info_arg), |
|
60 |
group_prefix_len(group_prefix_len_arg), |
|
61 |
group_key_parts(group_key_parts_arg), |
|
62 |
have_min(have_min_arg), |
|
63 |
have_max(have_max_arg), |
|
64 |
seen_first_key(false), |
|
65 |
min_max_arg_part(min_max_arg_part_arg), |
|
66 |
key_infix(key_infix_arg), |
|
67 |
key_infix_len(key_infix_len_arg), |
|
68 |
min_functions_it(NULL), |
|
69 |
max_functions_it(NULL) |
|
70 |
{
|
|
71 |
head= table; |
|
72 |
cursor= head->cursor; |
|
73 |
index= use_index; |
|
74 |
record= head->record[0]; |
|
1672.3.6
by Brian Aker
First pass in encapsulating row |
75 |
tmp_record= head->getUpdateRecord(); |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
76 |
read_time= read_cost_arg; |
77 |
records= records_arg; |
|
78 |
used_key_parts= used_key_parts_arg; |
|
79 |
real_key_parts= used_key_parts_arg; |
|
80 |
real_prefix_len= group_prefix_len + key_infix_len; |
|
81 |
group_prefix= NULL; |
|
82 |
min_max_arg_len= min_max_arg_part ? min_max_arg_part->store_length : 0; |
|
83 |
||
84 |
/*
|
|
85 |
We can't have parent_alloc set as the init function can't handle this case
|
|
86 |
yet.
|
|
87 |
*/
|
|
88 |
assert(! parent_alloc); |
|
89 |
if (! parent_alloc) |
|
90 |
{
|
|
2318.6.23
by Olaf van der Spek
Refactor |
91 |
alloc.init(join->session->variables.range_alloc_block_size); |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
92 |
join->session->mem_root= &alloc; |
93 |
}
|
|
94 |
else
|
|
1253.1.3
by Monty Taylor
MEM_ROOT == memory::Root |
95 |
memset(&alloc, 0, sizeof(memory::Root)); // ensure that it's not used |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
96 |
}
|
97 |
||
98 |
||
2318.6.54
by Olaf van der Spek
Refactor |
99 |
int QuickGroupMinMaxSelect::init() |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
100 |
{
|
101 |
if (group_prefix) /* Already initialized. */ |
|
102 |
return 0; |
|
103 |
||
2318.6.44
by Olaf van der Spek
Refactor |
104 |
last_prefix= alloc.alloc(group_prefix_len); |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
105 |
/*
|
106 |
We may use group_prefix to store keys with all select fields, so allocate
|
|
107 |
enough space for it.
|
|
108 |
*/
|
|
2318.6.44
by Olaf van der Spek
Refactor |
109 |
group_prefix= alloc.alloc(real_prefix_len + min_max_arg_len); |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
110 |
|
111 |
if (key_infix_len > 0) |
|
112 |
{
|
|
113 |
/*
|
|
114 |
The memory location pointed to by key_infix will be deleted soon, so
|
|
115 |
allocate a new buffer and copy the key_infix into it.
|
|
116 |
*/
|
|
2318.6.44
by Olaf van der Spek
Refactor |
117 |
unsigned char *tmp_key_infix= alloc.alloc(key_infix_len); |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
118 |
memcpy(tmp_key_infix, this->key_infix, key_infix_len); |
119 |
this->key_infix= tmp_key_infix; |
|
120 |
}
|
|
121 |
||
122 |
if (min_max_arg_part) |
|
123 |
{
|
|
2318.6.40
by Olaf van der Spek
Refactor |
124 |
min_functions= have_min ? new List<Item_sum> : NULL; |
125 |
max_functions= have_max ? new List<Item_sum> : NULL; |
|
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
126 |
Item_sum **func_ptr= join->sum_funcs; |
2318.6.40
by Olaf van der Spek
Refactor |
127 |
while (Item_sum* min_max_item= *(func_ptr++)) |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
128 |
{
|
129 |
if (have_min && (min_max_item->sum_func() == Item_sum::MIN_FUNC)) |
|
130 |
min_functions->push_back(min_max_item); |
|
131 |
else if (have_max && (min_max_item->sum_func() == Item_sum::MAX_FUNC)) |
|
132 |
max_functions->push_back(min_max_item); |
|
133 |
}
|
|
134 |
||
135 |
if (have_min) |
|
2318.6.40
by Olaf van der Spek
Refactor |
136 |
min_functions_it= new List<Item_sum>::iterator(min_functions->begin()); |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
137 |
if (have_max) |
2318.6.40
by Olaf van der Spek
Refactor |
138 |
max_functions_it= new List<Item_sum>::iterator(max_functions->begin()); |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
139 |
}
|
2318.6.46
by Olaf van der Spek
Refactor |
140 |
return 0; |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
141 |
}
|
142 |
||
2318.6.54
by Olaf van der Spek
Refactor |
143 |
QuickGroupMinMaxSelect::~QuickGroupMinMaxSelect() |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
144 |
{
|
145 |
if (cursor->inited != Cursor::NONE) |
|
146 |
{
|
|
1491.1.6
by Jay Pipes
Cursor::ha_index_init() -> Cursor::startIndexScan(). Cursor::ha_index_end() -> Cursor::endIndexScan() |
147 |
cursor->endIndexScan(); |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
148 |
}
|
149 |
if (min_max_arg_part) |
|
150 |
{
|
|
1237.13.29
by Padraig O'Sullivan
Replaced a DYNAMIC_ARRAY with std::vector in the range optimizer. |
151 |
for_each(min_max_ranges.begin(), |
152 |
min_max_ranges.end(), |
|
153 |
DeletePtr()); |
|
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
154 |
}
|
1237.13.31
by Padraig O'Sullivan
Minor revisions based on review comments from Jay. Thanks Jay! |
155 |
min_max_ranges.clear(); |
1487
by Brian Aker
More updates for memory::Root |
156 |
alloc.free_root(MYF(0)); |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
157 |
delete min_functions_it; |
158 |
delete max_functions_it; |
|
159 |
delete quick_prefix_select; |
|
160 |
}
|
|
161 |
||
162 |
||
2318.6.54
by Olaf van der Spek
Refactor |
163 |
bool QuickGroupMinMaxSelect::add_range(SEL_ARG *sel_range) |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
164 |
{
|
2318.6.54
by Olaf van der Spek
Refactor |
165 |
QuickRange *range= NULL; |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
166 |
uint32_t range_flag= sel_range->min_flag | sel_range->max_flag; |
167 |
||
168 |
/* Skip (-inf,+inf) ranges, e.g. (x < 5 or x > 4). */
|
|
169 |
if ((range_flag & NO_MIN_RANGE) && (range_flag & NO_MAX_RANGE)) |
|
170 |
return false; |
|
171 |
||
172 |
if (! (sel_range->min_flag & NO_MIN_RANGE) && |
|
173 |
! (sel_range->max_flag & NO_MAX_RANGE)) |
|
174 |
{
|
|
175 |
if (sel_range->maybe_null && |
|
176 |
sel_range->min_value[0] && sel_range->max_value[0]) |
|
177 |
range_flag|= NULL_RANGE; /* IS NULL condition */ |
|
178 |
else if (memcmp(sel_range->min_value, sel_range->max_value, |
|
179 |
min_max_arg_len) == 0) |
|
180 |
range_flag|= EQ_RANGE; /* equality condition */ |
|
181 |
}
|
|
2318.6.54
by Olaf van der Spek
Refactor |
182 |
range= new QuickRange(sel_range->min_value, |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
183 |
min_max_arg_len, |
184 |
make_keypart_map(sel_range->part), |
|
185 |
sel_range->max_value, |
|
186 |
min_max_arg_len, |
|
187 |
make_keypart_map(sel_range->part), |
|
188 |
range_flag); |
|
189 |
if (! range) |
|
190 |
return true; |
|
1237.13.29
by Padraig O'Sullivan
Replaced a DYNAMIC_ARRAY with std::vector in the range optimizer. |
191 |
min_max_ranges.push_back(range); |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
192 |
return false; |
193 |
}
|
|
194 |
||
195 |
||
2318.6.54
by Olaf van der Spek
Refactor |
196 |
void QuickGroupMinMaxSelect::adjust_prefix_ranges() |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
197 |
{
|
198 |
if (quick_prefix_select && |
|
199 |
group_prefix_len < quick_prefix_select->max_used_key_length) |
|
200 |
{
|
|
2221.7.2
by Olaf van der Spek
Refactor |
201 |
DYNAMIC_ARRAY& arr= quick_prefix_select->ranges; |
202 |
for (size_t inx= 0; inx < arr.size(); inx++) |
|
2318.6.54
by Olaf van der Spek
Refactor |
203 |
reinterpret_cast<QuickRange**>(arr.buffer)[inx]->flag &= ~(NEAR_MIN | NEAR_MAX); |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
204 |
}
|
205 |
}
|
|
206 |
||
207 |
||
2318.6.54
by Olaf van der Spek
Refactor |
208 |
void QuickGroupMinMaxSelect::update_key_stat() |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
209 |
{
|
210 |
max_used_key_length= real_prefix_len; |
|
1237.13.29
by Padraig O'Sullivan
Replaced a DYNAMIC_ARRAY with std::vector in the range optimizer. |
211 |
if (! min_max_ranges.empty()) |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
212 |
{
|
2318.6.54
by Olaf van der Spek
Refactor |
213 |
QuickRange *cur_range= NULL; |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
214 |
if (have_min) |
215 |
{ /* Check if the right-most range has a lower boundary. */ |
|
1237.13.31
by Padraig O'Sullivan
Minor revisions based on review comments from Jay. Thanks Jay! |
216 |
cur_range= min_max_ranges.back(); |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
217 |
if (! (cur_range->flag & NO_MIN_RANGE)) |
218 |
{
|
|
219 |
max_used_key_length+= min_max_arg_len; |
|
220 |
used_key_parts++; |
|
221 |
return; |
|
222 |
}
|
|
223 |
}
|
|
224 |
if (have_max) |
|
225 |
{ /* Check if the left-most range has an upper boundary. */ |
|
1237.13.31
by Padraig O'Sullivan
Minor revisions based on review comments from Jay. Thanks Jay! |
226 |
cur_range= min_max_ranges.front(); |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
227 |
if (! (cur_range->flag & NO_MAX_RANGE)) |
228 |
{
|
|
229 |
max_used_key_length+= min_max_arg_len; |
|
230 |
used_key_parts++; |
|
231 |
return; |
|
232 |
}
|
|
233 |
}
|
|
234 |
}
|
|
235 |
else if (have_min && min_max_arg_part && |
|
236 |
min_max_arg_part->field->real_maybe_null()) |
|
237 |
{
|
|
238 |
/*
|
|
239 |
If a MIN/MAX argument value is NULL, we can quickly determine
|
|
240 |
that we're in the beginning of the next group, because NULLs
|
|
241 |
are always < any other value. This allows us to quickly
|
|
242 |
determine the end of the current group and jump to the next
|
|
243 |
group (see next_min()) and thus effectively increases the
|
|
244 |
usable key length.
|
|
245 |
*/
|
|
246 |
max_used_key_length+= min_max_arg_len; |
|
247 |
used_key_parts++; |
|
248 |
}
|
|
249 |
}
|
|
250 |
||
251 |
||
2318.6.54
by Olaf van der Spek
Refactor |
252 |
int QuickGroupMinMaxSelect::reset(void) |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
253 |
{
|
254 |
int result; |
|
255 |
||
256 |
cursor->extra(HA_EXTRA_KEYREAD); /* We need only the key attributes */ |
|
1491.1.6
by Jay Pipes
Cursor::ha_index_init() -> Cursor::startIndexScan(). Cursor::ha_index_end() -> Cursor::endIndexScan() |
257 |
if ((result= cursor->startIndexScan(index,1))) |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
258 |
return result; |
259 |
if (quick_prefix_select && quick_prefix_select->reset()) |
|
260 |
return 0; |
|
261 |
result= cursor->index_last(record); |
|
262 |
if (result == HA_ERR_END_OF_FILE) |
|
263 |
return 0; |
|
264 |
/* Save the prefix of the last group. */
|
|
265 |
key_copy(last_prefix, record, index_info, group_prefix_len); |
|
266 |
||
267 |
return 0; |
|
268 |
}
|
|
269 |
||
270 |
||
2318.6.54
by Olaf van der Spek
Refactor |
271 |
int QuickGroupMinMaxSelect::get_next() |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
272 |
{
|
273 |
int min_res= 0; |
|
274 |
int max_res= 0; |
|
275 |
int result= 0; |
|
276 |
int is_last_prefix= 0; |
|
277 |
||
278 |
/*
|
|
279 |
Loop until a group is found that satisfies all query conditions or the last
|
|
280 |
group is reached.
|
|
281 |
*/
|
|
282 |
do
|
|
283 |
{
|
|
284 |
result= next_prefix(); |
|
285 |
/*
|
|
286 |
Check if this is the last group prefix. Notice that at this point
|
|
287 |
this->record contains the current prefix in record format.
|
|
288 |
*/
|
|
289 |
if (! result) |
|
290 |
{
|
|
291 |
is_last_prefix= key_cmp(index_info->key_part, last_prefix, |
|
292 |
group_prefix_len); |
|
293 |
assert(is_last_prefix <= 0); |
|
294 |
}
|
|
295 |
else
|
|
296 |
{
|
|
297 |
if (result == HA_ERR_KEY_NOT_FOUND) |
|
298 |
continue; |
|
299 |
break; |
|
300 |
}
|
|
301 |
||
302 |
if (have_min) |
|
303 |
{
|
|
304 |
min_res= next_min(); |
|
305 |
if (min_res == 0) |
|
306 |
update_min_result(); |
|
307 |
}
|
|
308 |
/* If there is no MIN in the group, there is no MAX either. */
|
|
309 |
if ((have_max && !have_min) || |
|
310 |
(have_max && have_min && (min_res == 0))) |
|
311 |
{
|
|
312 |
max_res= next_max(); |
|
313 |
if (max_res == 0) |
|
314 |
update_max_result(); |
|
315 |
/* If a MIN was found, a MAX must have been found as well. */
|
|
316 |
assert(((have_max && !have_min) || |
|
317 |
(have_max && have_min && (max_res == 0)))); |
|
318 |
}
|
|
319 |
/*
|
|
320 |
If this is just a GROUP BY or DISTINCT without MIN or MAX and there
|
|
321 |
are equality predicates for the key parts after the group, find the
|
|
322 |
first sub-group with the extended prefix.
|
|
323 |
*/
|
|
324 |
if (! have_min && ! have_max && key_infix_len > 0) |
|
325 |
result= cursor->index_read_map(record, |
|
326 |
group_prefix, |
|
327 |
make_prev_keypart_map(real_key_parts), |
|
328 |
HA_READ_KEY_EXACT); |
|
329 |
||
330 |
result= have_min ? min_res : have_max ? max_res : result; |
|
331 |
} while ((result == HA_ERR_KEY_NOT_FOUND || result == HA_ERR_END_OF_FILE) && |
|
332 |
is_last_prefix != 0); |
|
333 |
||
334 |
if (result == 0) |
|
335 |
{
|
|
336 |
/*
|
|
337 |
Partially mimic the behavior of end_select_send. Copy the
|
|
338 |
field data from Item_field::field into Item_field::result_field
|
|
339 |
of each non-aggregated field (the group fields, and optionally
|
|
340 |
other fields in non-ANSI SQL mode).
|
|
341 |
*/
|
|
342 |
copy_fields(&join->tmp_table_param); |
|
343 |
}
|
|
344 |
else if (result == HA_ERR_KEY_NOT_FOUND) |
|
345 |
result= HA_ERR_END_OF_FILE; |
|
346 |
||
347 |
return result; |
|
348 |
}
|
|
349 |
||
350 |
||
2318.6.54
by Olaf van der Spek
Refactor |
351 |
int QuickGroupMinMaxSelect::next_min() |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
352 |
{
|
353 |
int result= 0; |
|
354 |
||
355 |
/* Find the MIN key using the eventually extended group prefix. */
|
|
1237.13.29
by Padraig O'Sullivan
Replaced a DYNAMIC_ARRAY with std::vector in the range optimizer. |
356 |
if (! min_max_ranges.empty()) |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
357 |
{
|
358 |
if ((result= next_min_in_range())) |
|
359 |
return result; |
|
360 |
}
|
|
361 |
else
|
|
362 |
{
|
|
363 |
/* Apply the constant equality conditions to the non-group select fields */
|
|
364 |
if (key_infix_len > 0) |
|
365 |
{
|
|
366 |
if ((result= cursor->index_read_map(record, |
|
367 |
group_prefix, |
|
368 |
make_prev_keypart_map(real_key_parts), |
|
369 |
HA_READ_KEY_EXACT))) |
|
370 |
return result; |
|
371 |
}
|
|
372 |
||
373 |
/*
|
|
374 |
If the min/max argument field is NULL, skip subsequent rows in the same
|
|
375 |
group with NULL in it. Notice that:
|
|
376 |
- if the first row in a group doesn't have a NULL in the field, no row
|
|
377 |
in the same group has (because NULL < any other value),
|
|
378 |
- min_max_arg_part->field->ptr points to some place in 'record'.
|
|
379 |
*/
|
|
380 |
if (min_max_arg_part && min_max_arg_part->field->is_null()) |
|
381 |
{
|
|
382 |
/* Find the first subsequent record without NULL in the MIN/MAX field. */
|
|
383 |
key_copy(tmp_record, record, index_info, 0); |
|
384 |
result= cursor->index_read_map(record, |
|
385 |
tmp_record, |
|
386 |
make_keypart_map(real_key_parts), |
|
387 |
HA_READ_AFTER_KEY); |
|
388 |
/*
|
|
389 |
Check if the new record belongs to the current group by comparing its
|
|
390 |
prefix with the group's prefix. If it is from the next group, then the
|
|
391 |
whole group has NULLs in the MIN/MAX field, so use the first record in
|
|
392 |
the group as a result.
|
|
393 |
TODO:
|
|
394 |
It is possible to reuse this new record as the result candidate for the
|
|
395 |
next call to next_min(), and to save one lookup in the next call. For
|
|
396 |
this add a new member 'this->next_group_prefix'.
|
|
397 |
*/
|
|
398 |
if (! result) |
|
399 |
{
|
|
400 |
if (key_cmp(index_info->key_part, group_prefix, real_prefix_len)) |
|
401 |
key_restore(record, tmp_record, index_info, 0); |
|
402 |
}
|
|
403 |
else if (result == HA_ERR_KEY_NOT_FOUND || result == HA_ERR_END_OF_FILE) |
|
404 |
result= 0; /* There is a result in any case. */ |
|
405 |
}
|
|
406 |
}
|
|
407 |
||
408 |
/*
|
|
409 |
If the MIN attribute is non-nullable, this->record already contains the
|
|
410 |
MIN key in the group, so just return.
|
|
411 |
*/
|
|
412 |
return result; |
|
413 |
}
|
|
414 |
||
415 |
||
2318.6.54
by Olaf van der Spek
Refactor |
416 |
int QuickGroupMinMaxSelect::next_max() |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
417 |
{
|
418 |
/* Get the last key in the (possibly extended) group. */
|
|
2318.6.53
by Olaf van der Spek
Refactor |
419 |
return min_max_ranges.empty() |
420 |
? cursor->index_read_map(record, group_prefix, make_prev_keypart_map(real_key_parts), HA_READ_PREFIX_LAST) |
|
421 |
: next_max_in_range(); |
|
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
422 |
}
|
423 |
||
424 |
||
2318.6.54
by Olaf van der Spek
Refactor |
425 |
int QuickGroupMinMaxSelect::next_prefix() |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
426 |
{
|
427 |
int result= 0; |
|
428 |
||
429 |
if (quick_prefix_select) |
|
430 |
{
|
|
431 |
unsigned char *cur_prefix= seen_first_key ? group_prefix : NULL; |
|
432 |
if ((result= quick_prefix_select->get_next_prefix(group_prefix_len, |
|
433 |
make_prev_keypart_map(group_key_parts), |
|
434 |
cur_prefix))) |
|
435 |
return result; |
|
436 |
seen_first_key= true; |
|
437 |
}
|
|
438 |
else
|
|
439 |
{
|
|
440 |
if (! seen_first_key) |
|
441 |
{
|
|
442 |
result= cursor->index_first(record); |
|
443 |
if (result) |
|
444 |
return result; |
|
445 |
seen_first_key= true; |
|
446 |
}
|
|
447 |
else
|
|
448 |
{
|
|
449 |
/* Load the first key in this group into record. */
|
|
450 |
result= cursor->index_read_map(record, |
|
451 |
group_prefix, |
|
452 |
make_prev_keypart_map(group_key_parts), |
|
453 |
HA_READ_AFTER_KEY); |
|
454 |
if (result) |
|
455 |
return result; |
|
456 |
}
|
|
457 |
}
|
|
458 |
||
459 |
/* Save the prefix of this group for subsequent calls. */
|
|
460 |
key_copy(group_prefix, record, index_info, group_prefix_len); |
|
461 |
/* Append key_infix to group_prefix. */
|
|
462 |
if (key_infix_len > 0) |
|
463 |
memcpy(group_prefix + group_prefix_len, |
|
464 |
key_infix, |
|
465 |
key_infix_len); |
|
466 |
||
467 |
return 0; |
|
468 |
}
|
|
469 |
||
470 |
||
2318.6.54
by Olaf van der Spek
Refactor |
471 |
int QuickGroupMinMaxSelect::next_min_in_range() |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
472 |
{
|
473 |
ha_rkey_function find_flag; |
|
474 |
key_part_map keypart_map; |
|
2318.6.54
by Olaf van der Spek
Refactor |
475 |
QuickRange *cur_range= NULL; |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
476 |
bool found_null= false; |
477 |
int result= HA_ERR_KEY_NOT_FOUND; |
|
478 |
basic_string<unsigned char> max_key; |
|
479 |
||
480 |
max_key.reserve(real_prefix_len + min_max_arg_len); |
|
481 |
||
1237.13.29
by Padraig O'Sullivan
Replaced a DYNAMIC_ARRAY with std::vector in the range optimizer. |
482 |
assert(! min_max_ranges.empty()); |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
483 |
|
2318.6.54
by Olaf van der Spek
Refactor |
484 |
for (vector<QuickRange *>::iterator it= min_max_ranges.begin(); it != min_max_ranges.end(); ++it) |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
485 |
{ /* Search from the left-most range to the right. */ |
1237.13.29
by Padraig O'Sullivan
Replaced a DYNAMIC_ARRAY with std::vector in the range optimizer. |
486 |
cur_range= *it; |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
487 |
|
488 |
/*
|
|
489 |
If the current value for the min/max argument is bigger than the right
|
|
490 |
boundary of cur_range, there is no need to check this range.
|
|
491 |
*/
|
|
1237.13.29
by Padraig O'Sullivan
Replaced a DYNAMIC_ARRAY with std::vector in the range optimizer. |
492 |
if (it != min_max_ranges.begin() && |
493 |
! (cur_range->flag & NO_MAX_RANGE) && |
|
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
494 |
(key_cmp(min_max_arg_part, |
495 |
(const unsigned char*) cur_range->max_key, |
|
496 |
min_max_arg_len) == 1)) |
|
497 |
continue; |
|
498 |
||
499 |
if (cur_range->flag & NO_MIN_RANGE) |
|
500 |
{
|
|
501 |
keypart_map= make_prev_keypart_map(real_key_parts); |
|
502 |
find_flag= HA_READ_KEY_EXACT; |
|
503 |
}
|
|
504 |
else
|
|
505 |
{
|
|
506 |
/* Extend the search key with the lower boundary for this range. */
|
|
507 |
memcpy(group_prefix + real_prefix_len, |
|
508 |
cur_range->min_key, |
|
509 |
cur_range->min_length); |
|
510 |
keypart_map= make_keypart_map(real_key_parts); |
|
511 |
find_flag= (cur_range->flag & (EQ_RANGE | NULL_RANGE)) ? |
|
512 |
HA_READ_KEY_EXACT : (cur_range->flag & NEAR_MIN) ? |
|
513 |
HA_READ_AFTER_KEY : HA_READ_KEY_OR_NEXT; |
|
514 |
}
|
|
515 |
||
516 |
result= cursor->index_read_map(record, group_prefix, keypart_map, find_flag); |
|
517 |
if (result) |
|
518 |
{
|
|
519 |
if ((result == HA_ERR_KEY_NOT_FOUND || result == HA_ERR_END_OF_FILE) && |
|
520 |
(cur_range->flag & (EQ_RANGE | NULL_RANGE))) |
|
521 |
continue; /* Check the next range. */ |
|
522 |
||
523 |
/*
|
|
524 |
In all other cases (HA_ERR_*, HA_READ_KEY_EXACT with NO_MIN_RANGE,
|
|
525 |
HA_READ_AFTER_KEY, HA_READ_KEY_OR_NEXT) if the lookup failed for this
|
|
526 |
range, it can't succeed for any other subsequent range.
|
|
527 |
*/
|
|
528 |
break; |
|
529 |
}
|
|
530 |
||
531 |
/* A key was found. */
|
|
532 |
if (cur_range->flag & EQ_RANGE) |
|
533 |
break; /* No need to perform the checks below for equal keys. */ |
|
534 |
||
535 |
if (cur_range->flag & NULL_RANGE) |
|
536 |
{
|
|
537 |
/*
|
|
538 |
Remember this key, and continue looking for a non-NULL key that
|
|
539 |
satisfies some other condition.
|
|
540 |
*/
|
|
1532.1.15
by Brian Aker
Partial encapsulation of TableShare from Table. |
541 |
memcpy(tmp_record, record, head->getShare()->rec_buff_length); |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
542 |
found_null= true; |
543 |
continue; |
|
544 |
}
|
|
545 |
||
546 |
/* Check if record belongs to the current group. */
|
|
547 |
if (key_cmp(index_info->key_part, group_prefix, real_prefix_len)) |
|
548 |
{
|
|
549 |
result= HA_ERR_KEY_NOT_FOUND; |
|
550 |
continue; |
|
551 |
}
|
|
552 |
||
553 |
/* If there is an upper limit, check if the found key is in the range. */
|
|
554 |
if (! (cur_range->flag & NO_MAX_RANGE) ) |
|
555 |
{
|
|
556 |
/* Compose the MAX key for the range. */
|
|
557 |
max_key.clear(); |
|
558 |
max_key.append(group_prefix, real_prefix_len); |
|
559 |
max_key.append(cur_range->max_key, cur_range->max_length); |
|
560 |
/* Compare the found key with max_key. */
|
|
561 |
int cmp_res= key_cmp(index_info->key_part, |
|
562 |
max_key.data(), |
|
563 |
real_prefix_len + min_max_arg_len); |
|
564 |
if (! (((cur_range->flag & NEAR_MAX) && (cmp_res == -1)) || |
|
565 |
(cmp_res <= 0))) |
|
566 |
{
|
|
567 |
result= HA_ERR_KEY_NOT_FOUND; |
|
568 |
continue; |
|
569 |
}
|
|
570 |
}
|
|
571 |
/* If we got to this point, the current key qualifies as MIN. */
|
|
572 |
assert(result == 0); |
|
573 |
break; |
|
574 |
}
|
|
575 |
/*
|
|
576 |
If there was a key with NULL in the MIN/MAX field, and there was no other
|
|
577 |
key without NULL from the same group that satisfies some other condition,
|
|
578 |
then use the key with the NULL.
|
|
579 |
*/
|
|
580 |
if (found_null && result) |
|
581 |
{
|
|
1532.1.15
by Brian Aker
Partial encapsulation of TableShare from Table. |
582 |
memcpy(record, tmp_record, head->getShare()->rec_buff_length); |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
583 |
result= 0; |
584 |
}
|
|
585 |
return result; |
|
586 |
}
|
|
587 |
||
588 |
||
2318.6.54
by Olaf van der Spek
Refactor |
589 |
int QuickGroupMinMaxSelect::next_max_in_range() |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
590 |
{
|
591 |
ha_rkey_function find_flag; |
|
592 |
key_part_map keypart_map; |
|
2318.6.54
by Olaf van der Spek
Refactor |
593 |
QuickRange *cur_range= NULL; |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
594 |
int result= 0; |
595 |
basic_string<unsigned char> min_key; |
|
596 |
min_key.reserve(real_prefix_len + min_max_arg_len); |
|
597 |
||
1237.13.29
by Padraig O'Sullivan
Replaced a DYNAMIC_ARRAY with std::vector in the range optimizer. |
598 |
assert(! min_max_ranges.empty()); |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
599 |
|
2318.6.54
by Olaf van der Spek
Refactor |
600 |
for (vector<QuickRange *>::reverse_iterator rit= min_max_ranges.rbegin(); |
1237.13.29
by Padraig O'Sullivan
Replaced a DYNAMIC_ARRAY with std::vector in the range optimizer. |
601 |
rit != min_max_ranges.rend(); |
602 |
++rit) |
|
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
603 |
{ /* Search from the right-most range to the left. */ |
1237.13.29
by Padraig O'Sullivan
Replaced a DYNAMIC_ARRAY with std::vector in the range optimizer. |
604 |
cur_range= *rit; |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
605 |
|
606 |
/*
|
|
607 |
If the current value for the min/max argument is smaller than the left
|
|
608 |
boundary of cur_range, there is no need to check this range.
|
|
609 |
*/
|
|
1237.13.29
by Padraig O'Sullivan
Replaced a DYNAMIC_ARRAY with std::vector in the range optimizer. |
610 |
if (rit != min_max_ranges.rbegin() && |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
611 |
! (cur_range->flag & NO_MIN_RANGE) && |
612 |
(key_cmp(min_max_arg_part, |
|
613 |
(const unsigned char*) cur_range->min_key, |
|
614 |
min_max_arg_len) == -1)) |
|
615 |
continue; |
|
616 |
||
617 |
if (cur_range->flag & NO_MAX_RANGE) |
|
618 |
{
|
|
619 |
keypart_map= make_prev_keypart_map(real_key_parts); |
|
620 |
find_flag= HA_READ_PREFIX_LAST; |
|
621 |
}
|
|
622 |
else
|
|
623 |
{
|
|
624 |
/* Extend the search key with the upper boundary for this range. */
|
|
625 |
memcpy(group_prefix + real_prefix_len, |
|
626 |
cur_range->max_key, |
|
627 |
cur_range->max_length); |
|
628 |
keypart_map= make_keypart_map(real_key_parts); |
|
629 |
find_flag= (cur_range->flag & EQ_RANGE) ? |
|
630 |
HA_READ_KEY_EXACT : (cur_range->flag & NEAR_MAX) ? |
|
631 |
HA_READ_BEFORE_KEY : HA_READ_PREFIX_LAST_OR_PREV; |
|
632 |
}
|
|
633 |
||
634 |
result= cursor->index_read_map(record, group_prefix, keypart_map, find_flag); |
|
635 |
||
636 |
if (result) |
|
637 |
{
|
|
638 |
if ((result == HA_ERR_KEY_NOT_FOUND || result == HA_ERR_END_OF_FILE) && |
|
639 |
(cur_range->flag & EQ_RANGE)) |
|
640 |
continue; /* Check the next range. */ |
|
641 |
||
642 |
/*
|
|
643 |
In no key was found with this upper bound, there certainly are no keys
|
|
644 |
in the ranges to the left.
|
|
645 |
*/
|
|
646 |
return result; |
|
647 |
}
|
|
648 |
/* A key was found. */
|
|
649 |
if (cur_range->flag & EQ_RANGE) |
|
650 |
return 0; /* No need to perform the checks below for equal keys. */ |
|
651 |
||
652 |
/* Check if record belongs to the current group. */
|
|
653 |
if (key_cmp(index_info->key_part, group_prefix, real_prefix_len)) |
|
654 |
continue; // Row not found |
|
655 |
||
656 |
/* If there is a lower limit, check if the found key is in the range. */
|
|
657 |
if (! (cur_range->flag & NO_MIN_RANGE) ) |
|
658 |
{
|
|
659 |
/* Compose the MIN key for the range. */
|
|
660 |
min_key.clear(); |
|
661 |
min_key.append(group_prefix, real_prefix_len); |
|
662 |
min_key.append(cur_range->min_key, cur_range->min_length); |
|
663 |
||
664 |
/* Compare the found key with min_key. */
|
|
665 |
int cmp_res= key_cmp(index_info->key_part, |
|
666 |
min_key.data(), |
|
667 |
real_prefix_len + min_max_arg_len); |
|
668 |
if (! (((cur_range->flag & NEAR_MIN) && (cmp_res == 1)) || |
|
669 |
(cmp_res >= 0))) |
|
670 |
continue; |
|
671 |
}
|
|
672 |
/* If we got to this point, the current key qualifies as MAX. */
|
|
673 |
return result; |
|
674 |
}
|
|
675 |
return HA_ERR_KEY_NOT_FOUND; |
|
676 |
}
|
|
677 |
||
678 |
||
2318.6.54
by Olaf van der Spek
Refactor |
679 |
void QuickGroupMinMaxSelect::update_min_result() |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
680 |
{
|
2183.2.1
by Olaf van der Spek
x |
681 |
*min_functions_it= min_functions->begin(); |
2179.1.11
by Olaf van der Spek
x |
682 |
for (Item_sum *min_func; (min_func= (*min_functions_it)++); ) |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
683 |
min_func->reset(); |
684 |
}
|
|
685 |
||
686 |
||
2318.6.54
by Olaf van der Spek
Refactor |
687 |
void QuickGroupMinMaxSelect::update_max_result() |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
688 |
{
|
2183.2.1
by Olaf van der Spek
x |
689 |
*max_functions_it= max_functions->begin(); |
2179.1.11
by Olaf van der Spek
x |
690 |
for (Item_sum *max_func; (max_func= (*max_functions_it)++); ) |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
691 |
max_func->reset(); |
692 |
}
|
|
693 |
||
694 |
||
2318.6.54
by Olaf van der Spek
Refactor |
695 |
void QuickGroupMinMaxSelect::add_keys_and_lengths(string *key_names, |
2170.4.4
by Stewart Smith
tmp3 String to std::string in explain_plan (and used_lengths parameter to add_keys_and_lengths |
696 |
string *used_lengths) |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
697 |
{
|
698 |
char buf[64]; |
|
699 |
key_names->append(index_info->name); |
|
1280.1.10
by Monty Taylor
Put everything in drizzled into drizzled namespace. |
700 |
uint32_t length= internal::int64_t2str(max_used_key_length, buf, 10) - buf; |
1237.13.18
by Padraig O'Sullivan
Split the QUICK_GROUP_MIN_MAX_SELECT class out into its own header and implementation files. |
701 |
used_lengths->append(buf, length); |
702 |
}
|
|
703 |
||
2318.6.54
by Olaf van der Spek
Refactor |
704 |
}
|
1280.1.10
by Monty Taylor
Put everything in drizzled into drizzled namespace. |
705 |
} /* namespace drizzled */ |