summaryrefslogtreecommitdiff
path: root/sql/item_cmpfunc.cc
diff options
context:
space:
mode:
authorSergei Golubchik <sergii@pisem.net>2011-06-07 18:13:02 +0200
committerSergei Golubchik <sergii@pisem.net>2011-06-07 18:13:02 +0200
commit9b98cae4cc44fa39813675b361b7aa65d129b29d (patch)
tree7f4baeea245f91006e88c62508c2859ed9390c2d /sql/item_cmpfunc.cc
parent29af1aefe914da6aca73498c077f7e37a36d7de4 (diff)
parent4d128777dde904c5f0adab9b093e854c9c580d41 (diff)
downloadmariadb-git-9b98cae4cc44fa39813675b361b7aa65d129b29d.tar.gz
merge with 5.1-micro
Diffstat (limited to 'sql/item_cmpfunc.cc')
-rw-r--r--sql/item_cmpfunc.cc449
1 files changed, 150 insertions, 299 deletions
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index bae8c4308e1..99428d9d1de 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -29,7 +29,7 @@
#include <m_ctype.h>
#include "sql_select.h"
-static bool convert_constant_item(THD *, Item_field *, Item **);
+static bool convert_const_to_int(THD *, Item_field *, Item **);
static Item_result item_store_type(Item_result a, Item *item,
my_bool unsigned_flag)
@@ -73,6 +73,30 @@ static void agg_result_type(Item_result *type, Item **items, uint nitems)
}
+/**
+ find an temporal type (item) that others will be converted to
+ for the purpose of comparison.
+
+ this is the type that will be used in warnings like
+ "Incorrect <<TYPE>> value".
+*/
+Item *find_date_time_item(Item **args, uint nargs, uint col)
+{
+ Item *date_arg= 0, **arg, **arg_end;
+ for (arg= args, arg_end= args + nargs; arg != arg_end ; arg++)
+ {
+ Item *item= arg[0]->element_index(col);
+ if (item->cmp_type() != TIME_RESULT)
+ continue;
+ if (item->field_type() == MYSQL_TYPE_DATETIME)
+ return item;
+ if (!date_arg)
+ date_arg= item;
+ }
+ return date_arg;
+}
+
+
/*
Compare row signature of two expressions
@@ -204,7 +228,7 @@ static uint collect_cmp_types(Item **items, uint nitems, bool skip_nulls= FALSE)
{
uint i;
uint found_types;
- Item_result left_result= items[0]->result_type();
+ Item_result left_result= items[0]->cmp_type();
DBUG_ASSERT(nitems > 1);
found_types= 0;
for (i= 1; i < nitems ; i++)
@@ -212,11 +236,11 @@ static uint collect_cmp_types(Item **items, uint nitems, bool skip_nulls= FALSE)
if (skip_nulls && items[i]->type() == Item::NULL_ITEM)
continue; // Skip NULL constant items
if ((left_result == ROW_RESULT ||
- items[i]->result_type() == ROW_RESULT) &&
+ items[i]->cmp_type() == ROW_RESULT) &&
cmp_row_type(items[0], items[i]))
return 0;
found_types|= 1<< (uint)item_cmp_type(left_result,
- items[i]->result_type());
+ items[i]->cmp_type());
}
/*
Even if all right-hand items are NULLs and we are skipping them all, we need
@@ -392,12 +416,24 @@ longlong Item_func_nop_all::val_int()
1 Item was replaced with an integer version of the item
*/
-static bool convert_constant_item(THD *thd, Item_field *field_item,
+static bool convert_const_to_int(THD *thd, Item_field *field_item,
Item **item)
{
Field *field= field_item->field;
int result= 0;
+ /*
+ We don't need to convert an integer to an integer,
+ pretend it's already converted.
+
+ But we still convert it if it is compared with a Field_year,
+ as YEAR(2) may change the value of an integer when converting it
+ to an integer (say, 0 to 70).
+ */
+ if ((*item)->cmp_type() == INT_RESULT &&
+ field_item->field_type() != MYSQL_TYPE_YEAR)
+ return 1;
+
if ((*item)->const_item())
{
TABLE *table= field->table;
@@ -502,9 +538,7 @@ void Item_bool_func2::fix_length_and_dec()
{
Item_field *field_item= (Item_field*) (args[field]->real_item());
if (field_item->cmp_type() == INT_RESULT &&
- (field_item->field->special_const_compare() ||
- args[!field]->result_type() == STRING_RESULT) &&
- convert_constant_item(thd, field_item, &args[!field]))
+ convert_const_to_int(thd, field_item, &args[!field]))
args[0]->cmp_context= args[1]->cmp_context= INT_RESULT;
}
}
@@ -680,36 +714,6 @@ bool get_mysql_time_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 pack_time(&l_time);
-}
-
-/**
Prepare the comparator (set the comparison function) for comparing
items *a1 and *a2 in the context of 'type'.
@@ -841,108 +845,28 @@ get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg,
{
longlong UNINIT_VAR(value);
Item *item= **item_arg;
- enum_field_types f_type= warn_item->field_type();
+ enum_field_types f_type= item->cmp_type() == TIME_RESULT ?
+ item->field_type() : warn_item->field_type();
- switch (item->cmp_type()) {
- case TIME_RESULT:
- /* if it's our Item_cache_int, as created below, we simply use the value */
- if (item->result_type() == INT_RESULT)
- {
- value= item->val_int();
- cache_arg= 0;
- }
- else
- {
- MYSQL_TIME buf;
- if (item->get_date_result(&buf, TIME_FUZZY_DATE | TIME_INVALID_DATES))
- DBUG_ASSERT(item->null_value);
- else
- value= pack_time(&buf);
- f_type= item->field_type(); // for Item_cache_int below.
- }
- break;
- case INT_RESULT:
+ if (item->result_type() == INT_RESULT && item->cmp_type() == TIME_RESULT)
+ {
+ /* it's our Item_cache_int, as created below */
value= item->val_int();
-
- if (item->field_type() == MYSQL_TYPE_YEAR)
- {
- /*
- Coerce value to the 19XX form in order to correctly compare
- YEAR(2) & YEAR(4) types.
- Here we are converting all item values but YEAR(4) fields since
- 1) YEAR(4) already has a regular YYYY form and
- 2) we don't want to convert zero/bad YEAR(4) values to the
- value of 2000.
- */
- Item *real_item= item->real_item();
- if (real_item->max_length == 2)
- {
- if (value < 70)
- value+= 100;
- if (value <= 1900)
- value+= 1900;
- }
- value*= 13ULL * 32ULL * 24ULL * 60ULL * 60ULL * 1000000ULL;
- }
+ }
+ else
+ {
+ MYSQL_TIME ltime;
+ uint fuzzydate= TIME_FUZZY_DATE | TIME_INVALID_DATES;
+ if (f_type == MYSQL_TYPE_TIME)
+ fuzzydate|= TIME_TIME_ONLY;
+ if (item->get_date(&ltime, fuzzydate))
+ value= 0; /* invalid date */
else
- {
- MYSQL_TIME buf;
- int was_cut;
- longlong res;
-
- if (f_type == MYSQL_TYPE_TIME)
- res= number_to_time((double)value, &buf, &was_cut);
- else
- res= number_to_datetime(value, &buf, TIME_INVALID_DATES|TIME_FUZZY_DATE,
- &was_cut);
- if (res == -1)
- {
- const Lazy_string_num str(value);
- make_truncated_value_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, &str,
- mysql_type_to_time_type(f_type),
- warn_item->field_name_or_null());
- value= 0;
- }
- else
- value= pack_time(&buf);
- }
- break;
- case STRING_RESULT:
- case DECIMAL_RESULT:
- case REAL_RESULT:
- {
- char strbuf[MAX_DATETIME_FULL_WIDTH];
- String buf(strbuf, sizeof(strbuf), &my_charset_bin), *str;
- if ((str= item->val_str(&buf)))
- {
- /*
- Convert strings to the integer DATE/DATETIME representation.
-
- Even if both dates provided in strings we cannot compare them
- directly as strings as there is no warranty that they are correct
- and do not miss some insignificant zeros.
- */
- bool error;
- value= (longlong) get_date_from_str(thd, str,
- mysql_type_to_time_type(f_type),
- warn_item->field_name_or_null(),
- &error);
- /*
- If str did not contain a valid date according to the current
- SQL_MODE, get_date_from_str() has already thrown a warning,
- and we don't want to throw NULL on invalid date (see 5.2.6
- "SQL modes" in the manual), so we're done here.
- */
- }
- break;
- }
- case ROW_RESULT:
- case IMPOSSIBLE_RESULT:
- DBUG_ASSERT(0);
+ value= pack_time(&ltime);
}
if ((*is_null= item->null_value))
return ~(ulonglong) 0;
- if (cache_arg && item->const_item())
+ if (cache_arg && item->const_item() && item->type() != Item::CACHE_ITEM)
{
/*
cache the packed datetime value in the Item_cache object.
@@ -952,8 +876,7 @@ get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg,
MYSQL_TIMESTAMP_DATE or MYSQL_TYPE_DATETIME), and thus it will have
cmp_type() == TIME_RESULT.
As no other item can have this combination of cmp_type() and
- result_type(), it allows us to identify our cache items, see
- 'case TIME_RESULT:' above.
+ result_type(), it allows us to identify our cache items.
*/
Query_arena backup;
Query_arena *save_arena= thd->switch_to_arena_for_cached_items(&backup);
@@ -2178,18 +2101,7 @@ void Item_func_between::fix_length_and_dec()
strings as.
*/
if (cmp_type == TIME_RESULT)
- {
- for (int i= 0; i < 3; i++)
- {
- if (args[i]->cmp_type() == TIME_RESULT)
- {
- if (args[i]->field_type() != MYSQL_TYPE_TIME ||
- (args[i]->field_type() == MYSQL_TYPE_TIME && compare_as_dates==0))
- compare_as_dates= args[i];
- continue;
- }
- }
- }
+ compare_as_dates= find_date_time_item(args, 3, 0);
/* See the comment about the similar block in Item_bool_func2 */
if (args[0]->real_item()->type() == FIELD_ITEM &&
@@ -2198,17 +2110,14 @@ void Item_func_between::fix_length_and_dec()
Item_field *field_item= (Item_field*) (args[0]->real_item());
if (field_item->cmp_type() == INT_RESULT)
{
- bool special= field_item->field->special_const_compare();
/*
- The following can't be recoded with || as convert_constant_item
+ The following can't be recoded with || as convert_const_to_int
changes the argument
*/
- if ((special || args[1]->result_type() == STRING_RESULT) &&
- convert_constant_item(thd, field_item, &args[1]))
- cmp_type=INT_RESULT; // Works for all types.
- if ((special || args[2]->result_type() == STRING_RESULT) &&
- convert_constant_item(thd, field_item, &args[2]))
- cmp_type=INT_RESULT; // Works for all types.
+ if (convert_const_to_int(thd, field_item, &args[1]))
+ cmp_type=INT_RESULT;
+ if (convert_const_to_int(thd, field_item, &args[2]))
+ cmp_type=INT_RESULT;
}
}
}
@@ -2966,16 +2875,17 @@ void Item_func_case::fix_length_and_dec()
found_types |= (1 << item_cmp_type(left_result_type, STRING_RESULT));
}
- for (i= 0; i <= (uint)DECIMAL_RESULT; i++)
+ for (i= 0; i <= (uint)TIME_RESULT; i++)
{
if (found_types & (1 << i) && !cmp_items[i])
{
DBUG_ASSERT((Item_result)i != ROW_RESULT);
+ DBUG_ASSERT((Item_result)i != TIME_RESULT);
if ((Item_result)i == STRING_RESULT &&
agg_arg_charsets(cmp_collation, agg, nagg, MY_COLL_CMP_CONV, 1))
return;
if (!(cmp_items[i]=
- cmp_item::get_comparator((Item_result)i,
+ cmp_item::get_comparator((Item_result)i, 0,
cmp_collation.collation)))
return;
}
@@ -3055,7 +2965,7 @@ void Item_func_case::cleanup()
uint i;
DBUG_ENTER("Item_func_case::cleanup");
Item_func::cleanup();
- for (i= 0; i <= (uint)DECIMAL_RESULT; i++)
+ for (i= 0; i <= (uint)TIME_RESULT; i++)
{
delete cmp_items[i];
cmp_items[i]= 0;
@@ -3486,7 +3396,7 @@ uchar *in_decimal::get_value(Item *item)
}
-cmp_item* cmp_item::get_comparator(Item_result type,
+cmp_item* cmp_item::get_comparator(Item_result type, Item *warn_item,
CHARSET_INFO *cs)
{
switch (type) {
@@ -3501,6 +3411,7 @@ cmp_item* cmp_item::get_comparator(Item_result type,
case DECIMAL_RESULT:
return new cmp_item_decimal;
case TIME_RESULT:
+ return new cmp_item_datetime(warn_item);
case IMPOSSIBLE_RESULT:
DBUG_ASSERT(0);
break;
@@ -3566,7 +3477,7 @@ void cmp_item_row::store_value(Item *item)
{
if (!comparators[i])
if (!(comparators[i]=
- cmp_item::get_comparator(item->element_index(i)->result_type(),
+ cmp_item::get_comparator(item->element_index(i)->result_type(), 0,
item->element_index(i)->collation.collation)))
break; // new failed
comparators[i]->store_value(item->element_index(i));
@@ -3767,20 +3678,17 @@ static int srtcmp_in(CHARSET_INFO *cs, const String *x,const String *y)
(uchar *) y->ptr(),y->length(), 0);
}
-
void Item_func_in::fix_length_and_dec()
{
Item **arg, **arg_end;
bool const_itm= 1;
THD *thd= current_thd;
- bool datetime_found= FALSE;
/* TRUE <=> arguments values will be compared as DATETIMEs. */
- bool compare_as_datetime= FALSE;
Item *date_arg= 0;
uint found_types= 0;
uint type_cnt= 0, i;
Item_result cmp_type= STRING_RESULT;
- left_result_type= args[0]->result_type();
+ left_result_type= args[0]->cmp_type();
if (!(found_types= collect_cmp_types(args, arg_count, true)))
return;
@@ -3792,7 +3700,7 @@ void Item_func_in::fix_length_and_dec()
break;
}
}
- for (i= 0; i <= (uint)DECIMAL_RESULT; i++)
+ for (i= 0; i <= (uint)TIME_RESULT; i++)
{
if (found_types & 1 << i)
{
@@ -3807,16 +3715,12 @@ void Item_func_in::fix_length_and_dec()
agg_arg_charsets(cmp_collation, args, arg_count, MY_COLL_CMP_CONV, 1))
return;
arg_types_compatible= TRUE;
- }
- if (type_cnt == 1)
- {
- /*
- When comparing rows create the row comparator object beforehand to ease
- the DATETIME comparison detection procedure.
- */
+
if (cmp_type == ROW_RESULT)
{
+ uint cols= args[0]->cols();
cmp_item_row *cmp= 0;
+
if (const_itm && !nulls_in_row())
{
array= new in_row(arg_count-1, 0);
@@ -3828,66 +3732,20 @@ void Item_func_in::fix_length_and_dec()
return;
cmp_items[ROW_RESULT]= cmp;
}
- cmp->n= args[0]->cols();
+ cmp->n= cols;
cmp->alloc_comparators();
- }
- /* All DATE/DATETIME fields/functions has the STRING result type. */
- if (cmp_type == STRING_RESULT || cmp_type == ROW_RESULT)
- {
- uint col, cols= args[0]->cols();
- for (col= 0; col < cols; col++)
+ for (uint col= 0; col < cols; col++)
{
- bool skip_column= FALSE;
- /*
- Check that all items to be compared has the STRING result type and at
- least one of them is a DATE/DATETIME item.
- */
- for (arg= args, arg_end= args + arg_count; arg != arg_end ; arg++)
- {
- Item *itm= ((cmp_type == STRING_RESULT) ? arg[0] :
- arg[0]->element_index(col));
- if (itm->result_type() != STRING_RESULT)
- {
- skip_column= TRUE;
- break;
- }
- else if (itm->cmp_type() == TIME_RESULT)
- {
- datetime_found= TRUE;
- /*
- Internally all DATE/DATETIME values are converted to the DATETIME
- type. So try to find a DATETIME item to issue correct warnings.
- */
- if (!date_arg)
- date_arg= itm;
- else if (itm->field_type() == MYSQL_TYPE_DATETIME)
- {
- date_arg= itm;
- /* All arguments are already checked to have the STRING result. */
- if (cmp_type == STRING_RESULT)
- break;
- }
- }
- }
- if (skip_column)
- continue;
- if (datetime_found)
+ date_arg= find_date_time_item(args, arg_count, col);
+ if (date_arg)
{
- if (cmp_type == ROW_RESULT)
- {
- cmp_item **cmp= 0;
- if (array)
- cmp= ((in_row*)array)->tmp.comparators + col;
- else
- cmp= ((cmp_item_row*)cmp_items[ROW_RESULT])->comparators + col;
- *cmp= new cmp_item_datetime(date_arg);
- /* Reset variables for the next column. */
- date_arg= 0;
- datetime_found= FALSE;
- }
+ cmp_item **cmp= 0;
+ if (array)
+ cmp= ((in_row*)array)->tmp.comparators + col;
else
- compare_as_datetime= TRUE;
+ cmp= ((cmp_item_row*)cmp_items[ROW_RESULT])->comparators + col;
+ *cmp= new cmp_item_datetime(date_arg);
}
}
}
@@ -3898,65 +3756,60 @@ void Item_func_in::fix_length_and_dec()
*/
if (type_cnt == 1 && const_itm && !nulls_in_row())
{
- if (compare_as_datetime)
- array= new in_datetime(date_arg, arg_count - 1);
- else
+ /*
+ IN must compare INT columns and constants as int values (the same
+ way as equality does).
+ So we must check here if the column on the left and all the constant
+ values on the right can be compared as integers and adjust the
+ comparison type accordingly.
+
+ See the comment about the similar block in Item_bool_func2
+ */
+ if (args[0]->real_item()->type() == FIELD_ITEM &&
+ !thd->lex->is_ps_or_view_context_analysis() && cmp_type != INT_RESULT)
{
- /*
- IN must compare INT columns and constants as int values (the same
- way as equality does).
- So we must check here if the column on the left and all the constant
- values on the right can be compared as integers and adjust the
- comparison type accordingly.
-
- See the comment about the similar block in Item_bool_func2
- */
- if (args[0]->real_item()->type() == FIELD_ITEM &&
- !thd->lex->is_ps_or_view_context_analysis() &&
- cmp_type != INT_RESULT)
+ Item_field *field_item= (Item_field*) (args[0]->real_item());
+ if (field_item->cmp_type() == INT_RESULT)
{
- Item_field *field_item= (Item_field*) (args[0]->real_item());
- if (field_item->cmp_type() == INT_RESULT)
+ bool all_converted= TRUE;
+ for (arg=args+1, arg_end=args+arg_count; arg != arg_end ; arg++)
{
- bool special= field_item->field->special_const_compare();
- bool all_converted= TRUE;
- for (arg=args+1, arg_end=args+arg_count; arg != arg_end ; arg++)
- {
- if (!(special || arg[0]->result_type() == STRING_RESULT) ||
- !convert_constant_item(thd, field_item, &arg[0]))
- all_converted= FALSE;
- }
- if (all_converted)
- cmp_type= INT_RESULT;
+ if (!convert_const_to_int(thd, field_item, &arg[0]))
+ all_converted= FALSE;
}
+ if (all_converted)
+ cmp_type= INT_RESULT;
}
- switch (cmp_type) {
- case STRING_RESULT:
- array=new in_string(arg_count-1,(qsort2_cmp) srtcmp_in,
- cmp_collation.collation);
- break;
- case INT_RESULT:
- array= new in_longlong(arg_count-1);
- break;
- case REAL_RESULT:
- array= new in_double(arg_count-1);
- break;
- case ROW_RESULT:
- /*
- The row comparator was created at the beginning but only DATETIME
- items comparators were initialized. Call store_value() to setup
- others.
- */
- ((in_row*)array)->tmp.store_value(args[0]);
- break;
- case DECIMAL_RESULT:
- array= new in_decimal(arg_count - 1);
- break;
- case TIME_RESULT:
- case IMPOSSIBLE_RESULT:
- DBUG_ASSERT(0);
- break;
- }
+ }
+ switch (cmp_type) {
+ case STRING_RESULT:
+ array=new in_string(arg_count-1,(qsort2_cmp) srtcmp_in,
+ cmp_collation.collation);
+ break;
+ case INT_RESULT:
+ array= new in_longlong(arg_count-1);
+ break;
+ case REAL_RESULT:
+ array= new in_double(arg_count-1);
+ break;
+ case ROW_RESULT:
+ /*
+ The row comparator was created at the beginning but only DATETIME
+ items comparators were initialized. Call store_value() to setup
+ others.
+ */
+ ((in_row*)array)->tmp.store_value(args[0]);
+ break;
+ case DECIMAL_RESULT:
+ array= new in_decimal(arg_count - 1);
+ break;
+ case TIME_RESULT:
+ date_arg= find_date_time_item(args, arg_count, 0);
+ array= new in_datetime(date_arg, arg_count - 1);
+ break;
+ case IMPOSSIBLE_RESULT:
+ DBUG_ASSERT(0);
+ break;
}
if (array && !(thd->is_fatal_error)) // If not EOM
{
@@ -3975,23 +3828,21 @@ void Item_func_in::fix_length_and_dec()
}
else
{
- if (compare_as_datetime)
- cmp_items[STRING_RESULT]= new cmp_item_datetime(date_arg);
- else
+ for (i= 0; i <= (uint) TIME_RESULT; i++)
{
- for (i= 0; i <= (uint) DECIMAL_RESULT; i++)
+ if (found_types & (1 << i) && !cmp_items[i])
{
- if (found_types & (1 << i) && !cmp_items[i])
- {
- if ((Item_result)i == STRING_RESULT &&
- agg_arg_charsets(cmp_collation, args, arg_count,
- MY_COLL_CMP_CONV, 1))
- return;
- if (!cmp_items[i] && !(cmp_items[i]=
- cmp_item::get_comparator((Item_result)i,
- cmp_collation.collation)))
- return;
- }
+ if ((Item_result)i == STRING_RESULT &&
+ agg_arg_charsets(cmp_collation, args, arg_count,
+ MY_COLL_CMP_CONV, 1))
+ return;
+ if ((Item_result)i == TIME_RESULT)
+ date_arg= find_date_time_item(args, arg_count, 0);
+
+ if (!cmp_items[i] && !(cmp_items[i]=
+ cmp_item::get_comparator((Item_result)i, date_arg,
+ cmp_collation.collation)))
+ return;
}
}
}
@@ -4059,7 +3910,7 @@ longlong Item_func_in::val_int()
have_null= TRUE;
continue;
}
- Item_result cmp_type= item_cmp_type(left_result_type, args[i]->result_type());
+ Item_result cmp_type= item_cmp_type(left_result_type, args[i]->cmp_type());
in_item= cmp_items[(uint)cmp_type];
DBUG_ASSERT(in_item);
if (!(value_added_map & (1 << (uint)cmp_type)))
@@ -5677,7 +5528,7 @@ longlong Item_equal::val_int()
void Item_equal::fix_length_and_dec()
{
Item *item= get_first(NULL);
- eval_item= cmp_item::get_comparator(item->result_type(),
+ eval_item= cmp_item::get_comparator(item->result_type(), 0,
item->collation.collation);
}