Commit 9e65634b authored by Sergey Petrunia's avatar Sergey Petrunia

MWL#17: Table elimination

- Make elimination check to be able detect cases like  t.primary_key_col1=othertbl.col AND t.primary_key_col2=func(t.primary_key_col1).
  These are needed to handle e.g. the case of func() being a correlated subquery that selects the latest value.
- If we've removed a condition with subquery predicate, EXPLAIN [EXTENDED] won't show the subquery anymore

sql/item.cc:
  MWL#17: Table elimination
  - Add tem_field::check_column_usage_processor(). it allows to check which key parts a condition depends on.
sql/item.h:
  MWL#17: Table elimination
  - Add tem_field::check_column_usage_processor(). it allows to check which key parts a condition depends on.
sql/item_subselect.cc:
  MWL#17: Table elimination
  - Item_subselect got 'eliminated' attribute. It is used only to determine if the subselect should be printed by EXPLAIN.
  - Item_subselect got List<Item> refers_to - a list of item in the current select that are referred to from within the subselect.
  - Added Item_*::check_column_usage_processor(). it allows to check which key parts a condition depends on.
  - Added a comment about possible problem in Item_subselect::walk
sql/item_subselect.h:
  MWL#17: Table elimination
  - Item_subselect got 'eliminated' attribute. It is used only to determine if the subselect should be printed by EXPLAIN.
  - Item_subselect got List<Item> refers_to - a list of item in the current select that are referred to from within the subselect.
  - Added Item_*::check_column_usage_processor(). it allows to check which key parts a condition depends on.
sql/item_sum.cc:
  MWL#17: Table elimination
sql/sql_lex.cc:
  MWL#17: Table elimination
sql/sql_lex.h:
  MWL#17: Table elimination
sql/sql_select.h:
  MWL#17: Table elimination
parent 7a9f45c6
...@@ -1915,6 +1915,30 @@ void Item_field::reset_field(Field *f) ...@@ -1915,6 +1915,30 @@ void Item_field::reset_field(Field *f)
name= (char*) f->field_name; name= (char*) f->field_name;
} }
bool Item_field::check_column_usage_processor(uchar *arg)
{
Field_processor_info* info=(Field_processor_info*)arg;
if (used_tables() & ~info->allowed_tables)
return FALSE;
if (field->table == info->table)
{
if (!(field->part_of_key.is_set(info->keyno)))
return TRUE;
KEY *key= &field->table->key_info[info->keyno];
for (uint part= 0; part < key->key_parts; part++)
{
if (field->field_index == key->key_part[part].field->field_index)
{
info->needed_key_parts |= key_part_map(1) << part;
break;
}
}
}
return FALSE;
}
const char *Item_ident::full_name() const const char *Item_ident::full_name() const
{ {
char *tmp; char *tmp;
...@@ -3380,7 +3404,7 @@ static void mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current, ...@@ -3380,7 +3404,7 @@ static void mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current,
/* store pointer on SELECT_LEX from which item is dependent */ /* store pointer on SELECT_LEX from which item is dependent */
if (mark_item) if (mark_item)
mark_item->depended_from= last; mark_item->depended_from= last;
current->mark_as_dependent(last); current->mark_as_dependent(last, resolved_item);
if (thd->lex->describe & DESCRIBE_EXTENDED) if (thd->lex->describe & DESCRIBE_EXTENDED)
{ {
char warn_buff[MYSQL_ERRMSG_SIZE]; char warn_buff[MYSQL_ERRMSG_SIZE];
......
...@@ -888,6 +888,8 @@ public: ...@@ -888,6 +888,8 @@ public:
virtual bool reset_query_id_processor(uchar *query_id_arg) { return 0; } virtual bool reset_query_id_processor(uchar *query_id_arg) { return 0; }
virtual bool is_expensive_processor(uchar *arg) { return 0; } virtual bool is_expensive_processor(uchar *arg) { return 0; }
virtual bool register_field_in_read_map(uchar *arg) { return 0; } virtual bool register_field_in_read_map(uchar *arg) { return 0; }
virtual bool check_column_usage_processor(uchar *arg) { return 0; }
virtual bool mark_as_eliminated_processor(uchar *arg) { return 0; }
/* /*
Check if a partition function is allowed Check if a partition function is allowed
SYNOPSIS SYNOPSIS
...@@ -1012,6 +1014,14 @@ public: ...@@ -1012,6 +1014,14 @@ public:
}; };
typedef struct
{
table_map allowed_tables;
TABLE *table;
uint keyno;
uint needed_key_parts;
} Field_processor_info;
class sp_head; class sp_head;
...@@ -1477,6 +1487,7 @@ public: ...@@ -1477,6 +1487,7 @@ public:
bool find_item_in_field_list_processor(uchar *arg); bool find_item_in_field_list_processor(uchar *arg);
bool register_field_in_read_map(uchar *arg); bool register_field_in_read_map(uchar *arg);
bool check_partition_func_processor(uchar *int_arg) {return FALSE;} bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
bool check_column_usage_processor(uchar *arg);
void cleanup(); void cleanup();
bool result_as_longlong() bool result_as_longlong()
{ {
......
...@@ -39,7 +39,7 @@ inline Item * and_items(Item* cond, Item *item) ...@@ -39,7 +39,7 @@ inline Item * and_items(Item* cond, Item *item)
Item_subselect::Item_subselect(): Item_subselect::Item_subselect():
Item_result_field(), value_assigned(0), thd(0), substitution(0), Item_result_field(), value_assigned(0), thd(0), substitution(0),
engine(0), old_engine(0), used_tables_cache(0), have_to_be_excluded(0), engine(0), old_engine(0), used_tables_cache(0), have_to_be_excluded(0),
const_item_cache(1), engine_changed(0), changed(0), is_correlated(FALSE) const_item_cache(1), in_fix_fields(0), engine_changed(0), changed(0), is_correlated(FALSE)
{ {
with_subselect= 1; with_subselect= 1;
reset(); reset();
...@@ -151,10 +151,14 @@ bool Item_subselect::fix_fields(THD *thd_param, Item **ref) ...@@ -151,10 +151,14 @@ bool Item_subselect::fix_fields(THD *thd_param, Item **ref)
DBUG_ASSERT(fixed == 0); DBUG_ASSERT(fixed == 0);
engine->set_thd((thd= thd_param)); engine->set_thd((thd= thd_param));
if (!in_fix_fields)
refers_to.empty();
eliminated= FALSE;
if (check_stack_overrun(thd, STACK_MIN_SIZE, (uchar*)&res)) if (check_stack_overrun(thd, STACK_MIN_SIZE, (uchar*)&res))
return TRUE; return TRUE;
in_fix_fields++;
res= engine->prepare(); res= engine->prepare();
// all transformation is done (used by prepared statements) // all transformation is done (used by prepared statements)
...@@ -181,12 +185,14 @@ bool Item_subselect::fix_fields(THD *thd_param, Item **ref) ...@@ -181,12 +185,14 @@ bool Item_subselect::fix_fields(THD *thd_param, Item **ref)
if (!(*ref)->fixed) if (!(*ref)->fixed)
ret= (*ref)->fix_fields(thd, ref); ret= (*ref)->fix_fields(thd, ref);
thd->where= save_where; thd->where= save_where;
in_fix_fields--;
return ret; return ret;
} }
// Is it one field subselect? // Is it one field subselect?
if (engine->cols() > max_columns) if (engine->cols() > max_columns)
{ {
my_error(ER_OPERAND_COLUMNS, MYF(0), 1); my_error(ER_OPERAND_COLUMNS, MYF(0), 1);
in_fix_fields--;
return TRUE; return TRUE;
} }
fix_length_and_dec(); fix_length_and_dec();
...@@ -203,11 +209,30 @@ bool Item_subselect::fix_fields(THD *thd_param, Item **ref) ...@@ -203,11 +209,30 @@ bool Item_subselect::fix_fields(THD *thd_param, Item **ref)
fixed= 1; fixed= 1;
err: err:
in_fix_fields--;
thd->where= save_where; thd->where= save_where;
return res; return res;
} }
bool Item_subselect::check_column_usage_processor(uchar *arg)
{
List_iterator<Item> it(refers_to);
Item *item;
while ((item= it++))
{
if (item->walk(&Item::check_column_usage_processor,FALSE, arg))
return TRUE;
}
return FALSE;
}
bool Item_subselect::mark_as_eliminated_processor(uchar *arg)
{
eliminated= TRUE;
return FALSE;
}
bool Item_subselect::walk(Item_processor processor, bool walk_subquery, bool Item_subselect::walk(Item_processor processor, bool walk_subquery,
uchar *argument) uchar *argument)
{ {
...@@ -225,6 +250,7 @@ bool Item_subselect::walk(Item_processor processor, bool walk_subquery, ...@@ -225,6 +250,7 @@ bool Item_subselect::walk(Item_processor processor, bool walk_subquery,
if (lex->having && (lex->having)->walk(processor, walk_subquery, if (lex->having && (lex->having)->walk(processor, walk_subquery,
argument)) argument))
return 1; return 1;
/* TODO: why doesn't this walk the OUTER JOINs' ON expressions */
while ((item=li++)) while ((item=li++))
{ {
......
...@@ -52,8 +52,16 @@ protected: ...@@ -52,8 +52,16 @@ protected:
bool have_to_be_excluded; bool have_to_be_excluded;
/* cache of constant state */ /* cache of constant state */
bool const_item_cache; bool const_item_cache;
public: public:
/*
References from inside the subquery to the select that this predicate is
in. References to parent selects not included.
*/
List<Item> refers_to;
int in_fix_fields;
bool eliminated;
/* changed engine indicator */ /* changed engine indicator */
bool engine_changed; bool engine_changed;
/* subquery is transformed */ /* subquery is transformed */
...@@ -126,6 +134,8 @@ public: ...@@ -126,6 +134,8 @@ public:
virtual void reset_value_registration() {} virtual void reset_value_registration() {}
enum_parsing_place place() { return parsing_place; } enum_parsing_place place() { return parsing_place; }
bool walk(Item_processor processor, bool walk_subquery, uchar *arg); bool walk(Item_processor processor, bool walk_subquery, uchar *arg);
bool mark_as_eliminated_processor(uchar *arg);
bool check_column_usage_processor(uchar *arg);
/** /**
Get the SELECT_LEX structure associated with this Item. Get the SELECT_LEX structure associated with this Item.
......
...@@ -350,7 +350,7 @@ bool Item_sum::register_sum_func(THD *thd, Item **ref) ...@@ -350,7 +350,7 @@ bool Item_sum::register_sum_func(THD *thd, Item **ref)
sl= sl->master_unit()->outer_select() ) sl= sl->master_unit()->outer_select() )
sl->master_unit()->item->with_sum_func= 1; sl->master_unit()->item->with_sum_func= 1;
} }
thd->lex->current_select->mark_as_dependent(aggr_sel); thd->lex->current_select->mark_as_dependent(aggr_sel, NULL);
return FALSE; return FALSE;
} }
......
...@@ -1778,7 +1778,7 @@ void st_select_lex_unit::exclude_tree() ...@@ -1778,7 +1778,7 @@ void st_select_lex_unit::exclude_tree()
'last' should be reachable from this st_select_lex_node 'last' should be reachable from this st_select_lex_node
*/ */
void st_select_lex::mark_as_dependent(st_select_lex *last) void st_select_lex::mark_as_dependent(st_select_lex *last, Item *dependency)
{ {
/* /*
Mark all selects from resolved to 1 before select where was Mark all selects from resolved to 1 before select where was
...@@ -1804,6 +1804,8 @@ void st_select_lex::mark_as_dependent(st_select_lex *last) ...@@ -1804,6 +1804,8 @@ void st_select_lex::mark_as_dependent(st_select_lex *last)
} }
is_correlated= TRUE; is_correlated= TRUE;
this->master_unit()->item->is_correlated= TRUE; this->master_unit()->item->is_correlated= TRUE;
if (dependency)
this->master_unit()->item->refers_to.push_back(dependency);
} }
bool st_select_lex_node::set_braces(bool value) { return 1; } bool st_select_lex_node::set_braces(bool value) { return 1; }
......
...@@ -743,7 +743,7 @@ public: ...@@ -743,7 +743,7 @@ public:
return master_unit()->return_after_parsing(); return master_unit()->return_after_parsing();
} }
void mark_as_dependent(st_select_lex *last); void mark_as_dependent(st_select_lex *last, Item *dependency);
bool set_braces(bool value); bool set_braces(bool value);
bool inc_in_sum_expr(); bool inc_in_sum_expr();
......
This diff is collapsed.
...@@ -51,6 +51,7 @@ typedef struct keyuse_t { ...@@ -51,6 +51,7 @@ typedef struct keyuse_t {
NULL - Otherwise (the source equality can't be turned off) NULL - Otherwise (the source equality can't be turned off)
*/ */
bool *cond_guard; bool *cond_guard;
bool usable;
} KEYUSE; } KEYUSE;
class store_key; class store_key;
......
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