mirror of
https://github.com/MariaDB/server.git
synced 2025-08-08 11:22:35 +03:00
Subquery optimizations: non-semijoin materialization
- Backport into Maria DB 5.3, part 1
This commit is contained in:
34
sql/item.h
34
sql/item.h
@@ -878,6 +878,9 @@ public:
|
|||||||
static CHARSET_INFO *default_charset();
|
static CHARSET_INFO *default_charset();
|
||||||
virtual CHARSET_INFO *compare_collation() { return NULL; }
|
virtual CHARSET_INFO *compare_collation() { return NULL; }
|
||||||
|
|
||||||
|
/* Cache of the result of is_expensive(). */
|
||||||
|
int8 is_expensive_cache;
|
||||||
|
|
||||||
virtual bool walk(Item_processor processor, bool walk_subquery, uchar *arg)
|
virtual bool walk(Item_processor processor, bool walk_subquery, uchar *arg)
|
||||||
{
|
{
|
||||||
return (this->*processor)(arg);
|
return (this->*processor)(arg);
|
||||||
@@ -1081,6 +1084,29 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual bool result_as_longlong() { return FALSE; }
|
virtual bool result_as_longlong() { return FALSE; }
|
||||||
bool is_datetime();
|
bool is_datetime();
|
||||||
|
|
||||||
|
/*
|
||||||
|
Test whether an expression is expensive to compute. Used during
|
||||||
|
optimization to avoid computing expensive expressions during this
|
||||||
|
phase. Also used to force temp tables when sorting on expensive
|
||||||
|
functions.
|
||||||
|
TODO:
|
||||||
|
Normally we should have a method:
|
||||||
|
cost Item::execution_cost(),
|
||||||
|
where 'cost' is either 'double' or some structure of various cost
|
||||||
|
parameters.
|
||||||
|
|
||||||
|
NOTE
|
||||||
|
This function is now used to prevent evaluation of materialized IN
|
||||||
|
subquery predicates before it is allowed. grep for
|
||||||
|
DontEvaluateMaterializedSubqueryTooEarly to see the uses.
|
||||||
|
*/
|
||||||
|
virtual bool is_expensive()
|
||||||
|
{
|
||||||
|
if (is_expensive_cache < 0)
|
||||||
|
is_expensive_cache= walk(&Item::is_expensive_processor, 0, (uchar*)0);
|
||||||
|
return test(is_expensive_cache);
|
||||||
|
}
|
||||||
virtual Field::geometry_type get_geometry_type() const
|
virtual Field::geometry_type get_geometry_type() const
|
||||||
{ return Field::GEOM_GEOMETRY; };
|
{ return Field::GEOM_GEOMETRY; };
|
||||||
String *check_well_formed_result(String *str, bool send_error= 0);
|
String *check_well_formed_result(String *str, bool send_error= 0);
|
||||||
@@ -2842,9 +2868,10 @@ class Cached_item_field :public Cached_item
|
|||||||
uint length;
|
uint length;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Cached_item_field(Item_field *item)
|
Cached_item_field(Field *arg_field) : field(arg_field)
|
||||||
{
|
{
|
||||||
field= item->field;
|
field= arg_field;
|
||||||
|
/* TODO: take the memory allocation below out of the constructor. */
|
||||||
buff= (uchar*) sql_calloc(length=field->pack_length());
|
buff= (uchar*) sql_calloc(length=field->pack_length());
|
||||||
}
|
}
|
||||||
bool cmp(void);
|
bool cmp(void);
|
||||||
@@ -3271,7 +3298,8 @@ void mark_select_range_as_dependent(THD *thd,
|
|||||||
Field *found_field, Item *found_item,
|
Field *found_field, Item *found_item,
|
||||||
Item_ident *resolved_item);
|
Item_ident *resolved_item);
|
||||||
|
|
||||||
extern Cached_item *new_Cached_item(THD *thd, Item *item);
|
extern Cached_item *new_Cached_item(THD *thd, Item *item,
|
||||||
|
bool use_result_field);
|
||||||
extern Item_result item_cmp_type(Item_result a,Item_result b);
|
extern Item_result item_cmp_type(Item_result a,Item_result b);
|
||||||
extern void resolve_const_item(THD *thd, Item **ref, Item *cmp_item);
|
extern void resolve_const_item(THD *thd, Item **ref, Item *cmp_item);
|
||||||
extern int stored_field_cmp_to_item(Field *field, Item *item);
|
extern int stored_field_cmp_to_item(Field *field, Item *item);
|
||||||
|
@@ -27,11 +27,16 @@
|
|||||||
Create right type of Cached_item for an item.
|
Create right type of Cached_item for an item.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Cached_item *new_Cached_item(THD *thd, Item *item)
|
Cached_item *new_Cached_item(THD *thd, Item *item, bool use_result_field)
|
||||||
{
|
{
|
||||||
if (item->real_item()->type() == Item::FIELD_ITEM &&
|
if (item->real_item()->type() == Item::FIELD_ITEM &&
|
||||||
!(((Item_field *) (item->real_item()))->field->flags & BLOB_FLAG))
|
!(((Item_field *) (item->real_item()))->field->flags & BLOB_FLAG))
|
||||||
return new Cached_item_field((Item_field *) (item->real_item()));
|
{
|
||||||
|
Item_field *real_item= (Item_field *) item->real_item();
|
||||||
|
Field *cached_field= use_result_field ? real_item->result_field :
|
||||||
|
real_item->field;
|
||||||
|
return new Cached_item_field(cached_field);
|
||||||
|
}
|
||||||
switch (item->result_type()) {
|
switch (item->result_type()) {
|
||||||
case STRING_RESULT:
|
case STRING_RESULT:
|
||||||
return new Cached_item_str(thd, (Item_field *) item);
|
return new Cached_item_str(thd, (Item_field *) item);
|
||||||
|
@@ -490,12 +490,12 @@ Field *Item_func::tmp_table_field(TABLE *table)
|
|||||||
return field;
|
return field;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
bool Item_func::is_expensive_processor(uchar *arg)
|
bool Item_func::is_expensive_processor(uchar *arg)
|
||||||
{
|
{
|
||||||
return is_expensive();
|
return is_expensive();
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
my_decimal *Item_func::val_decimal(my_decimal *decimal_value)
|
my_decimal *Item_func::val_decimal(my_decimal *decimal_value)
|
||||||
{
|
{
|
||||||
|
@@ -192,8 +192,8 @@ public:
|
|||||||
Item_transformer transformer, uchar *arg_t);
|
Item_transformer transformer, uchar *arg_t);
|
||||||
void traverse_cond(Cond_traverser traverser,
|
void traverse_cond(Cond_traverser traverser,
|
||||||
void * arg, traverse_order order);
|
void * arg, traverse_order order);
|
||||||
bool is_expensive_processor(uchar *arg);
|
// bool is_expensive_processor(uchar *arg);
|
||||||
virtual bool is_expensive() { return 0; }
|
// virtual bool is_expensive() { return 0; }
|
||||||
inline double fix_result(double value)
|
inline double fix_result(double value)
|
||||||
{
|
{
|
||||||
if (isfinite(value))
|
if (isfinite(value))
|
||||||
@@ -1053,6 +1053,7 @@ class Item_udf_func :public Item_func
|
|||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
udf_handler udf;
|
udf_handler udf;
|
||||||
|
bool is_expensive_processor(uchar *arg) { return TRUE; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Item_udf_func(udf_func *udf_arg)
|
Item_udf_func(udf_func *udf_arg)
|
||||||
@@ -1677,6 +1678,9 @@ private:
|
|||||||
bool execute_impl(THD *thd);
|
bool execute_impl(THD *thd);
|
||||||
bool init_result_field(THD *thd);
|
bool init_result_field(THD *thd);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool is_expensive_processor(uchar *arg) { return TRUE; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Item_func_sp(Name_resolution_context *context_arg, sp_name *name);
|
Item_func_sp(Name_resolution_context *context_arg, sp_name *name);
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -22,9 +22,11 @@
|
|||||||
class st_select_lex;
|
class st_select_lex;
|
||||||
class st_select_lex_unit;
|
class st_select_lex_unit;
|
||||||
class JOIN;
|
class JOIN;
|
||||||
class select_subselect;
|
class select_result_interceptor;
|
||||||
class subselect_engine;
|
class subselect_engine;
|
||||||
|
class subselect_hash_sj_engine;
|
||||||
class Item_bool_func2;
|
class Item_bool_func2;
|
||||||
|
class Cached_item;
|
||||||
|
|
||||||
/* base class for subselects */
|
/* base class for subselects */
|
||||||
|
|
||||||
@@ -34,7 +36,18 @@ class Item_subselect :public Item_result_field
|
|||||||
public:
|
public:
|
||||||
/* thread handler, will be assigned in fix_fields only */
|
/* thread handler, will be assigned in fix_fields only */
|
||||||
THD *thd;
|
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;
|
Item *substitution;
|
||||||
public:
|
public:
|
||||||
/* unit of subquery */
|
/* unit of subquery */
|
||||||
@@ -82,11 +95,11 @@ public:
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
We need this method, because some compilers do not allow 'this'
|
We need this method, because some compilers do not allow 'this'
|
||||||
pointer in constructor initialization list, but we need pass pointer
|
pointer in constructor initialization list, but we need to pass a pointer
|
||||||
to subselect Item class to select_subselect classes constructor.
|
to subselect Item class to select_result_interceptor's constructor.
|
||||||
*/
|
*/
|
||||||
virtual void init (st_select_lex *select_lex,
|
virtual void init (st_select_lex *select_lex,
|
||||||
select_subselect *result);
|
select_result_interceptor *result);
|
||||||
|
|
||||||
~Item_subselect();
|
~Item_subselect();
|
||||||
void cleanup();
|
void cleanup();
|
||||||
@@ -148,8 +161,9 @@ public:
|
|||||||
@return the SELECT_LEX structure associated with this Item
|
@return the SELECT_LEX structure associated with this Item
|
||||||
*/
|
*/
|
||||||
st_select_lex* get_select_lex();
|
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 class Item_in_optimizer;
|
||||||
friend bool Item_field::fix_fields(THD *, Item **);
|
friend bool Item_field::fix_fields(THD *, Item **);
|
||||||
friend int Item_field::fix_outer_field(THD *, Field **, 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:
|
This class has:
|
||||||
- (as a descendant of Item_subselect) a "subquery execution engine" which
|
- A "subquery execution engine" (as a subclass of Item_subselect) that allows
|
||||||
allows it to evaluate subqueries. (and this class participates in
|
it to evaluate subqueries. (and this class participates in execution by
|
||||||
execution by having was_null variable where part of execution result
|
having was_null variable where part of execution result is stored.
|
||||||
is stored.
|
|
||||||
- Transformation methods (todo: more on this).
|
- Transformation methods (todo: more on this).
|
||||||
|
|
||||||
This class is not used directly, it is "wrapped" into Item_in_optimizer
|
This class is not used directly, it is "wrapped" into Item_in_optimizer
|
||||||
@@ -277,6 +292,13 @@ class Item_in_subselect :public Item_exists_subselect
|
|||||||
public:
|
public:
|
||||||
Item *left_expr;
|
Item *left_expr;
|
||||||
protected:
|
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
|
expr & optimizer used in subselect rewriting to store Item for
|
||||||
all JOIN in UNION
|
all JOIN in UNION
|
||||||
@@ -285,7 +307,6 @@ protected:
|
|||||||
Item_in_optimizer *optimizer;
|
Item_in_optimizer *optimizer;
|
||||||
bool was_null;
|
bool was_null;
|
||||||
bool abort_on_null;
|
bool abort_on_null;
|
||||||
bool transformed;
|
|
||||||
public:
|
public:
|
||||||
/* Used to trigger on/off conditions that were pushed down to subselect */
|
/* Used to trigger on/off conditions that were pushed down to subselect */
|
||||||
bool *pushed_cond_guards;
|
bool *pushed_cond_guards;
|
||||||
@@ -344,10 +365,11 @@ public:
|
|||||||
|
|
||||||
Item_in_subselect(Item * left_expr, st_select_lex *select_lex);
|
Item_in_subselect(Item * left_expr, st_select_lex *select_lex);
|
||||||
Item_in_subselect()
|
Item_in_subselect()
|
||||||
:Item_exists_subselect(), optimizer(0), abort_on_null(0), transformed(0),
|
:Item_exists_subselect(), left_expr_cache(0), first_execution(TRUE),
|
||||||
pushed_cond_guards(NULL), exec_method(NOT_TRANSFORMED), upper_item(0)
|
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; }
|
subs_type substype() { return IN_SUBS; }
|
||||||
void reset()
|
void reset()
|
||||||
{
|
{
|
||||||
@@ -359,6 +381,10 @@ public:
|
|||||||
trans_res select_in_like_transformer(JOIN *join, Comp_creator *func);
|
trans_res select_in_like_transformer(JOIN *join, Comp_creator *func);
|
||||||
trans_res single_value_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 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();
|
longlong val_int();
|
||||||
double val_real();
|
double val_real();
|
||||||
String *val_str(String*);
|
String *val_str(String*);
|
||||||
@@ -370,10 +396,15 @@ public:
|
|||||||
bool test_limit(st_select_lex_unit *unit);
|
bool test_limit(st_select_lex_unit *unit);
|
||||||
virtual void print(String *str, enum_query_type query_type);
|
virtual void print(String *str, enum_query_type query_type);
|
||||||
bool fix_fields(THD *thd, Item **ref);
|
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_ref_null_helper;
|
||||||
friend class Item_is_not_null_test;
|
friend class Item_is_not_null_test;
|
||||||
|
friend class Item_in_optimizer;
|
||||||
friend class subselect_indexsubquery_engine;
|
friend class subselect_indexsubquery_engine;
|
||||||
|
friend class subselect_hash_sj_engine;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -398,7 +429,7 @@ public:
|
|||||||
class subselect_engine: public Sql_alloc
|
class subselect_engine: public Sql_alloc
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
select_subselect *result; /* results storage class */
|
select_result_interceptor *result; /* results storage class */
|
||||||
THD *thd; /* pointer to current THD */
|
THD *thd; /* pointer to current THD */
|
||||||
Item_subselect *item; /* item, that use this engine */
|
Item_subselect *item; /* item, that use this engine */
|
||||||
enum Item_result res_type; /* type of results */
|
enum Item_result res_type; /* type of results */
|
||||||
@@ -406,7 +437,11 @@ protected:
|
|||||||
bool maybe_null; /* may be null (first item in select) */
|
bool maybe_null; /* may be null (first item in select) */
|
||||||
public:
|
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)
|
:thd(0)
|
||||||
{
|
{
|
||||||
result= res;
|
result= res;
|
||||||
@@ -456,11 +491,13 @@ public:
|
|||||||
virtual table_map upper_select_const_tables()= 0;
|
virtual table_map upper_select_const_tables()= 0;
|
||||||
static table_map calc_const_tables(TABLE_LIST *);
|
static table_map calc_const_tables(TABLE_LIST *);
|
||||||
virtual void print(String *str, enum_query_type query_type)= 0;
|
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 no_tables()= 0;
|
||||||
virtual bool is_executed() const { return FALSE; }
|
virtual bool is_executed() const { return FALSE; }
|
||||||
/* Check if subquery produced any rows during last query execution */
|
/* Check if subquery produced any rows during last query execution */
|
||||||
virtual bool no_rows() = 0;
|
virtual bool no_rows() = 0;
|
||||||
|
virtual enum_engine_type engine_type() { return ABSTRACT_ENGINE; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void set_row(List<Item> &item_list, Item_cache **row);
|
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 */
|
JOIN * join; /* corresponding JOIN structure */
|
||||||
public:
|
public:
|
||||||
subselect_single_select_engine(st_select_lex *select,
|
subselect_single_select_engine(st_select_lex *select,
|
||||||
select_subselect *result,
|
select_result_interceptor *result,
|
||||||
Item_subselect *item);
|
Item_subselect *item);
|
||||||
void cleanup();
|
void cleanup();
|
||||||
int prepare();
|
int prepare();
|
||||||
@@ -487,11 +524,15 @@ public:
|
|||||||
void exclude();
|
void exclude();
|
||||||
table_map upper_select_const_tables();
|
table_map upper_select_const_tables();
|
||||||
virtual void print (String *str, enum_query_type query_type);
|
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 no_tables();
|
||||||
bool may_be_null();
|
bool may_be_null();
|
||||||
bool is_executed() const { return executed; }
|
bool is_executed() const { return executed; }
|
||||||
bool no_rows();
|
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 */
|
st_select_lex_unit *unit; /* corresponding unit structure */
|
||||||
public:
|
public:
|
||||||
subselect_union_engine(st_select_lex_unit *u,
|
subselect_union_engine(st_select_lex_unit *u,
|
||||||
select_subselect *result,
|
select_result_interceptor *result,
|
||||||
Item_subselect *item);
|
Item_subselect *item);
|
||||||
void cleanup();
|
void cleanup();
|
||||||
int prepare();
|
int prepare();
|
||||||
@@ -511,10 +552,11 @@ public:
|
|||||||
void exclude();
|
void exclude();
|
||||||
table_map upper_select_const_tables();
|
table_map upper_select_const_tables();
|
||||||
virtual void print (String *str, enum_query_type query_type);
|
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 no_tables();
|
||||||
bool is_executed() const;
|
bool is_executed() const;
|
||||||
bool no_rows();
|
bool no_rows();
|
||||||
|
virtual enum_engine_type engine_type() { return UNION_ENGINE; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -568,11 +610,12 @@ public:
|
|||||||
void exclude();
|
void exclude();
|
||||||
table_map upper_select_const_tables() { return 0; }
|
table_map upper_select_const_tables() { return 0; }
|
||||||
virtual void print (String *str, enum_query_type query_type);
|
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 no_tables();
|
||||||
int scan_table();
|
int scan_table();
|
||||||
bool copy_ref_key();
|
bool copy_ref_key();
|
||||||
bool no_rows() { return empty_result_set; }
|
bool no_rows() { return empty_result_set; }
|
||||||
|
virtual enum_engine_type engine_type() { return UNIQUESUBQUERY_ENGINE; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -622,6 +665,7 @@ public:
|
|||||||
{}
|
{}
|
||||||
int exec();
|
int exec();
|
||||||
virtual void print (String *str, enum_query_type query_type);
|
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();
|
return engine->is_executed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline bool Item_subselect::is_uncacheable() const
|
inline bool Item_subselect::is_uncacheable() const
|
||||||
{
|
{
|
||||||
return engine->uncacheable();
|
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; }
|
||||||
|
};
|
||||||
|
|
||||||
|
@@ -5493,7 +5493,7 @@ static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param,COND *cond)
|
|||||||
DBUG_RETURN(tree);
|
DBUG_RETURN(tree);
|
||||||
}
|
}
|
||||||
/* Here when simple cond */
|
/* Here when simple cond */
|
||||||
if (cond->const_item())
|
if (cond->const_item() && !cond->is_expensive())
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
During the cond->val_int() evaluation we can come across a subselect
|
During the cond->val_int() evaluation we can come across a subselect
|
||||||
|
@@ -2076,16 +2076,28 @@ void st_select_lex::print_limit(THD *thd,
|
|||||||
{
|
{
|
||||||
SELECT_LEX_UNIT *unit= master_unit();
|
SELECT_LEX_UNIT *unit= master_unit();
|
||||||
Item_subselect *item= unit->item;
|
Item_subselect *item= unit->item;
|
||||||
if (item && unit->global_parameters == this &&
|
|
||||||
(item->substype() == Item_subselect::EXISTS_SUBS ||
|
if (item && unit->global_parameters == this)
|
||||||
item->substype() == Item_subselect::IN_SUBS ||
|
{
|
||||||
item->substype() == Item_subselect::ALL_SUBS))
|
Item_subselect::subs_type subs_type= item->substype();
|
||||||
|
if (subs_type == Item_subselect::EXISTS_SUBS ||
|
||||||
|
subs_type == Item_subselect::IN_SUBS ||
|
||||||
|
subs_type == Item_subselect::ALL_SUBS)
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(!item->fixed ||
|
DBUG_ASSERT(!item->fixed ||
|
||||||
(select_limit->val_int() == LL(1) && offset_limit == 0));
|
/*
|
||||||
|
If not using materialization both:
|
||||||
|
select_limit == 1, and there should be no offset_limit.
|
||||||
|
*/
|
||||||
|
(((subs_type == Item_subselect::IN_SUBS) &&
|
||||||
|
((Item_in_subselect*)item)->exec_method ==
|
||||||
|
Item_in_subselect::MATERIALIZATION) ?
|
||||||
|
TRUE :
|
||||||
|
(select_limit->val_int() == 1LL) &&
|
||||||
|
offset_limit == 0));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (explicit_limit)
|
if (explicit_limit)
|
||||||
{
|
{
|
||||||
str->append(STRING_WITH_LEN(" limit "));
|
str->append(STRING_WITH_LEN(" limit "));
|
||||||
@@ -2098,6 +2110,7 @@ void st_select_lex::print_limit(THD *thd,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief Restore the LEX and THD in case of a parse error.
|
@brief Restore the LEX and THD in case of a parse error.
|
||||||
|
|
||||||
|
@@ -559,7 +559,8 @@ public:
|
|||||||
bool add_fake_select_lex(THD *thd);
|
bool add_fake_select_lex(THD *thd);
|
||||||
void init_prepare_fake_select_lex(THD *thd);
|
void init_prepare_fake_select_lex(THD *thd);
|
||||||
inline bool is_prepared() { return prepared; }
|
inline bool is_prepared() { return prepared; }
|
||||||
bool change_result(select_subselect *result, select_subselect *old_result);
|
bool change_result(select_result_interceptor *result,
|
||||||
|
select_result_interceptor *old_result);
|
||||||
void set_limit(st_select_lex *values);
|
void set_limit(st_select_lex *values);
|
||||||
void set_thd(THD *thd_arg) { thd= thd_arg; }
|
void set_thd(THD *thd_arg) { thd= thd_arg; }
|
||||||
inline bool is_union ();
|
inline bool is_union ();
|
||||||
|
@@ -158,7 +158,7 @@ static enum_nested_loop_state
|
|||||||
evaluate_null_complemented_join_record(JOIN *join, JOIN_TAB *join_tab);
|
evaluate_null_complemented_join_record(JOIN *join, JOIN_TAB *join_tab);
|
||||||
static enum_nested_loop_state
|
static enum_nested_loop_state
|
||||||
end_send(JOIN *join, JOIN_TAB *join_tab, bool end_of_records);
|
end_send(JOIN *join, JOIN_TAB *join_tab, bool end_of_records);
|
||||||
static enum_nested_loop_state
|
enum_nested_loop_state
|
||||||
end_send_group(JOIN *join, JOIN_TAB *join_tab, bool end_of_records);
|
end_send_group(JOIN *join, JOIN_TAB *join_tab, bool end_of_records);
|
||||||
static enum_nested_loop_state
|
static enum_nested_loop_state
|
||||||
end_write(JOIN *join, JOIN_TAB *join_tab, bool end_of_records);
|
end_write(JOIN *join, JOIN_TAB *join_tab, bool end_of_records);
|
||||||
@@ -166,7 +166,7 @@ static enum_nested_loop_state
|
|||||||
end_update(JOIN *join, JOIN_TAB *join_tab, bool end_of_records);
|
end_update(JOIN *join, JOIN_TAB *join_tab, bool end_of_records);
|
||||||
static enum_nested_loop_state
|
static enum_nested_loop_state
|
||||||
end_unique_update(JOIN *join, JOIN_TAB *join_tab, bool end_of_records);
|
end_unique_update(JOIN *join, JOIN_TAB *join_tab, bool end_of_records);
|
||||||
static enum_nested_loop_state
|
enum_nested_loop_state
|
||||||
end_write_group(JOIN *join, JOIN_TAB *join_tab, bool end_of_records);
|
end_write_group(JOIN *join, JOIN_TAB *join_tab, bool end_of_records);
|
||||||
|
|
||||||
static int test_if_group_changed(List<Cached_item> &list);
|
static int test_if_group_changed(List<Cached_item> &list);
|
||||||
@@ -192,11 +192,14 @@ static int join_ft_read_first(JOIN_TAB *tab);
|
|||||||
static int join_ft_read_next(READ_RECORD *info);
|
static int join_ft_read_next(READ_RECORD *info);
|
||||||
int join_read_always_key_or_null(JOIN_TAB *tab);
|
int join_read_always_key_or_null(JOIN_TAB *tab);
|
||||||
int join_read_next_same_or_null(READ_RECORD *info);
|
int join_read_next_same_or_null(READ_RECORD *info);
|
||||||
static COND *make_cond_for_table(COND *cond,table_map table,
|
static COND *make_cond_for_table(Item *cond,table_map table,
|
||||||
table_map used_table);
|
table_map used_table,
|
||||||
static COND *make_cond_for_table_from_pred(COND *root_cond, COND *cond,
|
bool exclude_expensive_cond);
|
||||||
|
static COND *make_cond_for_table_from_pred(Item *root_cond, Item *cond,
|
||||||
table_map tables,
|
table_map tables,
|
||||||
table_map used_table);
|
table_map used_table,
|
||||||
|
bool exclude_expensive_cond);
|
||||||
|
|
||||||
static Item* part_of_refkey(TABLE *form,Field *field);
|
static Item* part_of_refkey(TABLE *form,Field *field);
|
||||||
uint find_shortest_key(TABLE *table, const key_map *usable_keys);
|
uint find_shortest_key(TABLE *table, const key_map *usable_keys);
|
||||||
static bool test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,
|
static bool test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,
|
||||||
@@ -707,8 +710,7 @@ JOIN::prepare(Item ***rref_pointer_array,
|
|||||||
// psergey-todo: duplicated_subselect_card_check: where it's done?
|
// psergey-todo: duplicated_subselect_card_check: where it's done?
|
||||||
if (in_subs->is_top_level_item() && // 4
|
if (in_subs->is_top_level_item() && // 4
|
||||||
!in_subs->is_correlated && // 5
|
!in_subs->is_correlated && // 5
|
||||||
in_subs->exec_method == Item_in_subselect::NOT_TRANSFORMED // 6
|
in_subs->exec_method == Item_in_subselect::NOT_TRANSFORMED) // 6
|
||||||
&& FALSE ) // psergey-merge: disable non-sj materialization
|
|
||||||
in_subs->exec_method= Item_in_subselect::MATERIALIZATION;
|
in_subs->exec_method= Item_in_subselect::MATERIALIZATION;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1501,7 +1503,7 @@ JOIN::optimize()
|
|||||||
"Impossible HAVING" : "Impossible WHERE";
|
"Impossible HAVING" : "Impossible WHERE";
|
||||||
tables= 0;
|
tables= 0;
|
||||||
error= 0;
|
error= 0;
|
||||||
DBUG_RETURN(0);
|
goto setup_subq_exit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1543,7 +1545,7 @@ JOIN::optimize()
|
|||||||
zero_result_cause= "No matching min/max row";
|
zero_result_cause= "No matching min/max row";
|
||||||
tables= 0;
|
tables= 0;
|
||||||
error=0;
|
error=0;
|
||||||
DBUG_RETURN(0);
|
goto setup_subq_exit;
|
||||||
}
|
}
|
||||||
if (res > 1)
|
if (res > 1)
|
||||||
{
|
{
|
||||||
@@ -1557,7 +1559,7 @@ JOIN::optimize()
|
|||||||
zero_result_cause= "No matching min/max row";
|
zero_result_cause= "No matching min/max row";
|
||||||
tables= 0;
|
tables= 0;
|
||||||
error=0;
|
error=0;
|
||||||
DBUG_RETURN(0);
|
goto setup_subq_exit;
|
||||||
}
|
}
|
||||||
DBUG_PRINT("info",("Select tables optimized away"));
|
DBUG_PRINT("info",("Select tables optimized away"));
|
||||||
zero_result_cause= "Select tables optimized away";
|
zero_result_cause= "Select tables optimized away";
|
||||||
@@ -1575,13 +1577,14 @@ JOIN::optimize()
|
|||||||
if (conds && !(thd->lex->describe & DESCRIBE_EXTENDED))
|
if (conds && !(thd->lex->describe & DESCRIBE_EXTENDED))
|
||||||
{
|
{
|
||||||
COND *table_independent_conds=
|
COND *table_independent_conds=
|
||||||
make_cond_for_table(conds, PSEUDO_TABLE_BITS, 0);
|
make_cond_for_table(conds, PSEUDO_TABLE_BITS, 0, FALSE);
|
||||||
DBUG_EXECUTE("where",
|
DBUG_EXECUTE("where",
|
||||||
print_where(table_independent_conds,
|
print_where(table_independent_conds,
|
||||||
"where after opt_sum_query()",
|
"where after opt_sum_query()",
|
||||||
QT_ORDINARY););
|
QT_ORDINARY););
|
||||||
conds= table_independent_conds;
|
conds= table_independent_conds;
|
||||||
}
|
}
|
||||||
|
goto setup_subq_exit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!tables_list)
|
if (!tables_list)
|
||||||
@@ -1619,7 +1622,7 @@ JOIN::optimize()
|
|||||||
zero_result_cause= "no matching row in const table";
|
zero_result_cause= "no matching row in const table";
|
||||||
DBUG_PRINT("error",("Error: %s", zero_result_cause));
|
DBUG_PRINT("error",("Error: %s", zero_result_cause));
|
||||||
error= 0;
|
error= 0;
|
||||||
DBUG_RETURN(0);
|
goto setup_subq_exit;
|
||||||
}
|
}
|
||||||
if (!(thd->options & OPTION_BIG_SELECTS) &&
|
if (!(thd->options & OPTION_BIG_SELECTS) &&
|
||||||
best_read > (double) thd->variables.max_join_size &&
|
best_read > (double) thd->variables.max_join_size &&
|
||||||
@@ -1690,7 +1693,7 @@ JOIN::optimize()
|
|||||||
{
|
{
|
||||||
zero_result_cause=
|
zero_result_cause=
|
||||||
"Impossible WHERE noticed after reading const tables";
|
"Impossible WHERE noticed after reading const tables";
|
||||||
DBUG_RETURN(0); // error == 0
|
goto setup_subq_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
error= -1; /* if goto err */
|
error= -1; /* if goto err */
|
||||||
@@ -1920,6 +1923,10 @@ JOIN::optimize()
|
|||||||
if (!(select_options & SELECT_DESCRIBE))
|
if (!(select_options & SELECT_DESCRIBE))
|
||||||
init_ftfuncs(thd, select_lex, test(order));
|
init_ftfuncs(thd, select_lex, test(order));
|
||||||
|
|
||||||
|
/* Create all structures needed for materialized subquery execution. */
|
||||||
|
if (setup_subquery_materialization())
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
is this simple IN subquery?
|
is this simple IN subquery?
|
||||||
*/
|
*/
|
||||||
@@ -2033,7 +2040,7 @@ JOIN::optimize()
|
|||||||
for (ORDER *tmp_order= order; tmp_order ; tmp_order=tmp_order->next)
|
for (ORDER *tmp_order= order; tmp_order ; tmp_order=tmp_order->next)
|
||||||
{
|
{
|
||||||
Item *item= *tmp_order->item;
|
Item *item= *tmp_order->item;
|
||||||
if (item->walk(&Item::is_expensive_processor, 0, (uchar*)0))
|
if (item->is_expensive())
|
||||||
{
|
{
|
||||||
/* Force tmp table without sort */
|
/* Force tmp table without sort */
|
||||||
need_tmp=1; simple_order=simple_group=0;
|
need_tmp=1; simple_order=simple_group=0;
|
||||||
@@ -2185,6 +2192,18 @@ JOIN::optimize()
|
|||||||
|
|
||||||
error= 0;
|
error= 0;
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
|
|
||||||
|
setup_subq_exit:
|
||||||
|
/*
|
||||||
|
Even with zero matching rows, subqueries in the HAVING clause may
|
||||||
|
need to be evaluated if there are aggregate functions in the
|
||||||
|
query. If we have planned to materialize the subquery, we need to
|
||||||
|
set it up properly before prematurely leaving optimize().
|
||||||
|
*/
|
||||||
|
if (setup_subquery_materialization())
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
error= 0;
|
||||||
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -2746,7 +2765,7 @@ JOIN::exec()
|
|||||||
|
|
||||||
Item* sort_table_cond= make_cond_for_table(curr_join->tmp_having,
|
Item* sort_table_cond= make_cond_for_table(curr_join->tmp_having,
|
||||||
used_tables,
|
used_tables,
|
||||||
used_tables);
|
used_tables, FALSE);
|
||||||
if (sort_table_cond)
|
if (sort_table_cond)
|
||||||
{
|
{
|
||||||
if (!curr_table->select)
|
if (!curr_table->select)
|
||||||
@@ -2773,7 +2792,7 @@ JOIN::exec()
|
|||||||
QT_ORDINARY););
|
QT_ORDINARY););
|
||||||
curr_join->tmp_having= make_cond_for_table(curr_join->tmp_having,
|
curr_join->tmp_having= make_cond_for_table(curr_join->tmp_having,
|
||||||
~ (table_map) 0,
|
~ (table_map) 0,
|
||||||
~used_tables);
|
~used_tables, FALSE);
|
||||||
DBUG_EXECUTE("where",print_where(curr_join->tmp_having,
|
DBUG_EXECUTE("where",print_where(curr_join->tmp_having,
|
||||||
"having after sort",
|
"having after sort",
|
||||||
QT_ORDINARY););
|
QT_ORDINARY););
|
||||||
@@ -3656,7 +3675,6 @@ skip_conversion:
|
|||||||
bool JOIN::setup_subquery_materialization()
|
bool JOIN::setup_subquery_materialization()
|
||||||
{
|
{
|
||||||
//psergey-merge: we don't have materialization so dont need that:
|
//psergey-merge: we don't have materialization so dont need that:
|
||||||
#if 0
|
|
||||||
for (SELECT_LEX_UNIT *un= select_lex->first_inner_unit(); un;
|
for (SELECT_LEX_UNIT *un= select_lex->first_inner_unit(); un;
|
||||||
un= un->next_unit())
|
un= un->next_unit())
|
||||||
{
|
{
|
||||||
@@ -3673,7 +3691,6 @@ bool JOIN::setup_subquery_materialization()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8685,7 +8702,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
|
|||||||
COND *const_cond=
|
COND *const_cond=
|
||||||
make_cond_for_table(cond,
|
make_cond_for_table(cond,
|
||||||
join->const_table_map,
|
join->const_table_map,
|
||||||
(table_map) 0);
|
(table_map) 0, TRUE);
|
||||||
DBUG_EXECUTE("where",print_where(const_cond,"constants", QT_ORDINARY););
|
DBUG_EXECUTE("where",print_where(const_cond,"constants", QT_ORDINARY););
|
||||||
for (JOIN_TAB *tab= join->join_tab+join->const_tables;
|
for (JOIN_TAB *tab= join->join_tab+join->const_tables;
|
||||||
tab < join->join_tab+join->tables ; tab++)
|
tab < join->join_tab+join->tables ; tab++)
|
||||||
@@ -8695,7 +8712,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
|
|||||||
JOIN_TAB *cond_tab= tab->first_inner;
|
JOIN_TAB *cond_tab= tab->first_inner;
|
||||||
COND *tmp= make_cond_for_table(*tab->on_expr_ref,
|
COND *tmp= make_cond_for_table(*tab->on_expr_ref,
|
||||||
join->const_table_map,
|
join->const_table_map,
|
||||||
( table_map) 0);
|
( table_map) 0, FALSE);
|
||||||
if (!tmp)
|
if (!tmp)
|
||||||
continue;
|
continue;
|
||||||
tmp= new Item_func_trig_cond(tmp, &cond_tab->not_null_compl);
|
tmp= new Item_func_trig_cond(tmp, &cond_tab->not_null_compl);
|
||||||
@@ -8783,7 +8800,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
|
|||||||
|
|
||||||
tmp= NULL;
|
tmp= NULL;
|
||||||
if (cond)
|
if (cond)
|
||||||
tmp= make_cond_for_table(cond,used_tables,current_map);
|
tmp= make_cond_for_table(cond, used_tables, current_map, FALSE);
|
||||||
if (cond && !tmp && tab->quick)
|
if (cond && !tmp && tab->quick)
|
||||||
{ // Outer join
|
{ // Outer join
|
||||||
if (tab->type != JT_ALL)
|
if (tab->type != JT_ALL)
|
||||||
@@ -8839,7 +8856,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
|
|||||||
if (thd->variables.engine_condition_pushdown && !first_inner_tab)
|
if (thd->variables.engine_condition_pushdown && !first_inner_tab)
|
||||||
{
|
{
|
||||||
COND *push_cond=
|
COND *push_cond=
|
||||||
make_cond_for_table(tmp, current_map, current_map);
|
make_cond_for_table(tmp, current_map, current_map, FALSE);
|
||||||
if (push_cond)
|
if (push_cond)
|
||||||
{
|
{
|
||||||
/* Push condition to handler */
|
/* Push condition to handler */
|
||||||
@@ -8968,7 +8985,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
|
|||||||
(tmp=make_cond_for_table(cond,
|
(tmp=make_cond_for_table(cond,
|
||||||
join->const_table_map |
|
join->const_table_map |
|
||||||
current_map,
|
current_map,
|
||||||
current_map)))
|
current_map, FALSE)))
|
||||||
{
|
{
|
||||||
DBUG_EXECUTE("where",print_where(tmp,"cache", QT_ORDINARY););
|
DBUG_EXECUTE("where",print_where(tmp,"cache", QT_ORDINARY););
|
||||||
tab->cache_select=(SQL_SELECT*)
|
tab->cache_select=(SQL_SELECT*)
|
||||||
@@ -8998,7 +9015,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
|
|||||||
JOIN_TAB *cond_tab= join_tab->first_inner;
|
JOIN_TAB *cond_tab= join_tab->first_inner;
|
||||||
COND *tmp= make_cond_for_table(*join_tab->on_expr_ref,
|
COND *tmp= make_cond_for_table(*join_tab->on_expr_ref,
|
||||||
join->const_table_map,
|
join->const_table_map,
|
||||||
(table_map) 0);
|
(table_map) 0, FALSE);
|
||||||
if (!tmp)
|
if (!tmp)
|
||||||
continue;
|
continue;
|
||||||
tmp= new Item_func_trig_cond(tmp, &cond_tab->not_null_compl);
|
tmp= new Item_func_trig_cond(tmp, &cond_tab->not_null_compl);
|
||||||
@@ -9033,7 +9050,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
|
|||||||
current_map= tab->table->map;
|
current_map= tab->table->map;
|
||||||
used_tables2|= current_map;
|
used_tables2|= current_map;
|
||||||
COND *tmp_cond= make_cond_for_table(on_expr, used_tables2,
|
COND *tmp_cond= make_cond_for_table(on_expr, used_tables2,
|
||||||
current_map);
|
current_map, FALSE);
|
||||||
if (tmp_cond)
|
if (tmp_cond)
|
||||||
{
|
{
|
||||||
JOIN_TAB *cond_tab= tab < first_inner_tab ? first_inner_tab : tab;
|
JOIN_TAB *cond_tab= tab < first_inner_tab ? first_inner_tab : tab;
|
||||||
@@ -13299,7 +13316,17 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value)
|
|||||||
return (COND*) 0;
|
return (COND*) 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (cond->const_item())
|
else if (cond->const_item() && !cond->is_expensive())
|
||||||
|
/*
|
||||||
|
DontEvaluateMaterializedSubqueryTooEarly:
|
||||||
|
TODO:
|
||||||
|
Excluding all expensive functions is too restritive we should exclude only
|
||||||
|
materialized IN subquery predicates because they can't yet be evaluated
|
||||||
|
here (they need additional initialization that is done later on).
|
||||||
|
|
||||||
|
The proper way to exclude the subqueries would be to walk the cond tree and
|
||||||
|
check for materialized subqueries there.
|
||||||
|
*/
|
||||||
{
|
{
|
||||||
*cond_value= eval_const_cond(cond) ? Item::COND_TRUE : Item::COND_FALSE;
|
*cond_value= eval_const_cond(cond) ? Item::COND_TRUE : Item::COND_FALSE;
|
||||||
return (COND*) 0;
|
return (COND*) 0;
|
||||||
@@ -16164,6 +16191,8 @@ int do_sj_dups_weedout(THD *thd, SJ_TMP_TABLE *sjtbl)
|
|||||||
int error;
|
int error;
|
||||||
SJ_TMP_TABLE::TAB *tab= sjtbl->tabs;
|
SJ_TMP_TABLE::TAB *tab= sjtbl->tabs;
|
||||||
SJ_TMP_TABLE::TAB *tab_end= sjtbl->tabs_end;
|
SJ_TMP_TABLE::TAB *tab_end= sjtbl->tabs_end;
|
||||||
|
uchar *ptr;
|
||||||
|
uchar *nulls_ptr;
|
||||||
|
|
||||||
DBUG_ENTER("do_sj_dups_weedout");
|
DBUG_ENTER("do_sj_dups_weedout");
|
||||||
|
|
||||||
@@ -16171,15 +16200,13 @@ int do_sj_dups_weedout(THD *thd, SJ_TMP_TABLE *sjtbl)
|
|||||||
{
|
{
|
||||||
if (sjtbl->have_confluent_row)
|
if (sjtbl->have_confluent_row)
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
else
|
|
||||||
{
|
|
||||||
sjtbl->have_confluent_row= TRUE;
|
sjtbl->have_confluent_row= TRUE;
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
uchar *ptr= sjtbl->tmp_table->record[0] + 1;
|
ptr= sjtbl->tmp_table->record[0] + 1;
|
||||||
uchar *nulls_ptr= ptr;
|
nulls_ptr= ptr;
|
||||||
|
|
||||||
/* Put the the rowids tuple into table->record[0]: */
|
/* Put the the rowids tuple into table->record[0]: */
|
||||||
|
|
||||||
@@ -17196,7 +17223,7 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
|
|||||||
|
|
||||||
|
|
||||||
/* ARGSUSED */
|
/* ARGSUSED */
|
||||||
static enum_nested_loop_state
|
enum_nested_loop_state
|
||||||
end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
|
end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
|
||||||
bool end_of_records)
|
bool end_of_records)
|
||||||
{
|
{
|
||||||
@@ -17504,7 +17531,7 @@ end_unique_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
|
|||||||
|
|
||||||
|
|
||||||
/* ARGSUSED */
|
/* ARGSUSED */
|
||||||
static enum_nested_loop_state
|
enum_nested_loop_state
|
||||||
end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
|
end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
|
||||||
bool end_of_records)
|
bool end_of_records)
|
||||||
{
|
{
|
||||||
@@ -17724,17 +17751,33 @@ static bool replace_where_subcondition(JOIN *join, Item **expr,
|
|||||||
Extracted condition
|
Extracted condition
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static COND *
|
static Item *
|
||||||
make_cond_for_table(COND *cond, table_map tables, table_map used_table)
|
make_cond_for_table(Item *cond, table_map tables, table_map used_table,
|
||||||
|
bool exclude_expensive_cond)
|
||||||
{
|
{
|
||||||
return make_cond_for_table_from_pred(cond, cond, tables, used_table);
|
return make_cond_for_table_from_pred(cond, cond, tables, used_table,
|
||||||
|
exclude_expensive_cond);
|
||||||
}
|
}
|
||||||
|
|
||||||
static COND *
|
static Item *
|
||||||
make_cond_for_table_from_pred(COND *root_cond, COND *cond,
|
make_cond_for_table_from_pred(Item *root_cond, Item *cond,
|
||||||
table_map tables, table_map used_table)
|
table_map tables, table_map used_table,
|
||||||
|
bool exclude_expensive_cond)
|
||||||
|
|
||||||
{
|
{
|
||||||
if (used_table && !(cond->used_tables() & used_table))
|
if (used_table && !(cond->used_tables() & used_table) &&
|
||||||
|
/*
|
||||||
|
Exclude constant conditions not checked at optimization time if
|
||||||
|
the table we are pushing conditions to is the first one.
|
||||||
|
As a result, such conditions are not considered as already checked
|
||||||
|
and will be checked at execution time, attached to the first table.
|
||||||
|
|
||||||
|
psergey: TODO: "used_table & 1" doesn't make sense in nearly any
|
||||||
|
context. Look at setup_table_map(), table bits reflect the order
|
||||||
|
the tables were encountered by the parser. Check what we should
|
||||||
|
replace this condition with.
|
||||||
|
*/
|
||||||
|
!((used_table & 1) && cond->is_expensive()))
|
||||||
return (COND*) 0; // Already checked
|
return (COND*) 0; // Already checked
|
||||||
if (cond->type() == Item::COND_ITEM)
|
if (cond->type() == Item::COND_ITEM)
|
||||||
{
|
{
|
||||||
@@ -17748,7 +17791,9 @@ make_cond_for_table_from_pred(COND *root_cond, COND *cond,
|
|||||||
Item *item;
|
Item *item;
|
||||||
while ((item=li++))
|
while ((item=li++))
|
||||||
{
|
{
|
||||||
Item *fix=make_cond_for_table_from_pred(root_cond, item, tables, used_table);
|
Item *fix=make_cond_for_table_from_pred(root_cond, item,
|
||||||
|
tables, used_table,
|
||||||
|
exclude_expensive_cond);
|
||||||
if (fix)
|
if (fix)
|
||||||
new_cond->argument_list()->push_back(fix);
|
new_cond->argument_list()->push_back(fix);
|
||||||
}
|
}
|
||||||
@@ -17778,7 +17823,9 @@ make_cond_for_table_from_pred(COND *root_cond, COND *cond,
|
|||||||
Item *item;
|
Item *item;
|
||||||
while ((item=li++))
|
while ((item=li++))
|
||||||
{
|
{
|
||||||
Item *fix=make_cond_for_table_from_pred(root_cond, item, tables, 0L);
|
Item *fix=make_cond_for_table_from_pred(root_cond, item,
|
||||||
|
tables, 0L,
|
||||||
|
exclude_expensive_cond);
|
||||||
if (!fix)
|
if (!fix)
|
||||||
return (COND*) 0; // Always true
|
return (COND*) 0; // Always true
|
||||||
new_cond->argument_list()->push_back(fix);
|
new_cond->argument_list()->push_back(fix);
|
||||||
@@ -17799,8 +17846,12 @@ make_cond_for_table_from_pred(COND *root_cond, COND *cond,
|
|||||||
table_count times, we mark each item that we have examined with the result
|
table_count times, we mark each item that we have examined with the result
|
||||||
of the test
|
of the test
|
||||||
*/
|
*/
|
||||||
|
if (cond->marker == 3 || (cond->used_tables() & ~tables) ||
|
||||||
if (cond->marker == 3 || (cond->used_tables() & ~tables))
|
/*
|
||||||
|
When extracting constant conditions, treat expensive conditions as
|
||||||
|
non-constant, so that they are not evaluated at optimization time.
|
||||||
|
*/
|
||||||
|
(!used_table && exclude_expensive_cond && cond->is_expensive()))
|
||||||
return (COND*) 0; // Can't check this yet
|
return (COND*) 0; // Can't check this yet
|
||||||
if (cond->marker == 2 || cond->eq_cmp_result() == Item::COND_OK)
|
if (cond->marker == 2 || cond->eq_cmp_result() == Item::COND_OK)
|
||||||
return cond; // Not boolean op
|
return cond; // Not boolean op
|
||||||
@@ -18937,7 +18988,8 @@ static bool fix_having(JOIN *join, Item **having)
|
|||||||
table_map used_tables= join->const_table_map | table->table->map;
|
table_map used_tables= join->const_table_map | table->table->map;
|
||||||
|
|
||||||
DBUG_EXECUTE("where",print_where(*having,"having", QT_ORDINARY););
|
DBUG_EXECUTE("where",print_where(*having,"having", QT_ORDINARY););
|
||||||
Item* sort_table_cond=make_cond_for_table(*having,used_tables,used_tables);
|
Item* sort_table_cond=make_cond_for_table(*having, used_tables, used_tables,
|
||||||
|
FALSE);
|
||||||
if (sort_table_cond)
|
if (sort_table_cond)
|
||||||
{
|
{
|
||||||
if (!table->select)
|
if (!table->select)
|
||||||
@@ -18955,7 +19007,7 @@ static bool fix_having(JOIN *join, Item **having)
|
|||||||
DBUG_EXECUTE("where",print_where(table->select_cond,
|
DBUG_EXECUTE("where",print_where(table->select_cond,
|
||||||
"select and having",
|
"select and having",
|
||||||
QT_ORDINARY););
|
QT_ORDINARY););
|
||||||
*having=make_cond_for_table(*having,~ (table_map) 0,~used_tables);
|
*having= make_cond_for_table(*having,~ (table_map) 0,~used_tables, FALSE);
|
||||||
DBUG_EXECUTE("where",
|
DBUG_EXECUTE("where",
|
||||||
print_where(*having,"having after make_cond", QT_ORDINARY););
|
print_where(*having,"having after make_cond", QT_ORDINARY););
|
||||||
}
|
}
|
||||||
@@ -20027,7 +20079,7 @@ alloc_group_fields(JOIN *join,ORDER *group)
|
|||||||
{
|
{
|
||||||
for (; group ; group=group->next)
|
for (; group ; group=group->next)
|
||||||
{
|
{
|
||||||
Cached_item *tmp=new_Cached_item(join->thd, *group->item);
|
Cached_item *tmp=new_Cached_item(join->thd, *group->item, FALSE);
|
||||||
if (!tmp || join->group_fields.push_front(tmp))
|
if (!tmp || join->group_fields.push_front(tmp))
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
@@ -20037,6 +20089,38 @@ alloc_group_fields(JOIN *join,ORDER *group)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Test if a single-row cache of items changed, and update the cache.
|
||||||
|
|
||||||
|
@details Test if a list of items that typically represents a result
|
||||||
|
row has changed. If the value of some item changed, update the cached
|
||||||
|
value for this item.
|
||||||
|
|
||||||
|
@param list list of <item, cached_value> pairs stored as Cached_item.
|
||||||
|
|
||||||
|
@return -1 if no item changed
|
||||||
|
@return index of the first item that changed
|
||||||
|
*/
|
||||||
|
|
||||||
|
int test_if_item_cache_changed(List<Cached_item> &list)
|
||||||
|
{
|
||||||
|
DBUG_ENTER("test_if_item_cache_changed");
|
||||||
|
List_iterator<Cached_item> li(list);
|
||||||
|
int idx= -1,i;
|
||||||
|
Cached_item *buff;
|
||||||
|
|
||||||
|
for (i=(int) list.elements-1 ; (buff=li++) ; i--)
|
||||||
|
{
|
||||||
|
if (buff->cmp())
|
||||||
|
idx=i;
|
||||||
|
}
|
||||||
|
DBUG_PRINT("info", ("idx: %d", idx));
|
||||||
|
DBUG_RETURN(idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
test_if_group_changed(List<Cached_item> &list)
|
test_if_group_changed(List<Cached_item> &list)
|
||||||
{
|
{
|
||||||
|
@@ -1199,6 +1199,14 @@ enum_nested_loop_state sub_select_sjm(JOIN *join, JOIN_TAB *join_tab,
|
|||||||
bool end_of_records);
|
bool end_of_records);
|
||||||
int do_sj_dups_weedout(THD *thd, SJ_TMP_TABLE *sjtbl);
|
int do_sj_dups_weedout(THD *thd, SJ_TMP_TABLE *sjtbl);
|
||||||
|
|
||||||
|
enum_nested_loop_state
|
||||||
|
end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
|
||||||
|
bool end_of_records);
|
||||||
|
enum_nested_loop_state
|
||||||
|
end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
|
||||||
|
bool end_of_records);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Information about a position of table within a join order. Used in join
|
Information about a position of table within a join order. Used in join
|
||||||
optimization.
|
optimization.
|
||||||
@@ -1945,6 +1953,7 @@ bool error_if_full_join(JOIN *join);
|
|||||||
int report_error(TABLE *table, int error);
|
int report_error(TABLE *table, int error);
|
||||||
int safe_index_read(JOIN_TAB *tab);
|
int safe_index_read(JOIN_TAB *tab);
|
||||||
COND *remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value);
|
COND *remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value);
|
||||||
|
int test_if_item_cache_changed(List<Cached_item> &list);
|
||||||
void calc_used_field_length(THD *thd, JOIN_TAB *join_tab);
|
void calc_used_field_length(THD *thd, JOIN_TAB *join_tab);
|
||||||
int join_init_read_record(JOIN_TAB *tab);
|
int join_init_read_record(JOIN_TAB *tab);
|
||||||
void set_position(JOIN *join,uint idx,JOIN_TAB *table,KEYUSE *key);
|
void set_position(JOIN *join,uint idx,JOIN_TAB *table,KEYUSE *key);
|
||||||
|
@@ -715,8 +715,8 @@ void st_select_lex_unit::reinit_exec_mechanism()
|
|||||||
TRUE - error
|
TRUE - error
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bool st_select_lex_unit::change_result(select_subselect *new_result,
|
bool st_select_lex_unit::change_result(select_result_interceptor *new_result,
|
||||||
select_subselect *old_result)
|
select_result_interceptor *old_result)
|
||||||
{
|
{
|
||||||
bool res= FALSE;
|
bool res= FALSE;
|
||||||
for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select())
|
for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select())
|
||||||
|
Reference in New Issue
Block a user