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.cc536
1 files changed, 318 insertions, 218 deletions
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 919015140c1..19809ed08c7 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -109,7 +109,6 @@ static int cmp_row_type(Item* item1, Item* item2)
SYNOPSIS:
agg_cmp_type()
- thd thread handle
type [out] the aggregated type
items array of items to aggregate the type from
nitems number of items in the array
@@ -126,7 +125,7 @@ static int cmp_row_type(Item* item1, Item* item2)
0 otherwise
*/
-static int agg_cmp_type(THD *thd, Item_result *type, Item **items, uint nitems)
+static int agg_cmp_type(Item_result *type, Item **items, uint nitems)
{
uint i;
type[0]= items[0]->result_type();
@@ -147,6 +146,42 @@ static int agg_cmp_type(THD *thd, Item_result *type, Item **items, uint nitems)
}
+/*
+ Collects different types for comparison of first item with each other items
+
+ SYNOPSIS
+ collect_cmp_types()
+ items Array of items to collect types from
+ nitems Number of items in the array
+
+ DESCRIPTION
+ This function collects different result types for comparison of the first
+ item in the list with each of the remaining items in the 'items' array.
+
+ RETURN
+ 0 - if row type incompatibility has been detected (see cmp_row_type)
+ Bitmap of collected types - otherwise
+*/
+
+static uint collect_cmp_types(Item **items, uint nitems)
+{
+ uint i;
+ uint found_types;
+ Item_result left_result= items[0]->result_type();
+ DBUG_ASSERT(nitems > 1);
+ found_types= 0;
+ for (i= 1; i < nitems ; i++)
+ {
+ if ((left_result == ROW_RESULT ||
+ items[i]->result_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());
+ }
+ return found_types;
+}
+
static void my_coll_agg_error(DTCollation &c1, DTCollation &c2,
const char *fname)
{
@@ -312,27 +347,45 @@ longlong Item_func_nop_all::val_int()
static bool convert_constant_item(THD *thd, Field *field, Item **item)
{
+ int result= 0;
+
if (!(*item)->with_subselect && (*item)->const_item())
{
- /* For comparison purposes allow invalid dates like 2000-01-32 */
+ TABLE *table= field->table;
ulong orig_sql_mode= thd->variables.sql_mode;
enum_check_fields orig_count_cuted_fields= thd->count_cuted_fields;
+ my_bitmap_map *old_write_map;
+ my_bitmap_map *old_read_map;
+
+ LINT_INIT(old_write_map);
+ LINT_INIT(old_read_map);
+
+ if (table)
+ {
+ old_write_map= dbug_tmp_use_all_columns(table, table->write_set);
+ old_read_map= dbug_tmp_use_all_columns(table, table->read_set);
+ }
+ /* For comparison purposes allow invalid dates like 2000-01-32 */
thd->variables.sql_mode= (orig_sql_mode & ~MODE_NO_ZERO_DATE) |
MODE_INVALID_DATES;
thd->count_cuted_fields= CHECK_FIELD_IGNORE;
if (!(*item)->save_in_field(field, 1) && !((*item)->null_value))
{
- Item *tmp=new Item_int_with_ref(field->val_int(), *item,
- test(field->flags & UNSIGNED_FLAG));
- thd->variables.sql_mode= orig_sql_mode;
+ Item *tmp= new Item_int_with_ref(field->val_int(), *item,
+ test(field->flags & UNSIGNED_FLAG));
if (tmp)
thd->change_item_tree(item, tmp);
- return 1; // Item was replaced
+ result= 1; // Item was replaced
}
thd->variables.sql_mode= orig_sql_mode;
thd->count_cuted_fields= orig_count_cuted_fields;
+ if (table)
+ {
+ dbug_tmp_restore_column_map(table->write_set, old_write_map);
+ dbug_tmp_restore_column_map(table->read_set, old_read_map);
+ }
}
- return 0;
+ return result;
}
@@ -478,8 +531,8 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type)
which would be transformed to:
WHERE col= 'j'
*/
- (*a)->walk(&Item::set_no_const_sub, (byte*) 0);
- (*b)->walk(&Item::set_no_const_sub, (byte*) 0);
+ (*a)->walk(&Item::set_no_const_sub, FALSE, (uchar*) 0);
+ (*b)->walk(&Item::set_no_const_sub, FALSE, (uchar*) 0);
}
break;
}
@@ -1290,7 +1343,8 @@ bool Item_in_optimizer::fix_left(THD *thd, Item **ref)
}
not_null_tables_cache= args[0]->not_null_tables();
with_sum_func= args[0]->with_sum_func;
- const_item_cache= args[0]->const_item();
+ if ((const_item_cache= args[0]->const_item()))
+ cache->store(args[0]);
return 0;
}
@@ -1517,8 +1571,10 @@ bool Item_func_opt_neg::eq(const Item *item, bool binary_cmp) const
void Item_func_interval::fix_length_and_dec()
{
- use_decimal_comparison= (row->element_index(0)->result_type() == DECIMAL_RESULT) ||
- (row->element_index(0)->result_type() == INT_RESULT);
+ use_decimal_comparison= ((row->element_index(0)->result_type() ==
+ DECIMAL_RESULT) ||
+ (row->element_index(0)->result_type() ==
+ INT_RESULT));
if (row->cols() > 8)
{
bool consts=1;
@@ -1713,7 +1769,6 @@ bool Item_func_between::fix_fields(THD *thd, Item **ref)
void Item_func_between::fix_length_and_dec()
{
max_length= 1;
- THD *thd= current_thd;
int i;
bool datetime_found= FALSE;
compare_as_dates= TRUE;
@@ -1724,7 +1779,7 @@ void Item_func_between::fix_length_and_dec()
*/
if (!args[0] || !args[1] || !args[2])
return;
- if ( agg_cmp_type(thd, &cmp_type, args, 3))
+ if ( agg_cmp_type(&cmp_type, args, 3))
return;
if (cmp_type == STRING_RESULT &&
agg_arg_charsets(cmp_collation, args, 3, MY_COLL_CMP_CONV, 1))
@@ -1943,7 +1998,7 @@ enum_field_types Item_func_ifnull::field_type() const
Field *Item_func_ifnull::tmp_table_field(TABLE *table)
{
- return tmp_table_field_from_field_type(table);
+ return tmp_table_field_from_field_type(table, 0);
}
double
@@ -2254,94 +2309,65 @@ Item_func_nullif::is_null()
return (null_value= (!cmp.compare() ? 1 : args[0]->null_value));
}
+
/*
- CASE expression
Return the matching ITEM or NULL if all compares (including else) failed
+
+ SYNOPSIS
+ find_item()
+ str Buffer string
+
+ DESCRIPTION
+ Find and return matching items for CASE or ELSE item if all compares
+ are failed or NULL if ELSE item isn't defined.
+
+ IMPLEMENTATION
+ In order to do correct comparisons of the CASE expression (the expression
+ between CASE and the first WHEN) with each WHEN expression several
+ comparators are used. One for each result type. CASE expression can be
+ evaluated up to # of different result types are used. To check whether
+ the CASE expression already was evaluated for a particular result type
+ a bit mapped variable value_added_map is used. Result types are mapped
+ to it according to their int values i.e. STRING_RESULT is mapped to bit
+ 0, REAL_RESULT to bit 1, so on.
+
+ RETURN
+ NULL - Nothing found and there is no ELSE expression defined
+ item - Found item or ELSE item if defined and all comparisons are
+ failed
*/
Item *Item_func_case::find_item(String *str)
{
- String *first_expr_str, *tmp;
- my_decimal *first_expr_dec, first_expr_dec_val;
- longlong first_expr_int;
- double first_expr_real;
- char buff[MAX_FIELD_WIDTH];
- String buff_str(buff,sizeof(buff),default_charset());
-
- /* These will be initialized later */
- LINT_INIT(first_expr_str);
- LINT_INIT(first_expr_int);
- LINT_INIT(first_expr_real);
- LINT_INIT(first_expr_dec);
+ uint value_added_map= 0;
- if (first_expr_num != -1)
+ if (first_expr_num == -1)
{
- switch (cmp_type)
- {
- case STRING_RESULT:
- // We can't use 'str' here as this may be overwritten
- if (!(first_expr_str= args[first_expr_num]->val_str(&buff_str)))
- return else_expr_num != -1 ? args[else_expr_num] : 0; // Impossible
- break;
- case INT_RESULT:
- first_expr_int= args[first_expr_num]->val_int();
- if (args[first_expr_num]->null_value)
- return else_expr_num != -1 ? args[else_expr_num] : 0;
- break;
- case REAL_RESULT:
- first_expr_real= args[first_expr_num]->val_real();
- if (args[first_expr_num]->null_value)
- return else_expr_num != -1 ? args[else_expr_num] : 0;
- break;
- case DECIMAL_RESULT:
- first_expr_dec= args[first_expr_num]->val_decimal(&first_expr_dec_val);
- if (args[first_expr_num]->null_value)
- return else_expr_num != -1 ? args[else_expr_num] : 0;
- break;
- case ROW_RESULT:
- default:
- // This case should never be chosen
- DBUG_ASSERT(0);
- break;
- }
- }
-
- // Compare every WHEN argument with it and return the first match
- for (uint i=0 ; i < ncases ; i+=2)
- {
- if (first_expr_num == -1)
+ for (uint i=0 ; i < ncases ; i+=2)
{
// No expression between CASE and the first WHEN
if (args[i]->val_bool())
return args[i+1];
continue;
}
- switch (cmp_type) {
- case STRING_RESULT:
- if ((tmp=args[i]->val_str(str))) // If not null
- if (sortcmp(tmp,first_expr_str,cmp_collation.collation)==0)
- return args[i+1];
- break;
- case INT_RESULT:
- if (args[i]->val_int()==first_expr_int && !args[i]->null_value)
- return args[i+1];
- break;
- case REAL_RESULT:
- if (args[i]->val_real() == first_expr_real && !args[i]->null_value)
- return args[i+1];
- break;
- case DECIMAL_RESULT:
+ }
+ else
+ {
+ /* Compare every WHEN argument with it and return the first match */
+ for (uint i=0 ; i < ncases ; i+=2)
{
- my_decimal value;
- if (my_decimal_cmp(args[i]->val_decimal(&value), first_expr_dec) == 0)
- return args[i+1];
- break;
- }
- case ROW_RESULT:
- default:
- // This case should never be chosen
- DBUG_ASSERT(0);
- break;
+ cmp_type= item_cmp_type(left_result_type, args[i]->result_type());
+ DBUG_ASSERT(cmp_type != ROW_RESULT);
+ DBUG_ASSERT(cmp_items[(uint)cmp_type]);
+ if (!(value_added_map & (1<<(uint)cmp_type)))
+ {
+ cmp_items[(uint)cmp_type]->store_value(args[first_expr_num]);
+ if ((null_value=args[first_expr_num]->null_value))
+ return else_expr_num != -1 ? args[else_expr_num] : 0;
+ value_added_map|= 1<<(uint)cmp_type;
+ }
+ if (!cmp_items[(uint)cmp_type]->cmp(args[i]) && !args[i]->null_value)
+ return args[i + 1];
}
}
// No, WHEN clauses all missed, return ELSE expression
@@ -2431,7 +2457,7 @@ bool Item_func_case::fix_fields(THD *thd, Item **ref)
Item_func_case::val_int() -> Item_func_case::find_item()
*/
#ifndef EMBEDDED_LIBRARY
- char buff[MAX_FIELD_WIDTH*2+sizeof(String)*2+sizeof(String*)*2+sizeof(double)*2+sizeof(longlong)*2];
+ uchar buff[MAX_FIELD_WIDTH*2+sizeof(String)*2+sizeof(String*)*2+sizeof(double)*2+sizeof(longlong)*2];
#endif
bool res= Item_func::fix_fields(thd, ref);
/*
@@ -2449,8 +2475,7 @@ void Item_func_case::fix_length_and_dec()
{
Item **agg;
uint nagg;
- THD *thd= current_thd;
-
+ uint found_types= 0;
if (!(agg= (Item**) sql_alloc(sizeof(Item*)*(ncases+1))))
return;
@@ -2477,17 +2502,32 @@ void Item_func_case::fix_length_and_dec()
*/
if (first_expr_num != -1)
{
+ uint i;
agg[0]= args[first_expr_num];
+ left_result_type= agg[0]->result_type();
+
for (nagg= 0; nagg < ncases/2 ; nagg++)
agg[nagg+1]= args[nagg*2];
nagg++;
- if (agg_cmp_type(thd, &cmp_type, agg, nagg))
- return;
- if ((cmp_type == STRING_RESULT) &&
- agg_arg_charsets(cmp_collation, agg, nagg, MY_COLL_CMP_CONV, 1))
+ if (!(found_types= collect_cmp_types(agg, nagg)))
return;
+
+ for (i= 0; i <= (uint)DECIMAL_RESULT; i++)
+ {
+ if (found_types & (1 << i) && !cmp_items[i])
+ {
+ DBUG_ASSERT((Item_result)i != ROW_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_collation.collation)))
+ return;
+ }
+ }
}
-
+
if (else_expr_num == -1 || args[else_expr_num]->maybe_null)
maybe_null=1;
@@ -2757,7 +2797,7 @@ static int cmp_decimal(void *cmp_arg, my_decimal *a, my_decimal *b)
int in_vector::find(Item *item)
{
- byte *result=get_value(item);
+ uchar *result=get_value(item);
if (!result || !used_count)
return 0; // Null value
@@ -2812,9 +2852,9 @@ void in_string::set(uint pos,Item *item)
}
-byte *in_string::get_value(Item *item)
+uchar *in_string::get_value(Item *item)
{
- return (byte*) item->val_str(&tmp);
+ return (uchar*) item->val_str(&tmp);
}
in_row::in_row(uint elements, Item * item)
@@ -2836,12 +2876,12 @@ in_row::~in_row()
delete [] (cmp_item_row*) base;
}
-byte *in_row::get_value(Item *item)
+uchar *in_row::get_value(Item *item)
{
tmp.store_value(item);
if (item->is_null())
return 0;
- return (byte *)&tmp;
+ return (uchar *)&tmp;
}
void in_row::set(uint pos, Item *item)
@@ -2864,13 +2904,13 @@ void in_longlong::set(uint pos,Item *item)
buff->unsigned_flag= item->unsigned_flag;
}
-byte *in_longlong::get_value(Item *item)
+uchar *in_longlong::get_value(Item *item)
{
tmp.val= item->val_int();
if (item->null_value)
return 0;
tmp.unsigned_flag= item->unsigned_flag;
- return (byte*) &tmp;
+ return (uchar*) &tmp;
}
void in_datetime::set(uint pos,Item *item)
@@ -2883,7 +2923,7 @@ void in_datetime::set(uint pos,Item *item)
buff->unsigned_flag= 1L;
}
-byte *in_datetime::get_value(Item *item)
+uchar *in_datetime::get_value(Item *item)
{
bool is_null;
Item **tmp_item= lval_cache ? &lval_cache : &item;
@@ -2891,7 +2931,7 @@ byte *in_datetime::get_value(Item *item)
if (item->null_value)
return 0;
tmp.unsigned_flag= 1L;
- return (byte*) &tmp;
+ return (uchar*) &tmp;
}
in_double::in_double(uint elements)
@@ -2903,12 +2943,12 @@ void in_double::set(uint pos,Item *item)
((double*) base)[pos]= item->val_real();
}
-byte *in_double::get_value(Item *item)
+uchar *in_double::get_value(Item *item)
{
tmp= item->val_real();
if (item->null_value)
return 0; /* purecov: inspected */
- return (byte*) &tmp;
+ return (uchar*) &tmp;
}
@@ -2930,12 +2970,12 @@ void in_decimal::set(uint pos, Item *item)
}
-byte *in_decimal::get_value(Item *item)
+uchar *in_decimal::get_value(Item *item)
{
my_decimal *result= item->val_decimal(&val);
if (item->null_value)
return 0;
- return (byte *)result;
+ return (uchar *)result;
}
@@ -3224,21 +3264,20 @@ static int srtcmp_in(CHARSET_INFO *cs, const String *x,const String *y)
void Item_func_in::fix_length_and_dec()
{
Item **arg, **arg_end;
- uint const_itm= 1;
+ 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;
-
- if (agg_cmp_type(thd, &cmp_type, args, arg_count))
- return;
-
- if (cmp_type == STRING_RESULT &&
- agg_arg_charsets(cmp_collation, args, arg_count, MY_COLL_CMP_CONV, 1))
+ uint found_types= 0;
+ uint type_cnt= 0, i;
+ Item_result cmp_type= STRING_RESULT;
+ left_result_type= args[0]->result_type();
+ if (!(found_types= collect_cmp_types(args, arg_count)))
return;
-
- for (arg=args+1, arg_end=args+arg_count; arg != arg_end ; arg++)
+
+ for (arg= args + 1, arg_end= args + arg_count; arg != arg_end ; arg++)
{
if (!arg[0]->const_item())
{
@@ -3246,92 +3285,111 @@ void Item_func_in::fix_length_and_dec()
break;
}
}
- /*
- When comparing rows create the row comparator object beforehand to ease
- the DATETIME comparison detection procedure.
- */
- if (cmp_type == ROW_RESULT)
+ for (i= 0; i <= (uint)DECIMAL_RESULT; i++)
{
- cmp_item_row *cmp= 0;
- if (const_itm && !nulls_in_row())
- {
- array= new in_row(arg_count-1, 0);
- cmp= &((in_row*)array)->tmp;
- }
- else
+ if (found_types & 1 << i)
{
- if (!(cmp= new cmp_item_row))
- return;
- in_item= cmp;
+ (type_cnt)++;
+ cmp_type= (Item_result) i;
}
- cmp->n= args[0]->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++)
+ if (type_cnt == 1)
+ {
+ if (cmp_type == STRING_RESULT &&
+ 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)
{
- 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++)
+ cmp_item_row *cmp= 0;
+ if (const_itm && !nulls_in_row())
{
- 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->is_datetime())
+ array= new in_row(arg_count-1, 0);
+ cmp= &((in_row*)array)->tmp;
+ }
+ else
+ {
+ if (!(cmp= new cmp_item_row))
+ return;
+ cmp_items[ROW_RESULT]= cmp;
+ }
+ cmp->n= args[0]->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++)
+ {
+ 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++)
{
- 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)
+ Item *itm= ((cmp_type == STRING_RESULT) ? arg[0] :
+ arg[0]->element_index(col));
+ if (itm->result_type() != STRING_RESULT)
{
- date_arg= itm;
- /* All arguments are already checked to have the STRING result. */
- if (cmp_type == STRING_RESULT)
- break;
+ skip_column= TRUE;
+ break;
+ }
+ else if (itm->is_datetime())
+ {
+ 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)
- {
- if (cmp_type == ROW_RESULT)
+ if (skip_column)
+ continue;
+ if (datetime_found)
{
- cmp_item **cmp= 0;
- if (array)
- cmp= ((in_row*)array)->tmp.comparators + col;
+ 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;
+ }
else
- cmp= ((cmp_item_row*)in_item)->comparators + col;
- *cmp= new cmp_item_datetime(date_arg);
- /* Reset variables for the next column. */
- date_arg= 0;
- datetime_found= FALSE;
+ compare_as_datetime= TRUE;
}
- else
- compare_as_datetime= TRUE;
}
}
}
/*
- Row item with NULLs inside can return NULL or FALSE =>
+ Row item with NULLs inside can return NULL or FALSE =>
they can't be processed as static
*/
- if (const_itm && !nulls_in_row())
+ if (type_cnt == 1 && const_itm && !nulls_in_row())
{
if (compare_as_datetime)
array= new in_datetime(date_arg, arg_count - 1);
@@ -3400,27 +3458,31 @@ void Item_func_in::fix_length_and_dec()
else
have_null= 1;
}
- if ((array->used_count=j))
+ if ((array->used_count= j))
array->sort();
}
}
else
{
- if (in_item)
+ if (compare_as_datetime)
+ cmp_items[STRING_RESULT]= new cmp_item_datetime(date_arg);
+ else
{
- /*
- The row comparator was created at the beginning but only DATETIME
- items comparators were initialized. Call store_value() to setup
- others.
- */
- in_item->store_value(args[0]);
+ for (i= 0; i <= (uint) DECIMAL_RESULT; 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;
+ }
+ }
}
- else if (compare_as_datetime)
- in_item= new cmp_item_datetime(date_arg);
- else
- in_item= cmp_item::get_comparator(cmp_type, cmp_collation.collation);
- if (cmp_type == STRING_RESULT)
- in_item->cmp_charset= cmp_collation.collation;
}
max_length= 1;
}
@@ -3438,25 +3500,61 @@ void Item_func_in::print(String *str)
}
+/*
+ Evaluate the function and return its value.
+
+ SYNOPSIS
+ val_int()
+
+ DESCRIPTION
+ Evaluate the function and return its value.
+
+ IMPLEMENTATION
+ If the array object is defined then the value of the function is
+ calculated by means of this array.
+ Otherwise several cmp_item objects are used in order to do correct
+ comparison of left expression and an expression from the values list.
+ One cmp_item object correspond to one used comparison type. Left
+ expression can be evaluated up to number of different used comparison
+ types. A bit mapped variable value_added_map is used to check whether
+ the left expression already was evaluated for a particular result type.
+ Result types are mapped to it according to their integer values i.e.
+ STRING_RESULT is mapped to bit 0, REAL_RESULT to bit 1, so on.
+
+ RETURN
+ Value of the function
+*/
+
longlong Item_func_in::val_int()
{
+ cmp_item *in_item;
DBUG_ASSERT(fixed == 1);
+ uint value_added_map= 0;
if (array)
{
int tmp=array->find(args[0]);
null_value=args[0]->null_value || (!tmp && have_null);
return (longlong) (!null_value && tmp != negated);
}
- in_item->store_value(args[0]);
- if ((null_value=args[0]->null_value))
- return 0;
- have_null= 0;
- for (uint i=1 ; i < arg_count ; i++)
+
+ for (uint i= 1 ; i < arg_count ; i++)
{
+ Item_result cmp_type= item_cmp_type(left_result_type, args[i]->result_type());
+ in_item= cmp_items[(uint)cmp_type];
+ DBUG_ASSERT(in_item);
+ if (!(value_added_map & (1 << (uint)cmp_type)))
+ {
+ in_item->store_value(args[0]);
+ if ((null_value=args[0]->null_value))
+ return 0;
+ have_null= 0;
+ value_added_map|= 1 << (uint)cmp_type;
+ }
if (!in_item->cmp(args[i]) && !args[i]->null_value)
return (longlong) (!negated);
have_null|= args[i]->null_value;
}
+
null_value= have_null;
return (longlong) (!null_value && negated);
}
@@ -3527,7 +3625,7 @@ Item_cond::fix_fields(THD *thd, Item **ref)
List_iterator<Item> li(list);
Item *item;
#ifndef EMBEDDED_LIBRARY
- char buff[sizeof(char*)]; // Max local vars in function
+ uchar buff[sizeof(char*)]; // Max local vars in function
#endif
not_null_tables_cache= used_tables_cache= 0;
const_item_cache= 1;
@@ -3594,14 +3692,14 @@ Item_cond::fix_fields(THD *thd, Item **ref)
return FALSE;
}
-bool Item_cond::walk(Item_processor processor, byte *arg)
+bool Item_cond::walk(Item_processor processor, bool walk_subquery, uchar *arg)
{
List_iterator_fast<Item> li(list);
Item *item;
while ((item= li++))
- if (item->walk(processor, arg))
+ if (item->walk(processor, walk_subquery, arg))
return 1;
- return Item_func::walk(processor, arg);
+ return Item_func::walk(processor, walk_subquery, arg);
}
@@ -3626,7 +3724,7 @@ bool Item_cond::walk(Item_processor processor, byte *arg)
Item returned as the result of transformation of the root node
*/
-Item *Item_cond::transform(Item_transformer transformer, byte *arg)
+Item *Item_cond::transform(Item_transformer transformer, uchar *arg)
{
DBUG_ASSERT(!current_thd->is_stmt_prepare());
@@ -3677,8 +3775,8 @@ Item *Item_cond::transform(Item_transformer transformer, byte *arg)
Item returned as the result of transformation of the root node
*/
-Item *Item_cond::compile(Item_analyzer analyzer, byte **arg_p,
- Item_transformer transformer, byte *arg_t)
+Item *Item_cond::compile(Item_analyzer analyzer, uchar **arg_p,
+ Item_transformer transformer, uchar *arg_t)
{
if (!(this->*analyzer)(arg_p))
return 0;
@@ -3691,7 +3789,7 @@ Item *Item_cond::compile(Item_analyzer analyzer, byte **arg_p,
The same parameter value of arg_p must be passed
to analyze any argument of the condition formula.
*/
- byte *arg_v= *arg_p;
+ uchar *arg_v= *arg_p;
Item *new_item= item->compile(analyzer, &arg_v, transformer, arg_t);
if (new_item && new_item != item)
li.replace(new_item);
@@ -3927,12 +4025,12 @@ longlong Item_is_not_null_test::val_int()
if (!used_tables_cache && !with_subselect)
{
owner->was_null|= (!cached_value);
- DBUG_PRINT("info", ("cached :%ld", (long) cached_value));
+ DBUG_PRINT("info", ("cached: %ld", (long) cached_value));
DBUG_RETURN(cached_value);
}
if (args[0]->is_null())
{
- DBUG_PRINT("info", ("null"))
+ DBUG_PRINT("info", ("null"));
owner->was_null|= 1;
DBUG_RETURN(0);
}
@@ -4925,17 +5023,19 @@ void Item_equal::fix_length_and_dec()
item->collation.collation);
}
-bool Item_equal::walk(Item_processor processor, byte *arg)
+bool Item_equal::walk(Item_processor processor, bool walk_subquery, uchar *arg)
{
List_iterator_fast<Item_field> it(fields);
Item *item;
while ((item= it++))
- if (item->walk(processor, arg))
+ {
+ if (item->walk(processor, walk_subquery, arg))
return 1;
- return Item_func::walk(processor, arg);
+ }
+ return Item_func::walk(processor, walk_subquery, arg);
}
-Item *Item_equal::transform(Item_transformer transformer, byte *arg)
+Item *Item_equal::transform(Item_transformer transformer, uchar *arg)
{
DBUG_ASSERT(!current_thd->is_stmt_prepare());