mirror of
https://github.com/MariaDB/server.git
synced 2025-01-18 13:02:28 +01:00
Merge bk-internal:/home/bk/mysql-5.1-opt
into dl145s.mysql.com:/data/bk/team_tree_merge/MERGE/mysql-5.1-opt
This commit is contained in:
commit
7a84e12442
7 changed files with 402 additions and 167 deletions
|
@ -343,3 +343,71 @@ some_id
|
|||
1
|
||||
2
|
||||
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);
|
|||
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);
|
||||
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;
|
|||
#
|
||||
# Bug #16069: VIEW does return the same results as underlying SELECT
|
||||
# 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,
|
||||
td date DEFAULT NULL, KEY idx(td));
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
if (a == STRING_RESULT && b == STRING_RESULT)
|
||||
|
|
|
@ -66,12 +66,10 @@ static void agg_result_type(Item_result *type, Item **items, uint nitems)
|
|||
/*
|
||||
Aggregates result types from the array of items.
|
||||
|
||||
SYNOPSIS:
|
||||
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
|
||||
items array of items to aggregate the type from
|
||||
nitems number of items in the array
|
||||
|
||||
DESCRIPTION
|
||||
This function aggregates result types from the array of items. Found type
|
||||
|
@ -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.
|
||||
*/
|
||||
|
||||
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;
|
||||
type[0]= items[0]->result_type();
|
||||
Item_result type= items[0]->result_type();
|
||||
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()
|
|||
*/
|
||||
if (!args[0] || !args[1] || !args[2])
|
||||
return;
|
||||
agg_cmp_type(thd, &cmp_type, args, 3);
|
||||
cmp_type= agg_cmp_type(args, 3);
|
||||
if (cmp_type == STRING_RESULT &&
|
||||
agg_arg_charsets(cmp_collation, args, 3, MY_COLL_CMP_CONV, 1))
|
||||
return;
|
||||
|
@ -1597,94 +1626,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());
|
||||
uint value_added_map= 0;
|
||||
|
||||
/* 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)
|
||||
{
|
||||
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
|
||||
|
@ -1791,7 +1791,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;
|
||||
|
||||
|
@ -1818,16 +1818,31 @@ 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++;
|
||||
agg_cmp_type(thd, &cmp_type, agg, nagg);
|
||||
if ((cmp_type == STRING_RESULT) &&
|
||||
agg_arg_charsets(cmp_collation, agg, nagg, MY_COLL_CMP_CONV, 1))
|
||||
return;
|
||||
found_types= collect_cmp_types(agg, nagg);
|
||||
|
||||
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;
|
||||
|
||||
|
@ -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()
|
||||
{
|
||||
Item **arg, **arg_end;
|
||||
uint const_itm= 1;
|
||||
bool const_itm= 1;
|
||||
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);
|
||||
|
||||
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++)
|
||||
for (arg= args + 1, arg_end= args + arg_count; arg != arg_end ; arg++)
|
||||
{
|
||||
if (!arg[0]->const_item())
|
||||
{
|
||||
|
@ -2429,26 +2442,39 @@ void Item_func_in::fix_length_and_dec()
|
|||
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
|
||||
*/
|
||||
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) {
|
||||
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);
|
||||
break;
|
||||
case INT_RESULT:
|
||||
array= new in_longlong(arg_count-1);
|
||||
array= new in_longlong(arg_count - 1);
|
||||
break;
|
||||
case REAL_RESULT:
|
||||
array= new in_double(arg_count-1);
|
||||
array= new in_double(arg_count - 1);
|
||||
break;
|
||||
case ROW_RESULT:
|
||||
array= new in_row(arg_count-1, args[0]);
|
||||
array= new in_row(arg_count - 1, args[0]);
|
||||
break;
|
||||
case DECIMAL_RESULT:
|
||||
array= new in_decimal(arg_count - 1);
|
||||
|
@ -2468,15 +2494,25 @@ 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
|
||||
{
|
||||
in_item= cmp_item::get_comparator(cmp_type, cmp_collation.collation);
|
||||
if (cmp_type == STRING_RESULT)
|
||||
in_item->cmp_charset= cmp_collation.collation;
|
||||
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_item::get_comparator((Item_result)i,
|
||||
cmp_collation.collation)))
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
maybe_null= args[0]->maybe_null;
|
||||
max_length= 1;
|
||||
|
@ -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()
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -589,49 +589,6 @@ public:
|
|||
};
|
||||
|
||||
|
||||
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 */
|
||||
|
||||
|
||||
|
@ -686,6 +643,7 @@ public:
|
|||
{
|
||||
return test(compare(collation, base + pos1*size, base + pos2*size));
|
||||
}
|
||||
virtual Item_result result_type()= 0;
|
||||
};
|
||||
|
||||
class in_string :public in_vector
|
||||
|
@ -707,6 +665,7 @@ public:
|
|||
Item_string *to= (Item_string*)item;
|
||||
to->str_value= *str;
|
||||
}
|
||||
Item_result result_type() { return STRING_RESULT; }
|
||||
};
|
||||
|
||||
class in_longlong :public in_vector
|
||||
|
@ -729,6 +688,7 @@ public:
|
|||
{
|
||||
((Item_int*)item)->value= ((longlong*)base)[pos];
|
||||
}
|
||||
Item_result result_type() { return INT_RESULT; }
|
||||
};
|
||||
|
||||
class in_double :public in_vector
|
||||
|
@ -746,6 +706,7 @@ public:
|
|||
{
|
||||
((Item_float*)item)->value= ((double*) base)[pos];
|
||||
}
|
||||
Item_result result_type() { return REAL_RESULT; }
|
||||
|
||||
};
|
||||
|
||||
|
@ -766,6 +727,8 @@ public:
|
|||
Item_decimal *item_dec= (Item_decimal*)item;
|
||||
item_dec->set_decimal_value(dec);
|
||||
}
|
||||
Item_result result_type() { return DECIMAL_RESULT; }
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -796,7 +759,9 @@ class cmp_item_string :public cmp_item
|
|||
protected:
|
||||
String *value_res;
|
||||
public:
|
||||
cmp_item_string () {}
|
||||
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_in_static;
|
||||
};
|
||||
|
@ -807,6 +772,8 @@ protected:
|
|||
char value_buff[STRING_BUFFER_USUAL_SIZE];
|
||||
String value;
|
||||
public:
|
||||
cmp_item_sort_string():
|
||||
cmp_item_string() {}
|
||||
cmp_item_sort_string(CHARSET_INFO *cs):
|
||||
cmp_item_string(cs),
|
||||
value(value_buff, sizeof(value_buff), cs) {}
|
||||
|
@ -828,6 +795,11 @@ public:
|
|||
return sortcmp(value_res, cmp->value_res, cmp_charset);
|
||||
}
|
||||
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
|
||||
|
@ -908,6 +880,7 @@ public:
|
|||
~in_row();
|
||||
void set(uint pos,Item *item);
|
||||
byte *get_value(Item *item);
|
||||
Item_result result_type() { return ROW_RESULT; }
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -943,18 +916,109 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
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
|
||||
{
|
||||
public:
|
||||
Item_result cmp_type;
|
||||
in_vector *array;
|
||||
cmp_item *in_item;
|
||||
bool have_null;
|
||||
Item_result left_result_type;
|
||||
cmp_item *cmp_items[5]; /* One cmp_item for each result type */
|
||||
DTCollation cmp_collation;
|
||||
|
||||
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
|
||||
}
|
||||
longlong val_int();
|
||||
|
@ -963,12 +1027,16 @@ public:
|
|||
uint decimal_precision() const { return 1; }
|
||||
void cleanup()
|
||||
{
|
||||
uint i;
|
||||
DBUG_ENTER("Item_func_in::cleanup");
|
||||
Item_int_func::cleanup();
|
||||
delete array;
|
||||
delete in_item;
|
||||
array= 0;
|
||||
in_item= 0;
|
||||
for (i= 0; i <= (uint)DECIMAL_RESULT; i++)
|
||||
{
|
||||
delete cmp_items[i];
|
||||
cmp_items[i]= 0;
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
optimize_type select_optimize() const
|
||||
|
|
|
@ -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;
|
||||
|
||||
/*
|
||||
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 (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, ...)",
|
||||
|
|
Loading…
Reference in a new issue