summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/item.cc101
-rw-r--r--sql/item.h4
-rw-r--r--sql/item_cmpfunc.cc11
-rw-r--r--sql/opt_range.cc57
-rw-r--r--sql/sql_select.cc344
-rw-r--r--sql/sql_select.h3
-rw-r--r--sql/table.h2
7 files changed, 389 insertions, 133 deletions
diff --git a/sql/item.cc b/sql/item.cc
index a17336ea634..c99c0a9ba6d 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -408,7 +408,7 @@ bool DTCollation::aggregate(DTCollation &dt, bool superset_conversion)
Item_field::Item_field(Field *f)
:Item_ident(NullS, f->table_name, f->field_name),
- item_equal(0),
+ item_equal(0), no_const_subst(0),
have_privileges(0), any_privileges(0)
{
set_field(f);
@@ -419,7 +419,7 @@ Item_field::Item_field(Field *f)
Item_field::Item_field(THD *thd, Field *f)
:Item_ident(NullS, thd->strdup(f->table_name),
thd->strdup(f->field_name)),
- item_equal(0),
+ item_equal(0), no_const_subst(0),
have_privileges(0), any_privileges(0)
{
set_field(f);
@@ -432,11 +432,12 @@ Item_field::Item_field(THD *thd, Item_field *item)
:Item_ident(thd, item),
field(item->field),
result_field(item->result_field),
+ item_equal(item->item_equal),
+ no_const_subst(item->no_const_subst),
have_privileges(item->have_privileges),
any_privileges(item->any_privileges)
{
collation.set(DERIVATION_IMPLICIT);
- item_equal= item->item_equal;
}
void Item_field::set_field(Field *field_par)
@@ -1607,7 +1608,101 @@ void Item_field::cleanup()
First Item_equal containing the field, if success
0, otherwise
*/
+Item_equal *Item_field::find_item_equal(COND_EQUAL *cond_equal)
+{
+ Item_equal *item= 0;
+ while (cond_equal)
+ {
+ List_iterator_fast<Item_equal> li(cond_equal->current_level);
+ while ((item= li++))
+ {
+ if (item->contains(field))
+ return item;
+ }
+ /*
+ The field is not found in any of the multiple equalities
+ of the current level. Look for it in upper levels
+ */
+ cond_equal= cond_equal->upper_levels;
+ }
+ return 0;
+}
+
+/*
+ Set a pointer to the multiple equality the field reference belongs to (if any)
+
+ SYNOPSIS
+ equal_fields_propagator()
+ arg - reference to list of multiple equalities where
+ the field (this object) is to be looked for
+
+ DESCRIPTION
+ The function looks for a multiple equality containing the field item
+ among those referenced by arg.
+ In the case such equality exists the function does the following.
+ If the found multiple equality contains a constant, then the field
+ reference is substituted for this constant, otherwise it sets a pointer
+ to the multiple equality in the field item.
+
+ NOTES
+ This function is supposed to be called as a callback parameter in calls
+ of the transform method.
+
+ RETURN VALUES
+ pointer to the replacing constant item, if the field item was substituted
+ pointer to the field item, otherwise.
+*/
+
+Item *Item_field::equal_fields_propagator(byte *arg)
+{
+ if (no_const_subst)
+ return this;
+ item_equal= find_item_equal((COND_EQUAL *) arg);
+ Item *item= 0;
+ if (item_equal)
+ item= item_equal->get_const();
+ if (!item)
+ item= this;
+ return item;
+}
+
+
+/*
+ Set a pointer to the multiple equality the field reference belongs to (if any)
+
+ SYNOPSIS
+ replace_equal_field_processor()
+ arg - a dummy parameter, is not used here
+
+ DESCRIPTION
+ The function replaces a pointer to a field in the Item_field object
+ by a pointer to another field.
+ The replacement field is taken from the very beginning of
+ the item_equal list which the Item_field object refers to (belongs to)
+ If the Item_field object does not refer any Item_equal object,
+ nothing is done.
+
+ NOTES
+ This function is supposed to be called as a callback parameter in calls
+ of the walk method.
+
+ RETURN VALUES
+ 0
+*/
+
+bool Item_field::replace_equal_field_processor(byte *arg)
+{
+ if (item_equal)
+ {
+ Item_field *subst= item_equal->get_first();
+ if (!field->eq(subst->field))
+ {
+ field= subst->field;
+ return 0;
+ }
+ }
+ return 0;
}
void Item::init_make_field(Send_field *tmp_field,
diff --git a/sql/item.h b/sql/item.h
index 9826bcb4a5a..c8e274b7205 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -457,6 +457,8 @@ protected:
void set_field(Field *field);
public:
Field *field,*result_field;
+ Item_equal *item_equal;
+ bool no_const_subst;
/*
if any_privileges set to TRUE then here real effective privileges will
be stored
@@ -468,7 +470,7 @@ public:
Item_field(const char *db_par,const char *table_name_par,
const char *field_name_par)
:Item_ident(db_par,table_name_par,field_name_par),
- field(0), result_field(0), item_equal(0),}
+ field(0), result_field(0), item_equal(0), no_const_subst(0),
have_privileges(0), any_privileges(0)
{ collation.set(DERIVATION_IMPLICIT); }
// Constructor need to process subselect with temporary tables (see Item)
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 1f2e744f714..66af96f671f 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -231,6 +231,8 @@ void Item_bool_func2::fix_length_and_dec()
conv->collation.set(args[weak]->collation.derivation);
conv->fix_fields(thd, 0, &conv);
}
+ if (args[weak]->type() == FIELD_ITEM)
+ ((Item_field *)args[weak])->no_const_subst= 1;
args[weak]= conv ? conv : args[weak];
}
}
@@ -1956,7 +1958,7 @@ Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
char buff[sizeof(char*)]; // Max local vars in function
#endif
not_null_tables_cache= used_tables_cache= 0;
- const_item_cache= 0;
+ const_item_cache= 1;
/*
and_table_cache is the value that Item_cond_or() returns for
not_null_tables()
@@ -1987,7 +1989,7 @@ Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
tmp_table_map= item->not_null_tables();
not_null_tables_cache|= tmp_table_map;
and_tables_cache&= tmp_table_map;
- const_item_cache&= item->const_item();
+ const_item_cache&= item->const_item();
with_sum_func= with_sum_func || item->with_sum_func;
if (item->maybe_null)
maybe_null=1;
@@ -2051,7 +2053,7 @@ void Item_cond::split_sum_func(Item **ref_pointer_array, List<Item> &fields)
List_iterator<Item> li(list);
Item *item;
used_tables_cache=0;
- const_item_cache=0;
+ const_item_cache=1;
while ((item=li++))
{
if (item->with_sum_func && item->type() != SUM_FUNC_ITEM)
@@ -2088,7 +2090,7 @@ void Item_cond::update_used_tables()
{
item->update_used_tables();
used_tables_cache|= item->used_tables();
- const_item_cache&= item->const_item();
+ const_item_cache&= item->const_item();
}
}
@@ -2934,6 +2936,7 @@ void Item_equal::add(Item *c)
}
Item_func_eq *func= new Item_func_eq(c, const_item);
func->set_cmp_func();
+ func->quick_fix_field();
cond_false = !(func->val_int());
}
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 502a8d51b07..fe34ac7235e 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -3339,6 +3339,63 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond)
}
DBUG_RETURN(ftree);
+ }
+ default:
+ if (cond_func->arguments()[0]->type() == Item::FIELD_ITEM)
+ {
+ field_item= (Item_field*) (cond_func->arguments()[0]);
+ value= cond_func->arg_count > 1 ? cond_func->arguments()[1] : 0;
+ }
+ else if (cond_func->have_rev_func() &&
+ cond_func->arguments()[1]->type() == Item::FIELD_ITEM)
+ {
+ field_item= (Item_field*) (cond_func->arguments()[1]);
+ value= cond_func->arguments()[0];
+ }
+ else
+ DBUG_RETURN(0);
+ }
+
+ /*
+ If the where condition contains a predicate (ti.field op const),
+ then not only SELL_TREE for this predicate is built, but
+ the trees for the results of substitution of ti.field for
+ each tj.field belonging to the same multiple equality as ti.field
+ are built as well.
+ E.g. for WHERE t1.a=t2.a AND t2.a > 10
+ a SEL_TREE for t2.a > 10 will be built for quick select from t2
+ and
+ a SEL_TREE for t1.a > 10 will be built for quick select from t1.
+ */
+
+ for (uint i= 0; i < cond_func->arg_count; i++)
+ {
+ Item *arg= cond_func->arguments()[i];
+ if (arg != field_item)
+ ref_tables|= arg->used_tables();
+ }
+ Field *field= field_item->field;
+ Item_result cmp_type= field->cmp_type();
+ if (!((ref_tables | field->table->map) & param_comp))
+ ftree= get_func_mm_tree(param, cond_func, field, value, cmp_type);
+ Item_equal *item_equal= field_item->item_equal;
+ if (item_equal)
+ {
+ Item_equal_iterator it(*item_equal);
+ Item_field *item;
+ while ((item= it++))
+ {
+ Field *f= item->field;
+ if (field->eq(f))
+ continue;
+ if (!((ref_tables | f->table->map) & param_comp))
+ {
+ tree= get_func_mm_tree(param, cond_func, f, value, cmp_type);
+ ftree= !ftree ? tree : tree_and(param, ftree, tree);
+ }
+ }
+ }
+ DBUG_RETURN(ftree);
}
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index b3355f6c57c..05df457da1b 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -91,8 +91,10 @@ static int return_zero_rows(JOIN *join, select_result *res,TABLE_LIST *tables,
uint select_options, const char *info,
Item *having, Procedure *proc,
SELECT_LEX_UNIT *unit);
-static COND *build_all_equal_items(COND *cond,
- COND_EQUAL *inherited);
+static COND *build_equal_items(COND *cond,
+ COND_EQUAL *inherited,
+ List<TABLE_LIST> *join_list,
+ COND_EQUAL **cond_equal_ref);
static COND* substitute_for_best_equal_field(COND *cond,
COND_EQUAL *cond_equal,
void *table_join_idx);
@@ -530,17 +532,29 @@ JOIN::optimize()
}
}
#endif
-
- /* Eliminate NOT operators */
- conds= eliminate_not_funcs(conds);
- DBUG_EXECUTE("where", print_where(conds, "after negation elimination"););
+ SELECT_LEX *sel= thd->lex->current_select;
+ if (sel->first_cond_optimization)
{
- TABLE_LIST *tables;
- for (tables= tables_list; tables; tables= tables->next)
- {
- if (tables->on_expr)
- tables->on_expr= eliminate_not_funcs(tables->on_expr);
- }
+ /*
+ The following code will allocate the new items in a permanent
+ MEMROOT for prepared statements and stored procedures.
+ */
+
+ Item_arena *arena= thd->current_arena, backup;
+ if (arena->is_conventional())
+ arena= 0; // For easier test
+ else
+ thd->set_n_backup_item_arena(arena, &backup);
+
+ sel->first_cond_optimization= 0;
+
+ /* Convert all outer joins to inner joins if possible */
+ conds= simplify_joins(this, join_list, conds, TRUE);
+
+ sel->prep_where= conds ? conds->copy_andor_structure(thd) : 0;
+
+ if (arena)
+ thd->restore_backup_item_arena(arena, &backup);
}
/*
@@ -550,32 +564,8 @@ JOIN::optimize()
that occurs in a function set a pointer to the multiple equality
predicate. Substitute a constant instead of this field if the
multiple equality contains a constant.
- */
- if (conds)
- {
- conds= build_all_equal_items(conds, NULL);
- conds->update_used_tables();
- if (conds->type() == Item::COND_ITEM &&
- ((Item_cond*) conds)->functype() == Item_func::COND_AND_FUNC)
- cond_equal= &((Item_cond_and*) conds)->cond_equal;
- else if (conds->type() == Item::FUNC_ITEM &&
- ((Item_cond*) conds)->functype() == Item_func::MULT_EQUAL_FUNC)
- {
- cond_equal= new COND_EQUAL;
- cond_equal->current_level.push_back((Item_equal *) conds);
- }
- }
- {
- TABLE_LIST *tables;
- for (tables= tables_list; tables; tables= tables->next)
- {
- if (tables->on_expr)
- {
- tables->on_expr= build_all_equal_items(tables->on_expr, cond_equal);
- tables->on_expr->update_used_tables();
- }
- }
- }
+ */
+ conds= build_equal_items(conds, NULL, join_list, &cond_equal);
conds= optimize_cond(this, conds,&cond_value);
if (thd->net.report_error)
@@ -669,31 +659,6 @@ JOIN::optimize()
if (const_tables && !thd->locked_tables &&
!(select_options & SELECT_NO_UNLOCK))
mysql_unlock_some_tables(thd, table, const_tables);
- /*
- Among the equal fields belonging to the same multiple equality
- choose the one that is to be retrieved first and substitute
- all references to these in where condition for a reference for
- the selected field.
- */
- if (conds)
- {
- conds= substitute_for_best_equal_field(conds, cond_equal, map2table);
- conds->update_used_tables();
- }
- {
- TABLE_LIST *tables;
- for (tables= tables_list; tables; tables= tables->next)
- {
- if (tables->on_expr)
- {
- tables->on_expr= substitute_for_best_equal_field(tables->on_expr,
- cond_equal,
- map2table);
- tables->on_expr->update_used_tables();
- map2table[tables->table->tablenr]->on_expr= tables->on_expr;
- }
- }
- }
if (!conds && outer_join)
{
/* Handle the case where we have an OUTER JOIN without a WHERE */
@@ -710,6 +675,32 @@ JOIN::optimize()
make_outerjoin_info(this);
+ /*
+ Among the equal fields belonging to the same multiple equality
+ choose the one that is to be retrieved first and substitute
+ all references to these in where condition for a reference for
+ the selected field.
+ */
+ if (conds)
+ {
+ conds= substitute_for_best_equal_field(conds, cond_equal, map2table);
+ conds->update_used_tables();
+ }
+ /*
+ Permorm the the optimization on fields evaluation mentioned above
+ for all on expressions.
+ */
+ for (JOIN_TAB *tab= join_tab + const_tables; tab < join_tab + tables ; tab++)
+ {
+ if (*tab->on_expr_ref)
+ {
+ *tab->on_expr_ref= substitute_for_best_equal_field(*tab->on_expr_ref,
+ tab->cond_equal,
+ map2table);
+ (*tab->on_expr_ref)->update_used_tables();
+ }
+ }
+
if (make_join_select(this, select, conds))
{
zero_result_cause=
@@ -1545,8 +1536,6 @@ JOIN::exec()
/*
table->keyuse is set in the case there was an original WHERE clause
on the table that was optimized away.
- table->on_expr tells us that it was a LEFT JOIN and there will be
- at least one row generated from the table.
*/
if (curr_table->select_cond ||
(curr_table->keyuse && !curr_table->first_inner))
@@ -1646,6 +1635,7 @@ JOIN::cleanup()
tmp_table_param.copy_field=0;
DBUG_RETURN(tmp_join->cleanup());
}
+ cond_equal= 0;
lock=0; // It's faster to unlock later
join_free(1);
@@ -1794,7 +1784,7 @@ Cursor::fetch(ulong num_rows)
{
THD *thd= join->thd;
JOIN_TAB *join_tab= join->join_tab + join->const_tables;;
- COND *on_expr= join_tab->on_expr;
+ COND *on_expr= *join_tab->on_expr_ref;
COND *select_cond= join_tab->select_cond;
READ_RECORD *info= &join_tab->read_record;
@@ -2156,7 +2146,8 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
s->dependent= tables->dep_tables;
s->key_dependent= 0;
- if ((s->on_expr=tables->on_expr))
+ s->on_expr_ref= &tables->on_expr;
+ if (*s->on_expr_ref)
{
/* s is the only inner table of an outer join */
if (!table->file->records)
@@ -2378,7 +2369,7 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
SQL_SELECT *select;
select= make_select(s->table, found_const_table_map,
found_const_table_map,
- s->on_expr ? s->on_expr : conds,
+ *s->on_expr_ref ? *s->on_expr_ref : conds,
&error);
records= get_quick_record_count(join->thd, select, s->table,
&s->const_keys, join->row_limit);
@@ -2396,7 +2387,7 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
join->const_table_map|= s->table->map;
set_position(join,const_count++,s,(KEYUSE*) 0);
s->type= JT_CONST;
- if (s->on_expr)
+ if (*s->on_expr_ref)
{
/* Generate empty row */
s->info= "Impossible ON condition";
@@ -2774,16 +2765,26 @@ add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level,
case Item_func::OPTIMIZE_NONE:
break;
case Item_func::OPTIMIZE_KEY:
- // BETWEEN, IN, NOT
+ {
+ // BETWEEN, IN, NE
if (cond_func->key_item()->real_item()->type() == Item::FIELD_ITEM &&
!(cond_func->used_tables() & OUTER_REF_TABLE_BIT))
- add_key_field(key_fields,*and_level,cond_func,
- ((Item_field*)(cond_func->key_item()->real_item()))->field,
- cond_func->argument_count() == 2 &&
- cond_func->functype() == Item_func::IN_FUNC,
- cond_func->arguments()+1, cond_func->argument_count()-1,
- usable_tables);
+ {
+ Item **values= cond_func->arguments()+1;
+ if (cond_func->functype() == Item_func::NE_FUNC &&
+ cond_func->arguments()[1]->real_item()->type() == Item::FIELD_ITEM &&
+ !(cond_func->arguments()[0]->used_tables() & OUTER_REF_TABLE_BIT))
+ values--;
+ add_key_equal_fields(key_fields, *and_level, cond_func,
+ (Item_field*) (cond_func->key_item()->real_item()),
+ cond_func->argument_count() == 2 &&
+ cond_func->functype() == Item_func::IN_FUNC,
+ values,
+ cond_func->argument_count()-1,
+ usable_tables);
+ }
break;
+ }
case Item_func::OPTIMIZE_OP:
{
bool equal_func=(cond_func->functype() == Item_func::EQ_FUNC ||
@@ -3048,9 +3049,9 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
for inner tables in outer joins these keys will be taken
into account as well.
*/
- if (join_tab[i].on_expr)
+ if (*join_tab[i].on_expr_ref)
{
- add_key_fields(join_tab,&end,&and_level,join_tab[i].on_expr,
+ add_key_fields(join_tab,&end,&and_level,*join_tab[i].on_expr_ref,
join_tab[i].table->map);
}
else
@@ -4654,7 +4655,7 @@ get_best_combination(JOIN *join)
form=join->table[tablenr]=j->table;
used_tables|= form->map;
form->reginfo.join_tab=j;
- if (!j->on_expr)
+ if (!*j->on_expr_ref)
form->reginfo.not_exists_optimize=0; // Only with LEFT JOIN
if (j->type == JT_CONST)
continue; // Handled in make_join_stat..
@@ -4909,7 +4910,7 @@ make_simple_join(JOIN *join,TABLE *tmp_table)
join_tab->type= JT_ALL; /* Map through all records */
join_tab->keys.init(~0); /* test everything in quick */
join_tab->info=0;
- join_tab->on_expr=0;
+ join_tab->on_expr_ref=0;
join_tab->last_inner= 0;
join_tab->first_unmatched= 0;
join_tab->ref.key = -1;
@@ -4978,7 +4979,7 @@ add_found_match_trig_cond(JOIN_TAB *tab, COND *cond, JOIN_TAB *root_tab)
first inner table of the embedding outer join operation, if there is any,
through the field t0->first_upper.
The on expression for the outer join operation is attached to the
- corresponding first inner table through the field t0->on_expr.
+ corresponding first inner table through the field t0->on_expr_ref.
Here ti are structures of the JOIN_TAB type.
EXAMPLE
@@ -4992,8 +4993,8 @@ add_found_match_trig_cond(JOIN_TAB *tab, COND *cond, JOIN_TAB *root_tab)
is selected, the following references will be set;
t4->last_inner=[t4], t4->first_inner=[t4], t4->first_upper=[t2]
t2->last_inner=[t4], t2->first_inner=t3->first_inner=[t2],
- on expression (t1.a=t2.a AND t1.b=t3.b) will be attached to t2->on_expr,
- while t3.a=t4.a will be attached to t4->on_expr.
+ on expression (t1.a=t2.a AND t1.b=t3.b) will be attached to
+ *t2->on_expr_ref, while t3.a=t4.a will be attached to *t4->on_expr_ref.
NOTES
The function assumes that the simplification procedure has been
@@ -5020,7 +5021,8 @@ make_outerjoin_info(JOIN *join)
is in the query above.)
*/
tab->last_inner= tab->first_inner= tab;
- tab->on_expr= tbl->on_expr;
+ tab->on_expr_ref= &tbl->on_expr;
+ tab->cond_equal= tbl->cond_equal;
if (embedding)
tab->first_upper= embedding->nested_join->first_nested;
}
@@ -5034,7 +5036,8 @@ make_outerjoin_info(JOIN *join)
Save reference to it in the nested join structure.
*/
nested_join->first_nested= tab;
- tab->on_expr= embedding->on_expr;
+ tab->on_expr_ref= &embedding->on_expr;
+ tab->cond_equal= tbl->cond_equal;
if (embedding->embedding)
tab->first_upper= embedding->embedding->nested_join->first_nested;
}
@@ -5069,10 +5072,10 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
for (JOIN_TAB *tab= join->join_tab+join->const_tables;
tab < join->join_tab+join->tables ; tab++)
{
- if (tab->on_expr)
+ if (*tab->on_expr_ref)
{
JOIN_TAB *cond_tab= tab->first_inner;
- COND *tmp= make_cond_for_table(tab->on_expr,
+ COND *tmp= make_cond_for_table(*tab->on_expr_ref,
join->const_table_map,
(table_map) 0);
if (!tmp)
@@ -5210,7 +5213,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
{
/* Join with outer join condition */
COND *orig_cond=sel->cond;
- sel->cond= and_conds(sel->cond, tab->on_expr);
+ sel->cond= and_conds(sel->cond, *tab->on_expr_ref);
if (sel->cond && !sel->cond->fixed)
sel->cond->fix_fields(join->thd, 0, &sel->cond);
if (sel->test_quick_select(join->thd, tab->keys,
@@ -5225,7 +5228,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
we have to check isn't it only "impossible ON" instead
*/
sel->cond=orig_cond;
- if (!tab->on_expr ||
+ if (!*tab->on_expr_ref ||
sel->test_quick_select(join->thd, tab->keys,
used_tables & ~ current_map,
(join->select_options &
@@ -5290,7 +5293,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
Table tab is the last inner table of an outer join.
An on expression is always attached to it.
*/
- COND *on_expr= first_inner_tab->on_expr;
+ COND *on_expr= *first_inner_tab->on_expr_ref;
table_map used_tables= join->const_table_map |
OUTER_REF_TABLE_BIT | RAND_TABLE_BIT;
@@ -5804,7 +5807,7 @@ remove_const(JOIN *join,ORDER *first_order, COND *cond, bool *simple_order)
table_map not_const_tables= ~join->const_table_map;
table_map ref;
prev_ptr= &first_order;
- *simple_order= join->join_tab[join->const_tables].on_expr ? 0 : 1;
+ *simple_order= *join->join_tab[join->const_tables].on_expr_ref ? 0 : 1;
/* NOTE: A variable of not_const_tables ^ first_table; breaks gcc 2.7 */
@@ -6024,7 +6027,7 @@ finish:
general case, its own constant for each fields from the multiple
equality. But at the same time it would allow us to get rid
of constant propagation completely: it would be done by the call
- to build_all_equal_items.
+ to build_equal_items_for_cond.
IMPLEMENTATION
The implementation does not follow exactly the above rules to
@@ -6156,7 +6159,7 @@ static bool check_equality(Item *item, COND_EQUAL *cond_equal)
bool copyfl;
if (field_item->result_type() == STRING_RESULT &&
- ((Field_str *) field_item)->charset() !=
+ ((Field_str *) field_item->field)->charset() !=
((Item_cond *) item)->compare_collation())
return FALSE;
@@ -6192,7 +6195,7 @@ static bool check_equality(Item *item, COND_EQUAL *cond_equal)
Replace all equality predicates in a condition by multiple equality items
SYNOPSIS
- build_all_equal_items()
+ build_equal_items_for_cond()
cond condition(expression) where to make replacement
inherited path to all inherited multiple equality items
@@ -6253,7 +6256,7 @@ static bool check_equality(Item *item, COND_EQUAL *cond_equal)
pointer to the transformed condition
*/
-static COND *build_all_equal_items(COND *cond,
+static COND *build_equal_items_for_cond(COND *cond,
COND_EQUAL *inherited)
{
Item_equal *item_equal;
@@ -6315,7 +6318,7 @@ static COND *build_all_equal_items(COND *cond,
while((item= li++))
{
Item *new_item;
- if ((new_item = build_all_equal_items(item, inherited))!= item)
+ if ((new_item = build_equal_items_for_cond(item, inherited))!= item)
{
/* This replacement happens only for standalone equalities */
li.replace(new_item);
@@ -6352,6 +6355,113 @@ static COND *build_all_equal_items(COND *cond,
cond->update_used_tables();
}
return cond;
+}
+
+/*
+ Build multiple equalities for a condition and all on expressions that
+ inherit these multiple equalities
+
+ SYNOPSIS
+ build_equal_items()
+ cond condition to build the multiple equalities for
+ inherited path to all inherited multiple equality items
+ join_list list of join tables to which the condition refers to
+ cond_equal_ref :out pointer to the structure to place built equalities in
+
+ DESCRIPTION
+ The function first applies the build_equal_items_for_cond function
+ to build all multiple equalities for condition cond utilizing equalities
+ referred through the parameter inherited. The extended set of
+ equalities is returned in the structure referred by the cond_equal_ref
+ parameter. After this the function calls itself recursively for
+ all on expressions whose direct references can be found in join_list
+ and who inherit directly the multiple equalities just having built.
+
+ NOTES
+ The on expression used in an outer join operation inherits all equalities
+ from the on expression of the embedding join, if there is any, or
+ otherwise - from the where condition.
+ This fact is not obvious, but presumably can be proved.
+ Consider the following query:
+ SELECT * FROM (t1,t2) LEFT JOIN (t3,t4) ON t1.a=t3.a AND t2.a=t4.a
+ WHERE t1.a=t2.a;
+ If the on expression in the query inherits =(t1.a,t2.a), then we
+ can build the multiple equality =(t1.a,t2.a,t3.a,t4.a) that infers
+ the equality t3.a=t4.a. Although the on expression
+ t1.a=t3.a AND t2.a=t4.a AND t3.a=t4.a is not equivalent to the one
+ in the query the latter can be replaced by the former: the new query
+ will return the same result set as the original one.
+
+ Interesting that multiple equality =(t1.a,t2.a,t3.a,t4.a) allows us
+ to use t1.a=t3.a AND t3.a=t4.a under the on condition:
+ SELECT * FROM (t1,t2) LEFT JOIN (t3,t4) ON t1.a=t3.a AND t3.a=t4.a
+ WHERE t1.a=t2.a
+ This query equivalent to:
+ SELECT * FROM (t1 LEFT JOIN (t3,t4) ON t1.a=t3.a AND t3.a=t4.a),t2
+ WHERE t1.a=t2.a
+ Similarly the original query can be rewritten to the query:
+ SELECT * FROM (t1,t2) LEFT JOIN (t3,t4) ON t2.a=t4.a AND t3.a=t4.a
+ WHERE t1.a=t2.a
+ that is equivalent to:
+ SELECT * FROM (t2 LEFT JOIN (t3,t4)ON t2.a=t4.a AND t3.a=t4.a), t1
+ WHERE t1.a=t2.a
+ Thus, applying equalities from the where condition we basically
+ can get more freedom in performing join operations.
+ Althogh we don't use this property now, it probably makes sense to use
+ it in the future.
+
+ RETURN
+ pointer to the transformed condition containing multiple equalities
+*/
+
+static COND *build_equal_items(COND *cond,
+ COND_EQUAL *inherited,
+ List<TABLE_LIST> *join_list,
+ COND_EQUAL **cond_equal_ref)
+{
+ COND_EQUAL *cond_equal= 0;
+
+ if (cond)
+ {
+ cond= build_equal_items_for_cond(cond, inherited);
+ cond->update_used_tables();
+ if (cond->type() == Item::COND_ITEM &&
+ ((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)
+ cond_equal= &((Item_cond_and*) cond)->cond_equal;
+ else if (cond->type() == Item::FUNC_ITEM &&
+ ((Item_cond*) cond)->functype() == Item_func::MULT_EQUAL_FUNC)
+ {
+ cond_equal= new COND_EQUAL;
+ cond_equal->current_level.push_back((Item_equal *) cond);
+ }
+ }
+ if (cond_equal)
+ {
+ cond_equal->upper_levels= inherited;
+ inherited= cond_equal;
+ }
+ *cond_equal_ref= cond_equal;
+
+ if (join_list)
+ {
+ TABLE_LIST *table;
+ List_iterator<TABLE_LIST> li(*join_list);
+
+ while ((table= li++))
+ {
+ if (table->on_expr)
+ {
+ List<TABLE_LIST> *join_list= table->nested_join ?
+ &table->nested_join->join_list : NULL;
+ table->on_expr= build_equal_items(table->on_expr,
+ inherited,
+ join_list,
+ &table->cond_equal);
+ }
+ }
+ }
+
+ return cond;
}
/*
@@ -6447,6 +6557,11 @@ static Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels,
{
List<Item> eq_list;
Item_func_eq *eq_item= 0;
+ if (((Item *) item_equal)->const_item() && !item_equal->val_int())
+ {
+ cond= new Item_int((char*) "FALSE",0,1);
+ return cond;
+ }
Item *item_const= item_equal->get_const();
Item_equal_iterator it(*item_equal);
Item *head;
@@ -6484,6 +6599,7 @@ static Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels,
if (!eq_item)
return 0;
eq_item->set_cmp_func();
+ eq_item->quick_fix_field();
}
}
@@ -6495,6 +6611,9 @@ static Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels,
cond= new Item_cond_and(eq_list);
else
((Item_cond *) cond)->add_at_head(&eq_list);
+
+ cond->quick_fix_field();
+ cond->update_used_tables();
return cond;
}
@@ -6589,7 +6708,6 @@ static COND* substitute_for_best_equal_field(COND *cond,
return cond;
}
-
/*
change field = field to field = const for each found field = const in the
and_level
@@ -6998,38 +7116,15 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top)
}
}
DBUG_RETURN(conds);
+}
static COND *
optimize_cond(JOIN *join, COND *conds, Item::cond_result *cond_value)
{
THD *thd= join->thd;
- SELECT_LEX *select= thd->lex->current_select;}
+ SELECT_LEX *select= thd->lex->current_select;
DBUG_ENTER("optimize_cond");
- if (select->first_cond_optimization)
- {
- /*
- The following code will allocate the new items in a permanent
- MEMROOT for prepared statements and stored procedures.
- */
-
- Item_arena *arena= thd->current_arena, backup;
- if (arena->is_conventional())
- arena= 0; // For easier test
- else
- thd->set_n_backup_item_arena(arena, &backup);
-
- select->first_cond_optimization= 0;
-
- /* Convert all outer joins to inner joins if possible */
- conds= simplify_joins(join, join->join_list, conds, TRUE);
-
- select->prep_where= conds ? conds->copy_andor_structure(thd) : 0;
-
- if (arena)
- thd->restore_backup_item_arena(arena, &backup);
- }
-
if (!conds)
{
*cond_value= Item::COND_TRUE;
@@ -7047,6 +7142,7 @@ optimize_cond(JOIN *join, COND *conds, Item::cond_result *cond_value)
DBUG_EXECUTE("where",print_where(conds,"after const change"););
conds= remove_eq_conds(thd, conds, cond_value) ;
DBUG_EXECUTE("info",print_where(conds,"after remove"););
+ }
DBUG_RETURN(conds);
}
@@ -8871,9 +8967,9 @@ join_read_const_table(JOIN_TAB *tab, POSITION *pos)
table->file->extra(HA_EXTRA_NO_KEYREAD);
}
}
- if (tab->on_expr && !table->null_row)
+ if (*tab->on_expr_ref && !table->null_row)
{
- if ((table->null_row= test(tab->on_expr->val_int() == 0)))
+ if ((table->null_row= test((*tab->on_expr_ref)->val_int() == 0)))
mark_as_null_row(table);
}
if (!table->null_row)
diff --git a/sql/sql_select.h b/sql/sql_select.h
index c9cfeb70225..18664624a77 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -91,7 +91,8 @@ typedef struct st_join_table {
SQL_SELECT *select;
COND *select_cond;
QUICK_SELECT_I *quick;
- Item *on_expr; /* associated on expression */
+ Item **on_expr_ref; /* pointer to the associated on expression */
+ COND_EQUAL *cond_equal; /* multiple equalities for the on expression */
st_join_table *first_inner; /* first inner table for including outerjoin */
bool found; /* true after all matches or null complement */
bool not_null_compl;/* true before null complement is added */
diff --git a/sql/table.h b/sql/table.h
index 35f6c6803fb..605cd516d9c 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -21,6 +21,7 @@ class Item; /* Needed by ORDER */
class GRANT_TABLE;
class st_select_lex_unit;
class st_select_lex;
+class COND_EQUAL;
/* Order clause list element */
@@ -209,6 +210,7 @@ typedef struct st_table_list
char *db, *alias, *real_name;
char *option; /* Used by cache index */
Item *on_expr; /* Used with outer join */
+ COND_EQUAL *cond_equal; /* Used with outer join */
struct st_table_list *natural_join; /* natural join on this table*/
/* ... join ... USE INDEX ... IGNORE INDEX */
List<String> *use_index, *ignore_index;