Commit f47b2d38 authored by Sergey Petrunya's avatar Sergey Petrunya

Subquery optimizations: non-semijoin materialization

- Backport into Maria DB 5.3, part 1
parent 742afd8e
......@@ -878,6 +878,9 @@ class Item {
static CHARSET_INFO *default_charset();
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)
{
return (this->*processor)(arg);
......@@ -1081,6 +1084,29 @@ class Item {
*/
virtual bool result_as_longlong() { return FALSE; }
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
{ return Field::GEOM_GEOMETRY; };
String *check_well_formed_result(String *str, bool send_error= 0);
......@@ -2842,9 +2868,10 @@ class Cached_item_field :public Cached_item
uint length;
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());
}
bool cmp(void);
......@@ -3271,7 +3298,8 @@ void mark_select_range_as_dependent(THD *thd,
Field *found_field, Item *found_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 void resolve_const_item(THD *thd, Item **ref, Item *cmp_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.
*/
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 &&
!(((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()) {
case STRING_RESULT:
return new Cached_item_str(thd, (Item_field *) item);
......
......@@ -490,12 +490,12 @@ Field *Item_func::tmp_table_field(TABLE *table)
return field;
}
/*
bool Item_func::is_expensive_processor(uchar *arg)
{
return is_expensive();
}
*/
my_decimal *Item_func::val_decimal(my_decimal *decimal_value)
{
......
......@@ -192,8 +192,8 @@ class Item_func :public Item_result_field
Item_transformer transformer, uchar *arg_t);
void traverse_cond(Cond_traverser traverser,
void * arg, traverse_order order);
bool is_expensive_processor(uchar *arg);
virtual bool is_expensive() { return 0; }
// bool is_expensive_processor(uchar *arg);
// virtual bool is_expensive() { return 0; }
inline double fix_result(double value)
{
if (isfinite(value))
......@@ -1053,6 +1053,7 @@ class Item_udf_func :public Item_func
{
protected:
udf_handler udf;
bool is_expensive_processor(uchar *arg) { return TRUE; }
public:
Item_udf_func(udf_func *udf_arg)
......@@ -1676,6 +1677,9 @@ class Item_func_sp :public Item_func
bool execute();
bool execute_impl(THD *thd);
bool init_result_field(THD *thd);
protected:
bool is_expensive_processor(uchar *arg) { return TRUE; }
public:
......
This diff is collapsed.
This diff is collapsed.
......@@ -5493,7 +5493,7 @@ static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param,COND *cond)
DBUG_RETURN(tree);
}
/* 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
......
......@@ -2076,16 +2076,28 @@ void st_select_lex::print_limit(THD *thd,
{
SELECT_LEX_UNIT *unit= master_unit();
Item_subselect *item= unit->item;
if (item && unit->global_parameters == this &&
(item->substype() == Item_subselect::EXISTS_SUBS ||
item->substype() == Item_subselect::IN_SUBS ||
item->substype() == Item_subselect::ALL_SUBS))
if (item && unit->global_parameters == this)
{
DBUG_ASSERT(!item->fixed ||
(select_limit->val_int() == LL(1) && offset_limit == 0));
return;
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 ||
/*
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;
}
}
if (explicit_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.
......
......@@ -559,7 +559,8 @@ class st_select_lex_unit: public st_select_lex_node {
bool add_fake_select_lex(THD *thd);
void init_prepare_fake_select_lex(THD *thd);
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_thd(THD *thd_arg) { thd= thd_arg; }
inline bool is_union ();
......
This diff is collapsed.
......@@ -1199,6 +1199,14 @@ enum_nested_loop_state sub_select_sjm(JOIN *join, JOIN_TAB *join_tab,
bool end_of_records);
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
optimization.
......@@ -1945,6 +1953,7 @@ bool error_if_full_join(JOIN *join);
int report_error(TABLE *table, int error);
int safe_index_read(JOIN_TAB *tab);
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);
int join_init_read_record(JOIN_TAB *tab);
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
*/
bool st_select_lex_unit::change_result(select_subselect *new_result,
select_subselect *old_result)
bool st_select_lex_unit::change_result(select_result_interceptor *new_result,
select_result_interceptor *old_result)
{
bool res= FALSE;
for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select())
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment