Commit 632f2307 authored by Alexander Barkov's avatar Alexander Barkov

MDEV-7950 Item_func::type() takes 0.26% in OLTP RO

Step#5: changing the function remove_eq_conds() into a virtual method in Item.
It removes 6 virtual calls for Item_func::type(), and adds only 2
virtual calls for Item***::remove_eq_conds().
parent fb3e9352
...@@ -1135,6 +1135,8 @@ public: ...@@ -1135,6 +1135,8 @@ public:
DBUG_ASSERT(!cond_equal_ref || !cond_equal_ref[0]); DBUG_ASSERT(!cond_equal_ref || !cond_equal_ref[0]);
return this; return this;
} }
virtual COND *remove_eq_conds(THD *thd, Item::cond_result *cond_value,
bool top_level);
/* /*
Checks whether the item is: Checks whether the item is:
- a simple equality (field=field_item or field=constant_item), or - a simple equality (field=field_item or field=constant_item), or
......
...@@ -409,6 +409,8 @@ public: ...@@ -409,6 +409,8 @@ public:
Item_bool_func::cleanup(); Item_bool_func::cleanup();
cmp.cleanup(); cmp.cleanup();
} }
COND *remove_eq_conds(THD *thd, Item::cond_result *cond_value,
bool top_level);
friend class Arg_comparator; friend class Arg_comparator;
}; };
...@@ -1467,6 +1469,8 @@ public: ...@@ -1467,6 +1469,8 @@ public:
const_item_cache= args[0]->const_item(); const_item_cache= args[0]->const_item();
} }
} }
COND *remove_eq_conds(THD *thd, Item::cond_result *cond_value,
bool top_level);
table_map not_null_tables() const { return 0; } table_map not_null_tables() const { return 0; }
Item *neg_transformer(THD *thd); Item *neg_transformer(THD *thd);
}; };
...@@ -1775,6 +1779,8 @@ public: ...@@ -1775,6 +1779,8 @@ public:
COND *build_equal_items(THD *thd, COND_EQUAL *inherited, COND *build_equal_items(THD *thd, COND_EQUAL *inherited,
bool link_item_fields, bool link_item_fields,
COND_EQUAL **cond_equal_ref); COND_EQUAL **cond_equal_ref);
COND *remove_eq_conds(THD *thd, Item::cond_result *cond_value,
bool top_level);
virtual void print(String *str, enum_query_type query_type); virtual void print(String *str, enum_query_type query_type);
void split_sum_func(THD *thd, Item **ref_pointer_array, List<Item> &fields); void split_sum_func(THD *thd, Item **ref_pointer_array, List<Item> &fields);
friend int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, friend int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
......
...@@ -372,7 +372,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ...@@ -372,7 +372,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
if (conds) if (conds)
{ {
Item::cond_result result; Item::cond_result result;
conds= remove_eq_conds(thd, conds, &result); conds= conds->remove_eq_conds(thd, &result, true);
if (result == Item::COND_FALSE) // Impossible where if (result == Item::COND_FALSE) // Impossible where
{ {
limit= 0; limit= 0;
......
...@@ -3862,7 +3862,7 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list, ...@@ -3862,7 +3862,7 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
COND_EQUAL *orig_cond_equal = join->cond_equal; COND_EQUAL *orig_cond_equal = join->cond_equal;
conds->update_used_tables(); conds->update_used_tables();
conds= remove_eq_conds(join->thd, conds, &join->cond_value); conds= conds->remove_eq_conds(join->thd, &join->cond_value, true);
if (conds && conds->type() == Item::COND_ITEM && if (conds && conds->type() == Item::COND_ITEM &&
((Item_cond*) conds)->functype() == Item_func::COND_AND_FUNC) ((Item_cond*) conds)->functype() == Item_func::COND_AND_FUNC)
join->cond_equal= &((Item_cond_and*) conds)->m_cond_equal; join->cond_equal= &((Item_cond_and*) conds)->m_cond_equal;
...@@ -14708,7 +14708,7 @@ optimize_cond(JOIN *join, COND *conds, ...@@ -14708,7 +14708,7 @@ optimize_cond(JOIN *join, COND *conds,
Remove all and-levels where CONST item != CONST item Remove all and-levels where CONST item != CONST item
*/ */
DBUG_EXECUTE("where",print_where(conds,"after const change", QT_ORDINARY);); DBUG_EXECUTE("where",print_where(conds,"after const change", QT_ORDINARY););
conds= remove_eq_conds(thd, conds, cond_value); conds= conds->remove_eq_conds(thd, cond_value, true);
if (conds && conds->type() == Item::COND_ITEM && if (conds && conds->type() == Item::COND_ITEM &&
((Item_cond*) conds)->functype() == Item_func::COND_AND_FUNC) ((Item_cond*) conds)->functype() == Item_func::COND_AND_FUNC)
*cond_equal= &((Item_cond_and*) conds)->m_cond_equal; *cond_equal= &((Item_cond_and*) conds)->m_cond_equal;
...@@ -14945,295 +14945,267 @@ bool cond_is_datetime_is_null(Item *cond) ...@@ -14945,295 +14945,267 @@ bool cond_is_datetime_is_null(Item *cond)
=> SELECT * FROM t1 WHERE (b = 5) AND (a = 5) => SELECT * FROM t1 WHERE (b = 5) AND (a = 5)
*/ */
static COND *
internal_remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value) COND *
Item_cond::remove_eq_conds(THD *thd, Item::cond_result *cond_value,
bool top_level)
{ {
if (cond->type() == Item::COND_ITEM) bool and_level= functype() == Item_func::COND_AND_FUNC;
{ List<Item> *cond_arg_list= argument_list();
bool and_level= ((Item_cond*) cond)->functype()
== Item_func::COND_AND_FUNC;
List<Item> *cond_arg_list= ((Item_cond*) cond)->argument_list();
if (and_level) if (and_level)
{ {
/* /*
Remove multiple equalities that became always true (e.g. after Remove multiple equalities that became always true (e.g. after
constant row substitution). constant row substitution).
They would be removed later in the function anyway, but the list of They would be removed later in the function anyway, but the list of
them cond_equal.current_level also must be adjusted correspondingly. them cond_equal.current_level also must be adjusted correspondingly.
So it's easier to do it at one pass through the list of the equalities. So it's easier to do it at one pass through the list of the equalities.
*/ */
List<Item_equal> *cond_equalities= List<Item_equal> *cond_equalities=
&((Item_cond_and *) cond)->m_cond_equal.current_level; &((Item_cond_and *) this)->m_cond_equal.current_level;
cond_arg_list->disjoin((List<Item> *) cond_equalities); cond_arg_list->disjoin((List<Item> *) cond_equalities);
List_iterator<Item_equal> it(*cond_equalities); List_iterator<Item_equal> it(*cond_equalities);
Item_equal *eq_item; Item_equal *eq_item;
while ((eq_item= it++)) while ((eq_item= it++))
{ {
if (eq_item->const_item() && eq_item->val_int()) if (eq_item->const_item() && eq_item->val_int())
it.remove(); it.remove();
} }
cond_arg_list->append((List<Item> *) cond_equalities); cond_arg_list->append((List<Item> *) cond_equalities);
} }
List<Item_equal> new_equalities; List<Item_equal> new_equalities;
List_iterator<Item> li(*cond_arg_list); List_iterator<Item> li(*cond_arg_list);
bool should_fix_fields= 0; bool should_fix_fields= 0;
Item::cond_result tmp_cond_value; Item::cond_result tmp_cond_value;
Item *item; Item *item;
/* /*
If the list cond_arg_list became empty then it consisted only If the list cond_arg_list became empty then it consisted only
of always true multiple equalities. of always true multiple equalities.
*/ */
*cond_value= cond_arg_list->elements ? Item::COND_UNDEF : Item::COND_TRUE; *cond_value= cond_arg_list->elements ? Item::COND_UNDEF : Item::COND_TRUE;
while ((item=li++)) while ((item=li++))
{
Item *new_item= item->remove_eq_conds(thd, &tmp_cond_value, false);
if (!new_item)
{ {
Item *new_item=internal_remove_eq_conds(thd, item, &tmp_cond_value); /* This can happen only when item is converted to TRUE or FALSE */
if (!new_item) li.remove();
{ }
/* This can happen only when item is converted to TRUE or FALSE */ else if (item != new_item)
li.remove(); {
} /*
else if (item != new_item) This can happen when:
- item was an OR formula converted to one disjunct
- item was an AND formula converted to one conjunct
In these cases the disjunct/conjunct must be merged into the
argument list of cond.
*/
if (new_item->type() == Item::COND_ITEM &&
item->type() == Item::COND_ITEM)
{ {
/* DBUG_ASSERT(functype() == ((Item_cond *) new_item)->functype());
This can happen when: List<Item> *new_item_arg_list=
- item was an OR formula converted to one disjunct ((Item_cond *) new_item)->argument_list();
- item was an AND formula converted to one conjunct if (and_level)
In these cases the disjunct/conjunct must be merged into the
argument list of cond.
*/
if (new_item->type() == Item::COND_ITEM &&
item->type() == Item::COND_ITEM)
{ {
DBUG_ASSERT(((Item_cond *) cond)->functype() == /*
((Item_cond *) new_item)->functype()); If new_item is an AND formula then multiple equalities
List<Item> *new_item_arg_list= of new_item_arg_list must merged into multiple equalities
((Item_cond *) new_item)->argument_list(); of cond_arg_list.
if (and_level) */
{ List<Item_equal> *new_item_equalities=
&((Item_cond_and *) new_item)->m_cond_equal.current_level;
if (!new_item_equalities->is_empty())
{
/* /*
If new_item is an AND formula then multiple equalities Cut the multiple equalities from the new_item_arg_list and
of new_item_arg_list must merged into multiple equalities append them on the list new_equalities. Later the equalities
of cond_arg_list. from this list will be merged into the multiple equalities
*/ of cond_arg_list all together.
List<Item_equal> *new_item_equalities= */
&((Item_cond_and *) new_item)->m_cond_equal.current_level; new_item_arg_list->disjoin((List<Item> *) new_item_equalities);
if (!new_item_equalities->is_empty()) new_equalities.append(new_item_equalities);
{
/*
Cut the multiple equalities from the new_item_arg_list and
append them on the list new_equalities. Later the equalities
from this list will be merged into the multiple equalities
of cond_arg_list all together.
*/
new_item_arg_list->disjoin((List<Item> *) new_item_equalities);
new_equalities.append(new_item_equalities);
}
}
if (new_item_arg_list->is_empty())
li.remove();
else
{
uint cnt= new_item_arg_list->elements;
li.replace(*new_item_arg_list);
/* Make iterator li ignore new items */
for (cnt--; cnt; cnt--)
li++;
should_fix_fields= 1;
} }
} }
else if (and_level && if (new_item_arg_list->is_empty())
new_item->type() == Item::FUNC_ITEM &&
((Item_cond*) new_item)->functype() ==
Item_func::MULT_EQUAL_FUNC)
{
li.remove(); li.remove();
new_equalities.push_back((Item_equal *) new_item);
}
else else
{ {
if (new_item->type() == Item::COND_ITEM && uint cnt= new_item_arg_list->elements;
((Item_cond*) new_item)->functype() == li.replace(*new_item_arg_list);
((Item_cond*) cond)->functype()) /* Make iterator li ignore new items */
{ for (cnt--; cnt; cnt--)
List<Item> *new_item_arg_list= li++;
((Item_cond *) new_item)->argument_list();
uint cnt= new_item_arg_list->elements;
li.replace(*new_item_arg_list);
/* Make iterator li ignore new items */
for (cnt--; cnt; cnt--)
li++;
}
else
li.replace(new_item);
should_fix_fields= 1; should_fix_fields= 1;
}
}
if (*cond_value == Item::COND_UNDEF)
*cond_value=tmp_cond_value;
switch (tmp_cond_value) {
case Item::COND_OK: // Not TRUE or FALSE
if (and_level || *cond_value == Item::COND_FALSE)
*cond_value=tmp_cond_value;
break;
case Item::COND_FALSE:
if (and_level)
{
*cond_value=tmp_cond_value;
return (COND*) 0; // Always false
}
break;
case Item::COND_TRUE:
if (!and_level)
{
*cond_value= tmp_cond_value;
return (COND*) 0; // Always true
}
break;
case Item::COND_UNDEF: // Impossible
break; /* purecov: deadcode */
}
}
if (!new_equalities.is_empty())
{
DBUG_ASSERT(and_level);
/*
Merge multiple equalities that were cut from the results of
simplification of OR formulas converted into AND formulas.
These multiple equalities are to be merged into the
multiple equalities of cond_arg_list.
*/
COND_EQUAL *cond_equal= &((Item_cond_and *) cond)->m_cond_equal;
List<Item_equal> *cond_equalities= &cond_equal->current_level;
cond_arg_list->disjoin((List<Item> *) cond_equalities);
Item_equal *equality;
List_iterator_fast<Item_equal> it(new_equalities);
while ((equality= it++))
{
equality->upper_levels= cond_equal->upper_levels;
equality->merge_into_list(thd, cond_equalities, false, false);
List_iterator_fast<Item_equal> ei(*cond_equalities);
while ((equality= ei++))
{
if (equality->const_item() && !equality->val_int())
{
*cond_value= Item::COND_FALSE;
return (COND*) 0;
}
} }
} }
cond_arg_list->append((List<Item> *) cond_equalities); else if (and_level &&
/* new_item->type() == Item::FUNC_ITEM &&
Propagate the newly formed multiple equalities to ((Item_cond*) new_item)->functype() ==
the all AND/OR levels of cond Item_func::MULT_EQUAL_FUNC)
*/
bool is_simplifiable_cond= false;
propagate_new_equalities(thd, cond, cond_equalities,
cond_equal->upper_levels,
&is_simplifiable_cond);
/*
If the above propagation of multiple equalities brings us
to multiple equalities that are always FALSE then try to
simplify the condition with remove_eq_cond() again.
*/
if (is_simplifiable_cond)
{ {
if (!(cond= internal_remove_eq_conds(thd, cond, cond_value))) li.remove();
return cond; new_equalities.push_back((Item_equal *) new_item);
} }
should_fix_fields= 1; else
{
if (new_item->type() == Item::COND_ITEM &&
((Item_cond*) new_item)->functype() == functype())
{
List<Item> *new_item_arg_list=
((Item_cond *) new_item)->argument_list();
uint cnt= new_item_arg_list->elements;
li.replace(*new_item_arg_list);
/* Make iterator li ignore new items */
for (cnt--; cnt; cnt--)
li++;
}
else
li.replace(new_item);
should_fix_fields= 1;
}
} }
if (should_fix_fields) if (*cond_value == Item::COND_UNDEF)
cond->update_used_tables(); *cond_value= tmp_cond_value;
switch (tmp_cond_value) {
if (!((Item_cond*) cond)->argument_list()->elements || case Item::COND_OK: // Not TRUE or FALSE
*cond_value != Item::COND_OK) if (and_level || *cond_value == Item::COND_FALSE)
return (COND*) 0; *cond_value=tmp_cond_value;
if (((Item_cond*) cond)->argument_list()->elements == 1) break;
{ // Remove list case Item::COND_FALSE:
item= ((Item_cond*) cond)->argument_list()->head(); if (and_level)
((Item_cond*) cond)->argument_list()->empty(); {
return item; *cond_value= tmp_cond_value;
return (COND*) 0; // Always false
}
break;
case Item::COND_TRUE:
if (!and_level)
{
*cond_value= tmp_cond_value;
return (COND*) 0; // Always true
}
break;
case Item::COND_UNDEF: // Impossible
break; /* purecov: deadcode */
} }
} }
else if (cond_is_datetime_is_null(cond)) COND *cond= this;
if (!new_equalities.is_empty())
{ {
/* fix to replace 'NULL' dates with '0' (shreeve@uci.edu) */ DBUG_ASSERT(and_level);
/* /*
See BUG#12594011 Merge multiple equalities that were cut from the results of
Documentation says that simplification of OR formulas converted into AND formulas.
SELECT datetime_notnull d FROM t1 WHERE d IS NULL These multiple equalities are to be merged into the
shall return rows where d=='0000-00-00' multiple equalities of cond_arg_list.
Thus, for DATE and DATETIME columns defined as NOT NULL,
"date_notnull IS NULL" has to be modified to
"date_notnull IS NULL OR date_notnull == 0" (if outer join)
"date_notnull == 0" (otherwise)
*/ */
Item **args= ((Item_func_isnull*) cond)->arguments(); COND_EQUAL *cond_equal= &((Item_cond_and *) this)->m_cond_equal;
Field *field=((Item_field*) args[0])->field; List<Item_equal> *cond_equalities= &cond_equal->current_level;
cond_arg_list->disjoin((List<Item> *) cond_equalities);
Item *item0= new(thd->mem_root) Item_int((longlong)0, 1); Item_equal *equality;
Item *eq_cond= new(thd->mem_root) Item_func_eq(args[0], item0); List_iterator_fast<Item_equal> it(new_equalities);
if (!eq_cond) while ((equality= it++))
return cond; {
equality->upper_levels= cond_equal->upper_levels;
if (field->table->pos_in_table_list->is_inner_table_of_outer_join()) equality->merge_into_list(thd, cond_equalities, false, false);
{ List_iterator_fast<Item_equal> ei(*cond_equalities);
// outer join: transform "col IS NULL" to "col IS NULL or col=0" while ((equality= ei++))
Item *or_cond= new(thd->mem_root) Item_cond_or(eq_cond, cond); {
if (!or_cond) if (equality->const_item() && !equality->val_int())
return cond; {
cond= or_cond; *cond_value= Item::COND_FALSE;
return (COND*) 0;
}
}
} }
else cond_arg_list->append((List<Item> *) cond_equalities);
/*
Propagate the newly formed multiple equalities to
the all AND/OR levels of cond
*/
bool is_simplifiable_cond= false;
propagate_new_equalities(thd, this, cond_equalities,
cond_equal->upper_levels,
&is_simplifiable_cond);
/*
If the above propagation of multiple equalities brings us
to multiple equalities that are always FALSE then try to
simplify the condition with remove_eq_cond() again.
*/
if (is_simplifiable_cond)
{ {
// not outer join: transform "col IS NULL" to "col=0" if (!(cond= cond->remove_eq_conds(thd, cond_value, false)))
cond= eq_cond; return cond;
} }
should_fix_fields= 1;
}
if (should_fix_fields)
cond->update_used_tables();
if (!((Item_cond*) cond)->argument_list()->elements ||
*cond_value != Item::COND_OK)
return (COND*) 0;
if (((Item_cond*) cond)->argument_list()->elements == 1)
{ // Remove list
item= ((Item_cond*) cond)->argument_list()->head();
((Item_cond*) cond)->argument_list()->empty();
return item;
}
*cond_value= Item::COND_OK;
return cond;
}
cond->fix_fields(thd, &cond);
if (cond->const_item() && !cond->is_expensive()) COND *
{ Item::remove_eq_conds(THD *thd, Item::cond_result *cond_value, bool top_level)
*cond_value= eval_const_cond(cond) ? Item::COND_TRUE : Item::COND_FALSE; {
return (COND*) 0; if (const_item() && !is_expensive())
} {
*cond_value= eval_const_cond(this) ? Item::COND_TRUE : Item::COND_FALSE;
return (COND*) 0;
} }
else if (cond->const_item() && !cond->is_expensive()) *cond_value= Item::COND_OK;
return this; // Point at next and level
}
COND *
Item_bool_func2::remove_eq_conds(THD *thd, Item::cond_result *cond_value,
bool top_level)
{
if (const_item() && !is_expensive())
{ {
*cond_value= eval_const_cond(cond) ? Item::COND_TRUE : Item::COND_FALSE; *cond_value= eval_const_cond(this) ? Item::COND_TRUE : Item::COND_FALSE;
return (COND*) 0; return (COND*) 0;
} }
else if ((*cond_value= cond->eq_cmp_result()) != Item::COND_OK) if ((*cond_value= eq_cmp_result()) != Item::COND_OK)
{ // boolan compare function {
Item *left_item= ((Item_func*) cond)->arguments()[0]; if (args[0]->eq(args[1], true))
Item *right_item= ((Item_func*) cond)->arguments()[1];
if (left_item->eq(right_item,1))
{ {
if (!left_item->maybe_null || if (!args[0]->maybe_null || functype() == Item_func::EQUAL_FUNC)
((Item_func*) cond)->functype() == Item_func::EQUAL_FUNC) return (COND*) 0; // Compare of identical items
return (COND*) 0; // Compare of identical items
} }
} }
*cond_value=Item::COND_OK; *cond_value= Item::COND_OK;
return cond; // Point at next and level return this; // Point at next and level
} }
/** /**
Remove const and eq items. Return new item, or NULL if no condition Remove const and eq items. Return new item, or NULL if no condition
cond_value is set to according: cond_value is set to according:
COND_OK query is possible (field = constant) COND_OK query is possible (field = constant)
COND_TRUE always true ( 1 = 1 ) COND_TRUE always true ( 1 = 1 )
COND_FALSE always false ( 1 = 2 ) COND_FALSE always false ( 1 = 2 )
SYNPOSIS SYNPOSIS
remove_eq_conds() remove_eq_conds()
thd THD environment thd THD environment
cond the condition to handle cond the condition to handle
cond_value the resulting value of the condition cond_value the resulting value of the condition
...@@ -15245,11 +15217,66 @@ internal_remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value) ...@@ -15245,11 +15217,66 @@ internal_remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value)
*/ */
COND * COND *
remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value) Item_func_isnull::remove_eq_conds(THD *thd, Item::cond_result *cond_value,
bool top_level)
{ {
if (cond->type() == Item::FUNC_ITEM && if (args[0]->type() == Item::FIELD_ITEM)
((Item_func*) cond)->functype() == Item_func::ISNULL_FUNC)
{ {
Field *field= ((Item_field*) args[0])->field;
if (((field->type() == MYSQL_TYPE_DATE) ||
(field->type() == MYSQL_TYPE_DATETIME)) &&
(field->flags & NOT_NULL_FLAG))
{
/* fix to replace 'NULL' dates with '0' (shreeve@uci.edu) */
/*
See BUG#12594011
Documentation says that
SELECT datetime_notnull d FROM t1 WHERE d IS NULL
shall return rows where d=='0000-00-00'
Thus, for DATE and DATETIME columns defined as NOT NULL,
"date_notnull IS NULL" has to be modified to
"date_notnull IS NULL OR date_notnull == 0" (if outer join)
"date_notnull == 0" (otherwise)
*/
Item *item0= new(thd->mem_root) Item_int((longlong)0, 1);
Item *eq_cond= new(thd->mem_root) Item_func_eq(args[0], item0);
if (!eq_cond)
return this;
COND *cond= this;
if (field->table->pos_in_table_list->is_inner_table_of_outer_join())
{
// outer join: transform "col IS NULL" to "col IS NULL or col=0"
Item *or_cond= new(thd->mem_root) Item_cond_or(eq_cond, this);
if (!or_cond)
return this;
cond= or_cond;
}
else
{
// not outer join: transform "col IS NULL" to "col=0"
cond= eq_cond;
}
cond->fix_fields(thd, &cond);
/*
Note: although args[0] is a field, cond can still be a constant
(in case field is a part of a dependent subquery).
Note: we call cond->Item::remove_eq_conds() non-virtually (statically)
for performance purpose.
A non-qualified call, i.e. just cond->remove_eq_conds(),
would call Item_bool_func2::remove_eq_conds() instead, which would
try to do some extra job to detect if args[0] and args[1] are
equivalent items. We know they are not (we have field=0 here).
*/
return cond->Item::remove_eq_conds(thd, cond_value, false);
}
/* /*
Handles this special case for some ODBC applications: Handles this special case for some ODBC applications:
The are requesting the row that was just updated with a auto_increment The are requesting the row that was just updated with a auto_increment
...@@ -15258,35 +15285,37 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value) ...@@ -15258,35 +15285,37 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value)
SELECT * from table_name where auto_increment_column IS NULL SELECT * from table_name where auto_increment_column IS NULL
This will be changed to: This will be changed to:
SELECT * from table_name where auto_increment_column = LAST_INSERT_ID SELECT * from table_name where auto_increment_column = LAST_INSERT_ID
Note, this substitution is done if the NULL test is the only condition!
If the NULL test is a part of a more complex condition, it is not
substituted and is treated normally:
WHERE auto_increment IS NULL AND something_else
*/ */
Item_func_isnull *func=(Item_func_isnull*) cond; if (top_level) // "auto_increment_column IS NULL" is the only condition
Item **args= func->arguments();
if (args[0]->type() == Item::FIELD_ITEM)
{ {
Field *field=((Item_field*) args[0])->field;
if (field->flags & AUTO_INCREMENT_FLAG && !field->table->maybe_null && if (field->flags & AUTO_INCREMENT_FLAG && !field->table->maybe_null &&
(thd->variables.option_bits & OPTION_AUTO_IS_NULL) && (thd->variables.option_bits & OPTION_AUTO_IS_NULL) &&
(thd->first_successful_insert_id_in_prev_stmt > 0 && (thd->first_successful_insert_id_in_prev_stmt > 0 &&
thd->substitute_null_with_insert_id)) thd->substitute_null_with_insert_id))
{ {
#ifdef HAVE_QUERY_CACHE #ifdef HAVE_QUERY_CACHE
query_cache_abort(&thd->query_cache_tls); query_cache_abort(&thd->query_cache_tls);
#endif #endif
COND *new_cond; COND *new_cond, *cond= this;
if ((new_cond= new Item_func_eq(args[0], if ((new_cond= new Item_func_eq(args[0],
new Item_int("last_insert_id()", new Item_int("last_insert_id()",
thd->read_first_successful_insert_id_in_prev_stmt(), thd->read_first_successful_insert_id_in_prev_stmt(),
MY_INT64_NUM_DECIMAL_DIGITS)))) MY_INT64_NUM_DECIMAL_DIGITS))))
{ {
cond=new_cond; cond= new_cond;
/* /*
Item_func_eq can't be fixed after creation so we do not check Item_func_eq can't be fixed after creation so we do not check
cond->fixed, also it do not need tables so we use 0 as second cond->fixed, also it do not need tables so we use 0 as second
argument. argument.
*/ */
cond->fix_fields(thd, &cond); cond->fix_fields(thd, &cond);
} }
/* /*
IS NULL should be mapped to LAST_INSERT_ID only for first row, so IS NULL should be mapped to LAST_INSERT_ID only for first row, so
clear for next row clear for next row
...@@ -15298,7 +15327,7 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value) ...@@ -15298,7 +15327,7 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value)
} }
} }
} }
return internal_remove_eq_conds(thd, cond, cond_value); // Scan all the condition return Item::remove_eq_conds(thd, cond_value, top_level);
} }
......
...@@ -1803,7 +1803,6 @@ bool cp_buffer_from_ref(THD *thd, TABLE *table, TABLE_REF *ref); ...@@ -1803,7 +1803,6 @@ bool cp_buffer_from_ref(THD *thd, TABLE *table, TABLE_REF *ref);
bool error_if_full_join(JOIN *join); 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);
int get_quick_record(SQL_SELECT *select); int get_quick_record(SQL_SELECT *select);
SORT_FIELD * make_unireg_sortorder(THD *thd, ORDER *order, uint *length, SORT_FIELD * make_unireg_sortorder(THD *thd, ORDER *order, uint *length,
SORT_FIELD *sortorder); SORT_FIELD *sortorder);
......
...@@ -377,7 +377,7 @@ int mysql_update(THD *thd, ...@@ -377,7 +377,7 @@ int mysql_update(THD *thd,
if (conds) if (conds)
{ {
Item::cond_result cond_value; Item::cond_result cond_value;
conds= remove_eq_conds(thd, conds, &cond_value); conds= conds->remove_eq_conds(thd, &cond_value, true);
if (cond_value == Item::COND_FALSE) if (cond_value == Item::COND_FALSE)
{ {
limit= 0; // Impossible WHERE limit= 0; // Impossible WHERE
......
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