1
by brian
clean slate |
1 |
/* Copyright (C) 2000 MySQL AB
|
2 |
||
3 |
This program is free software; you can redistribute it and/or modify
|
|
4 |
it under the terms of the GNU General Public License as published by
|
|
5 |
the Free Software Foundation; version 2 of the License.
|
|
6 |
||
7 |
This program is distributed in the hope that it will be useful,
|
|
8 |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
9 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
10 |
GNU General Public License for more details.
|
|
11 |
||
12 |
You should have received a copy of the GNU General Public License
|
|
13 |
along with this program; if not, write to the Free Software
|
|
14 |
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
|
15 |
||
16 |
/* subselect Item */
|
|
17 |
||
18 |
#ifdef USE_PRAGMA_INTERFACE
|
|
19 |
#pragma interface /* gcc class implementation */ |
|
20 |
#endif
|
|
21 |
||
22 |
class st_select_lex; |
|
23 |
class st_select_lex_unit; |
|
24 |
class JOIN; |
|
25 |
class select_result_interceptor; |
|
26 |
class subselect_engine; |
|
27 |
class subselect_hash_sj_engine; |
|
28 |
class Item_bool_func2; |
|
29 |
class Cached_item; |
|
30 |
||
31 |
/* base class for subselects */
|
|
32 |
||
33 |
class Item_subselect :public Item_result_field |
|
34 |
{
|
|
35 |
my_bool value_assigned; /* value already assigned to subselect */ |
|
36 |
public: |
|
37 |
/* thread handler, will be assigned in fix_fields only */
|
|
38 |
THD *thd; |
|
39 |
/* substitution instead of subselect in case of optimization */
|
|
40 |
Item *substitution; |
|
41 |
/* unit of subquery */
|
|
42 |
public: |
|
43 |
st_select_lex_unit *unit; |
|
44 |
protected: |
|
45 |
/* engine that perform execution of subselect (single select or union) */
|
|
46 |
subselect_engine *engine; |
|
47 |
/* old engine if engine was changed */
|
|
48 |
subselect_engine *old_engine; |
|
49 |
/* cache of used external tables */
|
|
50 |
table_map used_tables_cache; |
|
51 |
/* allowed number of columns (1 for single value subqueries) */
|
|
52 |
uint max_columns; |
|
53 |
/* where subquery is placed */
|
|
54 |
enum_parsing_place parsing_place; |
|
55 |
/* work with 'substitution' */
|
|
56 |
bool have_to_be_excluded; |
|
57 |
/* cache of constant state */
|
|
58 |
bool const_item_cache; |
|
59 |
||
60 |
public: |
|
61 |
/* changed engine indicator */
|
|
62 |
bool engine_changed; |
|
63 |
/* subquery is transformed */
|
|
64 |
bool changed; |
|
65 |
||
66 |
/* TRUE <=> The underlying SELECT is correlated w.r.t some ancestor select */
|
|
67 |
bool is_correlated; |
|
68 |
||
69 |
enum trans_res {RES_OK, RES_REDUCE, RES_ERROR}; |
|
70 |
enum subs_type {UNKNOWN_SUBS, SINGLEROW_SUBS, |
|
71 |
EXISTS_SUBS, IN_SUBS, ALL_SUBS, ANY_SUBS}; |
|
72 |
||
73 |
Item_subselect(); |
|
74 |
||
75 |
virtual subs_type substype() { return UNKNOWN_SUBS; } |
|
76 |
||
77 |
/*
|
|
78 |
We need this method, because some compilers do not allow 'this'
|
|
79 |
pointer in constructor initialization list, but we need to pass a pointer
|
|
80 |
to subselect Item class to select_result_interceptor's constructor.
|
|
81 |
*/
|
|
82 |
virtual void init (st_select_lex *select_lex, |
|
83 |
select_result_interceptor *result); |
|
84 |
||
85 |
~Item_subselect(); |
|
86 |
void cleanup(); |
|
87 |
virtual void reset() |
|
88 |
{
|
|
89 |
null_value= 1; |
|
90 |
}
|
|
91 |
virtual trans_res select_transformer(JOIN *join); |
|
92 |
bool assigned() { return value_assigned; } |
|
93 |
void assigned(bool a) { value_assigned= a; } |
|
94 |
enum Type type() const; |
|
95 |
bool is_null() |
|
96 |
{
|
|
97 |
update_null_value(); |
|
98 |
return null_value; |
|
99 |
}
|
|
100 |
bool fix_fields(THD *thd, Item **ref); |
|
101 |
virtual bool exec(); |
|
102 |
virtual void fix_length_and_dec(); |
|
103 |
table_map used_tables() const; |
|
104 |
table_map not_null_tables() const { return 0; } |
|
105 |
bool const_item() const; |
|
106 |
inline table_map get_used_tables_cache() { return used_tables_cache; } |
|
107 |
inline bool get_const_item_cache() { return const_item_cache; } |
|
108 |
Item *get_tmp_table_item(THD *thd); |
|
109 |
void update_used_tables(); |
|
110 |
virtual void print(String *str, enum_query_type query_type); |
|
51.1.24
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
111 |
virtual bool have_guarded_conds() { return false; } |
1
by brian
clean slate |
112 |
bool change_engine(subselect_engine *eng) |
113 |
{
|
|
114 |
old_engine= engine; |
|
115 |
engine= eng; |
|
116 |
engine_changed= 1; |
|
117 |
return eng == 0; |
|
118 |
}
|
|
119 |
/*
|
|
120 |
True if this subquery has been already evaluated. Implemented only for
|
|
121 |
single select and union subqueries only.
|
|
122 |
*/
|
|
123 |
bool is_evaluated() const; |
|
124 |
bool is_uncacheable() const; |
|
125 |
||
126 |
/*
|
|
127 |
Used by max/min subquery to initialize value presence registration
|
|
128 |
mechanism. Engine call this method before rexecution query.
|
|
129 |
*/
|
|
130 |
virtual void reset_value_registration() {} |
|
131 |
enum_parsing_place place() { return parsing_place; } |
|
132 |
bool walk(Item_processor processor, bool walk_subquery, uchar *arg); |
|
133 |
||
134 |
/**
|
|
135 |
Get the SELECT_LEX structure associated with this Item.
|
|
136 |
@return the SELECT_LEX structure associated with this Item
|
|
137 |
*/
|
|
138 |
st_select_lex* get_select_lex(); |
|
139 |
||
140 |
friend class select_result_interceptor; |
|
141 |
friend class Item_in_optimizer; |
|
142 |
friend bool Item_field::fix_fields(THD *, Item **); |
|
143 |
friend int Item_field::fix_outer_field(THD *, Field **, Item **); |
|
144 |
friend bool Item_ref::fix_fields(THD *, Item **); |
|
145 |
friend void mark_select_range_as_dependent(THD*, |
|
146 |
st_select_lex*, st_select_lex*, |
|
147 |
Field*, Item*, Item_ident*); |
|
148 |
};
|
|
149 |
||
150 |
/* single value subselect */
|
|
151 |
||
152 |
class Item_cache; |
|
153 |
class Item_singlerow_subselect :public Item_subselect |
|
154 |
{
|
|
155 |
protected: |
|
156 |
Item_cache *value, **row; |
|
157 |
public: |
|
158 |
Item_singlerow_subselect(st_select_lex *select_lex); |
|
159 |
Item_singlerow_subselect() :Item_subselect(), value(0), row (0) {} |
|
160 |
||
161 |
void cleanup(); |
|
162 |
subs_type substype() { return SINGLEROW_SUBS; } |
|
163 |
||
164 |
void reset(); |
|
165 |
trans_res select_transformer(JOIN *join); |
|
166 |
void store(uint i, Item* item); |
|
167 |
double val_real(); |
|
152
by Brian Aker
longlong replacement |
168 |
int64_t val_int (); |
1
by brian
clean slate |
169 |
String *val_str (String *); |
170 |
my_decimal *val_decimal(my_decimal *); |
|
171 |
bool val_bool(); |
|
172 |
enum Item_result result_type() const; |
|
173 |
enum_field_types field_type() const; |
|
174 |
void fix_length_and_dec(); |
|
175 |
||
176 |
uint cols(); |
|
177 |
Item* element_index(uint i) { return my_reinterpret_cast(Item*)(row[i]); } |
|
178 |
Item** addr(uint i) { return (Item**)row + i; } |
|
179 |
bool check_cols(uint c); |
|
180 |
bool null_inside(); |
|
181 |
void bring_value(); |
|
182 |
||
183 |
/**
|
|
184 |
This method is used to implement a special case of semantic tree
|
|
185 |
rewriting, mandated by a SQL:2003 exception in the specification.
|
|
186 |
The only caller of this method is handle_sql2003_note184_exception(),
|
|
187 |
see the code there for more details.
|
|
188 |
Note that this method breaks the object internal integrity, by
|
|
189 |
removing it's association with the corresponding SELECT_LEX,
|
|
190 |
making this object orphan from the parse tree.
|
|
191 |
No other method, beside the destructor, should be called on this
|
|
192 |
object, as it is now invalid.
|
|
193 |
@return the SELECT_LEX structure that was given in the constructor.
|
|
194 |
*/
|
|
195 |
st_select_lex* invalidate_and_restore_select_lex(); |
|
196 |
||
197 |
friend class select_singlerow_subselect; |
|
198 |
};
|
|
199 |
||
200 |
/* used in static ALL/ANY optimization */
|
|
201 |
class select_max_min_finder_subselect; |
|
202 |
class Item_maxmin_subselect :public Item_singlerow_subselect |
|
203 |
{
|
|
204 |
protected: |
|
205 |
bool max; |
|
206 |
bool was_values; // Set if we have found at least one row |
|
207 |
public: |
|
208 |
Item_maxmin_subselect(THD *thd, Item_subselect *parent, |
|
209 |
st_select_lex *select_lex, bool max); |
|
210 |
virtual void print(String *str, enum_query_type query_type); |
|
211 |
void cleanup(); |
|
212 |
bool any_value() { return was_values; } |
|
51.1.24
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
213 |
void register_value() { was_values= true; } |
214 |
void reset_value_registration() { was_values= false; } |
|
1
by brian
clean slate |
215 |
};
|
216 |
||
217 |
/* exists subselect */
|
|
218 |
||
219 |
class Item_exists_subselect :public Item_subselect |
|
220 |
{
|
|
221 |
protected: |
|
222 |
bool value; /* value of this item (boolean: exists/not-exists) */ |
|
223 |
||
224 |
public: |
|
225 |
Item_exists_subselect(st_select_lex *select_lex); |
|
226 |
Item_exists_subselect(): Item_subselect() {} |
|
227 |
||
228 |
subs_type substype() { return EXISTS_SUBS; } |
|
229 |
void reset() |
|
230 |
{
|
|
231 |
value= 0; |
|
232 |
}
|
|
233 |
||
234 |
enum Item_result result_type() const { return INT_RESULT;} |
|
152
by Brian Aker
longlong replacement |
235 |
int64_t val_int(); |
1
by brian
clean slate |
236 |
double val_real(); |
237 |
String *val_str(String*); |
|
238 |
my_decimal *val_decimal(my_decimal *); |
|
239 |
bool val_bool(); |
|
240 |
void fix_length_and_dec(); |
|
241 |
virtual void print(String *str, enum_query_type query_type); |
|
242 |
||
243 |
friend class select_exists_subselect; |
|
244 |
friend class subselect_uniquesubquery_engine; |
|
245 |
friend class subselect_indexsubquery_engine; |
|
246 |
};
|
|
247 |
||
248 |
||
249 |
/**
|
|
250 |
Representation of IN subquery predicates of the form
|
|
251 |
"left_expr IN (SELECT ...)".
|
|
252 |
||
253 |
@detail
|
|
254 |
This class has:
|
|
255 |
- A "subquery execution engine" (as a subclass of Item_subselect) that allows
|
|
256 |
it to evaluate subqueries. (and this class participates in execution by
|
|
257 |
having was_null variable where part of execution result is stored.
|
|
258 |
- Transformation methods (todo: more on this).
|
|
259 |
||
260 |
This class is not used directly, it is "wrapped" into Item_in_optimizer
|
|
261 |
which provides some small bits of subquery evaluation.
|
|
262 |
*/
|
|
263 |
||
264 |
class Item_in_subselect :public Item_exists_subselect |
|
265 |
{
|
|
266 |
public: |
|
267 |
Item *left_expr; |
|
268 |
protected: |
|
269 |
/*
|
|
270 |
Cache of the left operand of the subquery predicate. Allocated in the
|
|
271 |
runtime memory root, for each execution, thus need not be freed.
|
|
272 |
*/
|
|
273 |
List<Cached_item> *left_expr_cache; |
|
274 |
bool first_execution; |
|
275 |
||
276 |
/*
|
|
277 |
expr & optimizer used in subselect rewriting to store Item for
|
|
278 |
all JOIN in UNION
|
|
279 |
*/
|
|
280 |
Item *expr; |
|
281 |
Item_in_optimizer *optimizer; |
|
282 |
bool was_null; |
|
283 |
bool abort_on_null; |
|
284 |
||
285 |
public: |
|
286 |
/* Used to trigger on/off conditions that were pushed down to subselect */
|
|
287 |
bool *pushed_cond_guards; |
|
288 |
||
289 |
/* Priority of this predicate in the convert-to-semi-join-nest process. */
|
|
290 |
int sj_convert_priority; |
|
291 |
||
292 |
/*
|
|
293 |
Location of the subquery predicate. It is either
|
|
294 |
- pointer to join nest if the subquery predicate is in the ON expression
|
|
295 |
- (TABLE_LIST*)1 if the predicate is in the WHERE.
|
|
296 |
*/
|
|
297 |
TABLE_LIST *expr_join_nest; |
|
298 |
||
299 |
/* The method chosen to execute the IN predicate. */
|
|
300 |
enum enum_exec_method { |
|
301 |
NOT_TRANSFORMED, /* No execution method was chosen for this IN. */ |
|
302 |
SEMI_JOIN, /* IN was converted to semi-join nest and should be removed. */ |
|
303 |
IN_TO_EXISTS, /* IN was converted to correlated EXISTS. */ |
|
304 |
MATERIALIZATION /* IN will be executed via subquery materialization. */ |
|
305 |
};
|
|
306 |
enum_exec_method exec_method; |
|
307 |
||
308 |
bool *get_cond_guard(int i) |
|
309 |
{
|
|
310 |
return pushed_cond_guards ? pushed_cond_guards + i : NULL; |
|
311 |
}
|
|
312 |
void set_cond_guard_var(int i, bool v) |
|
313 |
{
|
|
314 |
if ( pushed_cond_guards) |
|
315 |
pushed_cond_guards[i]= v; |
|
316 |
}
|
|
317 |
bool have_guarded_conds() { return test(pushed_cond_guards); } |
|
318 |
||
319 |
Item_func_not_all *upper_item; // point on NOT/NOP before ALL/SOME subquery |
|
320 |
||
321 |
Item_in_subselect(Item * left_expr, st_select_lex *select_lex); |
|
322 |
Item_in_subselect() |
|
51.1.24
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
323 |
:Item_exists_subselect(), left_expr_cache(0), first_execution(true), |
1
by brian
clean slate |
324 |
optimizer(0), abort_on_null(0), pushed_cond_guards(NULL), |
325 |
exec_method(NOT_TRANSFORMED), upper_item(0) |
|
326 |
{}
|
|
327 |
void cleanup(); |
|
328 |
subs_type substype() { return IN_SUBS; } |
|
329 |
void reset() |
|
330 |
{
|
|
331 |
value= 0; |
|
332 |
null_value= 0; |
|
333 |
was_null= 0; |
|
334 |
}
|
|
335 |
trans_res select_transformer(JOIN *join); |
|
336 |
trans_res select_in_like_transformer(JOIN *join, Comp_creator *func); |
|
337 |
trans_res single_value_transformer(JOIN *join, Comp_creator *func); |
|
338 |
trans_res row_value_transformer(JOIN * join); |
|
339 |
trans_res single_value_in_to_exists_transformer(JOIN * join, |
|
340 |
Comp_creator *func); |
|
341 |
trans_res row_value_in_to_exists_transformer(JOIN * join); |
|
342 |
virtual bool exec(); |
|
152
by Brian Aker
longlong replacement |
343 |
int64_t val_int(); |
1
by brian
clean slate |
344 |
double val_real(); |
345 |
String *val_str(String*); |
|
346 |
my_decimal *val_decimal(my_decimal *); |
|
347 |
void update_null_value () { (void) val_bool(); } |
|
348 |
bool val_bool(); |
|
349 |
void top_level_item() { abort_on_null=1; } |
|
350 |
inline bool is_top_level_item() { return abort_on_null; } |
|
351 |
bool test_limit(st_select_lex_unit *unit); |
|
352 |
virtual void print(String *str, enum_query_type query_type); |
|
353 |
bool fix_fields(THD *thd, Item **ref); |
|
354 |
bool setup_engine(); |
|
355 |
bool init_left_expr_cache(); |
|
356 |
bool is_expensive_processor(uchar *arg); |
|
357 |
||
358 |
friend class Item_ref_null_helper; |
|
359 |
friend class Item_is_not_null_test; |
|
360 |
friend class Item_in_optimizer; |
|
361 |
friend class subselect_indexsubquery_engine; |
|
362 |
friend class subselect_hash_sj_engine; |
|
363 |
};
|
|
364 |
||
365 |
||
366 |
/* ALL/ANY/SOME subselect */
|
|
367 |
class Item_allany_subselect :public Item_in_subselect |
|
368 |
{
|
|
369 |
public: |
|
370 |
chooser_compare_func_creator func_creator; |
|
371 |
Comp_creator *func; |
|
372 |
bool all; |
|
373 |
||
374 |
Item_allany_subselect(Item * left_expr, chooser_compare_func_creator fc, |
|
375 |
st_select_lex *select_lex, bool all); |
|
376 |
||
377 |
// only ALL subquery has upper not
|
|
378 |
subs_type substype() { return all?ALL_SUBS:ANY_SUBS; } |
|
379 |
trans_res select_transformer(JOIN *join); |
|
380 |
virtual void print(String *str, enum_query_type query_type); |
|
381 |
};
|
|
382 |
||
383 |
||
384 |
class subselect_engine: public Sql_alloc |
|
385 |
{
|
|
386 |
protected: |
|
387 |
select_result_interceptor *result; /* results storage class */ |
|
388 |
THD *thd; /* pointer to current THD */ |
|
389 |
Item_subselect *item; /* item, that use this engine */ |
|
390 |
enum Item_result res_type; /* type of results */ |
|
391 |
enum_field_types res_field_type; /* column type of the results */ |
|
392 |
bool maybe_null; /* may be null (first item in select) */ |
|
393 |
public: |
|
394 |
||
395 |
enum enum_engine_type {ABSTRACT_ENGINE, SINGLE_SELECT_ENGINE, |
|
396 |
UNION_ENGINE, UNIQUESUBQUERY_ENGINE, |
|
397 |
INDEXSUBQUERY_ENGINE, HASH_SJ_ENGINE}; |
|
398 |
||
399 |
subselect_engine(Item_subselect *si, select_result_interceptor *res) |
|
400 |
:thd(0) |
|
401 |
{
|
|
402 |
result= res; |
|
403 |
item= si; |
|
404 |
res_type= STRING_RESULT; |
|
99
by Brian Aker
Second pass at removing old varchar. |
405 |
res_field_type= MYSQL_TYPE_STRING; |
1
by brian
clean slate |
406 |
maybe_null= 0; |
407 |
}
|
|
408 |
virtual ~subselect_engine() {}; // to satisfy compiler |
|
409 |
virtual void cleanup()= 0; |
|
410 |
||
411 |
/*
|
|
412 |
Also sets "thd" for subselect_engine::result.
|
|
413 |
Should be called before prepare().
|
|
414 |
*/
|
|
415 |
void set_thd(THD *thd_arg); |
|
416 |
THD * get_thd() { return thd; } |
|
417 |
virtual int prepare()= 0; |
|
418 |
virtual void fix_length_and_dec(Item_cache** row)= 0; |
|
419 |
/*
|
|
420 |
Execute the engine
|
|
421 |
||
422 |
SYNOPSIS
|
|
423 |
exec()
|
|
424 |
||
425 |
DESCRIPTION
|
|
426 |
Execute the engine. The result of execution is subquery value that is
|
|
427 |
either captured by previously set up select_result-based 'sink' or
|
|
428 |
stored somewhere by the exec() method itself.
|
|
429 |
||
430 |
A required side effect: If at least one pushed-down predicate is
|
|
431 |
disabled, subselect_engine->no_rows() must return correct result after
|
|
432 |
the exec() call.
|
|
433 |
||
434 |
RETURN
|
|
435 |
0 - OK
|
|
436 |
1 - Either an execution error, or the engine was "changed", and the
|
|
437 |
caller should call exec() again for the new engine.
|
|
438 |
*/
|
|
439 |
virtual int exec()= 0; |
|
440 |
virtual uint cols()= 0; /* return number of columns in select */ |
|
441 |
virtual uint8 uncacheable()= 0; /* query is uncacheable */ |
|
442 |
enum Item_result type() { return res_type; } |
|
443 |
enum_field_types field_type() { return res_field_type; } |
|
444 |
virtual void exclude()= 0; |
|
445 |
virtual bool may_be_null() { return maybe_null; }; |
|
446 |
virtual table_map upper_select_const_tables()= 0; |
|
447 |
static table_map calc_const_tables(TABLE_LIST *); |
|
448 |
virtual void print(String *str, enum_query_type query_type)= 0; |
|
449 |
virtual bool change_result(Item_subselect *si, |
|
450 |
select_result_interceptor *result)= 0; |
|
451 |
virtual bool no_tables()= 0; |
|
51.1.24
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
452 |
virtual bool is_executed() const { return false; } |
1
by brian
clean slate |
453 |
/* Check if subquery produced any rows during last query execution */
|
454 |
virtual bool no_rows() = 0; |
|
455 |
virtual enum_engine_type engine_type() { return ABSTRACT_ENGINE; } |
|
456 |
||
457 |
protected: |
|
458 |
void set_row(List<Item> &item_list, Item_cache **row); |
|
459 |
};
|
|
460 |
||
461 |
||
462 |
class subselect_single_select_engine: public subselect_engine |
|
463 |
{
|
|
464 |
my_bool prepared; /* simple subselect is prepared */ |
|
465 |
my_bool optimized; /* simple subselect is optimized */ |
|
466 |
my_bool executed; /* simple subselect is executed */ |
|
467 |
st_select_lex *select_lex; /* corresponding select_lex */ |
|
468 |
JOIN * join; /* corresponding JOIN structure */ |
|
469 |
public: |
|
470 |
subselect_single_select_engine(st_select_lex *select, |
|
471 |
select_result_interceptor *result, |
|
472 |
Item_subselect *item); |
|
473 |
void cleanup(); |
|
474 |
int prepare(); |
|
475 |
void fix_length_and_dec(Item_cache** row); |
|
476 |
int exec(); |
|
477 |
uint cols(); |
|
478 |
uint8 uncacheable(); |
|
479 |
void exclude(); |
|
480 |
table_map upper_select_const_tables(); |
|
481 |
virtual void print (String *str, enum_query_type query_type); |
|
482 |
bool change_result(Item_subselect *si, select_result_interceptor *result); |
|
483 |
bool no_tables(); |
|
484 |
bool may_be_null(); |
|
485 |
bool is_executed() const { return executed; } |
|
486 |
bool no_rows(); |
|
487 |
virtual enum_engine_type engine_type() { return SINGLE_SELECT_ENGINE; } |
|
488 |
||
489 |
friend class subselect_hash_sj_engine; |
|
490 |
friend class Item_in_subselect; |
|
491 |
};
|
|
492 |
||
493 |
||
494 |
class subselect_union_engine: public subselect_engine |
|
495 |
{
|
|
496 |
st_select_lex_unit *unit; /* corresponding unit structure */ |
|
497 |
public: |
|
498 |
subselect_union_engine(st_select_lex_unit *u, |
|
499 |
select_result_interceptor *result, |
|
500 |
Item_subselect *item); |
|
501 |
void cleanup(); |
|
502 |
int prepare(); |
|
503 |
void fix_length_and_dec(Item_cache** row); |
|
504 |
int exec(); |
|
505 |
uint cols(); |
|
506 |
uint8 uncacheable(); |
|
507 |
void exclude(); |
|
508 |
table_map upper_select_const_tables(); |
|
509 |
virtual void print (String *str, enum_query_type query_type); |
|
510 |
bool change_result(Item_subselect *si, select_result_interceptor *result); |
|
511 |
bool no_tables(); |
|
512 |
bool is_executed() const; |
|
513 |
bool no_rows(); |
|
514 |
virtual enum_engine_type engine_type() { return UNION_ENGINE; } |
|
515 |
};
|
|
516 |
||
517 |
||
518 |
struct st_join_table; |
|
519 |
||
520 |
||
521 |
/*
|
|
522 |
A subquery execution engine that evaluates the subquery by doing one index
|
|
523 |
lookup in a unique index.
|
|
524 |
||
525 |
This engine is used to resolve subqueries in forms
|
|
526 |
|
|
527 |
outer_expr IN (SELECT tbl.unique_key FROM tbl WHERE subq_where)
|
|
528 |
|
|
529 |
or, tuple-based:
|
|
530 |
|
|
531 |
(oe1, .. oeN) IN (SELECT uniq_key_part1, ... uniq_key_partK
|
|
532 |
FROM tbl WHERE subqwhere)
|
|
533 |
|
|
534 |
i.e. the subquery is a single table SELECT without GROUP BY, aggregate
|
|
535 |
functions, etc.
|
|
536 |
*/
|
|
537 |
||
538 |
class subselect_uniquesubquery_engine: public subselect_engine |
|
539 |
{
|
|
540 |
protected: |
|
541 |
st_join_table *tab; |
|
542 |
Item *cond; /* The WHERE condition of subselect */ |
|
543 |
/*
|
|
544 |
TRUE<=> last execution produced empty set. Valid only when left
|
|
545 |
expression is NULL.
|
|
546 |
*/
|
|
547 |
bool empty_result_set; |
|
548 |
bool null_keypart; /* TRUE <=> constructed search tuple has a NULL */ |
|
549 |
public: |
|
550 |
||
551 |
// constructor can assign THD because it will be called after JOIN::prepare
|
|
552 |
subselect_uniquesubquery_engine(THD *thd_arg, st_join_table *tab_arg, |
|
553 |
Item_subselect *subs, Item *where) |
|
554 |
:subselect_engine(subs, 0), tab(tab_arg), cond(where) |
|
555 |
{
|
|
556 |
set_thd(thd_arg); |
|
557 |
}
|
|
558 |
void cleanup(); |
|
559 |
int prepare(); |
|
560 |
void fix_length_and_dec(Item_cache** row); |
|
561 |
int exec(); |
|
562 |
uint cols() { return 1; } |
|
563 |
uint8 uncacheable() { return UNCACHEABLE_DEPENDENT; } |
|
564 |
void exclude(); |
|
565 |
table_map upper_select_const_tables() { return 0; } |
|
566 |
virtual void print (String *str, enum_query_type query_type); |
|
567 |
bool change_result(Item_subselect *si, select_result_interceptor *result); |
|
568 |
bool no_tables(); |
|
569 |
int scan_table(); |
|
570 |
bool copy_ref_key(); |
|
571 |
bool no_rows() { return empty_result_set; } |
|
572 |
virtual enum_engine_type engine_type() { return UNIQUESUBQUERY_ENGINE; } |
|
573 |
};
|
|
574 |
||
575 |
||
576 |
class subselect_indexsubquery_engine: public subselect_uniquesubquery_engine |
|
577 |
{
|
|
578 |
/* FALSE for 'ref', TRUE for 'ref-or-null'. */
|
|
579 |
bool check_null; |
|
580 |
/*
|
|
581 |
The "having" clause. This clause (further reffered to as "artificial
|
|
582 |
having") was inserted by subquery transformation code. It contains
|
|
583 |
Item(s) that have a side-effect: they record whether the subquery has
|
|
584 |
produced a row with NULL certain components. We need to use it for cases
|
|
585 |
like
|
|
586 |
(oe1, oe2) IN (SELECT t.key, t.no_key FROM t1)
|
|
587 |
where we do index lookup on t.key=oe1 but need also to check if there
|
|
588 |
was a row such that t.no_key IS NULL.
|
|
589 |
|
|
590 |
NOTE: This is currently here and not in the uniquesubquery_engine. Ideally
|
|
591 |
it should have been in uniquesubquery_engine in order to allow execution of
|
|
592 |
subqueries like
|
|
593 |
|
|
594 |
(oe1, oe2) IN (SELECT primary_key, non_key_maybe_null_field FROM tbl)
|
|
595 |
||
596 |
We could use uniquesubquery_engine for the first component and let
|
|
597 |
Item_is_not_null_test( non_key_maybe_null_field) to handle the second.
|
|
598 |
||
599 |
However, subqueries like the above are currently not handled by index
|
|
600 |
lookup-based subquery engines, the engine applicability check misses
|
|
601 |
them: it doesn't switch the engine for case of artificial having and
|
|
602 |
[eq_]ref access (only for artifical having + ref_or_null or no having).
|
|
603 |
The above example subquery is handled as a full-blown SELECT with eq_ref
|
|
604 |
access to one table.
|
|
605 |
||
606 |
Due to this limitation, the "artificial having" currently needs to be
|
|
607 |
checked by only in indexsubquery_engine.
|
|
608 |
*/
|
|
609 |
Item *having; |
|
610 |
public: |
|
611 |
||
612 |
// constructor can assign THD because it will be called after JOIN::prepare
|
|
613 |
subselect_indexsubquery_engine(THD *thd_arg, st_join_table *tab_arg, |
|
614 |
Item_subselect *subs, Item *where, |
|
615 |
Item *having_arg, bool chk_null) |
|
616 |
:subselect_uniquesubquery_engine(thd_arg, tab_arg, subs, where), |
|
617 |
check_null(chk_null), |
|
618 |
having(having_arg) |
|
619 |
{}
|
|
620 |
int exec(); |
|
621 |
virtual void print (String *str, enum_query_type query_type); |
|
622 |
virtual enum_engine_type engine_type() { return INDEXSUBQUERY_ENGINE; } |
|
623 |
};
|
|
624 |
||
625 |
||
626 |
inline bool Item_subselect::is_evaluated() const |
|
627 |
{
|
|
628 |
return engine->is_executed(); |
|
629 |
}
|
|
630 |
||
631 |
||
632 |
inline bool Item_subselect::is_uncacheable() const |
|
633 |
{
|
|
634 |
return engine->uncacheable(); |
|
635 |
}
|
|
636 |
||
637 |
||
638 |
/**
|
|
639 |
Compute an IN predicate via a hash semi-join. The subquery is materialized
|
|
640 |
during the first evaluation of the IN predicate. The IN predicate is executed
|
|
641 |
via the functionality inherited from subselect_uniquesubquery_engine.
|
|
642 |
*/
|
|
643 |
||
644 |
class subselect_hash_sj_engine: public subselect_uniquesubquery_engine |
|
645 |
{
|
|
646 |
protected: |
|
647 |
/* TRUE if the subquery was materialized into a temp table. */
|
|
648 |
bool is_materialized; |
|
649 |
/*
|
|
650 |
The old engine already chosen at parse time and stored in permanent memory.
|
|
651 |
Through this member we can re-create and re-prepare materialize_join for
|
|
652 |
each execution of a prepared statement. We akso resuse the functionality
|
|
653 |
of subselect_single_select_engine::[prepare | cols].
|
|
654 |
*/
|
|
655 |
subselect_single_select_engine *materialize_engine; |
|
656 |
/*
|
|
657 |
QEP to execute the subquery and materialize its result into a
|
|
658 |
temporary table. Created during the first call to exec().
|
|
659 |
*/
|
|
660 |
JOIN *materialize_join; |
|
661 |
/* Temp table context of the outer select's JOIN. */
|
|
662 |
TMP_TABLE_PARAM *tmp_param; |
|
663 |
||
664 |
public: |
|
665 |
subselect_hash_sj_engine(THD *thd, Item_subselect *in_predicate, |
|
666 |
subselect_single_select_engine *old_engine) |
|
667 |
:subselect_uniquesubquery_engine(thd, NULL, in_predicate, NULL), |
|
51.1.24
by Jay Pipes
Removed DBUG symbols and fixed TRUE/FALSE |
668 |
is_materialized(false), materialize_engine(old_engine), |
1
by brian
clean slate |
669 |
materialize_join(NULL), tmp_param(NULL) |
670 |
{}
|
|
671 |
~subselect_hash_sj_engine(); |
|
672 |
||
673 |
bool init_permanent(List<Item> *tmp_columns); |
|
674 |
bool init_runtime(); |
|
675 |
void cleanup(); |
|
676 |
int prepare() { return 0; } |
|
677 |
int exec(); |
|
678 |
virtual void print (String *str, enum_query_type query_type); |
|
679 |
uint cols() |
|
680 |
{
|
|
681 |
return materialize_engine->cols(); |
|
682 |
}
|
|
683 |
virtual enum_engine_type engine_type() { return HASH_SJ_ENGINE; } |
|
684 |
};
|