Commit c3f665dc authored by Sergei Golubchik's avatar Sergei Golubchik

bugfixes:

  microsecond(TIME)
  alter table datetime<->datetime(6)
  max(TIME), mix(TIME) 

mysql-test/t/func_if.test:
  fix the test case of avoid overflow
sql/field.cc:
  don't use make_date() and make_time()
sql/field.h:
  correct eq_def() for temporal fields
sql/item.cc:
  move datetime caching from Item_cache_int
  to Item_cache_temporal
sql/item.h:
  move datetime caching from Item_cache_int
  to Item_cache_temporal
sql/item_func.cc:
  use existing helper methods, don't duplicate
sql/item_sum.cc:
  argument cache must use argument's cmp_type, not result_type.
sql/item_timefunc.cc:
  use existing methods, don't tuplicate.
  remove unused function.
  fix micorseconds() to support TIME argument
sql/mysql_priv.h:
  dead code
sql/time.cc:
  dead code
parent 9b98cae4
......@@ -507,7 +507,7 @@ f1 f2 f3
Warnings:
Warning 1292 Truncated incorrect datetime value: '2003-01-02 10:11:12.0012ABCD'
Warning 1292 Truncated incorrect time value: '-01:01:01.01 GGG'
Warning 1292 Truncated incorrect datetime value: '1997-12-31 23:59:59.01XXXX'
Warning 1292 Truncated incorrect time value: '1997-12-31 23:59:59.01XXXX'
select str_to_date("2003-04-05 g", "%Y-%m-%d") as f1,
str_to_date("2003-04-05 10:11:12.101010234567", "%Y-%m-%d %H:%i:%S.%f") as f2;
f1 f2
......
......@@ -177,12 +177,19 @@ IF((ROUND(t1.a,2)=1), 2,
IF((R
DROP TABLE t1;
CREATE TABLE t1 (c LONGTEXT);
INSERT INTO t1 VALUES(1), (2), (3), (4), ('12345678901234567890');
INSERT INTO t1 VALUES(1), (2), (3), (4), ('1234567890123456789');
SELECT IF(1, CAST(c AS UNSIGNED), 0) FROM t1;
IF(1, CAST(c AS UNSIGNED), 0)
1
2
3
4
1234567890123456789
SELECT * FROM (SELECT MAX(IF(1, CAST(c AS UNSIGNED), 0)) FROM t1) AS te;
MAX(IF(1, CAST(c AS UNSIGNED), 0))
12345678901234567890
1234567890123456789
SELECT * FROM (SELECT MAX(IFNULL(CAST(c AS UNSIGNED), 0)) FROM t1) AS te;
MAX(IFNULL(CAST(c AS UNSIGNED), 0))
12345678901234567890
1234567890123456789
DROP TABLE t1;
End of 5.0 tests
......@@ -250,6 +250,8 @@ a
select microsecond(19971231235959.01) as a;
a
10000
Warnings:
Warning 1292 Truncated incorrect time value: '19971231235959.01'
select date_add("1997-12-31",INTERVAL "10.09" SECOND_MICROSECOND) as a;
a
1997-12-31 00:00:10.090000
......
......@@ -1649,3 +1649,6 @@ greatest(cast("0-0-0" as date), cast("10:20:05" as time)) = '0000-00-00'
select cast(greatest(cast("0-0-0" as date), cast("10:20:05" as time)) as datetime(6));
cast(greatest(cast("0-0-0" as date), cast("10:20:05" as time)) as datetime(6))
0000-00-00 00:00:00.000000
select microsecond('12:00:00.123456'), microsecond('2009-12-31 23:59:59.000010');
microsecond('12:00:00.123456') microsecond('2009-12-31 23:59:59.000010')
123456 10
......@@ -333,4 +333,8 @@ update t1 set b=a;
select * from t1;
a b
2010-01-02 03:04:05 2010-01-02 03:04:05.000000
alter table t1 modify b datetime, modify a datetime(6);
select * from t1;
a b
2010-01-02 03:04:05.000000 2010-01-02 03:04:05
drop table t1;
......@@ -331,6 +331,9 @@ a
-00:00:01.0900
-00:00:01.1000
-00:00:01.1000
select min(a - interval 1 hour), max(a - interval 1 hour) from t1 where a < 0;
min(a - interval 1 hour) max(a - interval 1 hour)
-01:00:01.1000 -01:00:00.6000
drop table t1;
select cast(1e-6 as time(6));
cast(1e-6 as time(6))
......
......@@ -161,8 +161,9 @@ DROP TABLE t1;
#
CREATE TABLE t1 (c LONGTEXT);
INSERT INTO t1 VALUES(1), (2), (3), (4), ('12345678901234567890');
INSERT INTO t1 VALUES(1), (2), (3), (4), ('1234567890123456789');
SELECT IF(1, CAST(c AS UNSIGNED), 0) FROM t1;
SELECT * FROM (SELECT MAX(IF(1, CAST(c AS UNSIGNED), 0)) FROM t1) AS te;
SELECT * FROM (SELECT MAX(IFNULL(CAST(c AS UNSIGNED), 0)) FROM t1) AS te;
......
......@@ -1063,3 +1063,5 @@ select greatest(cast("0-0-0" as date), cast("10:20:05" as time));
select greatest(cast("0-0-0" as date), cast("10:20:05" as time)) = '0000-00-00';
select cast(greatest(cast("0-0-0" as date), cast("10:20:05" as time)) as datetime(6));
select microsecond('12:00:00.123456'), microsecond('2009-12-31 23:59:59.000010');
......@@ -65,5 +65,7 @@ create table t1 (a datetime, b datetime(6));
insert t1 values ('2010-01-02 03:04:05.678912', '2010-01-02 03:04:05.678912');
update t1 set b=a;
select * from t1;
alter table t1 modify b datetime, modify a datetime(6);
select * from t1;
drop table t1;
......@@ -6,6 +6,7 @@ create table t1 (a time(4) not null, key(a));
insert into t1 values ('1:2:3.001'),('1:2:3'), ('-00:00:00.6'),('-00:00:00.7'),('-00:00:00.8'),('-00:00:00.9'),('-00:00:01.0'),('-00:00:01.1'),('-00:00:01.000000'),('-00:00:01.100001'),('-00:00:01.000002'),('-00:00:01.090000');
select * from t1 order by a;
select * from t1 order by a desc;
select min(a - interval 1 hour), max(a - interval 1 hour) from t1 where a < 0;
drop table t1;
select cast(1e-6 as time(6));
......@@ -5289,7 +5289,13 @@ String *Field_time::val_str(String *val_buffer,
ltime.minute= (uint) (tmp/100 % 100);
ltime.second= (uint) (tmp % 100);
ltime.second_part= 0;
make_time((DATE_TIME_FORMAT*) 0, &ltime, val_buffer);
val_buffer->alloc(MAX_DATE_STRING_REP_LENGTH);
uint length= (uint) my_time_to_str(&ltime,
const_cast<char*>(val_buffer->ptr()), 0);
val_buffer->length(length);
val_buffer->set_charset(&my_charset_bin);
return val_buffer;
}
......@@ -5664,7 +5670,13 @@ String *Field_date::val_str(String *val_buffer,
ltime.year= (int) ((uint32) tmp/10000L % 10000);
ltime.month= (int) ((uint32) tmp/100 % 100);
ltime.day= (int) ((uint32) tmp % 100);
make_date((DATE_TIME_FORMAT *) 0, &ltime, val_buffer);
val_buffer->alloc(MAX_DATE_STRING_REP_LENGTH);
uint length= (uint) my_date_to_str(&ltime,
const_cast<char*>(val_buffer->ptr()));
val_buffer->length(length);
val_buffer->set_charset(&my_charset_bin);
return val_buffer;
}
......
......@@ -1317,6 +1317,10 @@ public:
int store(longlong nr, bool unsigned_val);
int store_time_dec(MYSQL_TIME *ltime, uint dec);
my_decimal *val_decimal(my_decimal*);
bool eq_def(Field *field)
{
return (Field_str::eq_def(field) && decimals() == field->decimals());
}
};
class Field_date :public Field_temporal {
......
......@@ -237,6 +237,21 @@ String *Item::val_string_from_decimal(String *str)
}
String *Item::val_string_from_date(String *str)
{
MYSQL_TIME ltime;
if (get_date(&ltime, TIME_FUZZY_DATE) ||
str->alloc(MAX_DATE_STRING_REP_LENGTH))
{
null_value= 1;
return (String *) 0;
}
str->length(my_TIME_to_str(&ltime, const_cast<char*>(str->ptr()), decimals));
str->set_charset(&my_charset_bin);
return str;
}
my_decimal *Item::val_decimal_from_real(my_decimal *decimal_value)
{
double nr= val_real();
......@@ -8094,8 +8109,7 @@ Item_cache* Item_cache::get_cache(const Item *item, const Item_result type)
case ROW_RESULT:
return new Item_cache_row();
case TIME_RESULT:
/* this item will store a packed datetime value as an integer */
return new Item_cache_int(MYSQL_TYPE_DATETIME);
return new Item_cache_temporal(item->field_type());
case IMPOSSIBLE_RESULT:
DBUG_ASSERT(0);
break;
......@@ -8138,16 +8152,6 @@ bool Item_cache_int::cache_value()
}
void Item_cache_int::store_longlong(Item *item, longlong val_arg)
{
/* An explicit values is given, save it. */
value_cached= TRUE;
value= val_arg;
null_value= item->null_value;
unsigned_flag= item->unsigned_flag;
}
String *Item_cache_int::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
......@@ -8196,7 +8200,48 @@ longlong Item_cache_int::val_int()
}
bool Item_cache_int::get_date(MYSQL_TIME *ltime, uint fuzzydate)
int Item_cache_int::save_in_field(Field *field, bool no_conversions)
{
int error;
if ((!value_cached && !cache_value()) || null_value)
return set_field_to_null_with_conversions(field, no_conversions);
field->set_notnull();
error= field->store(value, unsigned_flag);
return error ? error : field->table->in_use->is_error() ? 1 : 0;
}
String *Item_cache_temporal::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
if ((!value_cached && !cache_value()) || null_value)
{
null_value= true;
return NULL;
}
return val_string_from_date(str);
}
bool Item_cache_temporal::cache_value()
{
if (!example)
return false;
value_cached= true;
MYSQL_TIME ltime;
if (example->get_date(&ltime, TIME_FUZZY_DATE))
value=0;
else
value= pack_time(&ltime);
null_value= example->null_value;
return true;
}
bool Item_cache_temporal::get_date(MYSQL_TIME *ltime, uint fuzzydate)
{
Lazy_string_num str(value);
......@@ -8206,38 +8251,45 @@ bool Item_cache_int::get_date(MYSQL_TIME *ltime, uint fuzzydate)
return 1;
}
if (cmp_type() == TIME_RESULT)
unpack_time(value, ltime);
ltime->time_type= mysql_type_to_time_type(field_type());
if (ltime->time_type == MYSQL_TIMESTAMP_TIME)
{
unpack_time(value, ltime);
ltime->time_type= mysql_type_to_time_type(field_type());
return 0;
ltime->hour+= (ltime->month*32+ltime->day)*24;
ltime->month= ltime->day= 0;
}
return Item::get_date(ltime, fuzzydate);
return 0;
}
int Item_cache_int::save_in_field(Field *field, bool no_conversions)
int Item_cache_temporal::save_in_field(Field *field, bool no_conversions)
{
int error;
if ((!value_cached && !cache_value()) || null_value)
return set_field_to_null_with_conversions(field, no_conversions);
field->set_notnull();
if (cmp_type() == TIME_RESULT)
{
MYSQL_TIME ltime;
unpack_time(value, &ltime);
ltime.time_type= mysql_type_to_time_type(field_type());
error= field->store_time_dec(&ltime, decimals);
}
else
error= field->store(value, unsigned_flag);
MYSQL_TIME ltime;
unpack_time(value, &ltime);
ltime.time_type= mysql_type_to_time_type(field_type());
error= field->store_time_dec(&ltime, decimals);
return error ? error : field->table->in_use->is_error() ? 1 : 0;
}
void Item_cache_temporal::store_packed(longlong val_arg)
{
/* An explicit values is given, save it. */
value_cached= true;
value= val_arg;
null_value= false;
}
bool Item_cache_real::cache_value()
{
if (!example)
......
......@@ -808,6 +808,7 @@ public:
String *val_string_from_real(String *str);
String *val_string_from_int(String *str);
String *val_string_from_decimal(String *str);
String *val_string_from_date(String *str);
my_decimal *val_decimal_from_real(my_decimal *decimal_value);
my_decimal *val_decimal_from_int(my_decimal *decimal_value);
my_decimal *val_decimal_from_string(my_decimal *decimal_value);
......@@ -3564,16 +3565,31 @@ public:
Item_cache_int(enum_field_types field_type_arg):
Item_cache(field_type_arg), value(0) {}
virtual void store(Item *item){ Item_cache::store(item); }
void store_longlong(Item *item, longlong val_arg);
double val_real();
longlong val_int();
String* val_str(String *str);
my_decimal *val_decimal(my_decimal *);
enum Item_result result_type() const { return INT_RESULT; }
bool cache_value();
int save_in_field(Field *field, bool no_conversions);
};
class Item_cache_temporal: public Item_cache_int
{
public:
Item_cache_temporal(enum_field_types field_type_arg):
Item_cache_int(field_type_arg)
{
if (mysql_type_to_time_type(cached_field_type) == MYSQL_TIMESTAMP_ERROR)
cached_field_type= MYSQL_TYPE_DATETIME;
}
String* val_str(String *str);
bool cache_value();
bool get_date(MYSQL_TIME *ltime, uint fuzzydate);
int save_in_field(Field *field, bool no_conversions);
void store_packed(longlong val_arg);
/*
Having a clone_item method tells optimizer that this object
is a constant and need not be optimized further.
......@@ -3581,13 +3597,12 @@ public:
*/
Item *clone_item()
{
Item_cache_int *item= new Item_cache_int(cached_field_type);
item->store_longlong(this, value);
Item_cache_temporal *item= new Item_cache_temporal(cached_field_type);
item->store_packed(value);
return item;
}
};
class Item_cache_real: public Item_cache
{
double value;
......
......@@ -880,11 +880,11 @@ get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg,
*/
Query_arena backup;
Query_arena *save_arena= thd->switch_to_arena_for_cached_items(&backup);
Item_cache_int *cache= new Item_cache_int(f_type);
Item_cache_temporal *cache= new Item_cache_temporal(f_type);
if (save_arena)
thd->set_query_arena(save_arena);
cache->store_longlong(item, value);
cache->store_packed(value);
*cache_arg= cache;
*item_arg= cache_arg;
}
......
......@@ -2463,41 +2463,14 @@ String *Item_func_min_max::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
if (compare_as_dates)
{
MYSQL_TIME ltime;
if (get_date(&ltime, TIME_FUZZY_DATE))
return 0;
str->alloc(MAX_DATE_STRING_REP_LENGTH);
str->set_charset(collation.collation);
str->length(my_TIME_to_str(&ltime, const_cast<char*>(str->ptr()), decimals));
return str;
}
return val_string_from_date(str);
switch (cmp_type) {
case INT_RESULT:
{
longlong nr=val_int();
if (null_value)
return 0;
str->set_int(nr, unsigned_flag, &my_charset_bin);
return str;
}
return val_string_from_int(str);
case DECIMAL_RESULT:
{
my_decimal dec_buf, *dec_val= val_decimal(&dec_buf);
if (null_value)
return 0;
my_decimal2string(E_DEC_FATAL_ERROR, dec_val, 0, 0, 0, str);
return str;
}
return val_string_from_decimal(str);
case REAL_RESULT:
{
double nr= val_real();
if (null_value)
return 0; /* purecov: inspected */
str->set_real(nr,decimals,&my_charset_bin);
return str;
}
return val_string_from_real(str);
case STRING_RESULT:
{
String *UNINIT_VAR(res);
......
......@@ -670,7 +670,7 @@ void Item_sum_hybrid::setup_hybrid(Item *item, Item *value_arg)
/* Don't cache value, as it will change */
if (!item->const_item())
value->set_used_tables(RAND_TABLE_BIT);
if (!(arg_cache= Item_cache::get_cache(item)))
if (!(arg_cache= Item_cache::get_cache(item, item->cmp_type())))
return;
arg_cache->setup(item);
/* Don't cache value, as it will change */
......
......@@ -35,16 +35,6 @@
/** Day number for Dec 31st, 9999. */
#define MAX_DAY_NUMBER 3652424L
static bool make_datetime(MYSQL_TIME *ltime, String *str, uint decimals)
{
if (str->alloc(MAX_DATE_STRING_REP_LENGTH))
return 1;
str->length(my_TIME_to_str(ltime, const_cast<char*>(str->ptr()), decimals));
str->set_charset(&my_charset_bin);
return 0;
}
/*
Date formats corresponding to compound %r and %T conversion specifiers
......@@ -1370,15 +1360,7 @@ bool get_interval_value(Item *args,interval_type int_type,
String *Item_temporal_func::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
MYSQL_TIME ltime;
if (get_date(&ltime, TIME_FUZZY_DATE))
return (String *) 0;
if (make_datetime(&ltime, str, decimals))
{
null_value= 1;
return (String *) 0;
}
return str;
return val_string_from_date(str);
}
......@@ -2672,7 +2654,7 @@ longlong Item_func_microsecond::val_int()
{
DBUG_ASSERT(fixed == 1);
MYSQL_TIME ltime;
if (!get_arg0_date(&ltime, TIME_FUZZY_DATE))
if (!get_arg0_date(&ltime, TIME_TIME_ONLY))
return ltime.second_part;
return 0;
}
......
......@@ -2503,12 +2503,6 @@ const char *get_date_time_format_str(KNOWN_DATE_TIME_FORMAT *format,
timestamp_type type);
extern bool make_date_time(DATE_TIME_FORMAT *format, MYSQL_TIME *l_time,
timestamp_type type, String *str);
void make_datetime(const DATE_TIME_FORMAT *format, const MYSQL_TIME *l_time,
String *str);
void make_date(const DATE_TIME_FORMAT *format, const MYSQL_TIME *l_time,
String *str);
void make_time(const DATE_TIME_FORMAT *format, const MYSQL_TIME *l_time,
String *str);
int my_time_compare(MYSQL_TIME *a, MYSQL_TIME *b);
longlong get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg,
Item *warn_item, bool *is_null);
......
......@@ -756,49 +756,6 @@ const char *get_date_time_format_str(KNOWN_DATE_TIME_FORMAT *format,
}
}
/****************************************************************************
Functions to create default time/date/datetime strings
NOTE:
For the moment the DATE_TIME_FORMAT argument is ignored becasue
MySQL doesn't support comparing of date/time/datetime strings that
are not in arbutary order as dates are compared as strings in some
context)
This functions don't check that given MYSQL_TIME structure members are
in valid range. If they are not, return value won't reflect any
valid date either.
****************************************************************************/
void make_time(const DATE_TIME_FORMAT *format __attribute__((unused)),
const MYSQL_TIME *l_time, String *str)
{
str->alloc(MAX_DATE_STRING_REP_LENGTH);
uint length= (uint) my_time_to_str(l_time, (char*) str->ptr(), 0);
str->length(length);
str->set_charset(&my_charset_bin);
}
void make_date(const DATE_TIME_FORMAT *format __attribute__((unused)),
const MYSQL_TIME *l_time, String *str)
{
str->alloc(MAX_DATE_STRING_REP_LENGTH);
uint length= (uint) my_date_to_str(l_time, (char*) str->ptr());
str->length(length);
str->set_charset(&my_charset_bin);
}
void make_datetime(const DATE_TIME_FORMAT *format __attribute__((unused)),
const MYSQL_TIME *l_time, String *str)
{
str->alloc(MAX_DATE_STRING_REP_LENGTH);
uint length= (uint) my_datetime_to_str(l_time, (char*) str->ptr(), 0);
str->length(length);
str->set_charset(&my_charset_bin);
}
void make_truncated_value_warning(THD *thd,
MYSQL_ERROR::enum_warning_level level,
const Lazy_string *sval,
......
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