Commit 7655f05d authored by monty@mashka.mysql.fi's avatar monty@mashka.mysql.fi

LEFT JOIN optimization: Change LEFT JOIN to normal join if possible

parent 039554f3
...@@ -2569,16 +2569,46 @@ fld1 fld1 ...@@ -2569,16 +2569,46 @@ fld1 fld1
250503 250505 250503 250505
250504 250505 250504 250505
250505 250505 250505 250505
insert into t2 (fld1, companynr) values (999999,99);
select t2.companynr,companyname from t2 left join t4 using (companynr) where t4.companynr is null; select t2.companynr,companyname from t2 left join t4 using (companynr) where t4.companynr is null;
companynr companyname companynr companyname
99 NULL
select count(*) from t2 left join t4 using (companynr) where t4.companynr is not null;
count(*)
1199
explain select t2.companynr,companyname from t2 left join t4 using (companynr) where t4.companynr is null; explain select t2.companynr,companyname from t2 left join t4 using (companynr) where t4.companynr is null;
table type possible_keys key key_len ref rows Extra table type possible_keys key key_len ref rows Extra
t2 ALL NULL NULL NULL NULL 1199 t2 ALL NULL NULL NULL NULL 1200
t4 eq_ref PRIMARY PRIMARY 1 test.t2.companynr 1 Using where; Not exists t4 eq_ref PRIMARY PRIMARY 1 test.t2.companynr 1 Using where; Not exists
explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr is null; explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr is null;
table type possible_keys key key_len ref rows Extra table type possible_keys key key_len ref rows Extra
t4 ALL NULL NULL NULL NULL 12 t4 ALL NULL NULL NULL NULL 12
t2 ALL NULL NULL NULL NULL 1199 Using where; Not exists t2 ALL NULL NULL NULL NULL 1200 Using where; Not exists
delete from t2 where fld1=999999;
explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0;
table type possible_keys key key_len ref rows Extra
t2 ALL NULL NULL NULL NULL 1199 Using where
t4 eq_ref PRIMARY PRIMARY 1 test.t2.companynr 1
explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 or t2.companynr < 0;
table type possible_keys key key_len ref rows Extra
t2 ALL NULL NULL NULL NULL 1199 Using where
t4 eq_ref PRIMARY PRIMARY 1 test.t2.companynr 1
explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 and t4.companynr > 0;
table type possible_keys key key_len ref rows Extra
t2 ALL NULL NULL NULL NULL 1199 Using where
t4 eq_ref PRIMARY PRIMARY 1 test.t2.companynr 1 Using where
explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 or t2.companynr is null;
table type possible_keys key key_len ref rows Extra
t4 ALL NULL NULL NULL NULL 12
t2 ALL NULL NULL NULL NULL 1199 Using where
explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 or t2.companynr < 0 or t4.companynr > 0;
table type possible_keys key key_len ref rows Extra
t4 ALL PRIMARY NULL NULL NULL 12
t2 ALL NULL NULL NULL NULL 1199 Using where
explain select t2.companynr,companyname from t4 left join t2 using (companynr) where ifnull(t2.companynr,1)>0;
table type possible_keys key key_len ref rows Extra
t4 ALL NULL NULL NULL NULL 12
t2 ALL NULL NULL NULL NULL 1199 Using where
select distinct t2.companynr,t4.companynr from t2,t4 where t2.companynr=t4.companynr+1; select distinct t2.companynr,t4.companynr from t2,t4 where t2.companynr=t4.companynr+1;
companynr companynr companynr companynr
37 36 37 36
......
...@@ -1527,10 +1527,24 @@ select t2.fld1,t22.fld1 from t2,t2 t22 where t2.fld1 >= 250501 and t2.fld1 <= 25 ...@@ -1527,10 +1527,24 @@ select t2.fld1,t22.fld1 from t2,t2 t22 where t2.fld1 >= 250501 and t2.fld1 <= 25
# #
# Test of left join. # Test of left join.
# #
insert into t2 (fld1, companynr) values (999999,99);
select t2.companynr,companyname from t2 left join t4 using (companynr) where t4.companynr is null; select t2.companynr,companyname from t2 left join t4 using (companynr) where t4.companynr is null;
select count(*) from t2 left join t4 using (companynr) where t4.companynr is not null;
explain select t2.companynr,companyname from t2 left join t4 using (companynr) where t4.companynr is null; explain select t2.companynr,companyname from t2 left join t4 using (companynr) where t4.companynr is null;
explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr is null; explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr is null;
delete from t2 where fld1=999999;
#
# Test left join optimization
explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0;
explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 or t2.companynr < 0;
explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 and t4.companynr > 0;
# Following can't be optimized
explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 or t2.companynr is null;
explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 or t2.companynr < 0 or t4.companynr > 0;
explain select t2.companynr,companyname from t4 left join t2 using (companynr) where ifnull(t2.companynr,1)>0;
# #
# Joins with forms. # Joins with forms.
......
...@@ -71,7 +71,24 @@ public: ...@@ -71,7 +71,24 @@ public:
virtual double val_result() { return val(); } virtual double val_result() { return val(); }
virtual longlong val_int_result() { return val_int(); } virtual longlong val_int_result() { return val_int(); }
virtual String *str_result(String* tmp) { return val_str(tmp); } virtual String *str_result(String* tmp) { return val_str(tmp); }
/* bit map of tables used by item */
virtual table_map used_tables() const { return (table_map) 0L; } virtual table_map used_tables() const { return (table_map) 0L; }
/*
Return table map of tables that can't be NULL tables (tables that are
used in a context where if they would contain a NULL row generated
by a LEFT or RIGHT join, the item would not be true).
This expression is used on WHERE item to determinate if a LEFT JOIN can be
converted to a normal join.
Generally this function should return used_tables() if the function
would return null if any of the arguments are null
As this is only used in the beginning of optimization, the value don't
have to be updated in update_used_tables()
*/
virtual table_map not_null_tables() const { return used_tables(); }
/*
Returns true if this is a simple constant item like an integer, not
a constant expression
*/
virtual bool basic_const_item() const { return 0; } virtual bool basic_const_item() const { return 0; }
virtual Item *new_item() { return 0; } /* Only for const items */ virtual Item *new_item() { return 0; } /* Only for const items */
virtual cond_result eq_cmp_result() const { return COND_OK; } virtual cond_result eq_cmp_result() const { return COND_OK; }
......
...@@ -292,10 +292,12 @@ void Item_func_interval::fix_length_and_dec() ...@@ -292,10 +292,12 @@ void Item_func_interval::fix_length_and_dec()
} }
} }
maybe_null=0; max_length=2; maybe_null=0; max_length=2;
used_tables_cache|=item->used_tables(); used_tables_cache|= item->used_tables();
not_null_tables_cache&= item->not_null_tables();
with_sum_func= with_sum_func || item->with_sum_func; with_sum_func= with_sum_func || item->with_sum_func;
} }
void Item_func_interval::split_sum_func(List<Item> &fields) void Item_func_interval::split_sum_func(List<Item> &fields)
{ {
if (item->with_sum_func && item->type() != SUM_FUNC_ITEM) if (item->with_sum_func && item->type() != SUM_FUNC_ITEM)
...@@ -1073,8 +1075,9 @@ void Item_func_in::fix_length_and_dec() ...@@ -1073,8 +1075,9 @@ void Item_func_in::fix_length_and_dec()
} }
maybe_null= item->maybe_null; maybe_null= item->maybe_null;
max_length=2; max_length=2;
used_tables_cache|=item->used_tables(); used_tables_cache|= item->used_tables();
const_item_cache&=item->const_item(); not_null_tables_cache&= item->not_null_tables();
const_item_cache&= item->const_item();
} }
...@@ -1174,14 +1177,21 @@ Item_cond::fix_fields(THD *thd,TABLE_LIST *tables) ...@@ -1174,14 +1177,21 @@ Item_cond::fix_fields(THD *thd,TABLE_LIST *tables)
char buff[sizeof(char*)]; // Max local vars in function char buff[sizeof(char*)]; // Max local vars in function
used_tables_cache=0; used_tables_cache=0;
const_item_cache=0; const_item_cache=0;
/*
and_table_cache is the value that Item_cond_or() returns for
not_null_tables()
*/
and_tables_cache= ~(table_map) 0;
if (thd && check_stack_overrun(thd,buff)) if (thd && check_stack_overrun(thd,buff))
return 0; // Fatal error flag is set! return 0; // Fatal error flag is set!
while ((item=li++)) while ((item=li++))
{ {
table_map tmp_table_map;
while (item->type() == Item::COND_ITEM && while (item->type() == Item::COND_ITEM &&
((Item_cond*) item)->functype() == functype()) ((Item_cond*) item)->functype() == functype())
{ // Identical function { // Identical function
li.replace(((Item_cond*) item)->list); li.replace(((Item_cond*) item)->list);
((Item_cond*) item)->list.empty(); ((Item_cond*) item)->list.empty();
#ifdef DELETE_ITEMS #ifdef DELETE_ITEMS
...@@ -1193,9 +1203,12 @@ Item_cond::fix_fields(THD *thd,TABLE_LIST *tables) ...@@ -1193,9 +1203,12 @@ Item_cond::fix_fields(THD *thd,TABLE_LIST *tables)
item->top_level_item(); item->top_level_item();
if (item->fix_fields(thd,tables)) if (item->fix_fields(thd,tables))
return 1; /* purecov: inspected */ return 1; /* purecov: inspected */
used_tables_cache|=item->used_tables(); used_tables_cache|= item->used_tables();
with_sum_func= with_sum_func || item->with_sum_func; tmp_table_map= item->not_null_tables();
const_item_cache&=item->const_item(); not_null_tables_cache|= tmp_table_map;
and_tables_cache&= tmp_table_map;
const_item_cache&= item->const_item();
with_sum_func= with_sum_func || item->with_sum_func;
if (item->maybe_null) if (item->maybe_null)
maybe_null=1; maybe_null=1;
} }
...@@ -1234,17 +1247,19 @@ Item_cond::used_tables() const ...@@ -1234,17 +1247,19 @@ Item_cond::used_tables() const
return used_tables_cache; return used_tables_cache;
} }
void Item_cond::update_used_tables() void Item_cond::update_used_tables()
{ {
used_tables_cache=0;
const_item_cache=1;
List_iterator_fast<Item> li(list); List_iterator_fast<Item> li(list);
Item *item; Item *item;
used_tables_cache=0;
const_item_cache=1;
while ((item=li++)) while ((item=li++))
{ {
item->update_used_tables(); item->update_used_tables();
used_tables_cache|=item->used_tables(); used_tables_cache|= item->used_tables();
const_item_cache&= item->const_item(); const_item_cache&= item->const_item();
} }
} }
...@@ -1348,12 +1363,16 @@ Item *and_expressions(Item *a, Item *b, Item **org_item) ...@@ -1348,12 +1363,16 @@ Item *and_expressions(Item *a, Item *b, Item **org_item)
{ {
Item_cond *res; Item_cond *res;
if ((res= new Item_cond_and(a, (Item*) b))) if ((res= new Item_cond_and(a, (Item*) b)))
{
res->used_tables_cache= a->used_tables() | b->used_tables(); res->used_tables_cache= a->used_tables() | b->used_tables();
res->not_null_tables_cache= a->not_null_tables() | b->not_null_tables();
}
return res; return res;
} }
if (((Item_cond_and*) a)->add((Item*) b)) if (((Item_cond_and*) a)->add((Item*) b))
return 0; return 0;
((Item_cond_and*) a)->used_tables_cache|= b->used_tables(); ((Item_cond_and*) a)->used_tables_cache|= b->used_tables();
((Item_cond_and*) a)->not_null_tables_cache|= b->not_null_tables();
return a; return a;
} }
...@@ -1489,6 +1508,8 @@ Item_func_regex::fix_fields(THD *thd,TABLE_LIST *tables) ...@@ -1489,6 +1508,8 @@ Item_func_regex::fix_fields(THD *thd,TABLE_LIST *tables)
max_length=1; decimals=0; max_length=1; decimals=0;
binary=args[0]->binary || args[1]->binary; binary=args[0]->binary || args[1]->binary;
used_tables_cache=args[0]->used_tables() | args[1]->used_tables(); used_tables_cache=args[0]->used_tables() | args[1]->used_tables();
not_null_tables_cache= (args[0]->not_null_tables() |
args[1]->not_null_tables());
const_item_cache=args[0]->const_item() && args[1]->const_item(); const_item_cache=args[0]->const_item() && args[1]->const_item();
if (!regex_compiled && args[1]->const_item()) if (!regex_compiled && args[1]->const_item())
{ {
......
...@@ -204,7 +204,7 @@ public: ...@@ -204,7 +204,7 @@ public:
enum Item_result result_type () const { return cached_result_type; } enum Item_result result_type () const { return cached_result_type; }
void fix_length_and_dec(); void fix_length_and_dec();
const char *func_name() const { return "ifnull"; } const char *func_name() const { return "ifnull"; }
unsigned int size_of() { return sizeof(*this);} table_map not_null_tables() const { return 0; }
}; };
...@@ -224,7 +224,7 @@ public: ...@@ -224,7 +224,7 @@ public:
} }
void fix_length_and_dec(); void fix_length_and_dec();
const char *func_name() const { return "if"; } const char *func_name() const { return "if"; }
unsigned int size_of() { return sizeof(*this);} table_map not_null_tables() const { return 0; }
}; };
...@@ -239,7 +239,7 @@ public: ...@@ -239,7 +239,7 @@ public:
enum Item_result result_type () const { return cached_result_type; } enum Item_result result_type () const { return cached_result_type; }
void fix_length_and_dec(); void fix_length_and_dec();
const char *func_name() const { return "nullif"; } const char *func_name() const { return "nullif"; }
unsigned int size_of() { return sizeof(*this);} table_map not_null_tables() const { return 0; }
}; };
...@@ -254,9 +254,10 @@ public: ...@@ -254,9 +254,10 @@ public:
void fix_length_and_dec(); void fix_length_and_dec();
enum Item_result result_type () const { return cached_result_type; } enum Item_result result_type () const { return cached_result_type; }
const char *func_name() const { return "coalesce"; } const char *func_name() const { return "coalesce"; }
unsigned int size_of() { return sizeof(*this);} table_map not_null_tables() const { return 0; }
}; };
class Item_func_case :public Item_func class Item_func_case :public Item_func
{ {
Item * first_expr, *else_expr; Item * first_expr, *else_expr;
...@@ -270,6 +271,7 @@ public: ...@@ -270,6 +271,7 @@ public:
String *val_str(String *); String *val_str(String *);
void fix_length_and_dec(); void fix_length_and_dec();
void update_used_tables(); void update_used_tables();
table_map not_null_tables() const { return 0; }
enum Item_result result_type () const { return cached_result_type; } enum Item_result result_type () const { return cached_result_type; }
const char *func_name() const { return "case"; } const char *func_name() const { return "case"; }
void print(String *str); void print(String *str);
...@@ -479,10 +481,12 @@ public: ...@@ -479,10 +481,12 @@ public:
} }
} }
} }
table_map not_null_tables() const { return 0; }
optimize_type select_optimize() const { return OPTIMIZE_NULL; } optimize_type select_optimize() const { return OPTIMIZE_NULL; }
unsigned int size_of() { return sizeof(*this);} unsigned int size_of() { return sizeof(*this);}
}; };
class Item_func_isnotnull :public Item_bool_func class Item_func_isnotnull :public Item_bool_func
{ {
public: public:
...@@ -495,9 +499,10 @@ public: ...@@ -495,9 +499,10 @@ public:
} }
const char *func_name() const { return "isnotnull"; } const char *func_name() const { return "isnotnull"; }
optimize_type select_optimize() const { return OPTIMIZE_NULL; } optimize_type select_optimize() const { return OPTIMIZE_NULL; }
unsigned int size_of() { return sizeof(*this);} table_map not_null_tables() const { return 0; }
}; };
class Item_func_like :public Item_bool_func2 class Item_func_like :public Item_bool_func2
{ {
char escape; char escape;
...@@ -572,6 +577,8 @@ class Item_cond :public Item_bool_func ...@@ -572,6 +577,8 @@ class Item_cond :public Item_bool_func
protected: protected:
List<Item> list; List<Item> list;
bool abort_on_null; bool abort_on_null;
table_map and_tables_cache;
public: public:
/* Item_cond() is only used to create top level items */ /* Item_cond() is only used to create top level items */
Item_cond() : Item_bool_func(), abort_on_null(1) { const_item_cache=0; } Item_cond() : Item_bool_func(), abort_on_null(1) { const_item_cache=0; }
...@@ -611,6 +618,7 @@ public: ...@@ -611,6 +618,7 @@ public:
enum Functype functype() const { return COND_OR_FUNC; } enum Functype functype() const { return COND_OR_FUNC; }
longlong val_int(); longlong val_int();
const char *func_name() const { return "or"; } const char *func_name() const { return "or"; }
table_map not_null_tables() const { return and_tables_cache; }
}; };
......
...@@ -61,7 +61,7 @@ Item_func::fix_fields(THD *thd,TABLE_LIST *tables) ...@@ -61,7 +61,7 @@ Item_func::fix_fields(THD *thd,TABLE_LIST *tables)
Item **arg,**arg_end; Item **arg,**arg_end;
char buff[STACK_BUFF_ALLOC]; // Max argument in function char buff[STACK_BUFF_ALLOC]; // Max argument in function
binary=0; binary=0;
used_tables_cache=0; used_tables_cache= not_null_tables_cache= 0;
const_item_cache=1; const_item_cache=1;
if (thd && check_stack_overrun(thd,buff)) if (thd && check_stack_overrun(thd,buff))
...@@ -78,8 +78,9 @@ Item_func::fix_fields(THD *thd,TABLE_LIST *tables) ...@@ -78,8 +78,9 @@ Item_func::fix_fields(THD *thd,TABLE_LIST *tables)
if (item->binary) if (item->binary)
binary=1; binary=1;
with_sum_func= with_sum_func || item->with_sum_func; with_sum_func= with_sum_func || item->with_sum_func;
used_tables_cache|=item->used_tables(); used_tables_cache|= item->used_tables();
const_item_cache&= item->const_item(); not_null_tables_cache|= item->not_null_tables();
const_item_cache&= item->const_item();
} }
} }
fix_length_and_dec(); fix_length_and_dec();
...@@ -122,6 +123,13 @@ table_map Item_func::used_tables() const ...@@ -122,6 +123,13 @@ table_map Item_func::used_tables() const
return used_tables_cache; return used_tables_cache;
} }
table_map Item_func::not_null_tables() const
{
return not_null_tables_cache;
}
void Item_func::print(String *str) void Item_func::print(String *str)
{ {
str->append(func_name()); str->append(func_name());
......
...@@ -34,7 +34,7 @@ protected: ...@@ -34,7 +34,7 @@ protected:
Item **args,*tmp_arg[2]; Item **args,*tmp_arg[2];
public: public:
uint arg_count; uint arg_count;
table_map used_tables_cache; table_map used_tables_cache, not_null_tables_cache;
bool const_item_cache; bool const_item_cache;
enum Functype { UNKNOWN_FUNC,EQ_FUNC,EQUAL_FUNC,NE_FUNC,LT_FUNC,LE_FUNC, enum Functype { UNKNOWN_FUNC,EQ_FUNC,EQUAL_FUNC,NE_FUNC,LT_FUNC,LE_FUNC,
GE_FUNC,GT_FUNC,FT_FUNC, GE_FUNC,GT_FUNC,FT_FUNC,
...@@ -97,6 +97,7 @@ public: ...@@ -97,6 +97,7 @@ public:
bool fix_fields(THD *,struct st_table_list *); bool fix_fields(THD *,struct st_table_list *);
void make_field(Send_field *field); void make_field(Send_field *field);
table_map used_tables() const; table_map used_tables() const;
table_map not_null_tables() const;
void update_used_tables(); void update_used_tables();
bool eq(const Item *item, bool binary_cmp) const; bool eq(const Item *item, bool binary_cmp) const;
virtual optimize_type select_optimize() const { return OPTIMIZE_NONE; } virtual optimize_type select_optimize() const { return OPTIMIZE_NONE; }
...@@ -588,7 +589,8 @@ public: ...@@ -588,7 +589,8 @@ public:
void split_sum_func(List<Item> &fields); void split_sum_func(List<Item> &fields);
void update_used_tables() void update_used_tables()
{ {
item->update_used_tables() ; Item_func::update_used_tables(); item->update_used_tables();
Item_func::update_used_tables();
used_tables_cache|= item->used_tables(); used_tables_cache|= item->used_tables();
const_item_cache&= item->const_item(); const_item_cache&= item->const_item();
} }
...@@ -597,6 +599,7 @@ public: ...@@ -597,6 +599,7 @@ public:
{ {
maybe_null=0; max_length=3; maybe_null=0; max_length=3;
used_tables_cache|= item->used_tables(); used_tables_cache|= item->used_tables();
not_null_tables_cache&= item->not_null_tables();
const_item_cache&= item->const_item(); const_item_cache&= item->const_item();
with_sum_func= with_sum_func || item->with_sum_func; with_sum_func= with_sum_func || item->with_sum_func;
} }
...@@ -736,6 +739,7 @@ public: ...@@ -736,6 +739,7 @@ public:
return res; return res;
} }
Item_result result_type () const { return udf.result_type(); } Item_result result_type () const { return udf.result_type(); }
table_map not_null_tables() const { return 0; }
unsigned int size_of() { return sizeof(*this);} unsigned int size_of() { return sizeof(*this);}
}; };
...@@ -969,6 +973,7 @@ public: ...@@ -969,6 +973,7 @@ public:
} }
enum Functype functype() const { return FT_FUNC; } enum Functype functype() const { return FT_FUNC; }
void update_used_tables() {} void update_used_tables() {}
table_map not_null_tables() const { return 0; }
bool fix_fields(THD *thd,struct st_table_list *tlist); bool fix_fields(THD *thd,struct st_table_list *tlist);
bool eq(const Item *, bool binary_cmp) const; bool eq(const Item *, bool binary_cmp) const;
longlong val_int() { return val()!=0.0; } longlong val_int() { return val()!=0.0; }
......
...@@ -606,9 +606,10 @@ void Item_func_concat_ws::fix_length_and_dec() ...@@ -606,9 +606,10 @@ void Item_func_concat_ws::fix_length_and_dec()
max_length=MAX_BLOB_WIDTH; max_length=MAX_BLOB_WIDTH;
maybe_null=1; maybe_null=1;
} }
used_tables_cache|=separator->used_tables(); used_tables_cache|= separator->used_tables();
const_item_cache&=separator->const_item(); not_null_tables_cache&= separator->not_null_tables();
with_sum_func= with_sum_func || separator->with_sum_func; const_item_cache&= separator->const_item();
with_sum_func= with_sum_func || separator->with_sum_func;
} }
void Item_func_concat_ws::update_used_tables() void Item_func_concat_ws::update_used_tables()
...@@ -1509,8 +1510,9 @@ void Item_func_elt::fix_length_and_dec() ...@@ -1509,8 +1510,9 @@ void Item_func_elt::fix_length_and_dec()
} }
maybe_null=1; // NULL if wrong first arg maybe_null=1; // NULL if wrong first arg
with_sum_func= with_sum_func || item->with_sum_func; with_sum_func= with_sum_func || item->with_sum_func;
used_tables_cache|=item->used_tables(); used_tables_cache|= item->used_tables();
const_item_cache&=item->const_item(); not_null_tables_cache&= item->not_null_tables();
const_item_cache&= item->const_item();
} }
...@@ -1591,8 +1593,9 @@ void Item_func_make_set::fix_length_and_dec() ...@@ -1591,8 +1593,9 @@ void Item_func_make_set::fix_length_and_dec()
max_length=arg_count-1; max_length=arg_count-1;
for (uint i=1 ; i < arg_count ; i++) for (uint i=1 ; i < arg_count ; i++)
max_length+=args[i]->max_length; max_length+=args[i]->max_length;
used_tables_cache|=item->used_tables(); used_tables_cache|= item->used_tables();
const_item_cache&=item->const_item(); not_null_tables_cache&= item->not_null_tables();
const_item_cache&= item->const_item();
with_sum_func= with_sum_func || item->with_sum_func; with_sum_func= with_sum_func || item->with_sum_func;
} }
......
...@@ -1903,11 +1903,11 @@ bool setup_tables(TABLE_LIST *tables) ...@@ -1903,11 +1903,11 @@ bool setup_tables(TABLE_LIST *tables)
table->used_fields=0; table->used_fields=0;
table->const_table=0; table->const_table=0;
table->outer_join=table->null_row=0; table->null_row=0;
table->status=STATUS_NO_RECORD; table->status=STATUS_NO_RECORD;
table->keys_in_use_for_query= table->keys_in_use; table->keys_in_use_for_query= table->keys_in_use;
table->used_keys= table->keys_for_keyread; table->used_keys= table->keys_for_keyread;
table->maybe_null=test(table->outer_join=table_list->outer_join); table->maybe_null=test(table->outer_join= table_list->outer_join);
table->tablenr=tablenr; table->tablenr=tablenr;
table->map= (table_map) 1 << tablenr; table->map= (table_map) 1 << tablenr;
table->force_index= table_list->force_index; table->force_index= table_list->force_index;
...@@ -2027,6 +2027,7 @@ insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name, ...@@ -2027,6 +2027,7 @@ insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name,
int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
{ {
table_map not_null_tables= 0;
DBUG_ENTER("setup_conds"); DBUG_ENTER("setup_conds");
thd->set_query_id=1; thd->set_query_id=1;
thd->cond_count=0; thd->cond_count=0;
...@@ -2036,6 +2037,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) ...@@ -2036,6 +2037,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
thd->where="where clause"; thd->where="where clause";
if ((*conds)->fix_fields(thd,tables)) if ((*conds)->fix_fields(thd,tables))
DBUG_RETURN(1); DBUG_RETURN(1);
not_null_tables= (*conds)->not_null_tables();
} }
/* Check if we are using outer joins */ /* Check if we are using outer joins */
...@@ -2049,9 +2051,15 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) ...@@ -2049,9 +2051,15 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
DBUG_RETURN(1); DBUG_RETURN(1);
thd->cond_count++; thd->cond_count++;
/* If it's a normal join, add the ON/USING expression to the WHERE */ /*
if (!table->outer_join) If it's a normal join or a LEFT JOIN which can be optimized away
add the ON/USING expression to the WHERE
*/
if (!table->outer_join ||
((table->table->map & not_null_tables) &&
!(specialflag & SPECIAL_NO_NEW_FUNC)))
{ {
table->outer_join= 0;
if (!(*conds=and_conds(*conds, table->on_expr))) if (!(*conds=and_conds(*conds, table->on_expr)))
DBUG_RETURN(1); DBUG_RETURN(1);
table->on_expr=0; table->on_expr=0;
......
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