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:
DBUG_ASSERT(!cond_equal_ref || !cond_equal_ref[0]);
return this;
}
virtual COND *remove_eq_conds(THD *thd, Item::cond_result *cond_value,
bool top_level);
/*
Checks whether the item is:
- a simple equality (field=field_item or field=constant_item), or
......
......@@ -409,6 +409,8 @@ public:
Item_bool_func::cleanup();
cmp.cleanup();
}
COND *remove_eq_conds(THD *thd, Item::cond_result *cond_value,
bool top_level);
friend class Arg_comparator;
};
......@@ -1467,6 +1469,8 @@ public:
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; }
Item *neg_transformer(THD *thd);
};
......@@ -1775,6 +1779,8 @@ public:
COND *build_equal_items(THD *thd, COND_EQUAL *inherited,
bool link_item_fields,
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);
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,
......
......@@ -372,7 +372,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
if (conds)
{
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
{
limit= 0;
......
......@@ -3862,7 +3862,7 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
COND_EQUAL *orig_cond_equal = join->cond_equal;
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 &&
((Item_cond*) conds)->functype() == Item_func::COND_AND_FUNC)
join->cond_equal= &((Item_cond_and*) conds)->m_cond_equal;
......@@ -14708,7 +14708,7 @@ optimize_cond(JOIN *join, COND *conds,
Remove all and-levels where CONST item != CONST item
*/
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 &&
((Item_cond*) conds)->functype() == Item_func::COND_AND_FUNC)
*cond_equal= &((Item_cond_and*) conds)->m_cond_equal;
......@@ -14945,295 +14945,267 @@ bool cond_is_datetime_is_null(Item *cond)
=> 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= ((Item_cond*) cond)->functype()
== Item_func::COND_AND_FUNC;
List<Item> *cond_arg_list= ((Item_cond*) cond)->argument_list();
bool and_level= functype() == Item_func::COND_AND_FUNC;
List<Item> *cond_arg_list= argument_list();
if (and_level)
{
/*
Remove multiple equalities that became always true (e.g. after
constant row substitution).
They would be removed later in the function anyway, but the list of
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.
*/
List<Item_equal> *cond_equalities=
&((Item_cond_and *) cond)->m_cond_equal.current_level;
cond_arg_list->disjoin((List<Item> *) cond_equalities);
List_iterator<Item_equal> it(*cond_equalities);
Item_equal *eq_item;
while ((eq_item= it++))
{
if (eq_item->const_item() && eq_item->val_int())
it.remove();
}
cond_arg_list->append((List<Item> *) cond_equalities);
}
if (and_level)
{
/*
Remove multiple equalities that became always true (e.g. after
constant row substitution).
They would be removed later in the function anyway, but the list of
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.
*/
List<Item_equal> *cond_equalities=
&((Item_cond_and *) this)->m_cond_equal.current_level;
cond_arg_list->disjoin((List<Item> *) cond_equalities);
List_iterator<Item_equal> it(*cond_equalities);
Item_equal *eq_item;
while ((eq_item= it++))
{
if (eq_item->const_item() && eq_item->val_int())
it.remove();
}
cond_arg_list->append((List<Item> *) cond_equalities);
}
List<Item_equal> new_equalities;
List_iterator<Item> li(*cond_arg_list);
bool should_fix_fields= 0;
Item::cond_result tmp_cond_value;
Item *item;
List<Item_equal> new_equalities;
List_iterator<Item> li(*cond_arg_list);
bool should_fix_fields= 0;
Item::cond_result tmp_cond_value;
Item *item;
/*
If the list cond_arg_list became empty then it consisted only
of always true multiple equalities.
*/
*cond_value= cond_arg_list->elements ? Item::COND_UNDEF : Item::COND_TRUE;
/*
If the list cond_arg_list became empty then it consisted only
of always true multiple equalities.
*/
*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);
if (!new_item)
{
/* This can happen only when item is converted to TRUE or FALSE */
li.remove();
}
else if (item != new_item)
/* This can happen only when item is converted to TRUE or FALSE */
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)
{
/*
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());
List<Item> *new_item_arg_list=
((Item_cond *) new_item)->argument_list();
if (and_level)
{
DBUG_ASSERT(((Item_cond *) cond)->functype() ==
((Item_cond *) new_item)->functype());
List<Item> *new_item_arg_list=
((Item_cond *) new_item)->argument_list();
if (and_level)
{
/*
If new_item is an AND formula then multiple equalities
of new_item_arg_list must merged into multiple equalities
of cond_arg_list.
*/
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
of new_item_arg_list must merged into multiple equalities
of cond_arg_list.
*/
List<Item_equal> *new_item_equalities=
&((Item_cond_and *) new_item)->m_cond_equal.current_level;
if (!new_item_equalities->is_empty())
{
/*
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;
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);
}
}
else if (and_level &&
new_item->type() == Item::FUNC_ITEM &&
((Item_cond*) new_item)->functype() ==
Item_func::MULT_EQUAL_FUNC)
{
if (new_item_arg_list->is_empty())
li.remove();
new_equalities.push_back((Item_equal *) new_item);
}
else
{
if (new_item->type() == Item::COND_ITEM &&
((Item_cond*) new_item)->functype() ==
((Item_cond*) cond)->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);
{
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;
}
}
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);
/*
Propagate the newly formed multiple equalities to
the all AND/OR levels of cond
*/
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)
else if (and_level &&
new_item->type() == Item::FUNC_ITEM &&
((Item_cond*) new_item)->functype() ==
Item_func::MULT_EQUAL_FUNC)
{
if (!(cond= internal_remove_eq_conds(thd, cond, cond_value)))
return cond;
}
should_fix_fields= 1;
li.remove();
new_equalities.push_back((Item_equal *) new_item);
}
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)
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;
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 */
}
}
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
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)
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.
*/
Item **args= ((Item_func_isnull*) cond)->arguments();
Field *field=((Item_field*) args[0])->field;
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 cond;
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, cond);
if (!or_cond)
return cond;
cond= or_cond;
COND_EQUAL *cond_equal= &((Item_cond_and *) this)->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;
}
}
}
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"
cond= eq_cond;
if (!(cond= cond->remove_eq_conds(thd, cond_value, false)))
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_value= eval_const_cond(cond) ? Item::COND_TRUE : Item::COND_FALSE;
return (COND*) 0;
}
COND *
Item::remove_eq_conds(THD *thd, Item::cond_result *cond_value, bool top_level)
{
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;
}
else if ((*cond_value= cond->eq_cmp_result()) != Item::COND_OK)
{ // boolan compare function
Item *left_item= ((Item_func*) cond)->arguments()[0];
Item *right_item= ((Item_func*) cond)->arguments()[1];
if (left_item->eq(right_item,1))
if ((*cond_value= eq_cmp_result()) != Item::COND_OK)
{
if (args[0]->eq(args[1], true))
{
if (!left_item->maybe_null ||
((Item_func*) cond)->functype() == Item_func::EQUAL_FUNC)
return (COND*) 0; // Compare of identical items
if (!args[0]->maybe_null || functype() == Item_func::EQUAL_FUNC)
return (COND*) 0; // Compare of identical items
}
}
*cond_value=Item::COND_OK;
return cond; // Point at next and level
*cond_value= Item::COND_OK;
return this; // Point at next and level
}
/**
Remove const and eq items. Return new item, or NULL if no condition
cond_value is set to according:
COND_OK query is possible (field = constant)
COND_TRUE always true ( 1 = 1 )
COND_FALSE always false ( 1 = 2 )
COND_TRUE always true ( 1 = 1 )
COND_FALSE always false ( 1 = 2 )
SYNPOSIS
remove_eq_conds()
thd THD environment
thd THD environment
cond the condition to handle
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)
*/
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 &&
((Item_func*) cond)->functype() == Item_func::ISNULL_FUNC)
if (args[0]->type() == Item::FIELD_ITEM)
{
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:
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)
SELECT * from table_name where auto_increment_column IS NULL
This will be changed to:
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;
Item **args= func->arguments();
if (args[0]->type() == Item::FIELD_ITEM)
if (top_level) // "auto_increment_column IS NULL" is the only condition
{
Field *field=((Item_field*) args[0])->field;
if (field->flags & AUTO_INCREMENT_FLAG && !field->table->maybe_null &&
(thd->variables.option_bits & OPTION_AUTO_IS_NULL) &&
(thd->first_successful_insert_id_in_prev_stmt > 0 &&
(thd->variables.option_bits & OPTION_AUTO_IS_NULL) &&
(thd->first_successful_insert_id_in_prev_stmt > 0 &&
thd->substitute_null_with_insert_id))
{
#ifdef HAVE_QUERY_CACHE
query_cache_abort(&thd->query_cache_tls);
#endif
COND *new_cond;
if ((new_cond= new Item_func_eq(args[0],
new Item_int("last_insert_id()",
#ifdef HAVE_QUERY_CACHE
query_cache_abort(&thd->query_cache_tls);
#endif
COND *new_cond, *cond= this;
if ((new_cond= new Item_func_eq(args[0],
new Item_int("last_insert_id()",
thd->read_first_successful_insert_id_in_prev_stmt(),
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
cond->fixed, also it do not need tables so we use 0 as second
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
clear for next row
......@@ -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);
bool error_if_full_join(JOIN *join);
int report_error(TABLE *table, int error);
int safe_index_read(JOIN_TAB *tab);
COND *remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value);
int get_quick_record(SQL_SELECT *select);
SORT_FIELD * make_unireg_sortorder(THD *thd, ORDER *order, uint *length,
SORT_FIELD *sortorder);
......
......@@ -377,7 +377,7 @@ int mysql_update(THD *thd,
if (conds)
{
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)
{
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