summaryrefslogtreecommitdiff
path: root/sql/item_cmpfunc.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/item_cmpfunc.cc')
-rw-r--r--sql/item_cmpfunc.cc202
1 files changed, 120 insertions, 82 deletions
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index c29031d25b5..c6b88cd8188 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -636,56 +636,51 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type)
return 0;
}
-
/**
- @brief Convert date provided in a string to the int representation.
-
- @param[in] thd thread handle
- @param[in] str a string to convert
- @param[in] warn_type type of the timestamp for issuing the warning
- @param[in] warn_name field name for issuing the warning
- @param[out] error_arg could not extract a DATE or DATETIME
-
- @details Convert date provided in the string str to the int
- representation. If the string contains wrong date or doesn't
- contain it at all then a warning is issued. The warn_type and
- the warn_name arguments are used as the name and the type of the
- field when issuing the warning. If any input was discarded
- (trailing or non-timestampy characters), was_cut will be non-zero.
- was_type will return the type str_to_datetime() could correctly
- extract.
-
- @return
- converted value. 0 on error and on zero-dates -- check 'failure'
+ Parse date provided in a string to a MYSQL_TIME.
+
+ @param[in] thd Thread handle
+ @param[in] str A string to convert
+ @param[in] warn_type Type of the timestamp for issuing the warning
+ @param[in] warn_name Field name for issuing the warning
+ @param[out] l_time The MYSQL_TIME objects is initialized.
+
+ Parses a date provided in the string str into a MYSQL_TIME object. If the
+ string contains an incorrect date or doesn't correspond to a date at all
+ then a warning is issued. The warn_type and the warn_name arguments are used
+ as the name and the type of the field when issuing the warning. If any input
+ was discarded (trailing or non-timestamp-y characters), return value will be
+ TRUE.
+
+ @return Status flag
+ @retval FALSE Success.
+ @retval True Indicates failure.
*/
-static ulonglong
-get_date_from_str(THD *thd, String *str, timestamp_type warn_type,
- char *warn_name, bool *error_arg)
+bool get_mysql_time_from_str(THD *thd, String *str, timestamp_type warn_type,
+ const char *warn_name, MYSQL_TIME *l_time)
{
- ulonglong value= 0;
+ bool value;
int error;
- MYSQL_TIME l_time;
- enum_mysql_timestamp_type ret;
+ enum_mysql_timestamp_type timestamp_type;
- ret= str_to_datetime(str->ptr(), str->length(), &l_time,
- (TIME_FUZZY_DATE | MODE_INVALID_DATES |
- (thd->variables.sql_mode &
- (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE))),
- &error);
+ timestamp_type=
+ str_to_datetime(str->ptr(), str->length(), l_time,
+ (TIME_FUZZY_DATE | MODE_INVALID_DATES |
+ (thd->variables.sql_mode &
+ (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE))),
+ &error);
- if (ret == MYSQL_TIMESTAMP_DATETIME || ret == MYSQL_TIMESTAMP_DATE)
- {
+ if (timestamp_type == MYSQL_TIMESTAMP_DATETIME ||
+ timestamp_type == MYSQL_TIMESTAMP_DATE)
/*
Do not return yet, we may still want to throw a "trailing garbage"
warning.
*/
- *error_arg= FALSE;
- value= TIME_to_ulonglong_datetime(&l_time);
- }
+ value= FALSE;
else
{
- *error_arg= TRUE;
+ value= TRUE;
error= 1; /* force warning */
}
@@ -698,6 +693,37 @@ get_date_from_str(THD *thd, String *str, timestamp_type warn_type,
}
+/**
+ @brief Convert date provided in a string to the int representation.
+
+ @param[in] thd thread handle
+ @param[in] str a string to convert
+ @param[in] warn_type type of the timestamp for issuing the warning
+ @param[in] warn_name field name for issuing the warning
+ @param[out] error_arg could not extract a DATE or DATETIME
+
+ @details Convert date provided in the string str to the int
+ representation. If the string contains wrong date or doesn't
+ contain it at all then a warning is issued. The warn_type and
+ the warn_name arguments are used as the name and the type of the
+ field when issuing the warning.
+
+ @return
+ converted value. 0 on error and on zero-dates -- check 'failure'
+*/
+static ulonglong get_date_from_str(THD *thd, String *str,
+ timestamp_type warn_type,
+ const char *warn_name, bool *error_arg)
+{
+ MYSQL_TIME l_time;
+ *error_arg= get_mysql_time_from_str(thd, str, warn_type, warn_name, &l_time);
+
+ if (*error_arg)
+ return 0;
+ return TIME_to_ulonglong_datetime(&l_time);
+}
+
+
/*
Check whether compare_datetime() can be used to compare items.
@@ -1559,61 +1585,73 @@ longlong Item_in_optimizer::val_int()
if (cache->null_value)
{
+ /*
+ We're evaluating
+ "<outer_value_list> [NOT] IN (SELECT <inner_value_list>...)"
+ where one or more of the outer values is NULL.
+ */
if (((Item_in_subselect*)args[1])->is_top_level_item())
{
/*
- We're evaluating "NULL IN (SELECT ...)". The result can be NULL or
- FALSE, and we can return one instead of another. Just return NULL.
+ We're evaluating a top level item, e.g.
+ "<outer_value_list> IN (SELECT <inner_value_list>...)",
+ and in this case a NULL value in the outer_value_list means
+ that the result shall be NULL/FALSE (makes no difference for
+ top level items). The cached value is NULL, so just return
+ NULL.
*/
null_value= 1;
}
else
{
- if (!((Item_in_subselect*)args[1])->is_correlated &&
- result_for_null_param != UNKNOWN)
+ /*
+ We're evaluating an item where a NULL value in either the
+ outer or inner value list does not automatically mean that we
+ can return NULL/FALSE. An example of such a query is
+ "<outer_value_list> NOT IN (SELECT <inner_value_list>...)"
+ The result when there is at least one NULL value is: NULL if the
+ SELECT evaluated over the non-NULL values produces at least
+ one row, FALSE otherwise
+ */
+ Item_in_subselect *item_subs=(Item_in_subselect*)args[1];
+ bool all_left_cols_null= true;
+ const uint ncols= cache->cols();
+
+ /*
+ Turn off the predicates that are based on column compares for
+ which the left part is currently NULL
+ */
+ for (uint i= 0; i < ncols; i++)
{
- /* Use cached value from previous execution */
- null_value= result_for_null_param;
+ if (cache->element_index(i)->null_value)
+ item_subs->set_cond_guard_var(i, FALSE);
+ else
+ all_left_cols_null= false;
}
- else
+
+ if (!((Item_in_subselect*)args[1])->is_correlated &&
+ all_left_cols_null && result_for_null_param != UNKNOWN)
{
- /*
- We're evaluating "NULL IN (SELECT ...)". The result is:
- FALSE if SELECT produces an empty set, or
- NULL otherwise.
- We disable the predicates we've pushed down into subselect, run the
- subselect and see if it has produced any rows.
+ /*
+ This is a non-correlated subquery, all values in the outer
+ value list are NULL, and we have already evaluated the
+ subquery for all NULL values: Return the same result we
+ did last time without evaluating the subquery.
*/
- Item_in_subselect *item_subs=(Item_in_subselect*)args[1];
- if (cache->cols() == 1)
- {
- item_subs->set_cond_guard_var(0, FALSE);
- (void) args[1]->val_bool_result();
- result_for_null_param= null_value= !item_subs->engine->no_rows();
- item_subs->set_cond_guard_var(0, TRUE);
- }
- else
- {
- uint i;
- uint ncols= cache->cols();
- /*
- Turn off the predicates that are based on column compares for
- which the left part is currently NULL
- */
- for (i= 0; i < ncols; i++)
- {
- if (cache->element_index(i)->null_value)
- item_subs->set_cond_guard_var(i, FALSE);
- }
-
- (void) args[1]->val_bool_result();
- result_for_null_param= null_value= !item_subs->engine->no_rows();
-
- /* Turn all predicates back on */
- for (i= 0; i < ncols; i++)
- item_subs->set_cond_guard_var(i, TRUE);
- }
+ null_value= result_for_null_param;
+ }
+ else
+ {
+ /* The subquery has to be evaluated */
+ (void) args[1]->val_bool_result();
+ null_value= !item_subs->engine->no_rows();
+ if (all_left_cols_null)
+ result_for_null_param= null_value;
}
+
+ /* Turn all predicates back on */
+ for (uint i= 0; i < ncols; i++)
+ item_subs->set_cond_guard_var(i, TRUE);
}
return 0;
}
@@ -2191,7 +2229,7 @@ uint Item_func_ifnull::decimal_precision() const
int arg1_int_part= args[1]->decimal_int_part();
int max_int_part= max(arg0_int_part, arg1_int_part);
int precision= max_int_part + decimals;
- return precision;
+ return min(precision, DECIMAL_MAX_PRECISION);
}
@@ -2375,7 +2413,7 @@ uint Item_func_if::decimal_precision() const
int arg1_prec= args[1]->decimal_int_part();
int arg2_prec= args[2]->decimal_int_part();
int precision=max(arg1_prec,arg2_prec) + decimals;
- return precision;
+ return min(precision, DECIMAL_MAX_PRECISION);
}
@@ -2783,7 +2821,7 @@ uint Item_func_case::decimal_precision() const
if (else_expr_num != -1)
set_if_bigger(max_int_part, args[else_expr_num]->decimal_int_part());
- return max_int_part + decimals;
+ return min(max_int_part + decimals, DECIMAL_MAX_PRECISION);
}