Commit 7a84e124 authored by gkodinov@dl145s.mysql.com's avatar gkodinov@dl145s.mysql.com

Merge bk-internal:/home/bk/mysql-5.1-opt

into  dl145s.mysql.com:/data/bk/team_tree_merge/MERGE/mysql-5.1-opt
parents 3abb6043 16f59a5e
...@@ -343,3 +343,71 @@ some_id ...@@ -343,3 +343,71 @@ some_id
1 1
2 2
drop table t1; drop table t1;
create table t1(f1 char(1));
insert into t1 values ('a'),('b'),('1');
select f1 from t1 where f1 in ('a',1);
f1
a
1
select f1, case f1 when 'a' then '+' when 1 then '-' end from t1;
f1 case f1 when 'a' then '+' when 1 then '-' end
a +
b NULL
1 -
create index t1f1_idx on t1(f1);
select f1 from t1 where f1 in ('a',1);
f1
1
a
explain select f1 from t1 where f1 in ('a',1);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index NULL t1f1_idx 2 NULL 3 Using where; Using index
select f1 from t1 where f1 in ('a','b');
f1
a
b
explain select f1 from t1 where f1 in ('a','b');
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index t1f1_idx t1f1_idx 2 NULL 3 Using where; Using index
select f1 from t1 where f1 in (2,1);
f1
1
explain select f1 from t1 where f1 in (2,1);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index t1f1_idx t1f1_idx 2 NULL 3 Using where; Using index
create table t2(f2 int, index t2f2(f2));
insert into t2 values(0),(1),(2);
select f2 from t2 where f2 in ('a',2);
f2
0
2
Warnings:
Warning 1292 Truncated incorrect DOUBLE value: 'a'
Warning 1292 Truncated incorrect DOUBLE value: 'a'
Warning 1292 Truncated incorrect DOUBLE value: 'a'
explain select f2 from t2 where f2 in ('a',2);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 index NULL t2f2 5 NULL 3 Using where; Using index
select f2 from t2 where f2 in ('a','b');
f2
0
Warnings:
Warning 1292 Truncated incorrect DOUBLE value: 'a'
Warning 1292 Truncated incorrect DOUBLE value: 'b'
explain select f2 from t2 where f2 in ('a','b');
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 index t2f2 t2f2 5 NULL 3 Using where; Using index
Warnings:
Warning 1292 Truncated incorrect DOUBLE value: 'a'
Warning 1292 Truncated incorrect DOUBLE value: 'b'
select f2 from t2 where f2 in (1,'b');
f2
0
1
Warnings:
Warning 1292 Truncated incorrect DOUBLE value: 'b'
Warning 1292 Truncated incorrect DOUBLE value: 'b'
explain select f2 from t2 where f2 in (1,'b');
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 index NULL t2f2 5 NULL 3 Using where; Using index
drop table t1, t2;
...@@ -232,3 +232,27 @@ select some_id from t1 where some_id not in(2,-1); ...@@ -232,3 +232,27 @@ select some_id from t1 where some_id not in(2,-1);
select some_id from t1 where some_id not in(-4,-1,-4); select some_id from t1 where some_id not in(-4,-1,-4);
select some_id from t1 where some_id not in(-4,-1,3423534,2342342); select some_id from t1 where some_id not in(-4,-1,3423534,2342342);
drop table t1; drop table t1;
#
# Bug#18360: Type aggregation for IN and CASE may lead to a wrong result
#
create table t1(f1 char(1));
insert into t1 values ('a'),('b'),('1');
select f1 from t1 where f1 in ('a',1);
select f1, case f1 when 'a' then '+' when 1 then '-' end from t1;
create index t1f1_idx on t1(f1);
select f1 from t1 where f1 in ('a',1);
explain select f1 from t1 where f1 in ('a',1);
select f1 from t1 where f1 in ('a','b');
explain select f1 from t1 where f1 in ('a','b');
select f1 from t1 where f1 in (2,1);
explain select f1 from t1 where f1 in (2,1);
create table t2(f2 int, index t2f2(f2));
insert into t2 values(0),(1),(2);
select f2 from t2 where f2 in ('a',2);
explain select f2 from t2 where f2 in ('a',2);
select f2 from t2 where f2 in ('a','b');
explain select f2 from t2 where f2 in ('a','b');
select f2 from t2 where f2 in (1,'b');
explain select f2 from t2 where f2 in (1,'b');
drop table t1, t2;
...@@ -2443,7 +2443,7 @@ DROP TABLE t1, t2; ...@@ -2443,7 +2443,7 @@ DROP TABLE t1, t2;
# #
# Bug #16069: VIEW does return the same results as underlying SELECT # Bug #16069: VIEW does return the same results as underlying SELECT
# with WHERE condition containing BETWEEN over dates # with WHERE condition containing BETWEEN over dates
# Dates as strings should be casted to date type
CREATE TABLE t1 (id int NOT NULL PRIMARY KEY, CREATE TABLE t1 (id int NOT NULL PRIMARY KEY,
td date DEFAULT NULL, KEY idx(td)); td date DEFAULT NULL, KEY idx(td));
......
...@@ -5711,11 +5711,6 @@ void Item_trigger_field::cleanup() ...@@ -5711,11 +5711,6 @@ void Item_trigger_field::cleanup()
} }
/*
If item is a const function, calculate it and return a const item
The original item is freed if not returned
*/
Item_result item_cmp_type(Item_result a,Item_result b) Item_result item_cmp_type(Item_result a,Item_result b)
{ {
if (a == STRING_RESULT && b == STRING_RESULT) if (a == STRING_RESULT && b == STRING_RESULT)
......
...@@ -66,10 +66,8 @@ static void agg_result_type(Item_result *type, Item **items, uint nitems) ...@@ -66,10 +66,8 @@ static void agg_result_type(Item_result *type, Item **items, uint nitems)
/* /*
Aggregates result types from the array of items. Aggregates result types from the array of items.
SYNOPSIS: SYNOPSIS
agg_cmp_type() agg_cmp_type()
thd thread handle
type [out] the aggregated type
items array of items to aggregate the type from items array of items to aggregate the type from
nitems number of items in the array nitems number of items in the array
...@@ -79,12 +77,43 @@ static void agg_result_type(Item_result *type, Item **items, uint nitems) ...@@ -79,12 +77,43 @@ static void agg_result_type(Item_result *type, Item **items, uint nitems)
Aggregation itself is performed by the item_cmp_type() function. Aggregation itself is performed by the item_cmp_type() function.
*/ */
static void agg_cmp_type(THD *thd, Item_result *type, Item **items, uint nitems) static Item_result agg_cmp_type(Item **items, uint nitems)
{ {
uint i; uint i;
type[0]= items[0]->result_type(); Item_result type= items[0]->result_type();
for (i= 1 ; i < nitems ; i++) for (i= 1 ; i < nitems ; i++)
type[0]= item_cmp_type(type[0], items[i]->result_type()); type= item_cmp_type(type, items[i]->result_type());
return type;
}
/*
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
Bitmap of collected types
*/
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++)
found_types|= 1<< (uint)item_cmp_type(left_result,
items[i]->result_type());
return found_types;
} }
...@@ -1117,7 +1146,7 @@ void Item_func_between::fix_length_and_dec() ...@@ -1117,7 +1146,7 @@ void Item_func_between::fix_length_and_dec()
*/ */
if (!args[0] || !args[1] || !args[2]) if (!args[0] || !args[1] || !args[2])
return; return;
agg_cmp_type(thd, &cmp_type, args, 3); cmp_type= agg_cmp_type(args, 3);
if (cmp_type == STRING_RESULT && if (cmp_type == STRING_RESULT &&
agg_arg_charsets(cmp_collation, args, 3, MY_COLL_CMP_CONV, 1)) agg_arg_charsets(cmp_collation, args, 3, MY_COLL_CMP_CONV, 1))
return; return;
...@@ -1597,94 +1626,65 @@ Item_func_nullif::is_null() ...@@ -1597,94 +1626,65 @@ Item_func_nullif::is_null()
return (null_value= (!cmp.compare() ? 1 : args[0]->null_value)); return (null_value= (!cmp.compare() ? 1 : args[0]->null_value));
} }
/* /*
CASE expression
Return the matching ITEM or NULL if all compares (including else) failed 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) Item *Item_func_case::find_item(String *str)
{ {
String *first_expr_str, *tmp; uint value_added_map= 0;
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);
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) for (uint i=0 ; i < ncases ; i+=2)
{
if (first_expr_num == -1)
{ {
// No expression between CASE and the first WHEN // No expression between CASE and the first WHEN
if (args[i]->val_bool()) if (args[i]->val_bool())
return args[i+1]; return args[i+1];
continue; continue;
} }
switch (cmp_type) { }
case STRING_RESULT: else
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:
{ {
my_decimal value; /* Compare every WHEN argument with it and return the first match */
if (my_decimal_cmp(args[i]->val_decimal(&value), first_expr_dec) == 0) for (uint i=0 ; i < ncases ; i+=2)
return args[i+1]; {
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;
} }
case ROW_RESULT: if (!cmp_items[(uint)cmp_type]->cmp(args[i]) && !args[i]->null_value)
default: return args[i + 1];
// This case should never be chosen
DBUG_ASSERT(0);
break;
} }
} }
// No, WHEN clauses all missed, return ELSE expression // No, WHEN clauses all missed, return ELSE expression
...@@ -1791,7 +1791,7 @@ void Item_func_case::fix_length_and_dec() ...@@ -1791,7 +1791,7 @@ void Item_func_case::fix_length_and_dec()
Item **agg; Item **agg;
uint nagg; uint nagg;
THD *thd= current_thd; THD *thd= current_thd;
uint found_types= 0;
if (!(agg= (Item**) sql_alloc(sizeof(Item*)*(ncases+1)))) if (!(agg= (Item**) sql_alloc(sizeof(Item*)*(ncases+1))))
return; return;
...@@ -1818,14 +1818,29 @@ void Item_func_case::fix_length_and_dec() ...@@ -1818,14 +1818,29 @@ void Item_func_case::fix_length_and_dec()
*/ */
if (first_expr_num != -1) if (first_expr_num != -1)
{ {
uint i;
agg[0]= args[first_expr_num]; agg[0]= args[first_expr_num];
left_result_type= agg[0]->result_type();
for (nagg= 0; nagg < ncases/2 ; nagg++) for (nagg= 0; nagg < ncases/2 ; nagg++)
agg[nagg+1]= args[nagg*2]; agg[nagg+1]= args[nagg*2];
nagg++; nagg++;
agg_cmp_type(thd, &cmp_type, agg, nagg); found_types= collect_cmp_types(agg, nagg);
if ((cmp_type == STRING_RESULT) &&
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)) agg_arg_charsets(cmp_collation, agg, nagg, MY_COLL_CMP_CONV, 1))
return; 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) if (else_expr_num == -1 || args[else_expr_num]->maybe_null)
...@@ -2412,16 +2427,14 @@ static int srtcmp_in(CHARSET_INFO *cs, const String *x,const String *y) ...@@ -2412,16 +2427,14 @@ static int srtcmp_in(CHARSET_INFO *cs, const String *x,const String *y)
void Item_func_in::fix_length_and_dec() void Item_func_in::fix_length_and_dec()
{ {
Item **arg, **arg_end; Item **arg, **arg_end;
uint const_itm= 1; bool const_itm= 1;
THD *thd= current_thd; THD *thd= current_thd;
uint found_types= 0;
uint type_cnt= 0, i;
left_result_type= args[0]->result_type();
found_types= collect_cmp_types(args, arg_count);
agg_cmp_type(thd, &cmp_type, args, arg_count); for (arg= args + 1, arg_end= args + arg_count; arg != arg_end ; arg++)
if (cmp_type == STRING_RESULT &&
agg_arg_charsets(cmp_collation, args, arg_count, MY_COLL_CMP_CONV, 1))
return;
for (arg=args+1, arg_end=args+arg_count; arg != arg_end ; arg++)
{ {
if (!arg[0]->const_item()) if (!arg[0]->const_item())
{ {
...@@ -2429,26 +2442,39 @@ void Item_func_in::fix_length_and_dec() ...@@ -2429,26 +2442,39 @@ void Item_func_in::fix_length_and_dec()
break; break;
} }
} }
for (i= 0; i <= (uint)DECIMAL_RESULT; i++)
{
if (found_types & 1 << i)
(type_cnt)++;
}
/* /*
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 they can't be processed as static
*/ */
if (const_itm && !nulls_in_row()) if (type_cnt == 1 && const_itm && !nulls_in_row())
{ {
uint tmp_type;
Item_result cmp_type;
/* Only one cmp type was found. Extract it here */
for (tmp_type= 0; found_types - 1; found_types>>= 1)
tmp_type++;
cmp_type= (Item_result)tmp_type;
switch (cmp_type) { switch (cmp_type) {
case STRING_RESULT: case STRING_RESULT:
array=new in_string(arg_count-1,(qsort2_cmp) srtcmp_in, if (agg_arg_charsets(cmp_collation, args, arg_count, MY_COLL_CMP_CONV, 1))
return;
array=new in_string(arg_count - 1,(qsort2_cmp) srtcmp_in,
cmp_collation.collation); cmp_collation.collation);
break; break;
case INT_RESULT: case INT_RESULT:
array= new in_longlong(arg_count-1); array= new in_longlong(arg_count - 1);
break; break;
case REAL_RESULT: case REAL_RESULT:
array= new in_double(arg_count-1); array= new in_double(arg_count - 1);
break; break;
case ROW_RESULT: case ROW_RESULT:
array= new in_row(arg_count-1, args[0]); array= new in_row(arg_count - 1, args[0]);
break; break;
case DECIMAL_RESULT: case DECIMAL_RESULT:
array= new in_decimal(arg_count - 1); array= new in_decimal(arg_count - 1);
...@@ -2468,15 +2494,25 @@ void Item_func_in::fix_length_and_dec() ...@@ -2468,15 +2494,25 @@ void Item_func_in::fix_length_and_dec()
else else
have_null= 1; have_null= 1;
} }
if ((array->used_count=j)) if ((array->used_count= j))
array->sort(); array->sort();
} }
} }
else else
{ {
in_item= cmp_item::get_comparator(cmp_type, cmp_collation.collation); for (i= 0; i <= (uint) DECIMAL_RESULT; i++)
if (cmp_type == STRING_RESULT) {
in_item->cmp_charset= cmp_collation.collation; 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_item::get_comparator((Item_result)i,
cmp_collation.collation)))
return;
}
}
} }
maybe_null= args[0]->maybe_null; maybe_null= args[0]->maybe_null;
max_length= 1; max_length= 1;
...@@ -2495,25 +2531,61 @@ void Item_func_in::print(String *str) ...@@ -2495,25 +2531,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() longlong Item_func_in::val_int()
{ {
cmp_item *in_item;
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
uint value_added_map= 0;
if (array) if (array)
{ {
int tmp=array->find(args[0]); int tmp=array->find(args[0]);
null_value=args[0]->null_value || (!tmp && have_null); null_value=args[0]->null_value || (!tmp && have_null);
return (longlong) (!null_value && tmp != negated); return (longlong) (!null_value && tmp != negated);
} }
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]); in_item->store_value(args[0]);
if ((null_value=args[0]->null_value)) if ((null_value=args[0]->null_value))
return 0; return 0;
have_null= 0; have_null= 0;
for (uint i=1 ; i < arg_count ; i++) value_added_map|= 1 << (uint)cmp_type;
{ }
if (!in_item->cmp(args[i]) && !args[i]->null_value) if (!in_item->cmp(args[i]) && !args[i]->null_value)
return (longlong) (!negated); return (longlong) (!negated);
have_null|= args[i]->null_value; have_null|= args[i]->null_value;
} }
null_value= have_null; null_value= have_null;
return (longlong) (!null_value && negated); return (longlong) (!null_value && negated);
} }
......
...@@ -589,49 +589,6 @@ class Item_func_nullif :public Item_bool_func2 ...@@ -589,49 +589,6 @@ class Item_func_nullif :public Item_bool_func2
}; };
class Item_func_case :public Item_func
{
int first_expr_num, else_expr_num;
enum Item_result cached_result_type;
String tmp_value;
uint ncases;
Item_result cmp_type;
DTCollation cmp_collation;
public:
Item_func_case(List<Item> &list, Item *first_expr_arg, Item *else_expr_arg)
:Item_func(), first_expr_num(-1), else_expr_num(-1),
cached_result_type(INT_RESULT)
{
ncases= list.elements;
if (first_expr_arg)
{
first_expr_num= list.elements;
list.push_back(first_expr_arg);
}
if (else_expr_arg)
{
else_expr_num= list.elements;
list.push_back(else_expr_arg);
}
set_arguments(list);
}
double val_real();
longlong val_int();
String *val_str(String *);
my_decimal *val_decimal(my_decimal *);
bool fix_fields(THD *thd, Item **ref);
void fix_length_and_dec();
uint decimal_precision() const;
table_map not_null_tables() const { return 0; }
enum Item_result result_type () const { return cached_result_type; }
const char *func_name() const { return "case"; }
void print(String *str);
Item *find_item(String *str);
CHARSET_INFO *compare_collation() { return cmp_collation.collation; }
bool check_partition_func_processor(byte *bool_arg) { return 0;}
};
/* Functions to handle the optimized IN */ /* Functions to handle the optimized IN */
...@@ -686,6 +643,7 @@ class in_vector :public Sql_alloc ...@@ -686,6 +643,7 @@ class in_vector :public Sql_alloc
{ {
return test(compare(collation, base + pos1*size, base + pos2*size)); return test(compare(collation, base + pos1*size, base + pos2*size));
} }
virtual Item_result result_type()= 0;
}; };
class in_string :public in_vector class in_string :public in_vector
...@@ -707,6 +665,7 @@ class in_string :public in_vector ...@@ -707,6 +665,7 @@ class in_string :public in_vector
Item_string *to= (Item_string*)item; Item_string *to= (Item_string*)item;
to->str_value= *str; to->str_value= *str;
} }
Item_result result_type() { return STRING_RESULT; }
}; };
class in_longlong :public in_vector class in_longlong :public in_vector
...@@ -729,6 +688,7 @@ class in_longlong :public in_vector ...@@ -729,6 +688,7 @@ class in_longlong :public in_vector
{ {
((Item_int*)item)->value= ((longlong*)base)[pos]; ((Item_int*)item)->value= ((longlong*)base)[pos];
} }
Item_result result_type() { return INT_RESULT; }
}; };
class in_double :public in_vector class in_double :public in_vector
...@@ -746,6 +706,7 @@ class in_double :public in_vector ...@@ -746,6 +706,7 @@ class in_double :public in_vector
{ {
((Item_float*)item)->value= ((double*) base)[pos]; ((Item_float*)item)->value= ((double*) base)[pos];
} }
Item_result result_type() { return REAL_RESULT; }
}; };
...@@ -766,6 +727,8 @@ class in_decimal :public in_vector ...@@ -766,6 +727,8 @@ class in_decimal :public in_vector
Item_decimal *item_dec= (Item_decimal*)item; Item_decimal *item_dec= (Item_decimal*)item;
item_dec->set_decimal_value(dec); item_dec->set_decimal_value(dec);
} }
Item_result result_type() { return DECIMAL_RESULT; }
}; };
...@@ -796,7 +759,9 @@ class cmp_item_string :public cmp_item ...@@ -796,7 +759,9 @@ class cmp_item_string :public cmp_item
protected: protected:
String *value_res; String *value_res;
public: public:
cmp_item_string () {}
cmp_item_string (CHARSET_INFO *cs) { cmp_charset= cs; } cmp_item_string (CHARSET_INFO *cs) { cmp_charset= cs; }
void set_charset(CHARSET_INFO *cs) { cmp_charset= cs; }
friend class cmp_item_sort_string; friend class cmp_item_sort_string;
friend class cmp_item_sort_string_in_static; friend class cmp_item_sort_string_in_static;
}; };
...@@ -807,6 +772,8 @@ class cmp_item_sort_string :public cmp_item_string ...@@ -807,6 +772,8 @@ class cmp_item_sort_string :public cmp_item_string
char value_buff[STRING_BUFFER_USUAL_SIZE]; char value_buff[STRING_BUFFER_USUAL_SIZE];
String value; String value;
public: public:
cmp_item_sort_string():
cmp_item_string() {}
cmp_item_sort_string(CHARSET_INFO *cs): cmp_item_sort_string(CHARSET_INFO *cs):
cmp_item_string(cs), cmp_item_string(cs),
value(value_buff, sizeof(value_buff), cs) {} value(value_buff, sizeof(value_buff), cs) {}
...@@ -828,6 +795,11 @@ class cmp_item_sort_string :public cmp_item_string ...@@ -828,6 +795,11 @@ class cmp_item_sort_string :public cmp_item_string
return sortcmp(value_res, cmp->value_res, cmp_charset); return sortcmp(value_res, cmp->value_res, cmp_charset);
} }
cmp_item *make_same(); cmp_item *make_same();
void set_charset(CHARSET_INFO *cs)
{
cmp_charset= cs;
value.set_quick(value_buff, sizeof(value_buff), cs);
}
}; };
class cmp_item_int :public cmp_item class cmp_item_int :public cmp_item
...@@ -908,6 +880,7 @@ class in_row :public in_vector ...@@ -908,6 +880,7 @@ class in_row :public in_vector
~in_row(); ~in_row();
void set(uint pos,Item *item); void set(uint pos,Item *item);
byte *get_value(Item *item); byte *get_value(Item *item);
Item_result result_type() { return ROW_RESULT; }
}; };
/* /*
...@@ -943,18 +916,109 @@ class cmp_item_sort_string_in_static :public cmp_item_string ...@@ -943,18 +916,109 @@ class cmp_item_sort_string_in_static :public cmp_item_string
} }
}; };
/*
The class Item_func_case is the CASE ... WHEN ... THEN ... END function
implementation.
When there is no expression between CASE and the first WHEN
(the CASE expression) then this function simple checks all WHEN expressions
one after another. When some WHEN expression evaluated to TRUE then the
value of the corresponding THEN expression is returned.
When the CASE expression is specified then it is compared to each WHEN
expression individually. When an equal WHEN expression is found
corresponding THEN expression is returned.
In order to do correct comparisons several comparators are used. One for
each result type. Different result types that are used in particular
CASE ... END expression are collected in the fix_length_and_dec() member
function and only comparators for there result types are used.
*/
class Item_func_case :public Item_func
{
int first_expr_num, else_expr_num;
enum Item_result cached_result_type, left_result_type;
String tmp_value;
uint ncases;
Item_result cmp_type;
DTCollation cmp_collation;
cmp_item *cmp_items[5]; /* For all result types */
cmp_item *case_item;
public:
Item_func_case(List<Item> &list, Item *first_expr_arg, Item *else_expr_arg)
:Item_func(), first_expr_num(-1), else_expr_num(-1),
cached_result_type(INT_RESULT), left_result_type(INT_RESULT), case_item(0)
{
ncases= list.elements;
if (first_expr_arg)
{
first_expr_num= list.elements;
list.push_back(first_expr_arg);
}
if (else_expr_arg)
{
else_expr_num= list.elements;
list.push_back(else_expr_arg);
}
set_arguments(list);
bzero(&cmp_items, sizeof(cmp_items));
}
double val_real();
longlong val_int();
String *val_str(String *);
my_decimal *val_decimal(my_decimal *);
bool fix_fields(THD *thd, Item **ref);
void fix_length_and_dec();
uint decimal_precision() const;
table_map not_null_tables() const { return 0; }
enum Item_result result_type () const { return cached_result_type; }
const char *func_name() const { return "case"; }
void print(String *str);
Item *find_item(String *str);
CHARSET_INFO *compare_collation() { return cmp_collation.collation; }
bool check_partition_func_processor(byte *bool_arg) { return 0;}
void cleanup()
{
uint i;
DBUG_ENTER("Item_func_case::cleanup");
Item_func::cleanup();
for (i= 0; i <= (uint)DECIMAL_RESULT; i++)
{
delete cmp_items[i];
cmp_items[i]= 0;
}
DBUG_VOID_RETURN;
}
};
/*
The Item_func_in class implements the in_expr IN(values_list) function.
The current implementation distinguishes 2 cases:
1) all items in the value_list are constants and have the same
result type. This case is handled by in_vector class.
2) items in the value_list have different result types or there is some
non-constant items.
In this case Item_func_in employs several cmp_item objects to performs
comparisons of in_expr and an item from the values_list. One cmp_item
object for each result type. Different result types are collected in the
fix_length_and_dec() member function by means of collect_cmp_types()
function.
*/
class Item_func_in :public Item_func_opt_neg class Item_func_in :public Item_func_opt_neg
{ {
public: public:
Item_result cmp_type;
in_vector *array; in_vector *array;
cmp_item *in_item;
bool have_null; bool have_null;
Item_result left_result_type;
cmp_item *cmp_items[5]; /* One cmp_item for each result type */
DTCollation cmp_collation; DTCollation cmp_collation;
Item_func_in(List<Item> &list) Item_func_in(List<Item> &list)
:Item_func_opt_neg(list), array(0), in_item(0), have_null(0) :Item_func_opt_neg(list), array(0), have_null(0)
{ {
bzero(&cmp_items, sizeof(cmp_items));
allowed_arg_cols= 0; // Fetch this value from first argument allowed_arg_cols= 0; // Fetch this value from first argument
} }
longlong val_int(); longlong val_int();
...@@ -963,12 +1027,16 @@ class Item_func_in :public Item_func_opt_neg ...@@ -963,12 +1027,16 @@ class Item_func_in :public Item_func_opt_neg
uint decimal_precision() const { return 1; } uint decimal_precision() const { return 1; }
void cleanup() void cleanup()
{ {
uint i;
DBUG_ENTER("Item_func_in::cleanup"); DBUG_ENTER("Item_func_in::cleanup");
Item_int_func::cleanup(); Item_int_func::cleanup();
delete array; delete array;
delete in_item;
array= 0; array= 0;
in_item= 0; for (i= 0; i <= (uint)DECIMAL_RESULT; i++)
{
delete cmp_items[i];
cmp_items[i]= 0;
}
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
optimize_type select_optimize() const optimize_type select_optimize() const
......
...@@ -4913,9 +4913,17 @@ static SEL_TREE *get_func_mm_tree(RANGE_OPT_PARAM *param, Item_func *cond_func, ...@@ -4913,9 +4913,17 @@ static SEL_TREE *get_func_mm_tree(RANGE_OPT_PARAM *param, Item_func *cond_func,
{ {
Item_func_in *func=(Item_func_in*) cond_func; Item_func_in *func=(Item_func_in*) cond_func;
/*
Array for IN() is constructed when all values have the same result
type. Tree won't be built for values with different result types,
so we check it here to avoid unnecessary work.
*/
if (!func->array)
break;
if (inv) if (inv)
{ {
if (func->array && func->cmp_type != ROW_RESULT) if (func->array->result_type() != ROW_RESULT)
{ {
/* /*
We get here for conditions in form "t.key NOT IN (c1, c2, ...)", We get here for conditions in form "t.key NOT IN (c1, c2, ...)",
......
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