1039.2.1
by Jay Pipes
First phase refactoring the JOIN class: |
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; either version 2 of the License, or
|
|
9 |
* (at your option) any later version.
|
|
10 |
*
|
|
11 |
* This program is distributed in the hope that it will be useful,
|
|
12 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14 |
* GNU General Public License for more details.
|
|
15 |
*
|
|
16 |
* You should have received a copy of the GNU General Public License
|
|
17 |
* along with this program; if not, write to the Free Software
|
|
18 |
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
19 |
*/
|
|
20 |
||
21 |
/**
|
|
22 |
* @file
|
|
23 |
*
|
|
24 |
* Defines the JOIN class
|
|
25 |
*/
|
|
26 |
||
27 |
#ifndef DRIZZLED_JOIN_H
|
|
28 |
#define DRIZZLED_JOIN_H
|
|
29 |
||
30 |
class JOIN :public Sql_alloc |
|
31 |
{
|
|
32 |
JOIN(const JOIN &rhs); /**< not implemented */ |
|
33 |
JOIN& operator=(const JOIN &rhs); /**< not implemented */ |
|
34 |
public: |
|
35 |
JOIN_TAB *join_tab; |
|
36 |
JOIN_TAB **best_ref; |
|
37 |
JOIN_TAB **map2table; /**< mapping between table indexes and JOIN_TABs */ |
|
38 |
JOIN_TAB *join_tab_save; /**< saved join_tab for subquery reexecution */ |
|
39 |
||
40 |
Table **table; |
|
41 |
Table **all_tables; |
|
42 |
/**
|
|
43 |
The table which has an index that allows to produce the requried ordering.
|
|
44 |
A special value of 0x1 means that the ordering will be produced by
|
|
45 |
passing 1st non-const table to filesort(). NULL means no such table exists.
|
|
46 |
*/
|
|
47 |
Table *sort_by_table; |
|
48 |
||
49 |
uint32_t tables; /**< Number of tables in the join */ |
|
50 |
uint32_t outer_tables; /**< Number of tables that are not inside semijoin */ |
|
51 |
uint32_t const_tables; |
|
52 |
uint32_t send_group_parts; |
|
53 |
||
54 |
bool sort_and_group; |
|
55 |
bool first_record; |
|
56 |
bool full_join; |
|
57 |
bool group; |
|
58 |
bool no_field_update; |
|
59 |
bool do_send_rows; |
|
60 |
/**
|
|
61 |
true when we want to resume nested loop iterations when
|
|
62 |
fetching data from a cursor
|
|
63 |
*/
|
|
64 |
bool resume_nested_loop; |
|
65 |
/**
|
|
66 |
true <=> optimizer must not mark any table as a constant table.
|
|
67 |
This is needed for subqueries in form "a IN (SELECT .. UNION SELECT ..):
|
|
68 |
when we optimize the select that reads the results of the union from a
|
|
69 |
temporary table, we must not mark the temp. table as constant because
|
|
70 |
the number of rows in it may vary from one subquery execution to another.
|
|
71 |
*/
|
|
72 |
bool no_const_tables; |
|
73 |
bool select_distinct; /**< Set if SELECT DISTINCT */ |
|
74 |
/**
|
|
75 |
If we have the GROUP BY statement in the query,
|
|
76 |
but the group_list was emptied by optimizer, this
|
|
77 |
flag is true.
|
|
78 |
It happens when fields in the GROUP BY are from
|
|
79 |
constant table
|
|
80 |
*/
|
|
81 |
bool group_optimized_away; |
|
82 |
||
83 |
/*
|
|
84 |
simple_xxxxx is set if order_st/GROUP BY doesn't include any references
|
|
85 |
to other tables than the first non-constant table in the JOIN.
|
|
86 |
It's also set if order_st/GROUP BY is empty.
|
|
87 |
*/
|
|
88 |
bool simple_order; |
|
89 |
bool simple_group; |
|
90 |
/**
|
|
91 |
Is set only in case if we have a GROUP BY clause
|
|
92 |
and no order_st BY after constant elimination of 'order'.
|
|
93 |
*/
|
|
94 |
bool no_order; |
|
95 |
/** Is set if we have a GROUP BY and we have order_st BY on a constant. */
|
|
96 |
bool skip_sort_order; |
|
97 |
bool union_part; /**< this subselect is part of union */ |
|
98 |
bool optimized; /**< flag to avoid double optimization in EXPLAIN */ |
|
99 |
bool need_tmp; |
|
100 |
bool hidden_group_fields; |
|
101 |
||
102 |
table_map const_table_map; |
|
103 |
table_map found_const_table_map; |
|
104 |
table_map outer_join; |
|
105 |
||
106 |
ha_rows send_records; |
|
107 |
ha_rows found_records; |
|
108 |
ha_rows examined_rows; |
|
109 |
ha_rows row_limit; |
|
110 |
ha_rows select_limit; |
|
111 |
/**
|
|
112 |
Used to fetch no more than given amount of rows per one
|
|
113 |
fetch operation of server side cursor.
|
|
114 |
The value is checked in end_send and end_send_group in fashion, similar
|
|
115 |
to offset_limit_cnt:
|
|
116 |
- fetch_limit= HA_POS_ERROR if there is no cursor.
|
|
117 |
- when we open a cursor, we set fetch_limit to 0,
|
|
118 |
- on each fetch iteration we add num_rows to fetch to fetch_limit
|
|
119 |
*/
|
|
120 |
ha_rows fetch_limit; |
|
121 |
||
122 |
Session *session; |
|
123 |
List<Item> *fields; |
|
124 |
List<Item> &fields_list; /**< hold field list passed to mysql_select */ |
|
125 |
List<TableList> *join_list; /**< list of joined tables in reverse order */ |
|
126 |
/** unit structure (with global parameters) for this select */
|
|
127 |
Select_Lex_Unit *unit; |
|
128 |
/** select that processed */
|
|
129 |
Select_Lex *select_lex; |
|
130 |
SQL_SELECT *select; /**< created in optimisation phase */ |
|
131 |
Array<Item_in_subselect> sj_subselects; |
|
132 |
||
133 |
POSITION positions[MAX_TABLES+1]; |
|
134 |
POSITION best_positions[MAX_TABLES+1]; |
|
135 |
||
136 |
/**
|
|
137 |
Bitmap of nested joins embedding the position at the end of the current
|
|
138 |
partial join (valid only during join optimizer run).
|
|
139 |
*/
|
|
140 |
nested_join_map cur_embedding_map; |
|
141 |
||
142 |
double best_read; |
|
143 |
List<Cached_item> group_fields; |
|
144 |
List<Cached_item> group_fields_cache; |
|
145 |
Table *tmp_table; |
|
146 |
/** used to store 2 possible tmp table of SELECT */
|
|
147 |
Table *exec_tmp_table1; |
|
148 |
Table *exec_tmp_table2; |
|
149 |
Item_sum **sum_funcs; |
|
150 |
Item_sum ***sum_funcs_end; |
|
151 |
/** second copy of sumfuncs (for queries with 2 temporary tables */
|
|
152 |
Item_sum **sum_funcs2; |
|
153 |
Item_sum ***sum_funcs_end2; |
|
154 |
Item *having; |
|
155 |
Item *tmp_having; /**< To store having when processed temporary table */ |
|
156 |
Item *having_history; /**< Store having for explain */ |
|
157 |
uint64_t select_options; |
|
158 |
select_result *result; |
|
159 |
Tmp_Table_Param tmp_table_param; |
|
160 |
DRIZZLE_LOCK *lock; |
|
161 |
||
162 |
JOIN *tmp_join; /**< copy of this JOIN to be used with temporary tables */ |
|
163 |
ROLLUP rollup; /**< Used with rollup */ |
|
164 |
DYNAMIC_ARRAY keyuse; |
|
165 |
Item::cond_result cond_value; |
|
166 |
Item::cond_result having_value; |
|
167 |
List<Item> all_fields; /**< to store all fields that used in query */ |
|
168 |
/** Above list changed to use temporary table */
|
|
169 |
List<Item> tmp_all_fields1; |
|
170 |
List<Item> tmp_all_fields2; |
|
171 |
List<Item> tmp_all_fields3; |
|
172 |
/** Part, shared with list above, emulate following list */
|
|
173 |
List<Item> tmp_fields_list1; |
|
174 |
List<Item> tmp_fields_list2; |
|
175 |
List<Item> tmp_fields_list3; |
|
176 |
int error; |
|
177 |
||
178 |
order_st *order; |
|
179 |
order_st *group_list; /**< hold parameters of mysql_select */ |
|
180 |
COND *conds; // ---"--- |
|
181 |
Item *conds_history; /**< store WHERE for explain */ |
|
182 |
TableList *tables_list; /**< hold 'tables' parameter of mysql_select */ |
|
183 |
COND_EQUAL *cond_equal; |
|
184 |
JOIN_TAB *return_tab; /**< used only for outer joins */ |
|
185 |
Item **ref_pointer_array; /**< used pointer reference for this select */ |
|
186 |
/** Copy of above to be used with different lists */
|
|
187 |
Item **items0; |
|
188 |
Item **items1; |
|
189 |
Item **items2; |
|
190 |
Item **items3; |
|
191 |
Item **current_ref_pointer_array; |
|
192 |
uint32_t ref_pointer_array_size; ///< size of above in bytes |
|
193 |
const char *zero_result_cause; ///< not 0 if exec must return zero result |
|
194 |
||
195 |
/* Descriptions of temporary tables used to weed-out semi-join duplicates */
|
|
196 |
SJ_TMP_TABLE *sj_tmp_tables; |
|
197 |
||
198 |
table_map cur_emb_sj_nests; |
|
199 |
||
200 |
/*
|
|
201 |
storage for caching buffers allocated during query execution.
|
|
202 |
These buffers allocations need to be cached as the thread memory pool is
|
|
203 |
cleared only at the end of the execution of the whole query and not caching
|
|
204 |
allocations that occur in repetition at execution time will result in
|
|
205 |
excessive memory usage.
|
|
206 |
*/
|
|
207 |
SORT_FIELD *sortorder; // make_unireg_sortorder() |
|
208 |
Table **table_reexec; // make_simple_join() |
|
209 |
JOIN_TAB *join_tab_reexec; // make_simple_join() |
|
210 |
/* end of allocation caching storage */
|
|
211 |
||
212 |
/** Constructors */
|
|
213 |
JOIN(Session *session_arg, |
|
214 |
List<Item> &fields_arg, |
|
215 |
uint64_t select_options_arg, |
|
216 |
select_result *result_arg) |
|
217 |
:
|
|
218 |
join_tab(NULL), |
|
219 |
best_ref(NULL), |
|
220 |
map2table(NULL), |
|
221 |
join_tab_save(NULL), |
|
222 |
table(NULL), |
|
223 |
all_tables(NULL), |
|
224 |
sort_by_table(NULL), |
|
225 |
tables(0), |
|
226 |
outer_tables(0), |
|
227 |
const_tables(0), |
|
228 |
send_group_parts(0), |
|
229 |
sort_and_group(false), |
|
230 |
first_record(false), |
|
231 |
full_join(false), |
|
232 |
group(false), |
|
233 |
no_field_update(false), |
|
234 |
do_send_rows(true), |
|
235 |
resume_nested_loop(false), |
|
236 |
no_const_tables(false), |
|
237 |
select_distinct(false), |
|
238 |
group_optimized_away(false), |
|
239 |
simple_order(false), |
|
240 |
simple_group(false), |
|
241 |
no_order(false), |
|
242 |
skip_sort_order(false), |
|
243 |
union_part(false), |
|
244 |
optimized(false), |
|
245 |
need_tmp(false), |
|
246 |
hidden_group_fields(false), |
|
1054.2.1
by Monty Taylor
table_map takes ints, not pointers. |
247 |
const_table_map(0), |
248 |
found_const_table_map(0), |
|
249 |
outer_join(0), |
|
1039.2.1
by Jay Pipes
First phase refactoring the JOIN class: |
250 |
send_records(0), |
251 |
found_records(0), |
|
252 |
examined_rows(0), |
|
253 |
row_limit(0), |
|
254 |
select_limit(0), |
|
255 |
fetch_limit(HA_POS_ERROR), |
|
256 |
session(session_arg), |
|
257 |
fields_list(fields_arg), |
|
258 |
join_list(NULL), |
|
259 |
unit(NULL), |
|
260 |
select_lex(NULL), |
|
261 |
select(NULL), |
|
262 |
sj_subselects(session_arg->mem_root, 4), |
|
263 |
exec_tmp_table1(NULL), |
|
264 |
exec_tmp_table2(NULL), |
|
265 |
sum_funcs(NULL), |
|
266 |
sum_funcs2(NULL), |
|
267 |
having(NULL), |
|
268 |
tmp_having(NULL), |
|
269 |
having_history(NULL), |
|
270 |
select_options(select_options_arg), |
|
271 |
result(result_arg), |
|
272 |
lock(session_arg->lock), |
|
273 |
tmp_join(NULL), |
|
274 |
all_fields(fields_arg), |
|
275 |
error(0), |
|
276 |
cond_equal(NULL), |
|
277 |
return_tab(NULL), |
|
278 |
ref_pointer_array(NULL), |
|
279 |
items0(NULL), |
|
280 |
items1(NULL), |
|
281 |
items2(NULL), |
|
282 |
items3(NULL), |
|
283 |
ref_pointer_array_size(0), |
|
284 |
zero_result_cause(NULL), |
|
285 |
sj_tmp_tables(NULL), |
|
286 |
sortorder(NULL), |
|
287 |
table_reexec(NULL), |
|
288 |
join_tab_reexec(NULL) |
|
289 |
{
|
|
290 |
select_distinct= test(select_options & SELECT_DISTINCT); |
|
291 |
if (&fields_list != &fields_arg) /* only copy if not same*/ |
|
292 |
fields_list= fields_arg; |
|
293 |
memset(&keyuse, 0, sizeof(keyuse)); |
|
294 |
tmp_table_param.init(); |
|
295 |
tmp_table_param.end_write_records= HA_POS_ERROR; |
|
296 |
rollup.state= ROLLUP::STATE_NONE; |
|
297 |
}
|
|
298 |
||
299 |
/**
|
|
300 |
* This method is currently only used when a subselect EXPLAIN is performed.
|
|
301 |
* I pulled out the init() method and have simply reset the values to what
|
|
302 |
* was previously in the init() method. See the note about the hack in
|
|
303 |
* sql_union.cc...
|
|
304 |
*/
|
|
305 |
inline void reset(Session *session_arg, |
|
306 |
List<Item> &fields_arg, |
|
307 |
uint64_t select_options_arg, |
|
308 |
select_result *result_arg) |
|
309 |
{
|
|
310 |
join_tab= NULL; |
|
311 |
best_ref= NULL; |
|
312 |
map2table= NULL; |
|
313 |
join_tab_save= NULL; |
|
314 |
table= NULL; |
|
315 |
all_tables= NULL; |
|
316 |
sort_by_table= NULL; |
|
317 |
tables= 0; |
|
318 |
outer_tables= 0; |
|
319 |
const_tables= 0; |
|
320 |
send_group_parts= 0; |
|
321 |
sort_and_group= false; |
|
322 |
first_record= false; |
|
323 |
full_join= false; |
|
324 |
group= false; |
|
325 |
no_field_update= false; |
|
326 |
do_send_rows= true; |
|
327 |
resume_nested_loop= false; |
|
328 |
no_const_tables= false; |
|
329 |
select_distinct= false; |
|
330 |
group_optimized_away= false; |
|
331 |
simple_order= false; |
|
332 |
simple_group= false; |
|
333 |
no_order= false; |
|
334 |
skip_sort_order= false; |
|
335 |
union_part= false; |
|
336 |
optimized= false; |
|
337 |
need_tmp= false; |
|
338 |
hidden_group_fields= false; |
|
1054.2.1
by Monty Taylor
table_map takes ints, not pointers. |
339 |
const_table_map= 0; |
340 |
found_const_table_map= 0; |
|
341 |
outer_join= 0; |
|
1039.2.1
by Jay Pipes
First phase refactoring the JOIN class: |
342 |
send_records= 0; |
343 |
found_records= 0; |
|
344 |
examined_rows= 0; |
|
345 |
row_limit= 0; |
|
346 |
select_limit= 0; |
|
347 |
fetch_limit= HA_POS_ERROR; |
|
348 |
session= session_arg; |
|
349 |
fields_list= fields_arg; |
|
350 |
join_list= NULL; |
|
351 |
unit= NULL; |
|
352 |
select_lex= NULL; |
|
353 |
select= NULL; |
|
354 |
exec_tmp_table1= NULL; |
|
355 |
exec_tmp_table2= NULL; |
|
356 |
sum_funcs= NULL; |
|
357 |
sum_funcs2= NULL; |
|
358 |
having= NULL; |
|
359 |
tmp_having= NULL; |
|
360 |
having_history= NULL; |
|
361 |
select_options= select_options_arg; |
|
362 |
result= result_arg; |
|
363 |
lock= session_arg->lock; |
|
364 |
tmp_join= NULL; |
|
365 |
all_fields= fields_arg; |
|
366 |
error= 0; |
|
367 |
cond_equal= NULL; |
|
368 |
return_tab= NULL; |
|
369 |
ref_pointer_array= NULL; |
|
370 |
items0= NULL; |
|
371 |
items1= NULL; |
|
372 |
items2= NULL; |
|
373 |
items3= NULL; |
|
374 |
ref_pointer_array_size= 0; |
|
375 |
zero_result_cause= NULL; |
|
376 |
sj_tmp_tables= NULL; |
|
377 |
sortorder= NULL; |
|
378 |
table_reexec= NULL; |
|
379 |
join_tab_reexec= NULL; |
|
380 |
select_distinct= test(select_options & SELECT_DISTINCT); |
|
381 |
if (&fields_list != &fields_arg) /* only copy if not same*/ |
|
382 |
fields_list= fields_arg; |
|
383 |
memset(&keyuse, 0, sizeof(keyuse)); |
|
384 |
tmp_table_param.init(); |
|
385 |
tmp_table_param.end_write_records= HA_POS_ERROR; |
|
386 |
rollup.state= ROLLUP::STATE_NONE; |
|
387 |
}
|
|
388 |
||
389 |
int prepare(Item ***rref_pointer_array, |
|
390 |
TableList *tables, |
|
391 |
uint32_t wind_num, |
|
392 |
COND *conds, |
|
393 |
uint32_t og_num, |
|
394 |
order_st *order, |
|
395 |
order_st *group, |
|
396 |
Item *having, |
|
397 |
Select_Lex *select, |
|
398 |
Select_Lex_Unit *unit); |
|
399 |
int optimize(); |
|
400 |
int reinit(); |
|
401 |
void exec(); |
|
402 |
int destroy(); |
|
403 |
void restore_tmp(); |
|
404 |
bool alloc_func_list(); |
|
405 |
bool flatten_subqueries(); |
|
406 |
bool setup_subquery_materialization(); |
|
407 |
bool make_sum_func_list(List<Item> &all_fields, |
|
408 |
List<Item> &send_fields, |
|
409 |
bool before_group_by, |
|
410 |
bool recompute= false); |
|
411 |
||
412 |
inline void set_items_ref_array(Item **ptr) |
|
413 |
{
|
|
414 |
memcpy(ref_pointer_array, ptr, ref_pointer_array_size); |
|
415 |
current_ref_pointer_array= ptr; |
|
416 |
}
|
|
417 |
inline void init_items_ref_array() |
|
418 |
{
|
|
419 |
items0= ref_pointer_array + all_fields.elements; |
|
420 |
memcpy(items0, ref_pointer_array, ref_pointer_array_size); |
|
421 |
current_ref_pointer_array= items0; |
|
422 |
}
|
|
423 |
||
424 |
bool rollup_init(); |
|
425 |
bool rollup_make_fields(List<Item> &all_fields, |
|
426 |
List<Item> &fields, |
|
427 |
Item_sum ***func); |
|
428 |
int rollup_send_data(uint32_t idx); |
|
429 |
int rollup_write_data(uint32_t idx, Table *table); |
|
430 |
void remove_subq_pushed_predicates(Item **where); |
|
431 |
/**
|
|
432 |
Release memory and, if possible, the open tables held by this execution
|
|
433 |
plan (and nested plans). It's used to release some tables before
|
|
434 |
the end of execution in order to increase concurrency and reduce
|
|
435 |
memory consumption.
|
|
436 |
*/
|
|
437 |
void join_free(); |
|
438 |
/** Cleanup this JOIN, possibly for reuse */
|
|
439 |
void cleanup(bool full); |
|
440 |
void clear(); |
|
441 |
bool save_join_tab(); |
|
442 |
bool init_save_join_tab(); |
|
443 |
bool send_row_on_empty_set() |
|
444 |
{
|
|
445 |
return (do_send_rows && tmp_table_param.sum_func_count != 0 && |
|
446 |
!group_list); |
|
447 |
}
|
|
448 |
bool change_result(select_result *result); |
|
449 |
bool is_top_level_join() const |
|
450 |
{
|
|
451 |
return (unit == &session->lex->unit && (unit->fake_select_lex == 0 || |
|
452 |
select_lex == unit->fake_select_lex)); |
|
453 |
}
|
|
454 |
};
|
|
455 |
||
1039.2.2
by Jay Pipes
Phase 2 of JOIN refactoring. |
456 |
enum_nested_loop_state evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, int error); |
457 |
enum_nested_loop_state evaluate_null_complemented_join_record(JOIN *join, JOIN_TAB *join_tab); |
|
458 |
enum_nested_loop_state flush_cached_records(JOIN *join, JOIN_TAB *join_tab, bool skip_last); |
|
459 |
enum_nested_loop_state end_send(JOIN *join, JOIN_TAB *join_tab, bool end_of_records); |
|
460 |
enum_nested_loop_state end_write(JOIN *join, JOIN_TAB *join_tab, bool end_of_records); |
|
461 |
enum_nested_loop_state end_update(JOIN *join, JOIN_TAB *join_tab, bool end_of_records); |
|
462 |
enum_nested_loop_state end_unique_update(JOIN *join, JOIN_TAB *join_tab, bool end_of_records); |
|
463 |
||
1039.2.1
by Jay Pipes
First phase refactoring the JOIN class: |
464 |
#endif /* DRIZZLED_JOIN_H */ |