summaryrefslogtreecommitdiff
path: root/sql/item_cmpfunc.cc
diff options
context:
space:
mode:
authorAlexander Barkov <bar@mariadb.org>2015-09-10 17:13:35 +0400
committerAlexander Barkov <bar@mariadb.org>2015-09-10 17:13:35 +0400
commit4aebba3aeba2d413268455c3c8c7cbfd04e2f94f (patch)
tree048d73a20b078c43c6f567a5957e5e7e53005160 /sql/item_cmpfunc.cc
parent8e553c455c4740a51d2a7d0e23c3c79863b5df22 (diff)
downloadmariadb-git-4aebba3aeba2d413268455c3c8c7cbfd04e2f94f.tar.gz
MDEV-8740 Wrong result for SELECT..WHERE year_field=10 AND NULLIF(year_field,2011.1)='2011'
MDEV-8754 Wrong result for SELECT..WHERE year_field=2020 AND NULLIF(year_field,2010)='2020' Problems: 1. Item_func_nullif stored a copy of args[0] in a private member m_args0_copy, which was invisible for the inherited Item_func menthods, like update_used_tables(). As a result, after equal field propagation things like Item_func_nullif::const_item() could return wrong result and a non-constant NULLIF() was erroneously treated as a constant at optimize_cond() time. Solution: removing m_args0_copy and storing the return value item in args[2] instead. 2. Equal field propagation did not work well for Item_fun_nullif. Solution: using ANY_SUBST for args[0] and args[1], as they are in comparison, and IDENTITY_SUBST for args[2], as it's not in comparison.
Diffstat (limited to 'sql/item_cmpfunc.cc')
-rw-r--r--sql/item_cmpfunc.cc56
1 files changed, 28 insertions, 28 deletions
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 04afafd2915..7a7fd98dd74 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -473,7 +473,7 @@ static bool convert_const_to_int(THD *thd, Item_field *field_item,
*/
void Item_func::convert_const_compared_to_int_field(THD *thd)
{
- DBUG_ASSERT(arg_count == 2);
+ DBUG_ASSERT(arg_count >= 2); // Item_func_nullif has arg_count == 3
if (!thd->lex->is_ps_or_view_context_analysis())
{
int field;
@@ -491,7 +491,7 @@ void Item_func::convert_const_compared_to_int_field(THD *thd)
bool Item_func::setup_args_and_comparator(THD *thd, Arg_comparator *cmp)
{
- DBUG_ASSERT(arg_count == 2);
+ DBUG_ASSERT(arg_count >= 2); // Item_func_nullif has arg_count == 3
if (args[0]->cmp_type() == STRING_RESULT &&
args[1]->cmp_type() == STRING_RESULT &&
@@ -502,7 +502,7 @@ bool Item_func::setup_args_and_comparator(THD *thd, Arg_comparator *cmp)
DBUG_ASSERT(functype() != LIKE_FUNC);
convert_const_compared_to_int_field(thd);
- return cmp->set_cmp_func(this, tmp_arg, tmp_arg + 1, true);
+ return cmp->set_cmp_func(this, &args[0], &args[1], true);
}
@@ -2663,15 +2663,15 @@ bool Item_func_if::date_op(MYSQL_TIME *ltime, uint fuzzydate)
void
Item_func_nullif::fix_length_and_dec()
{
- if (!m_args0_copy) // Only false if EOM
+ if (!args[2]) // Only false if EOM
return;
- cached_result_type= m_args0_copy->result_type();
- cached_field_type= m_args0_copy->field_type();
- collation.set(m_args0_copy->collation);
- decimals= m_args0_copy->decimals;
- unsigned_flag= m_args0_copy->unsigned_flag;
- fix_char_length(m_args0_copy->max_char_length());
+ cached_result_type= args[2]->result_type();
+ cached_field_type= args[2]->field_type();
+ collation.set(args[2]->collation);
+ decimals= args[2]->decimals;
+ unsigned_flag= args[2]->unsigned_flag;
+ fix_char_length(args[2]->max_char_length());
maybe_null=1;
setup_args_and_comparator(current_thd, &cmp);
}
@@ -2683,16 +2683,16 @@ void Item_func_nullif::print(String *str, enum_query_type query_type)
NULLIF(a,b) is implemented according to the SQL standard as a short for
CASE WHEN a=b THEN NULL ELSE a END
- The constructor of Item_func_nullif sets args[0] and m_args0_copy to the
+ The constructor of Item_func_nullif sets args[0] and args[2] to the
same item "a", and sets args[1] to "b".
If "this" is a part of a WHERE or ON condition, then:
- the left "a" is a subject to equal field propagation with ANY_SUBST.
- the right "a" is a subject to equal field propagation with IDENTITY_SUBST.
- Therefore, after equal field propagation args[0] and m_args0_copy can point
+ Therefore, after equal field propagation args[0] and args[2] can point
to different items.
*/
- if (!(query_type & QT_ITEM_FUNC_NULLIF_TO_CASE) || args[0] == m_args0_copy)
+ if (!(query_type & QT_ITEM_FUNC_NULLIF_TO_CASE) || args[0] == args[2])
{
/*
If no QT_ITEM_FUNC_NULLIF_TO_CASE is requested,
@@ -2701,7 +2701,7 @@ void Item_func_nullif::print(String *str, enum_query_type query_type)
SHOW CREATE {VIEW|FUNCTION|PROCEDURE}
The original representation is possible only if
- args[0] and m_args0_copy still point to the same Item.
+ args[0] and args[2] still point to the same Item.
The caller must pass call print() with QT_ITEM_FUNC_NULLIF_TO_CASE
if an expression has undergone some optimization
@@ -2713,10 +2713,10 @@ void Item_func_nullif::print(String *str, enum_query_type query_type)
Note, the EXPLAIN EXTENDED and EXPLAIN FORMAT=JSON routines
do pass QT_ITEM_FUNC_NULLIF_TO_CASE to print().
*/
- DBUG_ASSERT(args[0] == m_args0_copy);
+ DBUG_ASSERT(args[0] == args[2]);
str->append(func_name());
str->append('(');
- m_args0_copy->print(str, query_type);
+ args[2]->print(str, query_type);
str->append(',');
args[1]->print(str, query_type);
str->append(')');
@@ -2724,7 +2724,7 @@ void Item_func_nullif::print(String *str, enum_query_type query_type)
else
{
/*
- args[0] and m_args0_copy are different items.
+ args[0] and args[2] are different items.
This is possible after WHERE optimization (equal fields propagation etc),
e.g. in EXPLAIN EXTENDED or EXPLAIN FORMAT=JSON.
As it's not possible to print as a function with 2 arguments any more,
@@ -2735,7 +2735,7 @@ void Item_func_nullif::print(String *str, enum_query_type query_type)
str->append(STRING_WITH_LEN(" = "));
args[1]->print(str, query_type);
str->append(STRING_WITH_LEN(" then NULL else "));
- m_args0_copy->print(str, query_type);
+ args[2]->print(str, query_type);
str->append(STRING_WITH_LEN(" end)"));
}
}
@@ -2761,8 +2761,8 @@ Item_func_nullif::real_op()
null_value=1;
return 0.0;
}
- value= m_args0_copy->val_real();
- null_value=m_args0_copy->null_value;
+ value= args[2]->val_real();
+ null_value= args[2]->null_value;
return value;
}
@@ -2776,8 +2776,8 @@ Item_func_nullif::int_op()
null_value=1;
return 0;
}
- value=m_args0_copy->val_int();
- null_value=m_args0_copy->null_value;
+ value= args[2]->val_int();
+ null_value= args[2]->null_value;
return value;
}
@@ -2791,8 +2791,8 @@ Item_func_nullif::str_op(String *str)
null_value=1;
return 0;
}
- res=m_args0_copy->val_str(str);
- null_value=m_args0_copy->null_value;
+ res= args[2]->val_str(str);
+ null_value= args[2]->null_value;
return res;
}
@@ -2807,8 +2807,8 @@ Item_func_nullif::decimal_op(my_decimal * decimal_value)
null_value=1;
return 0;
}
- res= m_args0_copy->val_decimal(decimal_value);
- null_value= m_args0_copy->null_value;
+ res= args[2]->val_decimal(decimal_value);
+ null_value= args[2]->null_value;
return res;
}
@@ -2819,14 +2819,14 @@ Item_func_nullif::date_op(MYSQL_TIME *ltime, uint fuzzydate)
DBUG_ASSERT(fixed == 1);
if (!cmp.compare())
return (null_value= true);
- return (null_value= m_args0_copy->get_date(ltime, fuzzydate));
+ return (null_value= args[2]->get_date(ltime, fuzzydate));
}
bool
Item_func_nullif::is_null()
{
- return (null_value= (!cmp.compare() ? 1 : m_args0_copy->null_value));
+ return (null_value= (!cmp.compare() ? 1 : args[2]->null_value));
}