summaryrefslogtreecommitdiff
path: root/sql/item_subselect.h
diff options
context:
space:
mode:
Diffstat (limited to 'sql/item_subselect.h')
-rw-r--r--sql/item_subselect.h145
1 files changed, 119 insertions, 26 deletions
diff --git a/sql/item_subselect.h b/sql/item_subselect.h
index 1085011915d..74faa7b84ac 100644
--- a/sql/item_subselect.h
+++ b/sql/item_subselect.h
@@ -22,9 +22,11 @@
class st_select_lex;
class st_select_lex_unit;
class JOIN;
-class select_subselect;
+class select_result_interceptor;
class subselect_engine;
+class subselect_hash_sj_engine;
class Item_bool_func2;
+class Cached_item;
/* base class for subselects */
@@ -34,7 +36,18 @@ class Item_subselect :public Item_result_field
public:
/* thread handler, will be assigned in fix_fields only */
THD *thd;
- /* substitution instead of subselect in case of optimization */
+ /*
+ Used inside Item_subselect::fix_fields() according to this scenario:
+ > Item_subselect::fix_fields
+ > engine->prepare
+ > child_join->prepare
+ (Here we realize we need to do the rewrite and set
+ substitution= some new Item, eg. Item_in_optimizer )
+ < child_join->prepare
+ < engine->prepare
+ *ref= substitution;
+ < Item_subselect::fix_fields
+ */
Item *substitution;
public:
/* unit of subquery */
@@ -54,7 +67,7 @@ protected:
bool have_to_be_excluded;
/* cache of constant state */
bool const_item_cache;
-
+
public:
/*
References from inside the subquery to the select that this predicate is
@@ -81,12 +94,12 @@ public:
virtual subs_type substype() { return UNKNOWN_SUBS; }
/*
- We need this method, because some compilers do not allow 'this'
- pointer in constructor initialization list, but we need pass pointer
- to subselect Item class to select_subselect classes constructor.
+ We need this method, because some compilers do not allow 'this'
+ pointer in constructor initialization list, but we need to pass a pointer
+ to subselect Item class to select_result_interceptor's constructor.
*/
virtual void init (st_select_lex *select_lex,
- select_subselect *result);
+ select_result_interceptor *result);
~Item_subselect();
void cleanup();
@@ -148,8 +161,9 @@ public:
@return the SELECT_LEX structure associated with this Item
*/
st_select_lex* get_select_lex();
+ const char *func_name() const { DBUG_ASSERT(0); return "subselect"; }
- friend class select_subselect;
+ friend class select_result_interceptor;
friend class Item_in_optimizer;
friend bool Item_field::fix_fields(THD *, Item **);
friend int Item_field::fix_outer_field(THD *, Field **, Item **);
@@ -258,14 +272,15 @@ public:
};
-/*
- IN subselect: this represents "left_exr IN (SELECT ...)"
+/**
+ Representation of IN subquery predicates of the form
+ "left_expr IN (SELECT ...)".
+ @detail
This class has:
- - (as a descendant of Item_subselect) a "subquery execution engine" which
- allows it to evaluate subqueries. (and this class participates in
- execution by having was_null variable where part of execution result
- is stored.
+ - A "subquery execution engine" (as a subclass of Item_subselect) that allows
+ it to evaluate subqueries. (and this class participates in execution by
+ having was_null variable where part of execution result is stored.
- Transformation methods (todo: more on this).
This class is not used directly, it is "wrapped" into Item_in_optimizer
@@ -278,6 +293,13 @@ public:
Item *left_expr;
protected:
/*
+ Cache of the left operand of the subquery predicate. Allocated in the
+ runtime memory root, for each execution, thus need not be freed.
+ */
+ List<Cached_item> *left_expr_cache;
+ bool first_execution;
+
+ /*
expr & optimizer used in subselect rewriting to store Item for
all JOIN in UNION
*/
@@ -285,7 +307,6 @@ protected:
Item_in_optimizer *optimizer;
bool was_null;
bool abort_on_null;
- bool transformed;
public:
/* Used to trigger on/off conditions that were pushed down to subselect */
bool *pushed_cond_guards;
@@ -344,10 +365,11 @@ public:
Item_in_subselect(Item * left_expr, st_select_lex *select_lex);
Item_in_subselect()
- :Item_exists_subselect(), optimizer(0), abort_on_null(0), transformed(0),
- pushed_cond_guards(NULL), exec_method(NOT_TRANSFORMED), upper_item(0)
+ :Item_exists_subselect(), left_expr_cache(0), first_execution(TRUE),
+ optimizer(0), abort_on_null(0), pushed_cond_guards(NULL),
+ exec_method(NOT_TRANSFORMED), upper_item(0)
{}
-
+ void cleanup();
subs_type substype() { return IN_SUBS; }
void reset()
{
@@ -359,6 +381,10 @@ public:
trans_res select_in_like_transformer(JOIN *join, Comp_creator *func);
trans_res single_value_transformer(JOIN *join, Comp_creator *func);
trans_res row_value_transformer(JOIN * join);
+ trans_res single_value_in_to_exists_transformer(JOIN * join,
+ Comp_creator *func);
+ trans_res row_value_in_to_exists_transformer(JOIN * join);
+ virtual bool exec();
longlong val_int();
double val_real();
String *val_str(String*);
@@ -370,10 +396,15 @@ public:
bool test_limit(st_select_lex_unit *unit);
virtual void print(String *str, enum_query_type query_type);
bool fix_fields(THD *thd, Item **ref);
+ bool setup_engine();
+ bool init_left_expr_cache();
+ bool is_expensive_processor(uchar *arg);
friend class Item_ref_null_helper;
friend class Item_is_not_null_test;
+ friend class Item_in_optimizer;
friend class subselect_indexsubquery_engine;
+ friend class subselect_hash_sj_engine;
};
@@ -398,7 +429,7 @@ public:
class subselect_engine: public Sql_alloc
{
protected:
- select_subselect *result; /* results storage class */
+ select_result_interceptor *result; /* results storage class */
THD *thd; /* pointer to current THD */
Item_subselect *item; /* item, that use this engine */
enum Item_result res_type; /* type of results */
@@ -406,7 +437,11 @@ protected:
bool maybe_null; /* may be null (first item in select) */
public:
- subselect_engine(Item_subselect *si, select_subselect *res)
+ enum enum_engine_type {ABSTRACT_ENGINE, SINGLE_SELECT_ENGINE,
+ UNION_ENGINE, UNIQUESUBQUERY_ENGINE,
+ INDEXSUBQUERY_ENGINE, HASH_SJ_ENGINE};
+
+ subselect_engine(Item_subselect *si, select_result_interceptor *res)
:thd(0)
{
result= res;
@@ -456,11 +491,13 @@ public:
virtual table_map upper_select_const_tables()= 0;
static table_map calc_const_tables(TABLE_LIST *);
virtual void print(String *str, enum_query_type query_type)= 0;
- virtual bool change_result(Item_subselect *si, select_subselect *result)= 0;
+ virtual bool change_result(Item_subselect *si,
+ select_result_interceptor *result)= 0;
virtual bool no_tables()= 0;
virtual bool is_executed() const { return FALSE; }
/* Check if subquery produced any rows during last query execution */
virtual bool no_rows() = 0;
+ virtual enum_engine_type engine_type() { return ABSTRACT_ENGINE; }
protected:
void set_row(List<Item> &item_list, Item_cache **row);
@@ -476,7 +513,7 @@ class subselect_single_select_engine: public subselect_engine
JOIN * join; /* corresponding JOIN structure */
public:
subselect_single_select_engine(st_select_lex *select,
- select_subselect *result,
+ select_result_interceptor *result,
Item_subselect *item);
void cleanup();
int prepare();
@@ -487,11 +524,15 @@ public:
void exclude();
table_map upper_select_const_tables();
virtual void print (String *str, enum_query_type query_type);
- bool change_result(Item_subselect *si, select_subselect *result);
+ bool change_result(Item_subselect *si, select_result_interceptor *result);
bool no_tables();
bool may_be_null();
bool is_executed() const { return executed; }
bool no_rows();
+ virtual enum_engine_type engine_type() { return SINGLE_SELECT_ENGINE; }
+
+ friend class subselect_hash_sj_engine;
+ friend class Item_in_subselect;
};
@@ -500,7 +541,7 @@ class subselect_union_engine: public subselect_engine
st_select_lex_unit *unit; /* corresponding unit structure */
public:
subselect_union_engine(st_select_lex_unit *u,
- select_subselect *result,
+ select_result_interceptor *result,
Item_subselect *item);
void cleanup();
int prepare();
@@ -511,10 +552,11 @@ public:
void exclude();
table_map upper_select_const_tables();
virtual void print (String *str, enum_query_type query_type);
- bool change_result(Item_subselect *si, select_subselect *result);
+ bool change_result(Item_subselect *si, select_result_interceptor *result);
bool no_tables();
bool is_executed() const;
bool no_rows();
+ virtual enum_engine_type engine_type() { return UNION_ENGINE; }
};
@@ -568,11 +610,12 @@ public:
void exclude();
table_map upper_select_const_tables() { return 0; }
virtual void print (String *str, enum_query_type query_type);
- bool change_result(Item_subselect *si, select_subselect *result);
+ bool change_result(Item_subselect *si, select_result_interceptor *result);
bool no_tables();
int scan_table();
bool copy_ref_key();
bool no_rows() { return empty_result_set; }
+ virtual enum_engine_type engine_type() { return UNIQUESUBQUERY_ENGINE; }
};
@@ -622,6 +665,7 @@ public:
{}
int exec();
virtual void print (String *str, enum_query_type query_type);
+ virtual enum_engine_type engine_type() { return INDEXSUBQUERY_ENGINE; }
};
@@ -630,9 +674,58 @@ inline bool Item_subselect::is_evaluated() const
return engine->is_executed();
}
+
inline bool Item_subselect::is_uncacheable() const
{
return engine->uncacheable();
}
+/**
+ Compute an IN predicate via a hash semi-join. The subquery is materialized
+ during the first evaluation of the IN predicate. The IN predicate is executed
+ via the functionality inherited from subselect_uniquesubquery_engine.
+*/
+
+class subselect_hash_sj_engine: public subselect_uniquesubquery_engine
+{
+protected:
+ /* TRUE if the subquery was materialized into a temp table. */
+ bool is_materialized;
+ /*
+ The old engine already chosen at parse time and stored in permanent memory.
+ Through this member we can re-create and re-prepare materialize_join for
+ each execution of a prepared statement. We akso resuse the functionality
+ of subselect_single_select_engine::[prepare | cols].
+ */
+ subselect_single_select_engine *materialize_engine;
+ /*
+ QEP to execute the subquery and materialize its result into a
+ temporary table. Created during the first call to exec().
+ */
+ JOIN *materialize_join;
+ /* Temp table context of the outer select's JOIN. */
+ TMP_TABLE_PARAM *tmp_param;
+
+public:
+ subselect_hash_sj_engine(THD *thd, Item_subselect *in_predicate,
+ subselect_single_select_engine *old_engine)
+ :subselect_uniquesubquery_engine(thd, NULL, in_predicate, NULL),
+ is_materialized(FALSE), materialize_engine(old_engine),
+ materialize_join(NULL), tmp_param(NULL)
+ {}
+ ~subselect_hash_sj_engine();
+
+ bool init_permanent(List<Item> *tmp_columns);
+ bool init_runtime();
+ void cleanup();
+ int prepare() { return 0; }
+ int exec();
+ virtual void print (String *str, enum_query_type query_type);
+ uint cols()
+ {
+ return materialize_engine->cols();
+ }
+ virtual enum_engine_type engine_type() { return HASH_SJ_ENGINE; }
+};
+