Commit 438b795f authored by Evgeny Potemkin's avatar Evgeny Potemkin

Manual merge of the fix for bug#43668.

parents 049dc018 726e8390
......@@ -885,7 +885,7 @@ cast(sum(distinct df) as signed)
3
select cast(min(df) as signed) from t1;
cast(min(df) as signed)
0
1
select 1e8 * sum(distinct df) from t1;
1e8 * sum(distinct df)
330000000
......@@ -1520,4 +1520,197 @@ max i
# Cleanup
#
DROP TABLE t1;
#
# Bug#43668: Wrong comparison and MIN/MAX for YEAR(2)
#
create table t1 (f1 year(2), f2 year(4), f3 date, f4 datetime);
insert into t1 values
(98,1998,19980101,"1998-01-01 00:00:00"),
(00,2000,20000101,"2000-01-01 00:00:01"),
(02,2002,20020101,"2002-01-01 23:59:59"),
(60,2060,20600101,"2060-01-01 11:11:11"),
(70,1970,19700101,"1970-11-11 22:22:22"),
(NULL,NULL,NULL,NULL);
select min(f1),max(f1) from t1;
min(f1) max(f1)
70 60
select min(f2),max(f2) from t1;
min(f2) max(f2)
1970 2060
select min(f3),max(f3) from t1;
min(f3) max(f3)
1970-01-01 2060-01-01
select min(f4),max(f4) from t1;
min(f4) max(f4)
1970-11-11 22:22:22 2060-01-01 11:11:11
select a.f1 as a, b.f1 as b, a.f1 > b.f1 as gt,
a.f1 < b.f1 as lt, a.f1<=>b.f1 as eq
from t1 a, t1 b;
a b gt lt eq
98 98 0 0 1
00 98 1 0 0
02 98 1 0 0
60 98 1 0 0
70 98 0 1 0
NULL 98 NULL NULL 0
98 00 0 1 0
00 00 0 0 1
02 00 1 0 0
60 00 1 0 0
70 00 0 1 0
NULL 00 NULL NULL 0
98 02 0 1 0
00 02 0 1 0
02 02 0 0 1
60 02 1 0 0
70 02 0 1 0
NULL 02 NULL NULL 0
98 60 0 1 0
00 60 0 1 0
02 60 0 1 0
60 60 0 0 1
70 60 0 1 0
NULL 60 NULL NULL 0
98 70 1 0 0
00 70 1 0 0
02 70 1 0 0
60 70 1 0 0
70 70 0 0 1
NULL 70 NULL NULL 0
98 NULL NULL NULL 0
00 NULL NULL NULL 0
02 NULL NULL NULL 0
60 NULL NULL NULL 0
70 NULL NULL NULL 0
NULL NULL NULL NULL 1
select a.f1 as a, b.f2 as b, a.f1 > b.f2 as gt,
a.f1 < b.f2 as lt, a.f1<=>b.f2 as eq
from t1 a, t1 b;
a b gt lt eq
98 1998 0 0 1
00 1998 1 0 0
02 1998 1 0 0
60 1998 1 0 0
70 1998 0 1 0
NULL 1998 NULL NULL 0
98 2000 0 1 0
00 2000 0 0 1
02 2000 1 0 0
60 2000 1 0 0
70 2000 0 1 0
NULL 2000 NULL NULL 0
98 2002 0 1 0
00 2002 0 1 0
02 2002 0 0 1
60 2002 1 0 0
70 2002 0 1 0
NULL 2002 NULL NULL 0
98 2060 0 1 0
00 2060 0 1 0
02 2060 0 1 0
60 2060 0 0 1
70 2060 0 1 0
NULL 2060 NULL NULL 0
98 1970 1 0 0
00 1970 1 0 0
02 1970 1 0 0
60 1970 1 0 0
70 1970 0 0 1
NULL 1970 NULL NULL 0
98 NULL NULL NULL 0
00 NULL NULL NULL 0
02 NULL NULL NULL 0
60 NULL NULL NULL 0
70 NULL NULL NULL 0
NULL NULL NULL NULL 1
select a.f1 as a, b.f3 as b, a.f1 > b.f3 as gt,
a.f1 < b.f3 as lt, a.f1<=>b.f3 as eq
from t1 a, t1 b;
a b gt lt eq
98 1998-01-01 0 1 0
00 1998-01-01 1 0 0
02 1998-01-01 1 0 0
60 1998-01-01 1 0 0
70 1998-01-01 0 1 0
NULL 1998-01-01 NULL NULL 0
98 2000-01-01 0 1 0
00 2000-01-01 0 1 0
02 2000-01-01 1 0 0
60 2000-01-01 1 0 0
70 2000-01-01 0 1 0
NULL 2000-01-01 NULL NULL 0
98 2002-01-01 0 1 0
00 2002-01-01 0 1 0
02 2002-01-01 0 1 0
60 2002-01-01 1 0 0
70 2002-01-01 0 1 0
NULL 2002-01-01 NULL NULL 0
98 2060-01-01 0 1 0
00 2060-01-01 0 1 0
02 2060-01-01 0 1 0
60 2060-01-01 0 1 0
70 2060-01-01 0 1 0
NULL 2060-01-01 NULL NULL 0
98 1970-01-01 1 0 0
00 1970-01-01 1 0 0
02 1970-01-01 1 0 0
60 1970-01-01 1 0 0
70 1970-01-01 0 1 0
NULL 1970-01-01 NULL NULL 0
98 NULL NULL NULL 0
00 NULL NULL NULL 0
02 NULL NULL NULL 0
60 NULL NULL NULL 0
70 NULL NULL NULL 0
NULL NULL NULL NULL 1
select a.f1 as a, b.f4 as b, a.f1 > b.f4 as gt,
a.f1 < b.f4 as lt, a.f1<=>b.f4 as eq
from t1 a, t1 b;
a b gt lt eq
98 1998-01-01 00:00:00 0 1 0
00 1998-01-01 00:00:00 1 0 0
02 1998-01-01 00:00:00 1 0 0
60 1998-01-01 00:00:00 1 0 0
70 1998-01-01 00:00:00 0 1 0
NULL 1998-01-01 00:00:00 NULL NULL 0
98 2000-01-01 00:00:01 0 1 0
00 2000-01-01 00:00:01 0 1 0
02 2000-01-01 00:00:01 1 0 0
60 2000-01-01 00:00:01 1 0 0
70 2000-01-01 00:00:01 0 1 0
NULL 2000-01-01 00:00:01 NULL NULL 0
98 2002-01-01 23:59:59 0 1 0
00 2002-01-01 23:59:59 0 1 0
02 2002-01-01 23:59:59 0 1 0
60 2002-01-01 23:59:59 1 0 0
70 2002-01-01 23:59:59 0 1 0
NULL 2002-01-01 23:59:59 NULL NULL 0
98 2060-01-01 11:11:11 0 1 0
00 2060-01-01 11:11:11 0 1 0
02 2060-01-01 11:11:11 0 1 0
60 2060-01-01 11:11:11 0 1 0
70 2060-01-01 11:11:11 0 1 0
NULL 2060-01-01 11:11:11 NULL NULL 0
98 1970-11-11 22:22:22 1 0 0
00 1970-11-11 22:22:22 1 0 0
02 1970-11-11 22:22:22 1 0 0
60 1970-11-11 22:22:22 1 0 0
70 1970-11-11 22:22:22 0 1 0
NULL 1970-11-11 22:22:22 NULL NULL 0
98 NULL NULL NULL 0
00 NULL NULL NULL 0
02 NULL NULL NULL 0
60 NULL NULL NULL 0
70 NULL NULL NULL 0
NULL NULL NULL NULL 1
select *, f1 = f2 from t1;
f1 f2 f3 f4 f1 = f2
98 1998 1998-01-01 1998-01-01 00:00:00 1
00 2000 2000-01-01 2000-01-01 00:00:01 1
02 2002 2002-01-01 2002-01-01 23:59:59 1
60 2060 2060-01-01 2060-01-01 11:11:11 1
70 1970 1970-01-01 1970-11-11 22:22:22 1
NULL NULL NULL NULL NULL
drop table t1;
#
End of 5.1 tests
......@@ -1053,4 +1053,35 @@ ORDER BY max;
--echo #
DROP TABLE t1;
--echo #
--echo # Bug#43668: Wrong comparison and MIN/MAX for YEAR(2)
--echo #
create table t1 (f1 year(2), f2 year(4), f3 date, f4 datetime);
insert into t1 values
(98,1998,19980101,"1998-01-01 00:00:00"),
(00,2000,20000101,"2000-01-01 00:00:01"),
(02,2002,20020101,"2002-01-01 23:59:59"),
(60,2060,20600101,"2060-01-01 11:11:11"),
(70,1970,19700101,"1970-11-11 22:22:22"),
(NULL,NULL,NULL,NULL);
select min(f1),max(f1) from t1;
select min(f2),max(f2) from t1;
select min(f3),max(f3) from t1;
select min(f4),max(f4) from t1;
select a.f1 as a, b.f1 as b, a.f1 > b.f1 as gt,
a.f1 < b.f1 as lt, a.f1<=>b.f1 as eq
from t1 a, t1 b;
select a.f1 as a, b.f2 as b, a.f1 > b.f2 as gt,
a.f1 < b.f2 as lt, a.f1<=>b.f2 as eq
from t1 a, t1 b;
select a.f1 as a, b.f3 as b, a.f1 > b.f3 as gt,
a.f1 < b.f3 as lt, a.f1<=>b.f3 as eq
from t1 a, t1 b;
select a.f1 as a, b.f4 as b, a.f1 > b.f4 as gt,
a.f1 < b.f4 as lt, a.f1<=>b.f4 as eq
from t1 a, t1 b;
select *, f1 = f2 from t1;
drop table t1;
--echo #
--echo End of 5.1 tests
......@@ -6957,7 +6957,7 @@ Item_cache* Item_cache::get_cache(const Item *item, const Item_result type)
{
switch (type) {
case INT_RESULT:
return new Item_cache_int();
return new Item_cache_int(item->field_type());
case REAL_RESULT:
return new Item_cache_real();
case DECIMAL_RESULT:
......@@ -6975,8 +6975,9 @@ Item_cache* Item_cache::get_cache(const Item *item, const Item_result type)
void Item_cache::store(Item *item)
{
if (item)
example= item;
example= item;
if (!item)
null_value= TRUE;
value_cached= FALSE;
}
......@@ -6990,12 +6991,15 @@ void Item_cache::print(String *str, enum_query_type query_type)
str->append(')');
}
void Item_cache_int::cache_value()
bool Item_cache_int::cache_value()
{
if (!example)
return FALSE;
value_cached= TRUE;
value= example->val_int_result();
null_value= example->null_value;
unsigned_flag= example->unsigned_flag;
return TRUE;
}
......@@ -7012,8 +7016,8 @@ void Item_cache_int::store(Item *item, longlong val_arg)
String *Item_cache_int::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
if (!value_cached)
cache_value();
if (!value_cached && !cache_value())
return NULL;
str->set(value, default_charset());
return str;
}
......@@ -7022,8 +7026,8 @@ String *Item_cache_int::val_str(String *str)
my_decimal *Item_cache_int::val_decimal(my_decimal *decimal_val)
{
DBUG_ASSERT(fixed == 1);
if (!value_cached)
cache_value();
if (!value_cached && !cache_value())
return NULL;
int2my_decimal(E_DEC_FATAL_ERROR, value, unsigned_flag, decimal_val);
return decimal_val;
}
......@@ -7031,40 +7035,43 @@ my_decimal *Item_cache_int::val_decimal(my_decimal *decimal_val)
double Item_cache_int::val_real()
{
DBUG_ASSERT(fixed == 1);
if (!value_cached)
cache_value();
if (!value_cached && !cache_value())
return 0.0;
return (double) value;
}
longlong Item_cache_int::val_int()
{
DBUG_ASSERT(fixed == 1);
if (!value_cached)
cache_value();
if (!value_cached && !cache_value())
return 0;
return value;
}
void Item_cache_real::cache_value()
bool Item_cache_real::cache_value()
{
if (!example)
return FALSE;
value_cached= TRUE;
value= example->val_result();
null_value= example->null_value;
return TRUE;
}
double Item_cache_real::val_real()
{
DBUG_ASSERT(fixed == 1);
if (!value_cached)
cache_value();
if (!value_cached && !cache_value())
return 0.0;
return value;
}
longlong Item_cache_real::val_int()
{
DBUG_ASSERT(fixed == 1);
if (!value_cached)
cache_value();
if (!value_cached && !cache_value())
return 0;
return (longlong) rint(value);
}
......@@ -7072,8 +7079,8 @@ longlong Item_cache_real::val_int()
String* Item_cache_real::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
if (!value_cached)
cache_value();
if (!value_cached && !cache_value())
return NULL;
str->set_real(value, decimals, default_charset());
return str;
}
......@@ -7082,27 +7089,30 @@ String* Item_cache_real::val_str(String *str)
my_decimal *Item_cache_real::val_decimal(my_decimal *decimal_val)
{
DBUG_ASSERT(fixed == 1);
if (!value_cached)
cache_value();
if (!value_cached && !cache_value())
return NULL;
double2my_decimal(E_DEC_FATAL_ERROR, value, decimal_val);
return decimal_val;
}
void Item_cache_decimal::cache_value()
bool Item_cache_decimal::cache_value()
{
if (!example)
return FALSE;
value_cached= TRUE;
my_decimal *val= example->val_decimal_result(&decimal_value);
if (!(null_value= example->null_value) && val != &decimal_value)
my_decimal2decimal(val, &decimal_value);
return TRUE;
}
double Item_cache_decimal::val_real()
{
DBUG_ASSERT(fixed);
double res;
if (!value_cached)
cache_value();
if (!value_cached && !cache_value())
return NULL;
my_decimal2double(E_DEC_FATAL_ERROR, &decimal_value, &res);
return res;
}
......@@ -7111,8 +7121,8 @@ longlong Item_cache_decimal::val_int()
{
DBUG_ASSERT(fixed);
longlong res;
if (!value_cached)
cache_value();
if (!value_cached && !cache_value())
return 0;
my_decimal2int(E_DEC_FATAL_ERROR, &decimal_value, unsigned_flag, &res);
return res;
}
......@@ -7120,8 +7130,8 @@ longlong Item_cache_decimal::val_int()
String* Item_cache_decimal::val_str(String *str)
{
DBUG_ASSERT(fixed);
if (!value_cached)
cache_value();
if (!value_cached && !cache_value())
return NULL;
my_decimal_round(E_DEC_FATAL_ERROR, &decimal_value, decimals, FALSE,
&decimal_value);
my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value, 0, 0, 0, str);
......@@ -7131,14 +7141,16 @@ String* Item_cache_decimal::val_str(String *str)
my_decimal *Item_cache_decimal::val_decimal(my_decimal *val)
{
DBUG_ASSERT(fixed);
if (!value_cached)
cache_value();
if (!value_cached && !cache_value())
return NULL;
return &decimal_value;
}
void Item_cache_str::cache_value()
bool Item_cache_str::cache_value()
{
if (!example)
return FALSE;
value_cached= TRUE;
value_buff.set(buffer, sizeof(buffer), example->collation.collation);
value= example->str_result(&value_buff);
......@@ -7157,6 +7169,7 @@ void Item_cache_str::cache_value()
value_buff.copy(*value);
value= &value_buff;
}
return TRUE;
}
double Item_cache_str::val_real()
......@@ -7164,8 +7177,8 @@ double Item_cache_str::val_real()
DBUG_ASSERT(fixed == 1);
int err_not_used;
char *end_not_used;
if (!value_cached)
cache_value();
if (!value_cached && !cache_value())
return 0.0;
if (value)
return my_strntod(value->charset(), (char*) value->ptr(),
value->length(), &end_not_used, &err_not_used);
......@@ -7177,8 +7190,8 @@ longlong Item_cache_str::val_int()
{
DBUG_ASSERT(fixed == 1);
int err;
if (!value_cached)
cache_value();
if (!value_cached && !cache_value())
return 0;
if (value)
return my_strntoll(value->charset(), value->ptr(),
value->length(), 10, (char**) 0, &err);
......@@ -7190,8 +7203,8 @@ longlong Item_cache_str::val_int()
String* Item_cache_str::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
if (!value_cached)
cache_value();
if (!value_cached && !cache_value())
return 0;
return value;
}
......@@ -7199,8 +7212,8 @@ String* Item_cache_str::val_str(String *str)
my_decimal *Item_cache_str::val_decimal(my_decimal *decimal_val)
{
DBUG_ASSERT(fixed == 1);
if (!value_cached)
cache_value();
if (!value_cached && !cache_value())
return NULL;
if (value)
string2my_decimal(E_DEC_FATAL_ERROR, value, decimal_val);
else
......@@ -7211,8 +7224,8 @@ my_decimal *Item_cache_str::val_decimal(my_decimal *decimal_val)
int Item_cache_str::save_in_field(Field *field, bool no_conversions)
{
if (!value_cached)
cache_value();
if (!value_cached && !cache_value())
return 0;
int res= Item_cache::save_in_field(field, no_conversions);
return (is_varbinary && field->type() == MYSQL_TYPE_STRING &&
value->length() < field->field_length) ? 1 : res;
......@@ -7247,13 +7260,21 @@ bool Item_cache_row::setup(Item * item)
void Item_cache_row::store(Item * item)
{
example= item;
if (!item)
{
null_value= TRUE;
return;
}
for (uint i= 0; i < item_count; i++)
values[i]->store(item->element_index(i));
}
void Item_cache_row::cache_value()
bool Item_cache_row::cache_value()
{
if (!example)
return FALSE;
value_cached= TRUE;
null_value= 0;
example->bring_value();
......@@ -7262,6 +7283,7 @@ void Item_cache_row::cache_value()
values[i]->cache_value();
null_value|= values[i]->null_value;
}
return TRUE;
}
......
......@@ -2138,6 +2138,23 @@ public:
save_in_field(result_field, no_conversions);
}
void cleanup();
/*
This method is used for debug purposes to print the name of an
item to the debug log. The second use of this method is as
a helper function of print() and error messages, where it is
applicable. To suit both goals it should return a meaningful,
distinguishable and sintactically correct string. This method
should not be used for runtime type identification, use enum
{Sum}Functype and Item_func::functype()/Item_sum::sum_func()
instead.
Added here, to the parent class of both Item_func and Item_sum_func.
NOTE: for Items inherited from Item_sum, func_name() return part of
function name till first argument (including '(') to make difference in
names for functions with 'distinct' clause and without 'distinct' and
also to make printing of items inherited from Item_sum uniform.
*/
virtual const char *func_name() const= 0;
};
......@@ -2947,7 +2964,7 @@ public:
return this == item;
}
virtual void store(Item *item);
virtual void cache_value()= 0;
virtual bool cache_value()= 0;
};
......@@ -2968,7 +2985,7 @@ public:
my_decimal *val_decimal(my_decimal *);
enum Item_result result_type() const { return INT_RESULT; }
bool result_as_longlong() { return TRUE; }
void cache_value();
bool cache_value();
};
......@@ -2984,7 +3001,7 @@ public:
String* val_str(String *str);
my_decimal *val_decimal(my_decimal *);
enum Item_result result_type() const { return REAL_RESULT; }
void cache_value();
bool cache_value();
};
......@@ -3000,7 +3017,7 @@ public:
String* val_str(String *str);
my_decimal *val_decimal(my_decimal *);
enum Item_result result_type() const { return DECIMAL_RESULT; }
void cache_value();
bool cache_value();
};
......@@ -3025,7 +3042,7 @@ public:
enum Item_result result_type() const { return STRING_RESULT; }
CHARSET_INFO *charset() const { return value->charset(); };
int save_in_field(Field *field, bool no_conversions);
void cache_value();
bool cache_value();
};
class Item_cache_row: public Item_cache
......@@ -3094,7 +3111,7 @@ public:
values= 0;
DBUG_VOID_RETURN;
}
void cache_value();
bool cache_value();
};
......
......@@ -30,6 +30,9 @@
#include "sql_select.h"
static bool convert_constant_item(THD *, Item_field *, Item **);
static longlong
get_year_value(THD *thd, Item ***item_arg, Item **cache_arg,
Item *warn_item, bool *is_null);
static Item_result item_store_type(Item_result a, Item *item,
my_bool unsigned_flag)
......@@ -533,11 +536,12 @@ void Item_bool_func2::fix_length_and_dec()
}
int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type)
int Arg_comparator::set_compare_func(Item_result_field *item, Item_result type)
{
owner= item;
func= comparator_matrix[type]
[test(owner->functype() == Item_func::EQUAL_FUNC)];
[is_owner_equal_func()];
switch (type) {
case ROW_RESULT:
{
......@@ -557,7 +561,8 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type)
my_error(ER_OPERAND_COLUMNS, MYF(0), (*a)->element_index(i)->cols());
return 1;
}
if (comparators[i].set_cmp_func(owner, (*a)->addr(i), (*b)->addr(i)))
if (comparators[i].set_cmp_func(owner, (*a)->addr(i), (*b)->addr(i),
set_null))
return 1;
}
break;
......@@ -571,7 +576,8 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type)
if (cmp_collation.set((*a)->collation, (*b)->collation) ||
cmp_collation.derivation == DERIVATION_NONE)
{
my_coll_agg_error((*a)->collation, (*b)->collation, owner->func_name());
my_coll_agg_error((*a)->collation, (*b)->collation,
owner->func_name());
return 1;
}
if (cmp_collation.collation == &my_charset_bin)
......@@ -881,7 +887,7 @@ get_time_value(THD *thd, Item ***item_arg, Item **cache_arg,
}
int Arg_comparator::set_cmp_func(Item_bool_func2 *owner_arg,
int Arg_comparator::set_cmp_func(Item_result_field *owner_arg,
Item **a1, Item **a2,
Item_result type)
{
......@@ -891,6 +897,8 @@ int Arg_comparator::set_cmp_func(Item_bool_func2 *owner_arg,
owner= owner_arg;
a= a1;
b= a2;
owner= owner_arg;
thd= current_thd;
if ((cmp_type= can_compare_as_dates(*a, *b, &const_value)))
{
......@@ -921,9 +929,10 @@ int Arg_comparator::set_cmp_func(Item_bool_func2 *owner_arg,
b= (Item **)&b_cache;
}
}
is_nulls_eq= test(owner && owner->functype() == Item_func::EQUAL_FUNC);
is_nulls_eq= is_owner_equal_func();
func= &Arg_comparator::compare_datetime;
get_value_func= &get_datetime_value;
get_value_a_func= &get_datetime_value;
get_value_b_func= &get_datetime_value;
return 0;
}
else if (type == STRING_RESULT && (*a)->field_type() == MYSQL_TYPE_TIME &&
......@@ -932,9 +941,10 @@ int Arg_comparator::set_cmp_func(Item_bool_func2 *owner_arg,
/* Compare TIME values as integers. */
a_cache= 0;
b_cache= 0;
is_nulls_eq= test(owner && owner->functype() == Item_func::EQUAL_FUNC);
is_nulls_eq= is_owner_equal_func();
func= &Arg_comparator::compare_datetime;
get_value_func= &get_time_value;
get_value_a_func= &get_time_value;
get_value_b_func= &get_time_value;
return 0;
}
else if (type == STRING_RESULT &&
......@@ -943,9 +953,29 @@ int Arg_comparator::set_cmp_func(Item_bool_func2 *owner_arg,
{
DTCollation coll;
coll.set((*a)->collation.collation);
if (agg_item_set_converter(coll, owner_arg->func_name(),
if (agg_item_set_converter(coll, owner->func_name(),
b, 1, MY_COLL_CMP_CONV, 1))
return 1;
} else if (type != ROW_RESULT && ((*a)->field_type() == MYSQL_TYPE_YEAR ||
(*b)->field_type() == MYSQL_TYPE_YEAR))
{
is_nulls_eq= is_owner_equal_func();
if ((*a)->is_datetime())
{
year_as_datetime= TRUE;
get_value_a_func= &get_datetime_value;
} else if ((*a)->field_type() == MYSQL_TYPE_YEAR)
get_value_a_func= &get_year_value;
if ((*b)->is_datetime())
{
year_as_datetime= TRUE;
get_value_b_func= &get_datetime_value;
} else if ((*b)->field_type() == MYSQL_TYPE_YEAR)
get_value_b_func= &get_year_value;
func= &Arg_comparator::compare_year;
return 0;
}
a= cache_converted_constant(thd, a, &a_cache, type);
......@@ -988,11 +1018,11 @@ Item** Arg_comparator::cache_converted_constant(THD *thd, Item **value,
}
void Arg_comparator::set_datetime_cmp_func(Item **a1, Item **b1)
void Arg_comparator::set_datetime_cmp_func(Item_result_field *owner_arg,
Item **a1, Item **b1)
{
thd= current_thd;
/* A caller will handle null values by itself. */
owner= NULL;
owner= owner_arg;
a= a1;
b= b1;
a_type= (*a)->field_type();
......@@ -1001,7 +1031,8 @@ void Arg_comparator::set_datetime_cmp_func(Item **a1, Item **b1)
b_cache= 0;
is_nulls_eq= FALSE;
func= &Arg_comparator::compare_datetime;
get_value_func= &get_datetime_value;
get_value_a_func= &get_datetime_value;
get_value_b_func= &get_datetime_value;
}
......@@ -1101,6 +1132,51 @@ get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg,
return value;
}
/*
Retrieves YEAR value of 19XX form from given item.
SYNOPSIS
get_year_value()
thd thread handle
item_arg [in/out] item to retrieve YEAR value from
cache_arg [in/out] pointer to place to store the caching item to
warn_item [in] item for issuing the conversion warning
is_null [out] TRUE <=> the item_arg is null
DESCRIPTION
Retrieves the YEAR value of 19XX form from given item for comparison by the
compare_year() function.
RETURN
obtained value
*/
static longlong
get_year_value(THD *thd, Item ***item_arg, Item **cache_arg,
Item *warn_item, bool *is_null)
{
longlong value= 0;
Item *item= **item_arg;
value= item->val_int();
*is_null= item->null_value;
if (*is_null)
return ~(ulonglong) 0;
/*
Coerce value to the 19XX form in order to correctly compare
YEAR(2) & YEAR(4) types.
*/
if (value < 70)
value+= 100;
if (value <= 1900)
value+= 1900;
return value;
}
/*
Compare items values as dates.
......@@ -1133,25 +1209,25 @@ int Arg_comparator::compare_datetime()
longlong a_value, b_value;
/* Get DATE/DATETIME/TIME value of the 'a' item. */
a_value= (*get_value_func)(thd, &a, &a_cache, *b, &a_is_null);
a_value= (*get_value_a_func)(thd, &a, &a_cache, *b, &a_is_null);
if (!is_nulls_eq && a_is_null)
{
if (owner)
if (set_null)
owner->null_value= 1;
return -1;
}
/* Get DATE/DATETIME/TIME value of the 'b' item. */
b_value= (*get_value_func)(thd, &b, &b_cache, *a, &b_is_null);
b_value= (*get_value_b_func)(thd, &b, &b_cache, *a, &b_is_null);
if (a_is_null || b_is_null)
{
if (owner)
if (set_null)
owner->null_value= is_nulls_eq ? 0 : 1;
return is_nulls_eq ? (a_is_null == b_is_null) : -1;
}
/* Here we have two not-NULL values. */
if (owner)
if (set_null)
owner->null_value= 0;
/* Compare values. */
......@@ -1164,15 +1240,17 @@ int Arg_comparator::compare_datetime()
int Arg_comparator::compare_string()
{
String *res1,*res2;
if ((res1= (*a)->val_str(&owner->tmp_value1)))
if ((res1= (*a)->val_str(&value1)))
{
if ((res2= (*b)->val_str(&owner->tmp_value2)))
if ((res2= (*b)->val_str(&value2)))
{
owner->null_value= 0;
if (set_null)
owner->null_value= 0;
return sortcmp(res1,res2,cmp_collation.collation);
}
}
owner->null_value= 1;
if (set_null)
owner->null_value= 1;
return -1;
}
......@@ -1191,18 +1269,20 @@ int Arg_comparator::compare_string()
int Arg_comparator::compare_binary_string()
{
String *res1,*res2;
if ((res1= (*a)->val_str(&owner->tmp_value1)))
if ((res1= (*a)->val_str(&value1)))
{
if ((res2= (*b)->val_str(&owner->tmp_value2)))
if ((res2= (*b)->val_str(&value2)))
{
owner->null_value= 0;
if (set_null)
owner->null_value= 0;
uint res1_length= res1->length();
uint res2_length= res2->length();
int cmp= memcmp(res1->ptr(), res2->ptr(), min(res1_length,res2_length));
return cmp ? cmp : (int) (res1_length - res2_length);
}
}
owner->null_value= 1;
if (set_null)
owner->null_value= 1;
return -1;
}
......@@ -1215,8 +1295,8 @@ int Arg_comparator::compare_binary_string()
int Arg_comparator::compare_e_string()
{
String *res1,*res2;
res1= (*a)->val_str(&owner->tmp_value1);
res2= (*b)->val_str(&owner->tmp_value2);
res1= (*a)->val_str(&value1);
res2= (*b)->val_str(&value2);
if (!res1 || !res2)
return test(res1 == res2);
return test(sortcmp(res1, res2, cmp_collation.collation) == 0);
......@@ -1226,8 +1306,8 @@ int Arg_comparator::compare_e_string()
int Arg_comparator::compare_e_binary_string()
{
String *res1,*res2;
res1= (*a)->val_str(&owner->tmp_value1);
res2= (*b)->val_str(&owner->tmp_value2);
res1= (*a)->val_str(&value1);
res2= (*b)->val_str(&value2);
if (!res1 || !res2)
return test(res1 == res2);
return test(stringcmp(res1, res2) == 0);
......@@ -1248,13 +1328,15 @@ int Arg_comparator::compare_real()
val2= (*b)->val_real();
if (!(*b)->null_value)
{
owner->null_value= 0;
if (set_null)
owner->null_value= 0;
if (val1 < val2) return -1;
if (val1 == val2) return 0;
return 1;
}
}
owner->null_value= 1;
if (set_null)
owner->null_value= 1;
return -1;
}
......@@ -1268,11 +1350,13 @@ int Arg_comparator::compare_decimal()
my_decimal *val2= (*b)->val_decimal(&value2);
if (!(*b)->null_value)
{
owner->null_value= 0;
if (set_null)
owner->null_value= 0;
return my_decimal_cmp(val1, val2);
}
}
owner->null_value= 1;
if (set_null)
owner->null_value= 1;
return -1;
}
......@@ -1310,7 +1394,8 @@ int Arg_comparator::compare_real_fixed()
val2= (*b)->val_real();
if (!(*b)->null_value)
{
owner->null_value= 0;
if (set_null)
owner->null_value= 0;
if (val1 == val2 || fabs(val1 - val2) < precision)
return 0;
if (val1 < val2)
......@@ -1318,7 +1403,8 @@ int Arg_comparator::compare_real_fixed()
return 1;
}
}
owner->null_value= 1;
if (set_null)
owner->null_value= 1;
return -1;
}
......@@ -1341,13 +1427,15 @@ int Arg_comparator::compare_int_signed()
longlong val2= (*b)->val_int();
if (!(*b)->null_value)
{
owner->null_value= 0;
if (set_null)
owner->null_value= 0;
if (val1 < val2) return -1;
if (val1 == val2) return 0;
return 1;
}
}
owner->null_value= 1;
if (set_null)
owner->null_value= 1;
return -1;
}
......@@ -1364,13 +1452,15 @@ int Arg_comparator::compare_int_unsigned()
ulonglong val2= (*b)->val_int();
if (!(*b)->null_value)
{
owner->null_value= 0;
if (set_null)
owner->null_value= 0;
if (val1 < val2) return -1;
if (val1 == val2) return 0;
return 1;
}
}
owner->null_value= 1;
if (set_null)
owner->null_value= 1;
return -1;
}
......@@ -1387,7 +1477,8 @@ int Arg_comparator::compare_int_signed_unsigned()
ulonglong uval2= (ulonglong)(*b)->val_int();
if (!(*b)->null_value)
{
owner->null_value= 0;
if (set_null)
owner->null_value= 0;
if (sval1 < 0 || (ulonglong)sval1 < uval2)
return -1;
if ((ulonglong)sval1 == uval2)
......@@ -1395,7 +1486,8 @@ int Arg_comparator::compare_int_signed_unsigned()
return 1;
}
}
owner->null_value= 1;
if (set_null)
owner->null_value= 1;
return -1;
}
......@@ -1412,7 +1504,8 @@ int Arg_comparator::compare_int_unsigned_signed()
longlong sval2= (*b)->val_int();
if (!(*b)->null_value)
{
owner->null_value= 0;
if (set_null)
owner->null_value= 0;
if (sval2 < 0)
return 1;
if (uval1 < (ulonglong)sval2)
......@@ -1422,7 +1515,8 @@ int Arg_comparator::compare_int_unsigned_signed()
return 1;
}
}
owner->null_value= 1;
if (set_null)
owner->null_value= 1;
return -1;
}
......@@ -1458,10 +1552,11 @@ int Arg_comparator::compare_row()
for (uint i= 0; i<n; i++)
{
res= comparators[i].compare();
if (owner->null_value)
/* Aggregate functions don't need special null handling. */
if (owner->null_value && owner->type() == Item::FUNC_ITEM)
{
// NULL was compared
switch (owner->functype()) {
switch (((Item_func*)owner)->functype()) {
case Item_func::NE_FUNC:
break; // NE never aborts on NULL even if abort_on_null is set
case Item_func::LT_FUNC:
......@@ -1470,7 +1565,7 @@ int Arg_comparator::compare_row()
case Item_func::GE_FUNC:
return -1; // <, <=, > and >= always fail on NULL
default: // EQ_FUNC
if (owner->abort_on_null)
if (((Item_bool_func2*)owner)->abort_on_null)
return -1; // We do not need correct NULL returning
}
was_null= 1;
......@@ -1507,6 +1602,67 @@ int Arg_comparator::compare_e_row()
}
/**
Compare values as YEAR.
@details
Compare items as YEAR for EQUAL_FUNC and for other comparison functions.
The YEAR values of form 19XX are obtained with help of the get_year_value()
function.
If one of arguments is of DATE/DATETIME type its value is obtained
with help of the get_datetime_value function. In this case YEAR values
prior to comparison are converted to the ulonglong YYYY-00-00 00:00:00
DATETIME form.
If an argument type neither YEAR nor DATE/DATEIME then val_int function
is used to obtain value for comparison.
RETURN
If is_nulls_eq is TRUE:
1 if items are equal or both are null
0 otherwise
If is_nulls_eq is FALSE:
-1 a < b
0 a == b or at least one of items is null
1 a > b
See the table:
is_nulls_eq | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 |
a_is_null | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 |
b_is_null | 1 | 1 | 0 | 0 | 1 | 1 | 0 | 0 |
result | 1 | 0 | 0 |0/1| 0 | 0 | 0 |-1/0/1|
*/
int Arg_comparator::compare_year()
{
bool a_is_null, b_is_null;
ulonglong val1= get_value_a_func ?
(*get_value_a_func)(thd, &a, &a_cache, *b, &a_is_null) :
(*a)->val_int();
ulonglong val2= get_value_b_func ?
(*get_value_b_func)(thd, &b, &b_cache, *a, &b_is_null) :
(*b)->val_int();
if (!(*a)->null_value)
{
if (!(*b)->null_value)
{
if (set_null)
owner->null_value= 0;
/* Convert year to DATETIME of form YYYY-00-00 00:00:00 when necessary. */
if((*a)->field_type() == MYSQL_TYPE_YEAR && year_as_datetime)
val1*= 10000000000LL;
if((*b)->field_type() == MYSQL_TYPE_YEAR && year_as_datetime)
val2*= 10000000000LL;
if (val1 < val2) return is_nulls_eq ? 0 : -1;
if (val1 == val2) return is_nulls_eq ? 1 : 0;
return is_nulls_eq ? 0 : 1;
}
}
if (set_null)
owner->null_value= is_nulls_eq ? 0 : 1;
return (is_nulls_eq && (*a)->null_value == (*b)->null_value) ? 1 : 0;
}
void Item_func_truth::fix_length_and_dec()
{
maybe_null= 0;
......@@ -1794,8 +1950,8 @@ longlong Item_func_lt::val_int()
longlong Item_func_strcmp::val_int()
{
DBUG_ASSERT(fixed == 1);
String *a=args[0]->val_str(&tmp_value1);
String *b=args[1]->val_str(&tmp_value2);
String *a=args[0]->val_str(&cmp.value1);
String *b=args[1]->val_str(&cmp.value2);
if (!a || !b)
{
null_value=1;
......@@ -2078,8 +2234,8 @@ void Item_func_between::fix_length_and_dec()
if (compare_as_dates)
{
ge_cmp.set_datetime_cmp_func(args, args + 1);
le_cmp.set_datetime_cmp_func(args, args + 2);
ge_cmp.set_datetime_cmp_func(this, args, args + 1);
le_cmp.set_datetime_cmp_func(this, args, args + 2);
}
else if (time_items_found == 3)
{
......@@ -4407,13 +4563,13 @@ void Item_func_isnotnull::print(String *str, enum_query_type query_type)
longlong Item_func_like::val_int()
{
DBUG_ASSERT(fixed == 1);
String* res = args[0]->val_str(&tmp_value1);
String* res = args[0]->val_str(&cmp.value1);
if (args[0]->null_value)
{
null_value=1;
return 0;
}
String* res2 = args[1]->val_str(&tmp_value2);
String* res2 = args[1]->val_str(&cmp.value2);
if (args[1]->null_value)
{
null_value=1;
......@@ -4437,7 +4593,7 @@ Item_func::optimize_type Item_func_like::select_optimize() const
{
if (args[1]->const_item())
{
String* res2= args[1]->val_str((String *)&tmp_value2);
String* res2= args[1]->val_str((String *)&cmp.value2);
if (!res2)
return OPTIMIZE_NONE;
......@@ -4468,7 +4624,7 @@ bool Item_func_like::fix_fields(THD *thd, Item **ref)
if (escape_item->const_item())
{
/* If we are on execution stage */
String *escape_str= escape_item->val_str(&tmp_value1);
String *escape_str= escape_item->val_str(&cmp.value1);
if (escape_str)
{
if (escape_used_in_parsing && (
......@@ -4523,7 +4679,7 @@ bool Item_func_like::fix_fields(THD *thd, Item **ref)
if (args[1]->const_item() && !use_strnxfrm(collation.collation) &&
!(specialflag & SPECIAL_NO_NEW_FUNC))
{
String* res2 = args[1]->val_str(&tmp_value2);
String* res2 = args[1]->val_str(&cmp.value2);
if (!res2)
return FALSE; // Null argument
......
......@@ -32,7 +32,7 @@ class Arg_comparator: public Sql_alloc
{
Item **a, **b;
arg_cmp_func func;
Item_bool_func2 *owner;
Item_result_field *owner;
Arg_comparator *comparators; // used only for compare_row()
double precision;
/* Fields used in DATE/DATETIME comparison. */
......@@ -40,30 +40,42 @@ class Arg_comparator: public Sql_alloc
enum_field_types a_type, b_type; // Types of a and b items
Item *a_cache, *b_cache; // Cached values of a and b items
bool is_nulls_eq; // TRUE <=> compare for the EQUAL_FUNC
bool set_null; // TRUE <=> set owner->null_value
// when one of arguments is NULL.
bool year_as_datetime; // TRUE <=> convert YEAR value to
// the YYYY-00-00 00:00:00 DATETIME
// format. See compare_year.
enum enum_date_cmp_type { CMP_DATE_DFLT= 0, CMP_DATE_WITH_DATE,
CMP_DATE_WITH_STR, CMP_STR_WITH_DATE };
longlong (*get_value_func)(THD *thd, Item ***item_arg, Item **cache_arg,
Item *warn_item, bool *is_null);
longlong (*get_value_a_func)(THD *thd, Item ***item_arg, Item **cache_arg,
Item *warn_item, bool *is_null);
longlong (*get_value_b_func)(THD *thd, Item ***item_arg, Item **cache_arg,
Item *warn_item, bool *is_null);
public:
DTCollation cmp_collation;
/* Allow owner function to use string buffers. */
String value1, value2;
Arg_comparator(): thd(0), a_cache(0), b_cache(0) {};
Arg_comparator(): thd(0), a_cache(0), b_cache(0), set_null(0),
year_as_datetime(0), get_value_a_func(0), get_value_b_func(0) {};
Arg_comparator(Item **a1, Item **a2): a(a1), b(a2), thd(0),
a_cache(0), b_cache(0) {};
a_cache(0), b_cache(0), set_null(0), year_as_datetime(0),
get_value_a_func(0), get_value_b_func(0) {};
int set_compare_func(Item_bool_func2 *owner, Item_result type);
inline int set_compare_func(Item_bool_func2 *owner_arg)
int set_compare_func(Item_result_field *owner, Item_result type);
inline int set_compare_func(Item_result_field *owner_arg)
{
return set_compare_func(owner_arg, item_cmp_type((*a)->result_type(),
(*b)->result_type()));
}
int set_cmp_func(Item_bool_func2 *owner_arg,
int set_cmp_func(Item_result_field *owner_arg,
Item **a1, Item **a2,
Item_result type);
inline int set_cmp_func(Item_bool_func2 *owner_arg,
Item **a1, Item **a2)
inline int set_cmp_func(Item_result_field *owner_arg,
Item **a1, Item **a2, bool set_null_arg)
{
set_null= set_null_arg;
return set_cmp_func(owner_arg, a1, a2,
item_cmp_type((*a1)->result_type(),
(*a2)->result_type()));
......@@ -89,14 +101,20 @@ public:
int compare_real_fixed();
int compare_e_real_fixed();
int compare_datetime(); // compare args[0] & args[1] as DATETIMEs
int compare_year();
static enum enum_date_cmp_type can_compare_as_dates(Item *a, Item *b,
ulonglong *const_val_arg);
void set_datetime_cmp_func(Item **a1, Item **b1);
Item** cache_converted_constant(THD *thd, Item **value, Item **cache,
Item_result type);
void set_datetime_cmp_func(Item_result_field *owner_arg, Item **a1, Item **b1);
static arg_cmp_func comparator_matrix [5][2];
inline bool is_owner_equal_func()
{
return (owner->type() == Item::FUNC_ITEM &&
((Item_func*)owner)->functype() == Item_func::EQUAL_FUNC);
}
friend class Item_func;
};
......@@ -326,7 +344,6 @@ class Item_bool_func2 :public Item_int_func
{ /* Bool with 2 string args */
protected:
Arg_comparator cmp;
String tmp_value1,tmp_value2;
bool abort_on_null;
public:
......@@ -335,7 +352,7 @@ public:
void fix_length_and_dec();
void set_cmp_func()
{
cmp.set_cmp_func(this, tmp_arg, tmp_arg+1);
cmp.set_cmp_func(this, tmp_arg, tmp_arg+1, TRUE);
}
optimize_type select_optimize() const { return OPTIMIZE_OP; }
virtual enum Functype rev_functype() const { return UNKNOWN_FUNC; }
......
......@@ -124,17 +124,6 @@ public:
virtual optimize_type select_optimize() const { return OPTIMIZE_NONE; }
virtual bool have_rev_func() const { return 0; }
virtual Item *key_item() const { return args[0]; }
/*
This method is used for debug purposes to print the name of an
item to the debug log. The second use of this method is as
a helper function of print(), where it is applicable.
To suit both goals it should return a meaningful,
distinguishable and sintactically correct string. This method
should not be used for runtime type identification, use enum
{Sum}Functype and Item_func::functype()/Item_sum::sum_func()
instead.
*/
virtual const char *func_name() const= 0;
virtual bool const_item() const { return const_item_cache; }
inline Item **arguments() const { return args; }
void set_arguments(List<Item> &list);
......
......@@ -511,8 +511,8 @@ err:
longlong Item_func_spatial_rel::val_int()
{
DBUG_ASSERT(fixed == 1);
String *res1= args[0]->val_str(&tmp_value1);
String *res2= args[1]->val_str(&tmp_value2);
String *res1= args[0]->val_str(&cmp.value1);
String *res2= args[1]->val_str(&cmp.value2);
Geometry_buffer buffer1, buffer2;
Geometry *g1, *g2;
MBR mbr1, mbr2;
......
......@@ -132,6 +132,7 @@ public:
@return the SELECT_LEX structure associated with this Item
*/
st_select_lex* get_select_lex();
const char *func_name() const { DBUG_ASSERT(0); return "subselect"; }
friend class select_subselect;
friend class Item_in_optimizer;
......
......@@ -615,35 +615,6 @@ Item_sum_num::fix_fields(THD *thd, Item **ref)
}
Item_sum_hybrid::Item_sum_hybrid(THD *thd, Item_sum_hybrid *item)
:Item_sum(thd, item), value(item->value), hybrid_type(item->hybrid_type),
hybrid_field_type(item->hybrid_field_type), cmp_sign(item->cmp_sign),
was_values(item->was_values)
{
/* copy results from old value */
switch (hybrid_type) {
case INT_RESULT:
sum_int= item->sum_int;
break;
case DECIMAL_RESULT:
my_decimal2decimal(&item->sum_dec, &sum_dec);
break;
case REAL_RESULT:
sum= item->sum;
break;
case STRING_RESULT:
/*
This can happen with ROLLUP. Note that the value is already
copied at function call.
*/
break;
case ROW_RESULT:
default:
DBUG_ASSERT(0);
}
collation.set(item->collation);
}
bool
Item_sum_hybrid::fix_fields(THD *thd, Item **ref)
{
......@@ -663,15 +634,12 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref)
switch (hybrid_type= item->result_type()) {
case INT_RESULT:
max_length= 20;
sum_int= 0;
break;
case DECIMAL_RESULT:
max_length= item->max_length;
my_decimal_set_zero(&sum_dec);
break;
case REAL_RESULT:
max_length= float_length(decimals);
sum= 0.0;
break;
case STRING_RESULT:
max_length= item->max_length;
......@@ -680,10 +648,10 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref)
default:
DBUG_ASSERT(0);
};
setup(args[0], NULL);
/* MIN/MAX can return NULL for empty set indepedent of the used column */
maybe_null= 1;
unsigned_flag=item->unsigned_flag;
collation.set(item->collation);
result_field=0;
null_value=1;
fix_length_and_dec();
......@@ -701,6 +669,30 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref)
return FALSE;
}
/**
MIN/MAX function setup.
@param item argument of MIN/MAX function
@param value_arg calculated value of MIN/MAX function
@details
Setup cache/comparator of MIN/MAX functions. When called by the
copy_or_same function value_arg parameter contains calculated value
of the original MIN/MAX object and it is saved in this object's cache.
*/
void Item_sum_hybrid::setup(Item *item, Item *value_arg)
{
value= Item_cache::get_cache(item);
value->setup(item);
value->store(value_arg);
cmp= new Arg_comparator();
cmp->set_cmp_func(this, args, (Item**)&value, FALSE);
collation.set(item->collation);
}
Field *Item_sum_hybrid::create_tmp_field(bool group, TABLE *table,
uint convert_blob_length)
{
......@@ -1592,19 +1584,7 @@ void Item_sum_variance::update_field()
void Item_sum_hybrid::clear()
{
switch (hybrid_type) {
case INT_RESULT:
sum_int= 0;
break;
case DECIMAL_RESULT:
my_decimal_set_zero(&sum_dec);
break;
case REAL_RESULT:
sum= 0.0;
break;
default:
value.length(0);
}
value->null_value= 1;
null_value= 1;
}
......@@ -1613,30 +1593,7 @@ double Item_sum_hybrid::val_real()
DBUG_ASSERT(fixed == 1);
if (null_value)
return 0.0;
switch (hybrid_type) {
case STRING_RESULT:
{
char *end_not_used;
int err_not_used;
String *res; res=val_str(&str_value);
return (res ? my_strntod(res->charset(), (char*) res->ptr(), res->length(),
&end_not_used, &err_not_used) : 0.0);
}
case INT_RESULT:
if (unsigned_flag)
return ulonglong2double(sum_int);
return (double) sum_int;
case DECIMAL_RESULT:
my_decimal2double(E_DEC_FATAL_ERROR, &sum_dec, &sum);
return sum;
case REAL_RESULT:
return sum;
case ROW_RESULT:
default:
// This case should never be choosen
DBUG_ASSERT(0);
return 0;
}
return value->val_real();
}
longlong Item_sum_hybrid::val_int()
......@@ -1644,18 +1601,7 @@ longlong Item_sum_hybrid::val_int()
DBUG_ASSERT(fixed == 1);
if (null_value)
return 0;
switch (hybrid_type) {
case INT_RESULT:
return sum_int;
case DECIMAL_RESULT:
{
longlong result;
my_decimal2int(E_DEC_FATAL_ERROR, &sum_dec, unsigned_flag, &result);
return sum_int;
}
default:
return (longlong) rint(Item_sum_hybrid::val_real());
}
return value->val_int();
}
......@@ -1664,26 +1610,7 @@ my_decimal *Item_sum_hybrid::val_decimal(my_decimal *val)
DBUG_ASSERT(fixed == 1);
if (null_value)
return 0;
switch (hybrid_type) {
case STRING_RESULT:
string2my_decimal(E_DEC_FATAL_ERROR, &value, val);
break;
case REAL_RESULT:
double2my_decimal(E_DEC_FATAL_ERROR, sum, val);
break;
case DECIMAL_RESULT:
val= &sum_dec;
break;
case INT_RESULT:
int2my_decimal(E_DEC_FATAL_ERROR, sum_int, unsigned_flag, val);
break;
case ROW_RESULT:
default:
// This case should never be choosen
DBUG_ASSERT(0);
break;
}
return val; // Keep compiler happy
return value->val_decimal(val);
}
......@@ -1693,25 +1620,7 @@ Item_sum_hybrid::val_str(String *str)
DBUG_ASSERT(fixed == 1);
if (null_value)
return 0;
switch (hybrid_type) {
case STRING_RESULT:
return &value;
case REAL_RESULT:
str->set_real(sum,decimals, &my_charset_bin);
break;
case DECIMAL_RESULT:
my_decimal2string(E_DEC_FATAL_ERROR, &sum_dec, 0, 0, 0, str);
return str;
case INT_RESULT:
str->set_int(sum_int, unsigned_flag, &my_charset_bin);
break;
case ROW_RESULT:
default:
// This case should never be choosen
DBUG_ASSERT(0);
break;
}
return str; // Keep compiler happy
return value->val_str(str);
}
......@@ -1720,7 +1629,9 @@ void Item_sum_hybrid::cleanup()
DBUG_ENTER("Item_sum_hybrid::cleanup");
Item_sum::cleanup();
forced_const= FALSE;
if (cmp)
delete cmp;
cmp= 0;
/*
by default it is TRUE to avoid TRUE reporting by
Item_func_not_all/Item_func_nop_all if this item was never called.
......@@ -1741,63 +1652,22 @@ void Item_sum_hybrid::no_rows_in_result()
Item *Item_sum_min::copy_or_same(THD* thd)
{
return new (thd->mem_root) Item_sum_min(thd, this);
Item_sum_min *item= new (thd->mem_root) Item_sum_min(thd, this);
item->setup(args[0], value);
return item;
}
bool Item_sum_min::add()
{
switch (hybrid_type) {
case STRING_RESULT:
/* args[0] < value */
int res= cmp->compare();
if (!args[0]->null_value &&
(null_value || res < 0))
{
String *result=args[0]->val_str(&tmp_value);
if (!args[0]->null_value &&
(null_value || sortcmp(&value,result,collation.collation) > 0))
{
value.copy(*result);
null_value=0;
}
}
break;
case INT_RESULT:
{
longlong nr=args[0]->val_int();
if (!args[0]->null_value && (null_value ||
(unsigned_flag &&
(ulonglong) nr < (ulonglong) sum_int) ||
(!unsigned_flag && nr < sum_int)))
{
sum_int=nr;
null_value=0;
}
}
break;
case DECIMAL_RESULT:
{
my_decimal value_buff, *val= args[0]->val_decimal(&value_buff);
if (!args[0]->null_value &&
(null_value || (my_decimal_cmp(&sum_dec, val) > 0)))
{
my_decimal2decimal(val, &sum_dec);
null_value= 0;
}
}
break;
case REAL_RESULT:
{
double nr= args[0]->val_real();
if (!args[0]->null_value && (null_value || nr < sum))
{
sum=nr;
null_value=0;
}
}
break;
case ROW_RESULT:
default:
// This case should never be choosen
DBUG_ASSERT(0);
break;
value->store(args[0]);
value->cache_value();
null_value= 0;
}
return 0;
}
......@@ -1805,63 +1675,22 @@ bool Item_sum_min::add()
Item *Item_sum_max::copy_or_same(THD* thd)
{
return new (thd->mem_root) Item_sum_max(thd, this);
Item_sum_max *item= new (thd->mem_root) Item_sum_max(thd, this);
item->setup(args[0], value);
return item;
}
bool Item_sum_max::add()
{
switch (hybrid_type) {
case STRING_RESULT:
/* args[0] > value */
int res= cmp->compare();
if (!args[0]->null_value &&
(null_value || res > 0))
{
String *result=args[0]->val_str(&tmp_value);
if (!args[0]->null_value &&
(null_value || sortcmp(&value,result,collation.collation) < 0))
{
value.copy(*result);
null_value=0;
}
}
break;
case INT_RESULT:
{
longlong nr=args[0]->val_int();
if (!args[0]->null_value && (null_value ||
(unsigned_flag &&
(ulonglong) nr > (ulonglong) sum_int) ||
(!unsigned_flag && nr > sum_int)))
{
sum_int=nr;
null_value=0;
}
}
break;
case DECIMAL_RESULT:
{
my_decimal value_buff, *val= args[0]->val_decimal(&value_buff);
if (!args[0]->null_value &&
(null_value || (my_decimal_cmp(val, &sum_dec) > 0)))
{
my_decimal2decimal(val, &sum_dec);
null_value= 0;
}
}
break;
case REAL_RESULT:
{
double nr= args[0]->val_real();
if (!args[0]->null_value && (null_value || nr > sum))
{
sum=nr;
null_value=0;
}
}
break;
case ROW_RESULT:
default:
// This case should never be choosen
DBUG_ASSERT(0);
break;
value->store(args[0]);
value->cache_value();
null_value= 0;
}
return 0;
}
......@@ -2226,14 +2055,15 @@ void Item_sum_hybrid::update_field()
void
Item_sum_hybrid::min_max_update_str_field()
{
String *res_str=args[0]->val_str(&value);
DBUG_ASSERT(cmp);
String *res_str=args[0]->val_str(&cmp->value1);
if (!args[0]->null_value)
{
result_field->val_str(&tmp_value);
result_field->val_str(&cmp->value2);
if (result_field->is_null() ||
(cmp_sign * sortcmp(res_str,&tmp_value,collation.collation)) < 0)
(cmp_sign * sortcmp(res_str,&cmp->value2,collation.collation)) < 0)
result_field->store(res_str->ptr(),res_str->length(),res_str->charset());
result_field->set_notnull();
}
......
......@@ -323,22 +323,6 @@ public:
virtual void update_field()=0;
virtual bool keep_field_type(void) const { return 0; }
virtual void fix_length_and_dec() { maybe_null=1; null_value=1; }
/*
This method is used for debug purposes to print the name of an
item to the debug log. The second use of this method is as
a helper function of print(), where it is applicable.
To suit both goals it should return a meaningful,
distinguishable and sintactically correct string. This method
should not be used for runtime type identification, use enum
{Sum}Functype and Item_func::functype()/Item_sum::sum_func()
instead.
NOTE: for Items inherited from Item_sum, func_name() return part of
function name till first argument (including '(') to make difference in
names for functions with 'distinct' clause and without 'distinct' and
also to make printing of items inherited from Item_sum uniform.
*/
virtual const char *func_name() const= 0;
virtual Item *result_item(Field *field)
{ return new Item_field(field); }
table_map used_tables() const { return used_tables_cache; }
......@@ -664,6 +648,7 @@ public:
}
void fix_length_and_dec() {}
enum Item_result result_type () const { return hybrid_type; }
const char *func_name() const { DBUG_ASSERT(0); return "avg_field"; }
};
......@@ -732,6 +717,7 @@ public:
}
void fix_length_and_dec() {}
enum Item_result result_type () const { return hybrid_type; }
const char *func_name() const { DBUG_ASSERT(0); return "variance_field"; }
};
......@@ -807,6 +793,7 @@ public:
my_decimal *val_decimal(my_decimal *);
enum Item_result result_type () const { return REAL_RESULT; }
enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE;}
const char *func_name() const { DBUG_ASSERT(0); return "std_field"; }
};
/*
......@@ -832,14 +819,13 @@ class Item_sum_std :public Item_sum_variance
};
// This class is a string or number function depending on num_func
class Arg_comparator;
class Item_cache;
class Item_sum_hybrid :public Item_sum
{
protected:
String value,tmp_value;
double sum;
longlong sum_int;
my_decimal sum_dec;
Item_cache *value;
Arg_comparator *cmp;
Item_result hybrid_type;
enum_field_types hybrid_field_type;
int cmp_sign;
......@@ -847,12 +833,17 @@ protected:
public:
Item_sum_hybrid(Item *item_par,int sign)
:Item_sum(item_par), sum(0.0), sum_int(0),
:Item_sum(item_par), value(0), cmp(0),
hybrid_type(INT_RESULT), hybrid_field_type(MYSQL_TYPE_LONGLONG),
cmp_sign(sign), was_values(TRUE)
{ collation.set(&my_charset_bin); }
Item_sum_hybrid(THD *thd, Item_sum_hybrid *item);
Item_sum_hybrid(THD *thd, Item_sum_hybrid *item)
:Item_sum(thd, item), value(item->value), hybrid_type(item->hybrid_type),
hybrid_field_type(item->hybrid_field_type), cmp_sign(item->cmp_sign),
was_values(item->was_values)
{ }
bool fix_fields(THD *, Item **);
void setup(Item *item, Item *value_arg);
void clear();
double val_real();
longlong val_int();
......
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