summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorSergei Golubchik <sergii@pisem.net>2011-03-01 13:24:36 +0100
committerSergei Golubchik <sergii@pisem.net>2011-03-01 13:24:36 +0100
commita8a757c6bb32bbf291afdf33df861127489889ab (patch)
treecee7858869789964ad21b2b90b420f1128d9a10d /sql
parent7e0e4b00c971b81b5ffd18db4f1ea977233e98be (diff)
downloadmariadb-git-a8a757c6bb32bbf291afdf33df861127489889ab.tar.gz
wl#173 - temporal types with sub-second resolution
and collateral changes. * introduce my_hrtime_t, my_timediff_t, and conversion macros * inroduce TIME_RESULT, but it can only be returned from Item::cmp_type(), never from Item::result_type() * pack_time/unpack_time function for "packed" representation of MYSQL_TIME in a longlong that can be compared * ADDTIME()/SUBTIME()/+- INTERVAL now work with TIME values * numbers aren't quoted in EXPLAIN EXTENDED * new column I_S.COLUMNS.DATETIME_PRECISION * date/time values are compares to anything as date/time, not as strings or numbers. * old timestamp(X) is no longer supported * MYSQL_TIME to string conversion functions take precision as an argument * unified the warnings from Field_timestamp/datetime/time/date/newdate store methods * Field_timestamp_hires, Field_datetime_hires, Field_time_hires * Field_temporal * Lazy_string class to pass a value (string, number, time) polymorphically down the stack * make_truncated_value_warning and Field::set_datetime_warning use Lazy_string as an argument, removed char*/int/double variants * removed Field::can_be_compared_as_longlong(). Use Field::cmp_type() == INT_RESULT instead * introduced Item::cmp_result() instead of Item::is_datetime() and Item::result_as_longlong() * in many cases date/time types are treated like other types, not as special cases * greatly simplified Arg_comparator (regarding date/time/year code) * SEC_TO_TIME is real function, not integer. * microsecond precision in NOW, CURTIME, etc * Item_temporal. All items derived from it only provide get_date, but no val* methods * replication of NOW(6) * Protocol::store(time) now takes the precision as an argument * @@TIMESTAMP is a double client/mysqlbinlog.cc: remove unneded casts include/my_sys.h: introduce my_hrtime_t, my_timediff_t, and conversion macros include/my_time.h: pack_time/unpack_time, etc. convenience functions to work with MYSQL_TIME::second_part libmysql/libmysql.c: str_to_time() is gone. str_to_datetime() does it now. my_TIME_to_str() takes the precision as an argument mysql-test/include/ps_conv.inc: time is not equal to datetime anymore mysql-test/r/distinct.result: a test for an old MySQL bug mysql-test/r/explain.result: numbers aren't quoted in EXPLAIN EXTENDED mysql-test/r/func_default.result: numbers aren't quoted in EXPLAIN EXTENDED mysql-test/r/func_sapdb.result: when decimals=NOT_FIXED_DEC it means "not fixed" indeed mysql-test/r/func_test.result: numbers aren't quoted in EXPLAIN EXTENDED mysql-test/r/func_time.result: ADDTIME()/SUBTIME()/+- INTERVAL now work with TIME values mysql-test/r/having.result: numbers aren't quoted in EXPLAIN EXTENDED mysql-test/r/information_schema.result: new column I_S.COLUMNS.DATETIME_PRECISION mysql-test/r/join_outer.result: numbers aren't quoted in EXPLAIN EXTENDED mysql-test/r/metadata.result: TIMESTAMP no longer has zerofill flag mysql-test/r/range.result: invalid datetime is not compared with as a string mysql-test/r/select.result: NO_ZERO_IN_DATE, etc only affect storage - according to the manual numbers aren't quoted in EXPLAIN EXTENDED mysql-test/r/subselect.result: numbers aren't quoted in EXPLAIN EXTENDED mysql-test/r/sysdate_is_now.result: when decimals=NOT_FIXED_DEC it means "not fixed" indeed mysql-test/r/type_blob.result: TIMESTAMP(N) is not deprecated mysql-test/r/type_timestamp.result: old TIMESTAMP(X) semantics is not supported anymore mysql-test/r/union.result: numbers aren't quoted in EXPLAIN EXTENDED mysql-test/r/varbinary.result: numbers aren't quoted in EXPLAIN EXTENDED mysql-test/t/distinct.test: test for an old MySQL bug mysql-test/t/func_time.test: +- INTERVAL now works with TIME values mysql-test/t/select.test: typo mysql-test/t/subselect.test: only one error per statement, please mysql-test/t/system_mysql_db_fix40123.test: old timestamp(X) is no longer supported mysql-test/t/system_mysql_db_fix50030.test: old timestamp(X) is no longer supported mysql-test/t/system_mysql_db_fix50117.test: old timestamp(X) is no longer supported mysql-test/t/type_blob.test: old timestamp(X) is no longer supported mysql-test/t/type_timestamp.test: old timestamp(X) is no longer supported mysys/my_getsystime.c: functions to get the time with microsecond precision mysys/my_init.c: move the my_getsystime.c initialization code to my_getsystime.c mysys/my_static.c: no need to make these variables extern mysys/my_static.h: no need to make these variables extern scripts/mysql_system_tables.sql: old timestamp(X) is no longer supported scripts/mysql_system_tables_fix.sql: old timestamp(X) is no longer supported scripts/mysqlhotcopy.sh: old timestamp(X) is no longer supported sql-common/my_time.c: * call str_to_time from str_to_datetime, as appropriate * date/time to string conversions take precision as an argument * number_to_time() * TIME_to_double() * pack_time() and unpack_time() sql/event_data_objects.cc: cast is not needed my_datetime_to_str() takes precision as an argument sql/event_db_repository.cc: avoid dangerous downcast (because the pointer is not always Field_timestamp, see events_1.test) sql/event_queue.cc: avoid silly double-work for cond_wait (having an endpoint of wait, subtract the current time to get the timeout, and use set_timespec() macro to fill in struct timespec, by adding the current time to the timeout) sql/field.cc: * remove virtual Field::get_time(), everyone should use only Field::get_date() * remove lots of #ifdef WORDS_BIGENDIAN * unified the warnings from Field_timestamp/datetime/time/date/newdate store methods * Field_timestamp_hires, Field_datetime_hires, Field_time_hires * Field_temporal * make_truncated_value_warning and Field::set_datetime_warning use Lazy_string as an argument, removed char*/int/double variants sql/field.h: * remove virtual Field::get_time(), everyone should use only Field::get_date() * remove lots of #ifdef WORDS_BIGENDIAN * unified the warnings from Field_timestamp/datetime/time/date/newdate store methods * Field_timestamp_hires, Field_datetime_hires, Field_time_hires * Field_temporal * make_truncated_value_warning and Field::set_datetime_warning use Lazy_string as an argument, removed char*/int/double variants * removed Field::can_be_compared_as_longlong(). Use Field::cmp_type() == INT_RESULT instead sql/filesort.cc: TIME_RESULT, cmp_time() sql/item.cc: * numbers aren't quoted in EXPLAIN EXTENDED * Item::cmp_result() instead of Item::is_datetime() and Item::result_as_longlong() * virtual Item::get_time() is gone * Item_param::field_type() is set correctly * Item_datetime, for a datetime constant * time to anything is compared as a time * Item_cache::print() prints the value is available * bug fixed in Item_cache_int::val_str() sql/item.h: * Item::print_value(), to be used from Item_xxx::print() when needed * Item::cmp_result() instead of Item::is_datetime() and Item::result_as_longlong() * virtual Item::get_time() is gone * Item_datetime, for a datetime constant * better default for cast_to_int_type() * Item_cache objects now *always* have the field_type() set sql/item_cmpfunc.cc: * get_year_value, get_time_value are gone. get_datetime_value does it all * get_value_a_func, get_value_b_func are gone * can_compare_as_dates() is gone too, TIME_RESULT is used instead * cmp_type() instead or result_type() when doing a comparison * compare_datetime and compate_e_datetime in the comparator_matrix, is_nulls_eq is gone * Item::cmp_result() instead of Item::is_datetime() and Item::result_as_longlong() sql/item_cmpfunc.h: greatly simplified Arg_comparator sql/item_create.cc: * fix a bug in error messages in CAST sql/item_func.cc: Item::cmp_result() instead of Item::is_datetime() and Item::result_as_longlong() mention all possibitiles in switch over Item_result values, or use default: sql/item_row.h: overwrite the default cmp_type() for Item_row, as no MYSQL_TYPE_xxx value corresponds to ROW_RESULT sql/item_timefunc.cc: rewrite make_datetime to support precision argument SEC_TO_TIME is real function, not integer. many functions that returned temporal values had duplicate code in val_* methods, some of them did not have get_date() which resulted in unnecessary date->str->date conversions. Now they all are derived from Item_temporal_func and *only* provide get_date, not val* methods. many fixes to set decimals (datetime precision) correctly. sql/item_timefunc.h: SEC_TO_TIME is real function, not integer. many functions that returned temporal values had duplicate code in val_* methods, some of them did not have get_date() which resulted in unnecessary date->str->date conversions. Now they all are derived from Item_temporal_func and *only* provide get_date, not val* methods. many fixes to set decimals (datetime precision) correctly. sql/log_event.cc: replication of NOW(6) sql/log_event.h: replication of NOW(6) sql/mysql_priv.h: Lazy_string class to pass a value (string, number, time) polymorphically down the stack. make_truncated_value_warning() that uses it. sql/mysqld.cc: datetime in Arg_comparator::comparator_matrix sql/opt_range.cc: cleanup: don't disable warnings before calling save_in_field_no_warnings() sql/protocol.cc: Protocol::store(time) now takes the precision as an argument sql/protocol.h: Protocol::store(time) now takes the precision as an argument sql/rpl_rli.cc: small cleanup sql/set_var.cc: SET TIMESTAMP=double sql/set_var.h: @@TIMESTAMP is a double sql/share/errmsg.txt: precision and scale are unsigned sql/slave.cc: replication of NOW(6) sql/sp_head.cc: cleanup sql/sql_class.cc: support for NOW(6) sql/sql_class.h: support for NOW(6) sql/sql_insert.cc: support for NOW(6) sql/sql_select.cc: use item->cmp_type(). move a comment where it belongs sql/sql_show.cc: new column I_S.COLUMNS.DATETIME_PRECISION sql/sql_yacc.yy: TIME(X), DATETIME(X), cast, NOW(X), CURTIME(X), etc sql/time.cc: fix date_add_interval() to support MYSQL_TIMESTAMP_TIME argument storage/myisam/ha_myisam.cc: TIMESTAMP no longer carries ZEROFIELD flag, still we keep MYI file compatible. strings/my_vsnprintf.c: warnings tests/mysql_client_test.c: old timestamp(X) does not work anymore datetime is no longer equal to time
Diffstat (limited to 'sql')
-rw-r--r--sql/event_data_objects.cc6
-rw-r--r--sql/event_db_repository.cc7
-rw-r--r--sql/event_parse_data.cc2
-rw-r--r--sql/event_queue.cc8
-rw-r--r--sql/event_queue.h2
-rw-r--r--sql/field.cc1878
-rw-r--r--sql/field.h356
-rw-r--r--sql/filesort.cc45
-rw-r--r--sql/item.cc235
-rw-r--r--sql/item.h60
-rw-r--r--sql/item_cmpfunc.cc741
-rw-r--r--sql/item_cmpfunc.h44
-rw-r--r--sql/item_create.cc50
-rw-r--r--sql/item_func.cc108
-rw-r--r--sql/item_func.h10
-rw-r--r--sql/item_row.h1
-rw-r--r--sql/item_sum.cc9
-rw-r--r--sql/item_timefunc.cc881
-rw-r--r--sql/item_timefunc.h407
-rw-r--r--sql/log.cc12
-rw-r--r--sql/log_event.cc71
-rw-r--r--sql/log_event.h25
-rw-r--r--sql/log_event_old.cc4
-rw-r--r--sql/mysql_priv.h70
-rw-r--r--sql/mysqld.cc5
-rw-r--r--sql/opt_range.cc30
-rw-r--r--sql/protocol.cc51
-rw-r--r--sql/protocol.h12
-rw-r--r--sql/rpl_rli.cc6
-rw-r--r--sql/set_var.cc20
-rw-r--r--sql/set_var.h6
-rw-r--r--sql/share/errmsg.txt8
-rw-r--r--sql/slave.cc6
-rw-r--r--sql/sp_head.cc14
-rw-r--r--sql/sql_class.cc8
-rw-r--r--sql/sql_class.h46
-rw-r--r--sql/sql_insert.cc13
-rw-r--r--sql/sql_parse.cc29
-rw-r--r--sql/sql_prepare.cc3
-rw-r--r--sql/sql_select.cc41
-rw-r--r--sql/sql_show.cc67
-rw-r--r--sql/sql_table.cc24
-rw-r--r--sql/sql_yacc.yy83
-rw-r--r--sql/time.cc105
-rw-r--r--sql/unireg.h5
45 files changed, 2295 insertions, 3319 deletions
diff --git a/sql/event_data_objects.cc b/sql/event_data_objects.cc
index 6119a97dbf9..da502b9e639 100644
--- a/sql/event_data_objects.cc
+++ b/sql/event_data_objects.cc
@@ -928,7 +928,7 @@ Event_queue_element::compute_next_execution_time()
goto ret;
}
- time_now= (my_time_t) current_thd->query_start();
+ time_now= current_thd->query_start();
DBUG_PRINT("info",("NOW: [%lu]", (ulong) time_now));
@@ -1131,7 +1131,7 @@ err:
void
Event_queue_element::mark_last_executed(THD *thd)
{
- last_executed= (my_time_t) thd->query_start();
+ last_executed= thd->query_start();
last_executed_changed= TRUE;
execution_count++;
@@ -1191,7 +1191,7 @@ append_datetime(String *buf, Time_zone *time_zone, my_time_t secs,
*/
MYSQL_TIME time;
time_zone->gmt_sec_to_TIME(&time, secs);
- buf->append(dtime_buff, my_datetime_to_str(&time, dtime_buff));
+ buf->append(dtime_buff, my_datetime_to_str(&time, dtime_buff, 0));
buf->append(STRING_WITH_LEN("'"));
}
diff --git a/sql/event_db_repository.cc b/sql/event_db_repository.cc
index 753e9d21b65..bf17c94df3e 100644
--- a/sql/event_db_repository.cc
+++ b/sql/event_db_repository.cc
@@ -231,6 +231,9 @@ mysql_event_fill_row(THD *thd,
rs|= fields[ET_FIELD_STATUS]->store((longlong)et->status, TRUE);
rs|= fields[ET_FIELD_ORIGINATOR]->store((longlong)et->originator, TRUE);
+ if (!is_update)
+ rs|= fields[ET_FIELD_CREATED]->set_time();
+
/*
Change the SQL_MODE only if body was present in an ALTER EVENT and of course
always during CREATE EVENT.
@@ -317,7 +320,7 @@ mysql_event_fill_row(THD *thd,
*/
}
- ((Field_timestamp *)fields[ET_FIELD_MODIFIED])->set_time();
+ rs|= fields[ET_FIELD_MODIFIED]->set_time();
if (et->comment.str)
{
@@ -671,8 +674,6 @@ Event_db_repository::create_event(THD *thd, Event_parse_data *parse_data,
goto end;
}
- ((Field_timestamp *)table->field[ET_FIELD_CREATED])->set_time();
-
/*
mysql_event_fill_row() calls my_error() in case of error so no need to
handle it here
diff --git a/sql/event_parse_data.cc b/sql/event_parse_data.cc
index 86905b38627..04416232eb4 100644
--- a/sql/event_parse_data.cc
+++ b/sql/event_parse_data.cc
@@ -111,7 +111,7 @@ Event_parse_data::init_name(THD *thd, sp_name *spn)
void
Event_parse_data::check_if_in_the_past(THD *thd, my_time_t ltime_utc)
{
- if (ltime_utc >= (my_time_t) thd->query_start())
+ if (ltime_utc >= thd->query_start())
return;
/*
diff --git a/sql/event_queue.cc b/sql/event_queue.cc
index 04d4f858b43..9ea5ff6e79f 100644
--- a/sql/event_queue.cc
+++ b/sql/event_queue.cc
@@ -513,9 +513,10 @@ Event_queue::empty_queue()
*/
void
-Event_queue::dbug_dump_queue(time_t now)
+Event_queue::dbug_dump_queue(my_time_t when)
{
#ifndef DBUG_OFF
+ my_time_t now= when;
Event_queue_element *et;
uint i;
DBUG_ENTER("Event_queue::dbug_dump_queue");
@@ -592,14 +593,13 @@ Event_queue::get_top_for_execution_if_time(THD *thd,
thd->set_current_time(); /* Get current time */
next_activation_at= top->execute_at;
- if (next_activation_at > thd->query_start())
+ if (next_activation_at >thd->query_start())
{
/*
Not yet time for top event, wait on condition with
time or until signaled. Release LOCK_queue while waiting.
*/
- struct timespec top_time;
- set_timespec(top_time, next_activation_at - thd->query_start());
+ struct timespec top_time= { next_activation_at, 0 };
cond_wait(thd, &top_time, queue_wait_msg, SCHED_FUNC, __LINE__);
continue;
diff --git a/sql/event_queue.h b/sql/event_queue.h
index 2870ecb4d0b..e1f814adf20 100644
--- a/sql/event_queue.h
+++ b/sql/event_queue.h
@@ -98,7 +98,7 @@ private:
void
- dbug_dump_queue(time_t now);
+ dbug_dump_queue(my_time_t now);
/* LOCK_event_queue is the mutex which protects the access to the queue. */
pthread_mutex_t LOCK_event_queue;
diff --git a/sql/field.cc b/sql/field.cc
index 724f8e0af73..43e210d1bc9 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -1735,18 +1735,8 @@ bool Field::get_date(MYSQL_TIME *ltime,uint fuzzydate)
char buff[40];
String tmp(buff,sizeof(buff),&my_charset_bin),*res;
if (!(res=val_str(&tmp)) ||
- str_to_datetime_with_warn(res->ptr(), res->length(),
- ltime, fuzzydate) <= MYSQL_TIMESTAMP_ERROR)
- return 1;
- return 0;
-}
-
-bool Field::get_time(MYSQL_TIME *ltime)
-{
- char buff[40];
- String tmp(buff,sizeof(buff),&my_charset_bin),*res;
- if (!(res=val_str(&tmp)) ||
- str_to_time_with_warn(res->ptr(), res->length(), ltime))
+ str_to_datetime_with_warn(res->ptr(), res->length(),
+ ltime, fuzzydate) <= MYSQL_TIMESTAMP_ERROR)
return 1;
return 0;
}
@@ -1762,7 +1752,7 @@ int Field::store_time(MYSQL_TIME *ltime, timestamp_type type_arg)
{
ASSERT_COLUMN_MARKED_FOR_WRITE;
char buff[MAX_DATE_STRING_REP_LENGTH];
- uint length= (uint) my_TIME_to_str(ltime, buff);
+ uint length= (uint) my_TIME_to_str(ltime, buff, decimals());
return store(buff, length, &my_charset_bin);
}
@@ -3151,13 +3141,9 @@ int Field_short::store(const char *from,uint len,CHARSET_INFO *cs)
error= get_int(cs, from, len, &rnd, UINT_MAX16, INT_MIN16, INT_MAX16);
store_tmp= unsigned_flag ? (int) (ulonglong) rnd : (int) rnd;
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- {
+ if (BIGENDIAN && table->s->db_low_byte_first)
int2store(ptr, store_tmp);
- }
else
-#endif
shortstore(ptr, (short) store_tmp);
return error;
}
@@ -3203,13 +3189,9 @@ int Field_short::store(double nr)
else
res=(int16) (int) nr;
}
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- {
+ if (BIGENDIAN && table->s->db_low_byte_first)
int2store(ptr,res);
- }
else
-#endif
shortstore(ptr,res);
return error;
}
@@ -3258,13 +3240,9 @@ int Field_short::store(longlong nr, bool unsigned_val)
else
res=(int16) nr;
}
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- {
+ if (BIGENDIAN && table->s->db_low_byte_first)
int2store(ptr,res);
- }
else
-#endif
shortstore(ptr,res);
return error;
}
@@ -3274,11 +3252,9 @@ double Field_short::val_real(void)
{
ASSERT_COLUMN_MARKED_FOR_READ;
short j;
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
+ if (BIGENDIAN && table->s->db_low_byte_first)
j=sint2korr(ptr);
else
-#endif
shortget(j,ptr);
return unsigned_flag ? (double) (unsigned short) j : (double) j;
}
@@ -3287,11 +3263,9 @@ longlong Field_short::val_int(void)
{
ASSERT_COLUMN_MARKED_FOR_READ;
short j;
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
+ if (BIGENDIAN && table->s->db_low_byte_first)
j=sint2korr(ptr);
else
-#endif
shortget(j,ptr);
return unsigned_flag ? (longlong) (unsigned short) j : (longlong) j;
}
@@ -3307,11 +3281,9 @@ String *Field_short::val_str(String *val_buffer,
val_buffer->alloc(mlength);
char *to=(char*) val_buffer->ptr();
short j;
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
+ if (BIGENDIAN && table->s->db_low_byte_first)
j=sint2korr(ptr);
else
-#endif
shortget(j,ptr);
if (unsigned_flag)
@@ -3335,14 +3307,12 @@ bool Field_short::send_binary(Protocol *protocol)
int Field_short::cmp(const uchar *a_ptr, const uchar *b_ptr)
{
short a,b;
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
+ if (BIGENDIAN && table->s->db_low_byte_first)
{
a=sint2korr(a_ptr);
b=sint2korr(b_ptr);
}
else
-#endif
{
shortget(a,a_ptr);
shortget(b,b_ptr);
@@ -3356,8 +3326,7 @@ int Field_short::cmp(const uchar *a_ptr, const uchar *b_ptr)
void Field_short::sort_string(uchar *to,uint length __attribute__((unused)))
{
-#ifdef WORDS_BIGENDIAN
- if (!table->s->db_low_byte_first)
+ if (BIGENDIAN && !table->s->db_low_byte_first)
{
if (unsigned_flag)
to[0] = ptr[0];
@@ -3366,7 +3335,6 @@ void Field_short::sort_string(uchar *to,uint length __attribute__((unused)))
to[1] = ptr[1];
}
else
-#endif
{
if (unsigned_flag)
to[0] = ptr[1];
@@ -3588,13 +3556,9 @@ int Field_long::store(const char *from,uint len,CHARSET_INFO *cs)
error= get_int(cs, from, len, &rnd, UINT_MAX32, INT_MIN32, INT_MAX32);
store_tmp= unsigned_flag ? (long) (ulonglong) rnd : (long) rnd;
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- {
+ if (BIGENDIAN && table->s->db_low_byte_first)
int4store(ptr, store_tmp);
- }
else
-#endif
longstore(ptr, store_tmp);
return error;
}
@@ -3640,13 +3604,9 @@ int Field_long::store(double nr)
if (error)
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- {
+ if (BIGENDIAN && table->s->db_low_byte_first)
int4store(ptr,res);
- }
else
-#endif
longstore(ptr,res);
return error;
}
@@ -3693,13 +3653,9 @@ int Field_long::store(longlong nr, bool unsigned_val)
if (error)
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- {
+ if (BIGENDIAN && table->s->db_low_byte_first)
int4store(ptr,res);
- }
else
-#endif
longstore(ptr,res);
return error;
}
@@ -3709,11 +3665,9 @@ double Field_long::val_real(void)
{
ASSERT_COLUMN_MARKED_FOR_READ;
int32 j;
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
+ if (BIGENDIAN && table->s->db_low_byte_first)
j=sint4korr(ptr);
else
-#endif
longget(j,ptr);
return unsigned_flag ? (double) (uint32) j : (double) j;
}
@@ -3724,11 +3678,9 @@ longlong Field_long::val_int(void)
int32 j;
/* See the comment in Field_long::store(long long) */
DBUG_ASSERT(table->in_use == current_thd);
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
+ if (BIGENDIAN && table->s->db_low_byte_first)
j=sint4korr(ptr);
else
-#endif
longget(j,ptr);
return unsigned_flag ? (longlong) (uint32) j : (longlong) j;
}
@@ -3743,11 +3695,9 @@ String *Field_long::val_str(String *val_buffer,
val_buffer->alloc(mlength);
char *to=(char*) val_buffer->ptr();
int32 j;
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
+ if (BIGENDIAN && table->s->db_low_byte_first)
j=sint4korr(ptr);
else
-#endif
longget(j,ptr);
if (unsigned_flag)
@@ -3770,14 +3720,12 @@ bool Field_long::send_binary(Protocol *protocol)
int Field_long::cmp(const uchar *a_ptr, const uchar *b_ptr)
{
int32 a,b;
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
+ if (BIGENDIAN && table->s->db_low_byte_first)
{
a=sint4korr(a_ptr);
b=sint4korr(b_ptr);
}
else
-#endif
{
longget(a,a_ptr);
longget(b,b_ptr);
@@ -3789,8 +3737,7 @@ int Field_long::cmp(const uchar *a_ptr, const uchar *b_ptr)
void Field_long::sort_string(uchar *to,uint length __attribute__((unused)))
{
-#ifdef WORDS_BIGENDIAN
- if (!table->s->db_low_byte_first)
+ if (BIGENDIAN && !table->s->db_low_byte_first)
{
if (unsigned_flag)
to[0] = ptr[0];
@@ -3801,7 +3748,6 @@ void Field_long::sort_string(uchar *to,uint length __attribute__((unused)))
to[3] = ptr[3];
}
else
-#endif
{
if (unsigned_flag)
to[0] = ptr[3];
@@ -3844,13 +3790,9 @@ int Field_longlong::store(const char *from,uint len,CHARSET_INFO *cs)
error= 1;
else
error= 0;
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- {
+ if (BIGENDIAN && table->s->db_low_byte_first)
int8store(ptr,tmp);
- }
else
-#endif
longlongstore(ptr,tmp);
return error;
}
@@ -3896,13 +3838,9 @@ int Field_longlong::store(double nr)
if (error)
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- {
+ if (BIGENDIAN && table->s->db_low_byte_first)
int8store(ptr,res);
- }
else
-#endif
longlongstore(ptr,res);
return error;
}
@@ -3927,13 +3865,9 @@ int Field_longlong::store(longlong nr, bool unsigned_val)
}
}
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- {
+ if (BIGENDIAN && table->s->db_low_byte_first)
int8store(ptr,nr);
- }
else
-#endif
longlongstore(ptr,nr);
return error;
}
@@ -3943,13 +3877,9 @@ double Field_longlong::val_real(void)
{
ASSERT_COLUMN_MARKED_FOR_READ;
longlong j;
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- {
+ if (BIGENDIAN && table->s->db_low_byte_first)
j=sint8korr(ptr);
- }
else
-#endif
longlongget(j,ptr);
/* The following is open coded to avoid a bug in gcc 3.3 */
if (unsigned_flag)
@@ -3965,11 +3895,9 @@ longlong Field_longlong::val_int(void)
{
ASSERT_COLUMN_MARKED_FOR_READ;
longlong j;
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
+ if (BIGENDIAN && table->s->db_low_byte_first)
j=sint8korr(ptr);
else
-#endif
longlongget(j,ptr);
return j;
}
@@ -3984,11 +3912,9 @@ String *Field_longlong::val_str(String *val_buffer,
val_buffer->alloc(mlength);
char *to=(char*) val_buffer->ptr();
longlong j;
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
+ if (BIGENDIAN && table->s->db_low_byte_first)
j=sint8korr(ptr);
else
-#endif
longlongget(j,ptr);
length=(uint) (cs->cset->longlong10_to_str)(cs,to,mlength,
@@ -4010,14 +3936,12 @@ bool Field_longlong::send_binary(Protocol *protocol)
int Field_longlong::cmp(const uchar *a_ptr, const uchar *b_ptr)
{
longlong a,b;
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
+ if (BIGENDIAN && table->s->db_low_byte_first)
{
a=sint8korr(a_ptr);
b=sint8korr(b_ptr);
}
else
-#endif
{
longlongget(a,a_ptr);
longlongget(b,b_ptr);
@@ -4030,8 +3954,7 @@ int Field_longlong::cmp(const uchar *a_ptr, const uchar *b_ptr)
void Field_longlong::sort_string(uchar *to,uint length __attribute__((unused)))
{
-#ifdef WORDS_BIGENDIAN
- if (!table->s->db_low_byte_first)
+ if (BIGENDIAN && !table->s->db_low_byte_first)
{
if (unsigned_flag)
to[0] = ptr[0];
@@ -4046,7 +3969,6 @@ void Field_longlong::sort_string(uchar *to,uint length __attribute__((unused)))
to[7] = ptr[7];
}
else
-#endif
{
if (unsigned_flag)
to[0] = ptr[7];
@@ -4082,8 +4004,7 @@ Field_real::pack(uchar *to, const uchar *from,
{
DBUG_ENTER("Field_real::pack");
DBUG_ASSERT(max_length >= pack_length());
-#ifdef WORDS_BIGENDIAN
- if (low_byte_first != table->s->db_low_byte_first)
+ if (BIGENDIAN && low_byte_first != table->s->db_low_byte_first)
{
const uchar *dptr= from + pack_length();
while (dptr-- > from)
@@ -4091,7 +4012,6 @@ Field_real::pack(uchar *to, const uchar *from,
DBUG_RETURN(to);
}
else
-#endif
DBUG_RETURN(Field::pack(to, from, max_length, low_byte_first));
}
@@ -4100,8 +4020,7 @@ Field_real::unpack(uchar *to, const uchar *from,
uint param_data, bool low_byte_first)
{
DBUG_ENTER("Field_real::unpack");
-#ifdef WORDS_BIGENDIAN
- if (low_byte_first != table->s->db_low_byte_first)
+ if (BIGENDIAN && low_byte_first != table->s->db_low_byte_first)
{
const uchar *dptr= from + pack_length();
while (dptr-- > from)
@@ -4109,7 +4028,6 @@ Field_real::unpack(uchar *to, const uchar *from,
DBUG_RETURN(from + pack_length());
}
else
-#endif
DBUG_RETURN(Field::unpack(to, from, param_data, low_byte_first));
}
@@ -4140,13 +4058,9 @@ int Field_float::store(double nr)
int error= truncate(&nr, FLT_MAX);
float j= (float)nr;
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- {
+ if (BIGENDIAN && table->s->db_low_byte_first)
float4store(ptr,j);
- }
else
-#endif
memcpy_fixed(ptr,(uchar*) &j,sizeof(j));
return error;
}
@@ -4163,13 +4077,9 @@ double Field_float::val_real(void)
{
ASSERT_COLUMN_MARKED_FOR_READ;
float j;
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- {
+ if (BIGENDIAN && table->s->db_low_byte_first)
float4get(j,ptr);
- }
else
-#endif
memcpy_fixed((uchar*) &j,ptr,sizeof(j));
return ((double) j);
}
@@ -4177,13 +4087,9 @@ double Field_float::val_real(void)
longlong Field_float::val_int(void)
{
float j;
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- {
+ if (BIGENDIAN && table->s->db_low_byte_first)
float4get(j,ptr);
- }
else
-#endif
memcpy_fixed((uchar*) &j,ptr,sizeof(j));
return (longlong) rint(j);
}
@@ -4194,13 +4100,9 @@ String *Field_float::val_str(String *val_buffer,
{
ASSERT_COLUMN_MARKED_FOR_READ;
float nr;
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- {
+ if (BIGENDIAN && table->s->db_low_byte_first)
float4get(nr,ptr);
- }
else
-#endif
memcpy_fixed((uchar*) &nr,ptr,sizeof(nr));
uint to_length=max(field_length,70);
@@ -4276,14 +4178,12 @@ String *Field_float::val_str(String *val_buffer,
int Field_float::cmp(const uchar *a_ptr, const uchar *b_ptr)
{
float a,b;
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
+ if (BIGENDIAN && table->s->db_low_byte_first)
{
float4get(a,a_ptr);
float4get(b,b_ptr);
}
else
-#endif
{
memcpy_fixed(&a,a_ptr,sizeof(float));
memcpy_fixed(&b,b_ptr,sizeof(float));
@@ -4296,13 +4196,9 @@ int Field_float::cmp(const uchar *a_ptr, const uchar *b_ptr)
void Field_float::sort_string(uchar *to,uint length __attribute__((unused)))
{
float nr;
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- {
+ if (BIGENDIAN && table->s->db_low_byte_first)
float4get(nr,ptr);
- }
else
-#endif
memcpy_fixed(&nr,ptr,sizeof(float));
uchar *tmp= to;
@@ -4401,13 +4297,9 @@ int Field_double::store(double nr)
ASSERT_COLUMN_MARKED_FOR_WRITE;
int error= truncate(&nr, DBL_MAX);
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- {
+ if (BIGENDIAN && table->s->db_low_byte_first)
float8store(ptr,nr);
- }
else
-#endif
doublestore(ptr,nr);
return error;
}
@@ -4488,13 +4380,9 @@ double Field_double::val_real(void)
{
ASSERT_COLUMN_MARKED_FOR_READ;
double j;
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- {
+ if (BIGENDIAN && table->s->db_low_byte_first)
float8get(j,ptr);
- }
else
-#endif
doubleget(j,ptr);
return j;
}
@@ -4504,13 +4392,9 @@ longlong Field_double::val_int(void)
ASSERT_COLUMN_MARKED_FOR_READ;
double j;
longlong res;
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- {
+ if (BIGENDIAN && table->s->db_low_byte_first)
float8get(j,ptr);
- }
else
-#endif
doubleget(j,ptr);
/* Check whether we fit into longlong range */
if (j <= (double) LONGLONG_MIN)
@@ -4552,13 +4436,9 @@ String *Field_double::val_str(String *val_buffer,
{
ASSERT_COLUMN_MARKED_FOR_READ;
double nr;
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- {
+ if (BIGENDIAN && table->s->db_low_byte_first)
float8get(nr,ptr);
- }
else
-#endif
doubleget(nr,ptr);
uint to_length= DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE;
@@ -4640,14 +4520,12 @@ bool Field_double::send_binary(Protocol *protocol)
int Field_double::cmp(const uchar *a_ptr, const uchar *b_ptr)
{
double a,b;
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
+ if (BIGENDIAN && table->s->db_low_byte_first)
{
float8get(a,a_ptr);
float8get(b,b_ptr);
}
else
-#endif
{
doubleget(a, a_ptr);
doubleget(b, b_ptr);
@@ -4663,13 +4541,9 @@ int Field_double::cmp(const uchar *a_ptr, const uchar *b_ptr)
void Field_double::sort_string(uchar *to,uint length __attribute__((unused)))
{
double nr;
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- {
+ if (BIGENDIAN && table->s->db_low_byte_first)
float8get(nr,ptr);
- }
else
-#endif
doubleget(nr,ptr);
change_double_for_sort(nr, to);
}
@@ -4758,12 +4632,12 @@ Field_timestamp::Field_timestamp(uchar *ptr_arg, uint32 len_arg,
const char *field_name_arg,
TABLE_SHARE *share,
CHARSET_INFO *cs)
- :Field_str(ptr_arg, MAX_DATETIME_WIDTH, null_ptr_arg, null_bit_arg,
+ :Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg, cs)
{
/* For 4.0 MYD and 4.0 InnoDB compatibility */
- flags|= ZEROFILL_FLAG | UNSIGNED_FLAG;
- if (!share->timestamp_field && unireg_check != NONE)
+ flags|= UNSIGNED_FLAG;
+ if (unireg_check != NONE && !share->timestamp_field)
{
/* This timestamp has auto-update */
share->timestamp_field= this;
@@ -4774,20 +4648,6 @@ Field_timestamp::Field_timestamp(uchar *ptr_arg, uint32 len_arg,
}
-Field_timestamp::Field_timestamp(bool maybe_null_arg,
- const char *field_name_arg,
- CHARSET_INFO *cs)
- :Field_str((uchar*) 0, MAX_DATETIME_WIDTH,
- maybe_null_arg ? (uchar*) "": 0, 0,
- NONE, field_name_arg, cs)
-{
- /* For 4.0 MYD and 4.0 InnoDB compatibility */
- flags|= ZEROFILL_FLAG | UNSIGNED_FLAG;
- if (unireg_check != TIMESTAMP_DN_FIELD)
- flags|= ON_UPDATE_NOW_FLAG;
-}
-
-
/**
Get auto-set type for TIMESTAMP field.
@@ -4822,136 +4682,136 @@ timestamp_auto_set_type Field_timestamp::get_auto_set_type() const
}
}
+long Field_timestamp::get_timestamp(ulong *sec_part) const
+{
+ ASSERT_COLUMN_MARKED_FOR_READ;
+ *sec_part= 0;
+ if (BIGENDIAN && table && table->s->db_low_byte_first)
+ return sint4korr(ptr);
+ long tmp;
+ longget(tmp,ptr);
+ return tmp;
+}
-int Field_timestamp::store(const char *from,uint len,CHARSET_INFO *cs)
+int Field_timestamp::store_TIME_with_warning(THD *thd, MYSQL_TIME *l_time,
+ const Lazy_string *str,
+ bool was_cut, bool have_smth_to_conv)
{
ASSERT_COLUMN_MARKED_FOR_WRITE;
- MYSQL_TIME l_time;
- my_time_t tmp= 0;
- int error;
- bool have_smth_to_conv;
+ uint error = 0;
+ my_time_t timestamp;
my_bool in_dst_time_gap;
- THD *thd= table ? table->in_use : current_thd;
- /* We don't want to store invalid or fuzzy datetime values in TIMESTAMP */
- have_smth_to_conv= (str_to_datetime(from, len, &l_time,
- (thd->variables.sql_mode &
- MODE_NO_ZERO_DATE) |
- MODE_NO_ZERO_IN_DATE, &error) >
- MYSQL_TIMESTAMP_ERROR);
-
- if (error || !have_smth_to_conv)
+ if (was_cut || !have_smth_to_conv)
{
error= 1;
set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED,
- from, len, MYSQL_TIMESTAMP_DATETIME, 1);
+ str, MYSQL_TIMESTAMP_DATETIME, 1);
}
-
- /* Only convert a correct date (not a zero date) */
- if (have_smth_to_conv && l_time.month)
+ if (have_smth_to_conv && l_time->month)
{
- if (!(tmp= TIME_to_timestamp(thd, &l_time, &in_dst_time_gap)))
+ if (!(timestamp= TIME_to_timestamp(thd, l_time, &in_dst_time_gap)))
{
set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARN_DATA_OUT_OF_RANGE,
- from, len, MYSQL_TIMESTAMP_DATETIME, !error);
+ str, MYSQL_TIMESTAMP_DATETIME, !error);
error= 1;
}
else if (in_dst_time_gap)
{
set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARN_INVALID_TIMESTAMP,
- from, len, MYSQL_TIMESTAMP_DATETIME, !error);
+ str, MYSQL_TIMESTAMP_DATETIME, !error);
error= 1;
}
}
- store_timestamp(tmp);
+ else
+ {
+ timestamp= 0;
+ l_time->second_part= 0;
+ }
+ store_TIME(timestamp, l_time->second_part);
return error;
}
+int Field_timestamp::store_time(MYSQL_TIME *ltime,timestamp_type time_type)
+{
+ THD *thd= table ? table->in_use : current_thd;
+ int unused;
+ MYSQL_TIME l_time= *ltime;
+ Lazy_string_time str(ltime);
+ bool valid= !check_date(&l_time, pack_time(&l_time) != 0,
+ (thd->variables.sql_mode & MODE_NO_ZERO_DATE) |
+ MODE_NO_ZERO_IN_DATE, &unused);
+
+ return store_TIME_with_warning(thd, &l_time, &str, false, valid);
+}
+
+int Field_timestamp::store(const char *from,uint len,CHARSET_INFO *cs)
+{
+ MYSQL_TIME l_time;
+ int error;
+ int have_smth_to_conv;
+ Lazy_string_str str(from, len);
+ THD *thd= table ? table->in_use : current_thd;
+
+ /* We don't want to store invalid or fuzzy datetime values in TIMESTAMP */
+ have_smth_to_conv= (str_to_datetime(from, len, &l_time,
+ (thd->variables.sql_mode &
+ MODE_NO_ZERO_DATE) |
+ MODE_NO_ZERO_IN_DATE, &error) >
+ MYSQL_TIMESTAMP_ERROR);
+ return store_TIME_with_warning(thd, &l_time, &str, error, have_smth_to_conv);
+}
+
int Field_timestamp::store(double nr)
{
- int error= 0;
- if (nr < 0 || nr > 99991231235959.0)
- {
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_OUT_OF_RANGE,
- nr, MYSQL_TIMESTAMP_DATETIME);
- nr= 0; // Avoid overflow on buff
- error= 1;
- }
- error|= Field_timestamp::store((longlong) rint(nr), FALSE);
- return error;
+ MYSQL_TIME l_time;
+ int error;
+ Lazy_string_dbl str(nr);
+ THD *thd= table ? table->in_use : current_thd;
+
+ /* We don't want to store invalid or fuzzy datetime values in TIMESTAMP */
+ longlong tmp= number_to_datetime((longlong) floor(nr),
+ &l_time, (thd->variables.sql_mode &
+ MODE_NO_ZERO_DATE) |
+ MODE_NO_ZERO_IN_DATE, &error);
+ l_time.second_part= (ulong)((nr-floor(nr))*1e6);
+ return store_TIME_with_warning(thd, &l_time, &str, error, tmp != LL(-1));
}
int Field_timestamp::store(longlong nr, bool unsigned_val)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE;
MYSQL_TIME l_time;
- my_time_t timestamp= 0;
int error;
- my_bool in_dst_time_gap;
+ Lazy_string_num str(nr);
THD *thd= table ? table->in_use : current_thd;
/* We don't want to store invalid or fuzzy datetime values in TIMESTAMP */
longlong tmp= number_to_datetime(nr, &l_time, (thd->variables.sql_mode &
MODE_NO_ZERO_DATE) |
MODE_NO_ZERO_IN_DATE, &error);
- if (tmp == LL(-1))
- {
- error= 2;
- }
-
- if (!error && tmp)
- {
- if (!(timestamp= TIME_to_timestamp(thd, &l_time, &in_dst_time_gap)))
- {
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_OUT_OF_RANGE,
- nr, MYSQL_TIMESTAMP_DATETIME, 1);
- error= 1;
- }
- if (in_dst_time_gap)
- {
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_INVALID_TIMESTAMP,
- nr, MYSQL_TIMESTAMP_DATETIME, 1);
- error= 1;
- }
- } else if (error)
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- WARN_DATA_TRUNCATED,
- nr, MYSQL_TIMESTAMP_DATETIME, 1);
-
- store_timestamp(timestamp);
- return error;
+ return store_TIME_with_warning(thd, &l_time, &str, error, tmp != LL(-1));
}
double Field_timestamp::val_real(void)
{
- ASSERT_COLUMN_MARKED_FOR_READ;
return (double) Field_timestamp::val_int();
}
longlong Field_timestamp::val_int(void)
{
- ASSERT_COLUMN_MARKED_FOR_READ;
- uint32 temp;
MYSQL_TIME time_tmp;
THD *thd= table ? table->in_use : current_thd;
thd->time_zone_used= 1;
-#ifdef WORDS_BIGENDIAN
- if (table && table->s->db_low_byte_first)
- temp=uint4korr(ptr);
- else
-#endif
- longget(temp,ptr);
+ ulong sec_part;
+ uint32 temp= get_timestamp(&sec_part);
- if (temp == 0L) // No time
- return(0); /* purecov: inspected */
+ if (temp == 0 && sec_part == 0)
+ return(0);
thd->variables.time_zone->gmt_sec_to_TIME(&time_tmp, (my_time_t)temp);
@@ -4960,13 +4820,12 @@ longlong Field_timestamp::val_int(void)
time_tmp.minute * 100 + time_tmp.second;
}
-
+static const char *zero_timestamp="0000-00-00 00:00:00.000000";
String *Field_timestamp::val_str(String *val_buffer, String *val_ptr)
{
- ASSERT_COLUMN_MARKED_FOR_READ;
- uint32 temp, temp2;
- MYSQL_TIME time_tmp;
+ uint32 temp2;
THD *thd= table ? table->in_use : current_thd;
+ MYSQL_TIME time_tmp;
char *to;
val_buffer->alloc(field_length+1);
@@ -4974,16 +4833,12 @@ String *Field_timestamp::val_str(String *val_buffer, String *val_ptr)
val_buffer->length(field_length);
thd->time_zone_used= 1;
-#ifdef WORDS_BIGENDIAN
- if (table && table->s->db_low_byte_first)
- temp=uint4korr(ptr);
- else
-#endif
- longget(temp,ptr);
+ ulong sec_part;
+ uint32 temp= get_timestamp(&sec_part);
- if (temp == 0L)
+ if (temp == 0 && sec_part == 0)
{ /* Zero time is "000000" */
- val_ptr->set(STRING_WITH_LEN("0000-00-00 00:00:00"), &my_charset_bin);
+ val_ptr->set(zero_timestamp, field_length, &my_charset_bin);
return val_ptr;
}
val_buffer->set_charset(&my_charset_bin); // Safety
@@ -5036,16 +4891,11 @@ String *Field_timestamp::val_str(String *val_buffer, String *val_ptr)
bool Field_timestamp::get_date(MYSQL_TIME *ltime, uint fuzzydate)
{
- long temp;
THD *thd= table ? table->in_use : current_thd;
thd->time_zone_used= 1;
-#ifdef WORDS_BIGENDIAN
- if (table && table->s->db_low_byte_first)
- temp=uint4korr(ptr);
- else
-#endif
- longget(temp,ptr);
- if (temp == 0L)
+ ulong sec_part;
+ uint32 temp= get_timestamp(&sec_part);
+ if (temp == 0 && sec_part == 0)
{ /* Zero time is "000000" */
if (fuzzydate & TIME_NO_ZERO_DATE)
return 1;
@@ -5054,38 +4904,31 @@ bool Field_timestamp::get_date(MYSQL_TIME *ltime, uint fuzzydate)
else
{
thd->variables.time_zone->gmt_sec_to_TIME(ltime, (my_time_t)temp);
+ ltime->second_part= sec_part;
}
return 0;
}
-bool Field_timestamp::get_time(MYSQL_TIME *ltime)
-{
- return Field_timestamp::get_date(ltime,0);
-}
-
-
bool Field_timestamp::send_binary(Protocol *protocol)
{
- MYSQL_TIME tm;
- Field_timestamp::get_date(&tm, 0);
- return protocol->store(&tm);
+ MYSQL_TIME ltime;
+ Field_timestamp::get_date(&ltime, 0);
+ return protocol->store(&ltime, 0);
}
int Field_timestamp::cmp(const uchar *a_ptr, const uchar *b_ptr)
{
int32 a,b;
-#ifdef WORDS_BIGENDIAN
- if (table && table->s->db_low_byte_first)
+ if (BIGENDIAN && table && table->s->db_low_byte_first)
{
a=sint4korr(a_ptr);
b=sint4korr(b_ptr);
}
else
-#endif
{
- longget(a,a_ptr);
- longget(b,b_ptr);
+ longget(a,a_ptr);
+ longget(b,b_ptr);
}
return ((uint32) a < (uint32) b) ? -1 : ((uint32) a > (uint32) b) ? 1 : 0;
}
@@ -5093,8 +4936,7 @@ int Field_timestamp::cmp(const uchar *a_ptr, const uchar *b_ptr)
void Field_timestamp::sort_string(uchar *to,uint length __attribute__((unused)))
{
-#ifdef WORDS_BIGENDIAN
- if (!table || !table->s->db_low_byte_first)
+ if (BIGENDIAN && !(table && table->s->db_low_byte_first))
{
to[0] = ptr[0];
to[1] = ptr[1];
@@ -5102,7 +4944,6 @@ void Field_timestamp::sort_string(uchar *to,uint length __attribute__((unused)))
to[3] = ptr[3];
}
else
-#endif
{
to[0] = ptr[3];
to[1] = ptr[2];
@@ -5118,146 +4959,421 @@ void Field_timestamp::sql_type(String &res) const
}
-void Field_timestamp::set_time()
+int Field_timestamp::set_time()
{
THD *thd= table ? table->in_use : current_thd;
- long tmp= (long) thd->query_start();
set_notnull();
- store_timestamp(tmp);
+ store_TIME(thd->query_start(), 0);
+ return 0;
}
-/****************************************************************************
-** time type
-** In string context: HH:MM:SS
-** In number context: HHMMSS
-** Stored as a 3 byte unsigned int
-****************************************************************************/
+void Field_timestamp_hires::sql_type(String &res) const
+{
+ CHARSET_INFO *cs=res.charset();
+ res.length(cs->cset->snprintf(cs, (char*) res.ptr(), res.alloced_length(),
+ "timestamp(%u)", dec));
+}
-int Field_time::store(const char *from,uint len,CHARSET_INFO *cs)
+static void store_native(ulonglong num, uchar *to, uint bytes)
{
- MYSQL_TIME ltime;
- long tmp;
- int error= 0;
- int warning;
+ switch(bytes) {
+ case 1: *to= (uchar)num; break;
+ case 2: shortstore(to, (ushort)num); break;
+ case 3: int3store(to, num); /* Sic!*/ break;
+ case 4: longstore(to, (ulong)num); break;
+ case 8: longlongstore(to, num); break;
+ default: DBUG_ASSERT(0);
+ }
+}
- if (str_to_time(from, len, &ltime, &warning))
- {
- tmp=0L;
- error= 2;
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED,
- from, len, MYSQL_TIMESTAMP_TIME, 1);
+static longlong read_native(const uchar *from, uint bytes)
+{
+ switch(bytes) {
+ case 1: return from[0];
+ case 2: { uint16 tmp; shortget(tmp, from); return tmp; }
+ case 3: return uint3korr(from);
+ case 4: { uint32 tmp; longget(tmp, from); return tmp; }
+ case 8: { longlong tmp; longlongget(tmp, from); return tmp; }
+ default: DBUG_ASSERT(0); return 0;
}
- else
- {
- if (warning & MYSQL_TIME_WARN_TRUNCATED)
- {
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- WARN_DATA_TRUNCATED,
- from, len, MYSQL_TIMESTAMP_TIME, 1);
- error= 1;
- }
- if (warning & MYSQL_TIME_WARN_OUT_OF_RANGE)
- {
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_OUT_OF_RANGE,
- from, len, MYSQL_TIMESTAMP_TIME, !error);
- error= 1;
- }
- if (ltime.month)
- ltime.day=0;
- tmp=(ltime.day*24L+ltime.hour)*10000L+(ltime.minute*100+ltime.second);
+}
+
+static void store_lowendian(ulonglong num, uchar *to, uint bytes)
+{
+ switch(bytes) {
+ case 1: *to= (uchar)num; break;
+ case 2: int2store(to, num); break;
+ case 3: int3store(to, num); break;
+ case 4: int4store(to, num); break;
+ case 8: int8store(to, num); break;
+ default: DBUG_ASSERT(0);
+ }
+}
+
+static longlong read_lowendian(const uchar *from, uint bytes)
+{
+ switch(bytes) {
+ case 1: return from[0];
+ case 2: return uint2korr(from);
+ case 3: return uint3korr(from);
+ case 4: return uint4korr(from);
+ case 8: return sint8korr(from);
+ default: DBUG_ASSERT(0); return 0;
}
+}
+
+static void store_bigendian(ulonglong num, uchar *to, uint bytes)
+{
+ switch(bytes) {
+ case 1: mi_int1store(to, num); break;
+ case 2: mi_int2store(to, num); break;
+ case 3: mi_int3store(to, num); break;
+ case 4: mi_int4store(to, num); break;
+ case 5: mi_int5store(to, num); break;
+ case 6: mi_int6store(to, num); break;
+ case 7: mi_int7store(to, num); break;
+ case 8: mi_int8store(to, num); break;
+ default: DBUG_ASSERT(0);
+ }
+}
+
+static longlong read_bigendian(const uchar *from, uint bytes)
+{
+ switch(bytes) {
+ case 1: return mi_uint1korr(from);
+ case 2: return mi_uint2korr(from);
+ case 3: return mi_uint3korr(from);
+ case 4: return mi_uint4korr(from);
+ case 5: return mi_uint5korr(from);
+ case 6: return mi_uint6korr(from);
+ case 7: return mi_uint7korr(from);
+ case 8: return mi_sint8korr(from);
+ default: DBUG_ASSERT(0); return 0;
+ }
+}
+
+static uint sec_part_bytes[MAX_DATETIME_PRECISION+1]= { 0, 1, 1, 2, 2, 3, 3 };
+
+void Field_timestamp_hires::store_TIME(my_time_t timestamp, ulong sec_part)
+{
+ mi_int4store(ptr, timestamp);
+ store_bigendian(sec_part_shift(sec_part, dec), ptr+4, sec_part_bytes[dec]);
+}
+
+long Field_timestamp_hires::get_timestamp(ulong *sec_part) const
+{
+ ASSERT_COLUMN_MARKED_FOR_READ;
+ *sec_part= sec_part_unshift(read_bigendian(ptr+4, sec_part_bytes[dec]), dec);
+ return mi_uint4korr(ptr);
+}
+
+double Field_timestamp_hires::val_real(void)
+{
+ MYSQL_TIME time_tmp;
+ THD *thd= table ? table->in_use : current_thd;
+
+ thd->time_zone_used= 1;
+ ulong sec_part;
+ uint32 temp= get_timestamp(&sec_part);
+
+ if (temp == 0 && sec_part == 0)
+ return(0);
- if (ltime.neg)
- tmp= -tmp;
- int3store(ptr,tmp);
- return error;
+ thd->variables.time_zone->gmt_sec_to_TIME(&time_tmp, (my_time_t)temp);
+
+ return time_tmp.year * 1e10 + time_tmp.month * 1e8 +
+ time_tmp.day * 1e6 + time_tmp.hour * 1e4 +
+ time_tmp.minute * 1e2 + time_tmp.second + sec_part*1e-6;
}
+String *Field_timestamp_hires::val_str(String *val_buffer, String *val_ptr)
+{
+ String *tmp= Field_timestamp::val_str(val_buffer, val_ptr);
+ ulong sec_part= read_bigendian(ptr+4, sec_part_bytes[dec]);
+
+ if (tmp->ptr() == zero_timestamp)
+ return tmp;
-int Field_time::store_time(MYSQL_TIME *ltime, timestamp_type time_type)
+ char *buf= const_cast<char*>(tmp->ptr() + MAX_DATETIME_WIDTH);
+ for (int i=dec; i>0; i--, sec_part/=10)
+ buf[i]= (sec_part % 10) + '0';
+ buf[0]= '.';
+ buf[dec+1]= 0;
+ return tmp;
+}
+
+
+int Field_timestamp_hires::store_decimal(const my_decimal *d)
{
- long tmp= ((ltime->month ? 0 : ltime->day * 24L) + ltime->hour) * 10000L +
- (ltime->minute * 100 + ltime->second);
- if (ltime->neg)
- tmp= -tmp;
- return Field_time::store((longlong) tmp, FALSE);
+ char buff[DECIMAL_MAX_STR_LENGTH+1];
+ String str(buff, sizeof(buff), &my_charset_bin);
+ my_decimal2string(E_DEC_FATAL_ERROR, d,
+ MAX_DATETIME_COMPRESSED_WIDTH + MAX_DATETIME_PRECISION,
+ 6, '0', &str);
+ return store(str.ptr(), str.length(), str.charset());
}
+int Field_timestamp_hires::set_time()
+{
+ THD *thd= table ? table->in_use : current_thd;
+ set_notnull();
+ store_TIME(thd->query_start(), thd->query_start_sec_part());
+ return 0;
+}
-int Field_time::store(double nr)
+bool Field_timestamp_hires::send_binary(Protocol *protocol)
+{
+ MYSQL_TIME ltime;
+ Field_timestamp::get_date(&ltime, 0);
+ return protocol->store(&ltime, dec);
+}
+
+
+int Field_timestamp_hires::cmp(const uchar *a_ptr, const uchar *b_ptr)
+{
+ int32 a,b;
+ ulong a_sec_part, b_sec_part;
+ a= mi_uint4korr(a_ptr);
+ a_sec_part= read_bigendian(a_ptr+4, sec_part_bytes[dec]);
+ b= mi_uint4korr(b_ptr);
+ b_sec_part= read_bigendian(b_ptr+4, sec_part_bytes[dec]);
+ return ((uint32) a < (uint32) b) ? -1 : ((uint32) a > (uint32) b) ? 1 :
+ a_sec_part < b_sec_part ? -1 : a_sec_part > b_sec_part ? 1 : 0;
+}
+
+
+void Field_timestamp_hires::sort_string(uchar *to,uint length)
+{
+ DBUG_ASSERT(length == Field_timestamp_hires::pack_length());
+ memcpy(to, ptr, length);
+}
+
+uint32 Field_timestamp_hires::pack_length() const
+{
+ return 4 + sec_part_bytes[dec];
+}
+
+void Field_timestamp_hires::make_field(Send_field *field)
+{
+ Field::make_field(field);
+ field->decimals= dec;
+}
+
+/*
+ Store string into a date/time field
+
+ RETURN
+ 0 ok
+ 1 Value was cut during conversion
+ 2 value was out of range
+ 3 Datetime value that was cut (warning level NOTE)
+ This is used by opt_range.cc:get_mm_leaf().
+*/
+int Field_temporal::store_TIME_with_warning(MYSQL_TIME *ltime,
+ const Lazy_string *str,
+ int was_cut, int have_smth_to_conv)
{
+ MYSQL_ERROR::enum_warning_level trunc_level= MYSQL_ERROR::WARN_LEVEL_WARN;
+ int ret= 2;
+
ASSERT_COLUMN_MARKED_FOR_WRITE;
- long tmp;
- int error= 0;
- if (nr > (double)TIME_MAX_VALUE)
- {
- tmp= TIME_MAX_VALUE;
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_OUT_OF_RANGE, nr, MYSQL_TIMESTAMP_TIME);
- error= 1;
- }
- else if (nr < (double)-TIME_MAX_VALUE)
+
+ if (was_cut == 0 &&
+ have_smth_to_conv == 0 &&
+ temporal_type() != MYSQL_TIMESTAMP_TIME) // special case: zero date
+ was_cut= MYSQL_TIME_WARN_OUT_OF_RANGE;
+ else
+ if (!have_smth_to_conv)
{
- tmp= -TIME_MAX_VALUE;
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_OUT_OF_RANGE, nr, MYSQL_TIMESTAMP_TIME);
- error= 1;
+ bzero(ltime, sizeof(*ltime));
+ was_cut= MYSQL_TIME_WARN_TRUNCATED;
+ ret= 1;
}
- else
+ else if (temporal_type() == MYSQL_TIMESTAMP_DATE &&
+ (ltime->hour || ltime->minute || ltime->second || ltime->second_part))
{
- tmp=(long) floor(fabs(nr)); // Remove fractions
- if (nr < 0)
- tmp= -tmp;
- if (tmp % 100 > 59 || tmp/100 % 100 > 59)
- {
- tmp=0;
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_OUT_OF_RANGE, nr,
- MYSQL_TIMESTAMP_TIME);
- error= 1;
- }
+ DBUG_ASSERT((was_cut & MYSQL_TIME_WARN_TRUNCATED) == 0);
+ trunc_level= MYSQL_ERROR::WARN_LEVEL_NOTE;
+ was_cut|= MYSQL_TIME_WARN_TRUNCATED;
+ ret= 3;
}
- int3store(ptr,tmp);
- return error;
+
+ /*
+ error code logic:
+ MYSQL_TIME_WARN_TRUNCATED means that the value was not a date/time at all.
+ it will be stored as zero date/time.
+ MYSQL_TIME_WARN_OUT_OF_RANGE means that the value was a date/time,
+ that is, it was parsed as such, but the value was invalid.
+
+ Also, MYSQL_TIME_WARN_TRUNCATED is used when storing a DATETIME in
+ a DATE field and non-zero time part is thrown away.
+ QQ Why don't we do the same when storing DATETIME in TIME?
+ */
+ if (was_cut & MYSQL_TIME_WARN_TRUNCATED)
+ set_datetime_warning(trunc_level, WARN_DATA_TRUNCATED,
+ str, temporal_type(), 1);
+ if (was_cut & MYSQL_TIME_WARN_OUT_OF_RANGE)
+ set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE,
+ str, temporal_type(), 1);
+
+ store_TIME(ltime);
+ return was_cut ? ret : 0;
}
-int Field_time::store(longlong nr, bool unsigned_val)
+int Field_temporal::store(const char *from,uint len,CHARSET_INFO *cs)
+{
+ MYSQL_TIME ltime;
+ int error;
+ enum enum_mysql_timestamp_type func_res;
+ THD *thd= table ? table->in_use : current_thd;
+ Lazy_string_str str(from, len);
+
+ func_res= str_to_datetime(from, len, &ltime,
+ (TIME_FUZZY_DATE |
+ (thd->variables.sql_mode &
+ (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
+ MODE_INVALID_DATES))),
+ &error);
+ return store_TIME_with_warning(&ltime, &str, error, func_res > MYSQL_TIMESTAMP_ERROR);
+}
+
+
+int Field_temporal::store(double nr)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE;
- long tmp;
int error= 0;
- if (nr < (longlong) -TIME_MAX_VALUE && !unsigned_val)
+ MYSQL_TIME ltime;
+ longlong tmp;
+ THD *thd= table ? table->in_use : current_thd;
+ Lazy_string_dbl str(nr);
+
+ if (nr < 0.0 || nr > 99991231235959.0)
{
- tmp= -TIME_MAX_VALUE;
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_OUT_OF_RANGE, nr,
- MYSQL_TIMESTAMP_TIME, 1);
+ tmp= -1;
error= 1;
}
- else if (nr > (longlong) TIME_MAX_VALUE || (nr < 0 && unsigned_val))
+ else
+ tmp= number_to_datetime((longlong) floor(nr), &ltime, (TIME_FUZZY_DATE |
+ (thd->variables.sql_mode &
+ (MODE_NO_ZERO_IN_DATE |
+ MODE_NO_ZERO_DATE |
+ MODE_INVALID_DATES))), &error);
+ ltime.second_part= (ulong)((nr-floor(nr))*1e6);
+ return store_TIME_with_warning(&ltime, &str, error, tmp != -1);
+}
+
+
+int Field_temporal::store(longlong nr, bool unsigned_val)
+{
+ int error;
+ MYSQL_TIME ltime;
+ longlong tmp;
+ THD *thd= table ? table->in_use : current_thd;
+ Lazy_string_num str(nr);
+
+ tmp= number_to_datetime(nr, &ltime, (TIME_FUZZY_DATE |
+ (thd->variables.sql_mode &
+ (MODE_NO_ZERO_IN_DATE |
+ MODE_NO_ZERO_DATE |
+ MODE_INVALID_DATES))), &error);
+
+ return store_TIME_with_warning(&ltime, &str, error, tmp != -1);
+}
+
+
+int Field_temporal::store_time(MYSQL_TIME *ltime,timestamp_type time_type)
+{
+ int error = 0, have_smth_to_conv= 1;
+ MYSQL_TIME l_time= *ltime;
+ Lazy_string_time str(ltime);
+ /*
+ We don't perform range checking here since values stored in TIME
+ structure always fit into DATETIME range.
+ */
+ if (time_type == MYSQL_TIMESTAMP_DATE ||
+ time_type == MYSQL_TIMESTAMP_DATETIME)
{
- tmp= TIME_MAX_VALUE;
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_OUT_OF_RANGE, nr,
- MYSQL_TIMESTAMP_TIME, 1);
- error= 1;
+ have_smth_to_conv= !check_date(&l_time, pack_time(&l_time) != 0,
+ (TIME_FUZZY_DATE |
+ (current_thd->variables.sql_mode &
+ (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
+ MODE_INVALID_DATES))), &error);
}
else
{
- tmp=(long) nr;
- if (tmp % 100 > 59 || tmp/100 % 100 > 59)
- {
- tmp=0;
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_OUT_OF_RANGE, nr,
- MYSQL_TIMESTAMP_TIME, 1);
- error= 1;
- }
+ error= 1;
+ have_smth_to_conv= 0;
}
+ return store_TIME_with_warning(&l_time, &str, error, have_smth_to_conv);
+}
+
+/****************************************************************************
+** time type
+** In string context: HH:MM:SS
+** In number context: HHMMSS
+** Stored as a 3 byte unsigned int
+****************************************************************************/
+
+void Field_time::store_TIME(MYSQL_TIME *ltime)
+{
+ long tmp= (ltime->day*24L+ltime->hour)*10000L +
+ (ltime->minute*100+ltime->second);
+ if (ltime->neg)
+ tmp= -tmp;
int3store(ptr,tmp);
- return error;
+}
+
+int Field_time::store(const char *from,uint len,CHARSET_INFO *cs)
+{
+ MYSQL_TIME ltime;
+ Lazy_string_str str(from, len);
+ int was_cut;
+ int have_smth_to_conv= str_to_datetime(from, len, &ltime, TIME_TIME_ONLY,
+ &was_cut) > MYSQL_TIMESTAMP_ERROR;
+
+ if (ltime.month)
+ ltime.day=0;
+ ltime.month= ltime.year= 0;
+
+ return store_TIME_with_warning(&ltime, &str, was_cut, have_smth_to_conv);
+}
+
+
+int Field_time::store_time(MYSQL_TIME *ltime, timestamp_type time_type)
+{
+ MYSQL_TIME l_time= *ltime;
+ Lazy_string_time str(ltime);
+ int was_cut= 0;
+
+ if (l_time.month)
+ l_time.day=0;
+ l_time.year= 0;
+ l_time.month= 0;
+
+ int have_smth_to_conv= !check_time_range(&l_time, &was_cut);
+ return store_TIME_with_warning(&l_time, &str, was_cut, have_smth_to_conv);
+}
+
+
+int Field_time::store(double nr)
+{
+ MYSQL_TIME ltime;
+ Lazy_string_dbl str(nr);
+ int was_cut;
+ int have_smth_to_conv= !number_to_time(nr, &ltime, &was_cut);
+
+ return store_TIME_with_warning(&ltime, &str, was_cut, have_smth_to_conv);
+}
+
+
+int Field_time::store(longlong nr, bool unsigned_val)
+{
+ MYSQL_TIME ltime;
+ Lazy_string_num str(nr);
+ int was_cut;
+ int have_smth_to_conv= !number_to_time(nr, &ltime, &was_cut);
+
+ return store_TIME_with_warning(&ltime, &str, was_cut, have_smth_to_conv);
}
@@ -5313,7 +5429,7 @@ String *Field_time::val_str(String *val_buffer,
bool Field_time::get_date(MYSQL_TIME *ltime, uint fuzzydate)
{
THD *thd= table ? table->in_use : current_thd;
- if (!(fuzzydate & TIME_FUZZY_DATE))
+ if (!(fuzzydate & (TIME_FUZZY_DATE|TIME_TIME_ONLY)))
{
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARN_DATA_OUT_OF_RANGE,
@@ -5321,12 +5437,6 @@ bool Field_time::get_date(MYSQL_TIME *ltime, uint fuzzydate)
thd->row_count);
return 1;
}
- return Field_time::get_time(ltime);
-}
-
-
-bool Field_time::get_time(MYSQL_TIME *ltime)
-{
long tmp=(long) sint3korr(ptr);
ltime->neg=0;
if (tmp < 0)
@@ -5347,11 +5457,9 @@ bool Field_time::get_time(MYSQL_TIME *ltime)
bool Field_time::send_binary(Protocol *protocol)
{
- MYSQL_TIME tm;
- Field_time::get_time(&tm);
- tm.day= tm.hour/24; // Move hours to days
- tm.hour-= tm.day*24;
- return protocol->store_time(&tm);
+ MYSQL_TIME ltime;
+ Field_time::get_date(&ltime, TIME_TIME_ONLY);
+ return protocol->store_time(&ltime, 0);
}
@@ -5375,6 +5483,87 @@ void Field_time::sql_type(String &res) const
res.set_ascii(STRING_WITH_LEN("time"));
}
+void Field_time_hires::store_TIME(MYSQL_TIME *ltime)
+{
+ ulonglong packed= sec_part_shift(pack_time(ltime), dec);
+ store_bigendian(packed, ptr, Field_time_hires::pack_length());
+}
+
+uint32 Field_time_hires::pack_length() const
+{
+ return 3 + sec_part_bytes[dec];
+}
+
+double Field_time_hires::val_real(void)
+{
+ ASSERT_COLUMN_MARKED_FOR_READ;
+ MYSQL_TIME ltime;
+ Field_time_hires::get_date(&ltime, TIME_TIME_ONLY);
+ return TIME_to_double(&ltime);
+}
+
+String *Field_time_hires::val_str(String *str,
+ String *unused __attribute__((unused)))
+{
+ ASSERT_COLUMN_MARKED_FOR_READ;
+ MYSQL_TIME ltime;
+ Field_time_hires::get_date(&ltime, TIME_TIME_ONLY);
+ str->alloc(field_length+1);
+ str->length(my_time_to_str(&ltime, (char*) str->ptr(), dec));
+ str->set_charset(&my_charset_bin);
+ return str;
+}
+
+bool Field_time_hires::get_date(MYSQL_TIME *ltime, uint fuzzydate)
+{
+ ulonglong packed= read_bigendian(ptr, Field_time_hires::pack_length());
+ unpack_time(sec_part_unshift(packed, dec), ltime);
+ /*
+ unpack_time() returns MYSQL_TIMESTAMP_DATETIME.
+ To get MYSQL_TIMESTAMP_TIME we few some adjustments
+ */
+ ltime->time_type= MYSQL_TIMESTAMP_TIME;
+ ltime->hour+= (ltime->month*32+ltime->day)*24;
+ ltime->month= ltime->day= 0;
+ return fuzzydate & (TIME_FUZZY_DATE|TIME_TIME_ONLY) ? 0 : 1;
+}
+
+
+bool Field_time_hires::send_binary(Protocol *protocol)
+{
+ MYSQL_TIME ltime;
+ Field_time_hires::get_date(&ltime, TIME_TIME_ONLY);
+ return protocol->store_time(&ltime, dec);
+}
+
+
+int Field_time_hires::cmp(const uchar *a_ptr, const uchar *b_ptr)
+{
+ ulonglong a=read_bigendian(a_ptr, Field_time_hires::pack_length());
+ ulonglong b=read_bigendian(b_ptr, Field_time_hires::pack_length());
+ return (a < b) ? -1 : (a > b) ? 1 : 0;
+}
+
+void Field_time_hires::sort_string(uchar *to,uint length __attribute__((unused)))
+{
+ DBUG_ASSERT(length == Field_time_hires::pack_length());
+ memcpy(to, ptr, length);
+ to[0]^= 128;
+}
+
+void Field_time_hires::sql_type(String &res) const
+{
+ CHARSET_INFO *cs=res.charset();
+ res.length(cs->cset->snprintf(cs, (char*) res.ptr(), res.alloced_length(),
+ "time(%u)", dec));
+}
+
+void Field_time_hires::make_field(Send_field *field)
+{
+ Field::make_field(field);
+ field->decimals= dec;
+}
+
/****************************************************************************
** year type
** Save in a byte the year 0, 1901->2155
@@ -5502,102 +5691,15 @@ void Field_year::sql_type(String &res) const
** Stored as a 4 byte unsigned int
****************************************************************************/
-int Field_date::store(const char *from, uint len,CHARSET_INFO *cs)
+void Field_date::store_TIME(MYSQL_TIME *ltime)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE;
- MYSQL_TIME l_time;
- uint32 tmp;
- int error;
- THD *thd= table ? table->in_use : current_thd;
-
- if (str_to_datetime(from, len, &l_time, TIME_FUZZY_DATE |
- (thd->variables.sql_mode &
- (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
- MODE_INVALID_DATES)),
- &error) <= MYSQL_TIMESTAMP_ERROR)
- {
- tmp= 0;
- error= 2;
- }
- else
- tmp=(uint32) l_time.year*10000L + (uint32) (l_time.month*100+l_time.day);
-
- if (error)
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED,
- from, len, MYSQL_TIMESTAMP_DATE, 1);
-
-#ifdef WORDS_BIGENDIAN
- if (table && table->s->db_low_byte_first)
- {
+ uint tmp= ltime->year*10000L + ltime->month*100+ltime->day;
+ if (BIGENDIAN && table && table->s->db_low_byte_first)
int4store(ptr,tmp);
- }
else
-#endif
longstore(ptr,tmp);
- return error;
}
-
-int Field_date::store(double nr)
-{
- longlong tmp;
- if (nr >= 19000000000000.0 && nr <= 99991231235959.0)
- nr=floor(nr/1000000.0); // Timestamp to date
- if (nr < 0.0 || nr > 99991231.0)
- {
- tmp= LL(0);
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_OUT_OF_RANGE,
- nr, MYSQL_TIMESTAMP_DATE);
- }
- else
- tmp= (longlong) rint(nr);
-
- return Field_date::store(tmp, TRUE);
-}
-
-
-int Field_date::store(longlong nr, bool unsigned_val)
-{
- ASSERT_COLUMN_MARKED_FOR_WRITE;
- MYSQL_TIME not_used;
- int error;
- longlong initial_nr= nr;
- THD *thd= table ? table->in_use : current_thd;
-
- nr= number_to_datetime(nr, &not_used, (TIME_FUZZY_DATE |
- (thd->variables.sql_mode &
- (MODE_NO_ZERO_IN_DATE |
- MODE_NO_ZERO_DATE |
- MODE_INVALID_DATES))), &error);
-
- if (nr == LL(-1))
- {
- nr= 0;
- error= 2;
- }
-
- if (nr >= 19000000000000.0 && nr <= 99991231235959.0)
- nr= (longlong) floor(nr/1000000.0); // Timestamp to date
-
- if (error)
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- error == 2 ? ER_WARN_DATA_OUT_OF_RANGE :
- WARN_DATA_TRUNCATED, initial_nr,
- MYSQL_TIMESTAMP_DATETIME, 1);
-
-#ifdef WORDS_BIGENDIAN
- if (table && table->s->db_low_byte_first)
- {
- int4store(ptr, nr);
- }
- else
-#endif
- longstore(ptr, nr);
- return error;
-}
-
-
bool Field_date::send_binary(Protocol *protocol)
{
longlong tmp= Field_date::val_int();
@@ -5613,11 +5715,9 @@ double Field_date::val_real(void)
{
ASSERT_COLUMN_MARKED_FOR_READ;
int32 j;
-#ifdef WORDS_BIGENDIAN
- if (table && table->s->db_low_byte_first)
+ if (BIGENDIAN && table && table->s->db_low_byte_first)
j=sint4korr(ptr);
else
-#endif
longget(j,ptr);
return (double) (uint32) j;
}
@@ -5627,11 +5727,9 @@ longlong Field_date::val_int(void)
{
ASSERT_COLUMN_MARKED_FOR_READ;
int32 j;
-#ifdef WORDS_BIGENDIAN
- if (table && table->s->db_low_byte_first)
+ if (BIGENDIAN && table && table->s->db_low_byte_first)
j=sint4korr(ptr);
else
-#endif
longget(j,ptr);
return (longlong) (uint32) j;
}
@@ -5644,11 +5742,9 @@ String *Field_date::val_str(String *val_buffer,
MYSQL_TIME ltime;
val_buffer->alloc(field_length);
int32 tmp;
-#ifdef WORDS_BIGENDIAN
- if (table && table->s->db_low_byte_first)
+ if (BIGENDIAN && table && table->s->db_low_byte_first)
tmp=sint4korr(ptr);
else
-#endif
longget(tmp,ptr);
ltime.neg= 0;
ltime.year= (int) ((uint32) tmp/10000L % 10000);
@@ -5659,24 +5755,15 @@ String *Field_date::val_str(String *val_buffer,
}
-bool Field_date::get_time(MYSQL_TIME *ltime)
-{
- bzero((char *)ltime, sizeof(MYSQL_TIME));
- return 0;
-}
-
-
int Field_date::cmp(const uchar *a_ptr, const uchar *b_ptr)
{
int32 a,b;
-#ifdef WORDS_BIGENDIAN
- if (table && table->s->db_low_byte_first)
+ if (BIGENDIAN && table && table->s->db_low_byte_first)
{
a=sint4korr(a_ptr);
b=sint4korr(b_ptr);
}
else
-#endif
{
longget(a,a_ptr);
longget(b,b_ptr);
@@ -5687,8 +5774,7 @@ int Field_date::cmp(const uchar *a_ptr, const uchar *b_ptr)
void Field_date::sort_string(uchar *to,uint length __attribute__((unused)))
{
-#ifdef WORDS_BIGENDIAN
- if (!table || !table->s->db_low_byte_first)
+ if (BIGENDIAN && !(table && table->s->db_low_byte_first))
{
to[0] = ptr[0];
to[1] = ptr[1];
@@ -5696,7 +5782,6 @@ void Field_date::sort_string(uchar *to,uint length __attribute__((unused)))
to[3] = ptr[3];
}
else
-#endif
{
to[0] = ptr[3];
to[1] = ptr[2];
@@ -5717,156 +5802,13 @@ void Field_date::sql_type(String &res) const
** In number context: YYYYMMDD
****************************************************************************/
-/*
- Store string into a date field
-
- SYNOPSIS
- Field_newdate::store()
- from Date string
- len Length of date field
- cs Character set (not used)
-
- RETURN
- 0 ok
- 1 Value was cut during conversion
- 2 Wrong date string
- 3 Datetime value that was cut (warning level NOTE)
- This is used by opt_range.cc:get_mm_leaf(). Note that there is a
- nearly-identical class Field_date doesn't ever return 3 from its
- store function.
-*/
-
-int Field_newdate::store(const char *from,uint len,CHARSET_INFO *cs)
-{
- ASSERT_COLUMN_MARKED_FOR_WRITE;
- long tmp;
- MYSQL_TIME l_time;
- int error;
- THD *thd= table ? table->in_use : current_thd;
- enum enum_mysql_timestamp_type ret;
- if ((ret= str_to_datetime(from, len, &l_time,
- (TIME_FUZZY_DATE |
- (thd->variables.sql_mode &
- (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
- MODE_INVALID_DATES))),
- &error)) <= MYSQL_TIMESTAMP_ERROR)
- {
- tmp= 0;
- error= 2;
- }
- else
- {
- tmp= l_time.day + l_time.month*32 + l_time.year*16*32;
- if (!error && (ret != MYSQL_TIMESTAMP_DATE) &&
- (l_time.hour || l_time.minute || l_time.second || l_time.second_part))
- error= 3; // Datetime was cut (note)
- }
-
- if (error)
- set_datetime_warning(error == 3 ? MYSQL_ERROR::WARN_LEVEL_NOTE :
- MYSQL_ERROR::WARN_LEVEL_WARN,
- WARN_DATA_TRUNCATED,
- from, len, MYSQL_TIMESTAMP_DATE, 1);
-
- int3store(ptr, tmp);
- return error;
-}
-
-
-int Field_newdate::store(double nr)
-{
- if (nr < 0.0 || nr > 99991231235959.0)
- {
- int3store(ptr,(int32) 0);
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- WARN_DATA_TRUNCATED, nr, MYSQL_TIMESTAMP_DATE);
- return 1;
- }
- return Field_newdate::store((longlong) rint(nr), FALSE);
-}
-
-int Field_newdate::store(longlong nr, bool unsigned_val)
+void Field_newdate::store_TIME(MYSQL_TIME *ltime)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE;
- MYSQL_TIME l_time;
- longlong tmp;
- int error;
- THD *thd= table ? table->in_use : current_thd;
- if (number_to_datetime(nr, &l_time,
- (TIME_FUZZY_DATE |
- (thd->variables.sql_mode &
- (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
- MODE_INVALID_DATES))),
- &error) == LL(-1))
- {
- tmp= 0L;
- error= 2;
- }
- else
- tmp= l_time.day + l_time.month*32 + l_time.year*16*32;
-
- if (!error && l_time.time_type != MYSQL_TIMESTAMP_DATE &&
- (l_time.hour || l_time.minute || l_time.second || l_time.second_part))
- error= 3;
-
- if (error)
- set_datetime_warning(error == 3 ? MYSQL_ERROR::WARN_LEVEL_NOTE :
- MYSQL_ERROR::WARN_LEVEL_WARN,
- error == 2 ?
- ER_WARN_DATA_OUT_OF_RANGE : WARN_DATA_TRUNCATED,
- nr,MYSQL_TIMESTAMP_DATE, 1);
-
+ uint tmp= ltime->year*16*32 + ltime->month*32+ltime->day;
int3store(ptr,tmp);
- return error;
}
-
-int Field_newdate::store_time(MYSQL_TIME *ltime,timestamp_type time_type)
-{
- ASSERT_COLUMN_MARKED_FOR_WRITE;
- long tmp;
- int error= 0;
- if (time_type == MYSQL_TIMESTAMP_DATE ||
- time_type == MYSQL_TIMESTAMP_DATETIME)
- {
- tmp=ltime->year*16*32+ltime->month*32+ltime->day;
- if (check_date(ltime, tmp != 0,
- (TIME_FUZZY_DATE |
- (current_thd->variables.sql_mode &
- (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
- MODE_INVALID_DATES))), &error))
- {
- char buff[MAX_DATE_STRING_REP_LENGTH];
- String str(buff, sizeof(buff), &my_charset_latin1);
- tmp= 0;
- make_date((DATE_TIME_FORMAT *) 0, ltime, &str);
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED,
- str.ptr(), str.length(), MYSQL_TIMESTAMP_DATE, 1);
- }
- if (!error && ltime->time_type != MYSQL_TIMESTAMP_DATE &&
- (ltime->hour || ltime->minute || ltime->second || ltime->second_part))
- {
- char buff[MAX_DATE_STRING_REP_LENGTH];
- String str(buff, sizeof(buff), &my_charset_latin1);
- make_datetime((DATE_TIME_FORMAT *) 0, ltime, &str);
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_NOTE,
- WARN_DATA_TRUNCATED,
- str.ptr(), str.length(), MYSQL_TIMESTAMP_DATE, 1);
- error= 3;
- }
- }
- else
- {
- tmp=0;
- error= 1;
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1);
- }
- int3store(ptr,tmp);
- return error;
-}
-
-
bool Field_newdate::send_binary(Protocol *protocol)
{
MYSQL_TIME tm;
@@ -5933,12 +5875,6 @@ bool Field_newdate::get_date(MYSQL_TIME *ltime,uint fuzzydate)
}
-bool Field_newdate::get_time(MYSQL_TIME *ltime)
-{
- return Field_newdate::get_date(ltime,0);
-}
-
-
int Field_newdate::cmp(const uchar *a_ptr, const uchar *b_ptr)
{
uint32 a,b;
@@ -5969,147 +5905,20 @@ void Field_newdate::sql_type(String &res) const
** Stored as a 8 byte unsigned int. Should sometimes be change to a 6 byte int.
****************************************************************************/
-int Field_datetime::store(const char *from,uint len,CHARSET_INFO *cs)
+void Field_datetime::store_TIME(MYSQL_TIME *ltime)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE;
- MYSQL_TIME time_tmp;
- int error;
- ulonglong tmp= 0;
- enum enum_mysql_timestamp_type func_res;
- THD *thd= table ? table->in_use : current_thd;
-
- func_res= str_to_datetime(from, len, &time_tmp,
- (TIME_FUZZY_DATE |
- (thd->variables.sql_mode &
- (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
- MODE_INVALID_DATES))),
- &error);
- if ((int) func_res > (int) MYSQL_TIMESTAMP_ERROR)
- tmp= TIME_to_ulonglong_datetime(&time_tmp);
- else
- error= 1; // Fix if invalid zero date
-
- if (error)
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_OUT_OF_RANGE,
- from, len, MYSQL_TIMESTAMP_DATETIME, 1);
-
-#ifdef WORDS_BIGENDIAN
- if (table && table->s->db_low_byte_first)
- {
+ ulonglong tmp= TIME_to_ulonglong_datetime(ltime);
+ if (BIGENDIAN && table && table->s->db_low_byte_first)
int8store(ptr,tmp);
- }
else
-#endif
longlongstore(ptr,tmp);
- return error;
-}
-
-
-int Field_datetime::store(double nr)
-{
- int error= 0;
- if (nr < 0.0 || nr > 99991231235959.0)
- {
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_OUT_OF_RANGE,
- nr, MYSQL_TIMESTAMP_DATETIME);
- nr= 0.0;
- error= 1;
- }
- error|= Field_datetime::store((longlong) rint(nr), FALSE);
- return error;
-}
-
-
-int Field_datetime::store(longlong nr, bool unsigned_val)
-{
- ASSERT_COLUMN_MARKED_FOR_WRITE;
- MYSQL_TIME not_used;
- int error;
- longlong initial_nr= nr;
- THD *thd= table ? table->in_use : current_thd;
-
- nr= number_to_datetime(nr, &not_used, (TIME_FUZZY_DATE |
- (thd->variables.sql_mode &
- (MODE_NO_ZERO_IN_DATE |
- MODE_NO_ZERO_DATE |
- MODE_INVALID_DATES))), &error);
-
- if (nr == LL(-1))
- {
- nr= 0;
- error= 2;
- }
-
- if (error)
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- error == 2 ? ER_WARN_DATA_OUT_OF_RANGE :
- WARN_DATA_TRUNCATED, initial_nr,
- MYSQL_TIMESTAMP_DATETIME, 1);
-
-#ifdef WORDS_BIGENDIAN
- if (table && table->s->db_low_byte_first)
- {
- int8store(ptr,nr);
- }
- else
-#endif
- longlongstore(ptr,nr);
- return error;
-}
-
-
-int Field_datetime::store_time(MYSQL_TIME *ltime,timestamp_type time_type)
-{
- ASSERT_COLUMN_MARKED_FOR_WRITE;
- longlong tmp;
- int error= 0;
- /*
- We don't perform range checking here since values stored in TIME
- structure always fit into DATETIME range.
- */
- if (time_type == MYSQL_TIMESTAMP_DATE ||
- time_type == MYSQL_TIMESTAMP_DATETIME)
- {
- tmp=((ltime->year*10000L+ltime->month*100+ltime->day)*LL(1000000)+
- (ltime->hour*10000L+ltime->minute*100+ltime->second));
- if (check_date(ltime, tmp != 0,
- (TIME_FUZZY_DATE |
- (current_thd->variables.sql_mode &
- (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
- MODE_INVALID_DATES))), &error))
- {
- char buff[MAX_DATE_STRING_REP_LENGTH];
- String str(buff, sizeof(buff), &my_charset_latin1);
- tmp= 0;
- make_datetime((DATE_TIME_FORMAT *) 0, ltime, &str);
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED,
- str.ptr(), str.length(), MYSQL_TIMESTAMP_DATETIME,1);
- }
- }
- else
- {
- tmp=0;
- error= 1;
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1);
- }
-#ifdef WORDS_BIGENDIAN
- if (table && table->s->db_low_byte_first)
- {
- int8store(ptr,tmp);
- }
- else
-#endif
- longlongstore(ptr,tmp);
- return error;
}
bool Field_datetime::send_binary(Protocol *protocol)
{
MYSQL_TIME tm;
Field_datetime::get_date(&tm, TIME_FUZZY_DATE);
- return protocol->store(&tm);
+ return protocol->store(&tm, 0);
}
@@ -6122,11 +5931,9 @@ longlong Field_datetime::val_int(void)
{
ASSERT_COLUMN_MARKED_FOR_READ;
longlong j;
-#ifdef WORDS_BIGENDIAN
- if (table && table->s->db_low_byte_first)
+ if (BIGENDIAN && table && table->s->db_low_byte_first)
j=sint8korr(ptr);
else
-#endif
longlongget(j,ptr);
return j;
}
@@ -6135,20 +5942,16 @@ longlong Field_datetime::val_int(void)
String *Field_datetime::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
- ASSERT_COLUMN_MARKED_FOR_READ;
val_buffer->alloc(field_length);
val_buffer->length(field_length);
+
+ ASSERT_COLUMN_MARKED_FOR_READ;
ulonglong tmp;
long part1,part2;
char *pos;
int part3;
-#ifdef WORDS_BIGENDIAN
- if (table && table->s->db_low_byte_first)
- tmp=sint8korr(ptr);
- else
-#endif
- longlongget(tmp,ptr);
+ tmp= Field_datetime::val_int();
/*
Avoid problem with slow longlong arithmetic and sprintf
@@ -6200,22 +6003,15 @@ bool Field_datetime::get_date(MYSQL_TIME *ltime, uint fuzzydate)
return (!(fuzzydate & TIME_FUZZY_DATE) && (!ltime->month || !ltime->day)) ? 1 : 0;
}
-bool Field_datetime::get_time(MYSQL_TIME *ltime)
-{
- return Field_datetime::get_date(ltime,0);
-}
-
int Field_datetime::cmp(const uchar *a_ptr, const uchar *b_ptr)
{
longlong a,b;
-#ifdef WORDS_BIGENDIAN
- if (table && table->s->db_low_byte_first)
+ if (BIGENDIAN && table && table->s->db_low_byte_first)
{
a=sint8korr(a_ptr);
b=sint8korr(b_ptr);
}
else
-#endif
{
longlongget(a,a_ptr);
longlongget(b,b_ptr);
@@ -6226,8 +6022,7 @@ int Field_datetime::cmp(const uchar *a_ptr, const uchar *b_ptr)
void Field_datetime::sort_string(uchar *to,uint length __attribute__((unused)))
{
-#ifdef WORDS_BIGENDIAN
- if (!table || !table->s->db_low_byte_first)
+ if (BIGENDIAN && !(table && table->s->db_low_byte_first))
{
to[0] = ptr[0];
to[1] = ptr[1];
@@ -6239,7 +6034,6 @@ void Field_datetime::sort_string(uchar *to,uint length __attribute__((unused)))
to[7] = ptr[7];
}
else
-#endif
{
to[0] = ptr[7];
to[1] = ptr[6];
@@ -6258,6 +6052,96 @@ void Field_datetime::sql_type(String &res) const
res.set_ascii(STRING_WITH_LEN("datetime"));
}
+void Field_datetime_hires::store_TIME(MYSQL_TIME *ltime)
+{
+ ulonglong packed= sec_part_shift(pack_time(ltime), dec);
+ store_bigendian(packed, ptr, Field_datetime_hires::pack_length());
+}
+
+int Field_datetime_hires::store_decimal(const my_decimal *d)
+{
+ char buff[DECIMAL_MAX_STR_LENGTH+1];
+ String str(buff, sizeof(buff), &my_charset_bin);
+ my_decimal2string(E_DEC_FATAL_ERROR, d,
+ MAX_DATETIME_COMPRESSED_WIDTH + MAX_DATETIME_PRECISION,
+ 6, '0', &str);
+ return store(str.ptr(), str.length(), str.charset());
+}
+
+bool Field_datetime_hires::send_binary(Protocol *protocol)
+{
+ MYSQL_TIME ltime;
+ Field_datetime_hires::get_date(&ltime, TIME_FUZZY_DATE);
+ return protocol->store(&ltime, dec);
+}
+
+
+double Field_datetime_hires::val_real(void)
+{
+ MYSQL_TIME ltime;
+ Field_datetime_hires::get_date(&ltime, TIME_FUZZY_DATE);
+ return TIME_to_double(&ltime);
+}
+
+longlong Field_datetime_hires::val_int(void)
+{
+ MYSQL_TIME ltime;
+ Field_datetime_hires::get_date(&ltime, TIME_FUZZY_DATE);
+ return TIME_to_ulonglong_datetime(&ltime);
+}
+
+
+String *Field_datetime_hires::val_str(String *str,
+ String *unused __attribute__((unused)))
+{
+ MYSQL_TIME ltime;
+ Field_datetime_hires::get_date(&ltime, TIME_FUZZY_DATE);
+ str->alloc(field_length+1);
+ str->length(field_length);
+ my_datetime_to_str(&ltime, (char*) str->ptr(), dec);
+ str->set_charset(&my_charset_bin);
+ return str;
+}
+
+bool Field_datetime_hires::get_date(MYSQL_TIME *ltime, uint fuzzydate)
+{
+ ulonglong packed= read_bigendian(ptr, Field_datetime_hires::pack_length());
+ unpack_time(sec_part_unshift(packed, dec), ltime);
+ return (!(fuzzydate & TIME_FUZZY_DATE) && (!ltime->month || !ltime->day)) ? 1 : 0;
+}
+
+uint32 Field_datetime_hires::pack_length() const
+{
+ return 5 + sec_part_bytes[dec];
+}
+
+int Field_datetime_hires::cmp(const uchar *a_ptr, const uchar *b_ptr)
+{
+ ulonglong a=read_bigendian(a_ptr, Field_datetime_hires::pack_length());
+ ulonglong b=read_bigendian(b_ptr, Field_datetime_hires::pack_length());
+ return a < b ? -1 : a > b ? 1 : 0;
+}
+
+void Field_datetime_hires::sort_string(uchar *to,uint length __attribute__((unused)))
+{
+ DBUG_ASSERT(length == Field_datetime_hires::pack_length());
+ memcpy(to, ptr, length);
+}
+
+
+void Field_datetime_hires::sql_type(String &res) const
+{
+ CHARSET_INFO *cs=res.charset();
+ res.length(cs->cset->snprintf(cs, (char*) res.ptr(), res.alloced_length(),
+ "datetime(%u)", dec));
+}
+
+void Field_datetime_hires::make_field(Send_field *field)
+{
+ Field::make_field(field);
+ field->decimals= dec;
+}
+
/****************************************************************************
** string type
** A string may be varchar or binary
@@ -7571,98 +7455,19 @@ void Field_blob::store_length(uchar *i_ptr,
uint32 i_number,
bool low_byte_first)
{
- switch (i_packlength) {
- case 1:
- i_ptr[0]= (uchar) i_number;
- break;
- case 2:
-#ifdef WORDS_BIGENDIAN
- if (low_byte_first)
- {
- int2store(i_ptr,(unsigned short) i_number);
- }
- else
-#endif
- shortstore(i_ptr,(unsigned short) i_number);
- break;
- case 3:
- int3store(i_ptr,i_number);
- break;
- case 4:
-#ifdef WORDS_BIGENDIAN
- if (low_byte_first)
- {
- int4store(i_ptr,i_number);
- }
- else
-#endif
- longstore(i_ptr,i_number);
- }
+ if (BIGENDIAN && low_byte_first)
+ store_lowendian(i_number, i_ptr, i_packlength);
+ else
+ store_native(i_number, i_ptr, i_packlength);
}
uint32 Field_blob::get_length(const uchar *pos, uint packlength_arg, bool low_byte_first)
{
- switch (packlength_arg) {
- case 1:
- return (uint32) pos[0];
- case 2:
- {
- uint16 tmp;
-#ifdef WORDS_BIGENDIAN
- if (low_byte_first)
- tmp=sint2korr(pos);
- else
-#endif
- shortget(tmp,pos);
- return (uint32) tmp;
- }
- case 3:
- return (uint32) uint3korr(pos);
- case 4:
- {
- uint32 tmp;
-#ifdef WORDS_BIGENDIAN
- if (low_byte_first)
- tmp=uint4korr(pos);
- else
-#endif
- longget(tmp,pos);
- return (uint32) tmp;
- }
- }
- /* When expanding this, see also MAX_FIELD_BLOBLENGTH. */
- return 0; // Impossible
-}
-
-
-/**
- Put a blob length field into a record buffer.
-
- Depending on the maximum length of a blob, its length field is
- put into 1 to 4 bytes. This is a property of the blob object,
- described by 'packlength'.
-
- @param pos Pointer into the record buffer.
- @param length The length value to put.
-*/
-
-void Field_blob::put_length(uchar *pos, uint32 length)
-{
- switch (packlength) {
- case 1:
- *pos= (char) length;
- break;
- case 2:
- int2store(pos, length);
- break;
- case 3:
- int3store(pos, length);
- break;
- case 4:
- int4store(pos, length);
- break;
- }
+ if (BIGENDIAN && table->s->db_low_byte_first)
+ return read_lowendian(pos, packlength_arg);
+ else
+ return read_native(pos, packlength_arg);
}
@@ -8001,20 +7806,7 @@ void Field_blob::sort_string(uchar *to,uint length)
length-= packlength;
pos= to+length;
- switch (packlength) {
- case 1:
- *pos= (char) blob_length;
- break;
- case 2:
- mi_int2store(pos, blob_length);
- break;
- case 3:
- mi_int3store(pos, blob_length);
- break;
- case 4:
- mi_int4store(pos, blob_length);
- break;
- }
+ store_bigendian(blob_length, pos, packlength);
}
memcpy_fixed(&blob,ptr+packlength,sizeof(char*));
@@ -8217,7 +8009,7 @@ Field_blob::unpack_key(uchar *to, const uchar *from, uint max_length,
length+= *from++ << 8;
/* put the length into the record buffer */
- put_length(to, length);
+ store_length(to, packlength, length, table->s->db_low_byte_first);
/* put the address of the blob buffer or NULL */
if (length)
@@ -8385,39 +8177,10 @@ enum ha_base_keytype Field_enum::key_type() const
void Field_enum::store_type(ulonglong value)
{
- switch (packlength) {
- case 1: ptr[0]= (uchar) value; break;
- case 2:
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- {
- int2store(ptr,(unsigned short) value);
- }
- else
-#endif
- shortstore(ptr,(unsigned short) value);
- break;
- case 3: int3store(ptr,(long) value); break;
- case 4:
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- {
- int4store(ptr,value);
- }
- else
-#endif
- longstore(ptr,(long) value);
- break;
- case 8:
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- {
- int8store(ptr,value);
- }
+ if (BIGENDIAN && table->s->db_low_byte_first)
+ store_lowendian(value, ptr, packlength);
else
-#endif
- longlongstore(ptr,value); break;
- }
+ store_native(value, ptr, packlength);
}
@@ -8503,46 +8266,10 @@ double Field_enum::val_real(void)
longlong Field_enum::val_int(void)
{
ASSERT_COLUMN_MARKED_FOR_READ;
- switch (packlength) {
- case 1:
- return (longlong) ptr[0];
- case 2:
- {
- uint16 tmp;
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- tmp=sint2korr(ptr);
- else
-#endif
- shortget(tmp,ptr);
- return (longlong) tmp;
- }
- case 3:
- return (longlong) uint3korr(ptr);
- case 4:
- {
- uint32 tmp;
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- tmp=uint4korr(ptr);
- else
-#endif
- longget(tmp,ptr);
- return (longlong) tmp;
- }
- case 8:
- {
- longlong tmp;
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- tmp=sint8korr(ptr);
- else
-#endif
- longlongget(tmp,ptr);
- return tmp;
- }
- }
- return 0; // impossible
+ if (BIGENDIAN && table->s->db_low_byte_first)
+ return read_lowendian(ptr, packlength);
+ else
+ return read_native(ptr, packlength);
}
@@ -9765,28 +9492,14 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
}
break;
case MYSQL_TYPE_TIMESTAMP:
- if (fld_length == NULL)
+ if (length > MAX_DATETIME_PRECISION)
{
- length= MAX_DATETIME_WIDTH;
- }
- else if (length != MAX_DATETIME_WIDTH)
- {
- /*
- We support only even TIMESTAMP lengths less or equal than 14
- and 19 as length of 4.1 compatible representation. Silently
- shrink it to MAX_DATETIME_COMPRESSED_WIDTH.
- */
- DBUG_ASSERT(MAX_DATETIME_COMPRESSED_WIDTH < UINT_MAX);
- if (length != UINT_MAX) /* avoid overflow; is safe because of min() */
- length= ((length+1)/2)*2;
- length= min(length, MAX_DATETIME_COMPRESSED_WIDTH);
+ my_error(ER_TOO_BIG_PRECISION, MYF(0), length, fld_name,
+ MAX_DATETIME_PRECISION);
+ DBUG_RETURN(TRUE);
}
- flags|= ZEROFILL_FLAG | UNSIGNED_FLAG;
- /*
- Since we silently rewrite down to MAX_DATETIME_COMPRESSED_WIDTH bytes,
- the parser should not raise errors unless bizzarely large.
- */
- max_field_charlength= UINT_MAX;
+ length+= MAX_DATETIME_WIDTH + (length ? 1 : 0);
+ flags|= UNSIGNED_FLAG;
if (fld_default_value)
{
@@ -9835,10 +9548,22 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
length= MAX_DATE_WIDTH;
break;
case MYSQL_TYPE_TIME:
- length= 10;
+ if (length > MAX_DATETIME_PRECISION)
+ {
+ my_error(ER_TOO_BIG_PRECISION, MYF(0), length, fld_name,
+ MAX_DATETIME_PRECISION);
+ DBUG_RETURN(TRUE);
+ }
+ length+= MIN_TIME_WIDTH + (length ? 1 : 0);
break;
case MYSQL_TYPE_DATETIME:
- length= MAX_DATETIME_WIDTH;
+ if (length > MAX_DATETIME_PRECISION)
+ {
+ my_error(ER_TOO_BIG_PRECISION, MYF(0), length, fld_name,
+ MAX_DATETIME_PRECISION);
+ DBUG_RETURN(TRUE);
+ }
+ length+= MAX_DATETIME_WIDTH + (length ? 1 : 0);
break;
case MYSQL_TYPE_SET:
{
@@ -9958,14 +9683,22 @@ uint32 calc_pack_length(enum_field_types type,uint32 length)
case MYSQL_TYPE_TINY : return 1;
case MYSQL_TYPE_SHORT : return 2;
case MYSQL_TYPE_INT24:
- case MYSQL_TYPE_NEWDATE:
- case MYSQL_TYPE_TIME: return 3;
+ case MYSQL_TYPE_NEWDATE: return 3;
+ case MYSQL_TYPE_TIME: return length > MIN_TIME_WIDTH
+ ? 3 + sec_part_bytes[length - 1 - MIN_TIME_WIDTH]
+ : 3;
case MYSQL_TYPE_TIMESTAMP:
+ return length > MAX_DATETIME_WIDTH
+ ? 4 + sec_part_bytes[length - 1 - MAX_DATETIME_WIDTH]
+ : 4;
case MYSQL_TYPE_DATE:
case MYSQL_TYPE_LONG : return 4;
case MYSQL_TYPE_FLOAT : return sizeof(float);
case MYSQL_TYPE_DOUBLE: return sizeof(double);
case MYSQL_TYPE_DATETIME:
+ return length > MAX_DATETIME_WIDTH
+ ? 5 + sec_part_bytes[length - 1 - MAX_DATETIME_WIDTH]
+ : 8;
case MYSQL_TYPE_LONGLONG: return 8; /* Don't crash if no longlong */
case MYSQL_TYPE_NULL : return 0;
case MYSQL_TYPE_TINY_BLOB: return 1+portable_sizeof_char_ptr;
@@ -10138,9 +9871,12 @@ Field *make_field(TABLE_SHARE *share, uchar *ptr, uint32 field_length,
f_is_zerofill(pack_flag) != 0,
f_is_dec(pack_flag) == 0);
case MYSQL_TYPE_TIMESTAMP:
- return new Field_timestamp(ptr,field_length, null_pos, null_bit,
- unireg_check, field_name, share,
- field_charset);
+ {
+ uint dec= field_length > MAX_DATETIME_WIDTH ?
+ field_length - MAX_DATETIME_WIDTH - 1: 0;
+ return new_Field_timestamp(ptr, null_pos, null_bit, unireg_check,
+ field_name, share, dec, field_charset);
+ }
case MYSQL_TYPE_YEAR:
return new Field_year(ptr,field_length,null_pos,null_bit,
unireg_check, field_name);
@@ -10151,11 +9887,19 @@ Field *make_field(TABLE_SHARE *share, uchar *ptr, uint32 field_length,
return new Field_newdate(ptr,null_pos,null_bit,
unireg_check, field_name, field_charset);
case MYSQL_TYPE_TIME:
- return new Field_time(ptr,null_pos,null_bit,
- unireg_check, field_name, field_charset);
+ {
+ uint dec= field_length > MIN_TIME_WIDTH ?
+ field_length - MIN_TIME_WIDTH - 1: 0;
+ return new_Field_time(ptr, null_pos, null_bit, unireg_check,
+ field_name, dec, field_charset);
+ }
case MYSQL_TYPE_DATETIME:
- return new Field_datetime(ptr,null_pos,null_bit,
- unireg_check, field_name, field_charset);
+ {
+ uint dec= field_length > MAX_DATETIME_WIDTH ?
+ field_length - MAX_DATETIME_WIDTH - 1: 0;
+ return new_Field_datetime(ptr, null_pos, null_bit, unireg_check,
+ field_name, dec, field_charset);
+ }
case MYSQL_TYPE_NULL:
return new Field_null(ptr, field_length, unireg_check, field_name,
field_charset);
@@ -10337,7 +10081,6 @@ Field::set_warning(MYSQL_ERROR::enum_warning_level level, uint code,
@param level level of message (Note/Warning/Error)
@param code error code of message to be produced
@param str string value which we tried to save
- @param str_length length of string which we tried to save
@param ts_type type of datetime value (datetime/date/time)
@param cuted_increment whenever we should increase cut fields count or not
@@ -10345,80 +10088,19 @@ Field::set_warning(MYSQL_ERROR::enum_warning_level level, uint code,
This function will always produce some warning but won't increase cut
fields counter if count_cuted_fields ==FIELD_CHECK_IGNORE for current
thread.
+
+ See also bug#2336
+
*/
-void
-Field::set_datetime_warning(MYSQL_ERROR::enum_warning_level level, uint code,
- const char *str, uint str_length,
+void Field::set_datetime_warning(MYSQL_ERROR::enum_warning_level level,
+ uint code, const Lazy_string *str,
timestamp_type ts_type, int cuted_increment)
{
THD *thd= table ? table->in_use : current_thd;
if ((thd->really_abort_on_warning() &&
level >= MYSQL_ERROR::WARN_LEVEL_WARN) ||
set_warning(level, code, cuted_increment))
- make_truncated_value_warning(thd, level, str, str_length, ts_type,
- field_name);
-}
-
-
-/**
- Produce warning or note about integer datetime value saved into field.
-
- @param level level of message (Note/Warning/Error)
- @param code error code of message to be produced
- @param nr numeric value which we tried to save
- @param ts_type type of datetime value (datetime/date/time)
- @param cuted_increment whenever we should increase cut fields count or not
-
- @note
- This function will always produce some warning but won't increase cut
- fields counter if count_cuted_fields == FIELD_CHECK_IGNORE for current
- thread.
-*/
-
-void
-Field::set_datetime_warning(MYSQL_ERROR::enum_warning_level level, uint code,
- longlong nr, timestamp_type ts_type,
- int cuted_increment)
-{
- THD *thd= table ? table->in_use : current_thd;
- if (thd->really_abort_on_warning() ||
- set_warning(level, code, cuted_increment))
- {
- char str_nr[22];
- char *str_end= longlong10_to_str(nr, str_nr, -10);
- make_truncated_value_warning(thd, level, str_nr, (uint) (str_end - str_nr),
- ts_type, field_name);
- }
+ make_truncated_value_warning(thd, level, str, ts_type, field_name);
}
-
-/**
- Produce warning or note about double datetime data saved into field.
-
- @param level level of message (Note/Warning/Error)
- @param code error code of message to be produced
- @param nr double value which we tried to save
- @param ts_type type of datetime value (datetime/date/time)
-
- @note
- This function will always produce some warning but won't increase cut
- fields counter if count_cuted_fields == FIELD_CHECK_IGNORE for current
- thread.
-*/
-
-void
-Field::set_datetime_warning(MYSQL_ERROR::enum_warning_level level, uint code,
- double nr, timestamp_type ts_type)
-{
- THD *thd= table ? table->in_use : current_thd;
- if (thd->really_abort_on_warning() ||
- set_warning(level, code, 1))
- {
- /* DBL_DIG is enough to print '-[digits].E+###' */
- char str_nr[DBL_DIG + 8];
- uint str_len= sprintf(str_nr, "%g", nr);
- make_truncated_value_warning(thd, level, str_nr, str_len, ts_type,
- field_name);
- }
-}
diff --git a/sql/field.h b/sql/field.h
index cbdfa686ff8..9475e28bc0f 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -22,8 +22,13 @@
#pragma interface /* gcc class implementation */
#endif
+#ifdef WORDS_BIGENDIAN
+#define BIGENDIAN 1
+#else
+#define BIGENDIAN 0
+#endif
+
#define NOT_FIXED_DEC 31
-#define DATETIME_DEC 6
const uint32 max_field_size= (uint32) 4294967295U;
class Send_field;
@@ -299,14 +304,6 @@ public:
virtual void make_field(Send_field *);
virtual void sort_string(uchar *buff,uint length)=0;
virtual bool optimize_range(uint idx, uint part);
- /*
- This should be true for fields which, when compared with constant
- items, can be casted to longlong. In this case we will at 'fix_fields'
- stage cast the constant items to longlongs and at the execution stage
- use field->val_int() for comparison. Used to optimize clauses like
- 'a_column BETWEEN date_const, date_const'.
- */
- virtual bool can_be_compared_as_longlong() const { return FALSE; }
virtual void free() {}
virtual Field *new_field(MEM_ROOT *root, struct st_table *new_table,
bool keep_type);
@@ -447,7 +444,7 @@ public:
void copy_from_tmp(int offset);
uint fill_cache_field(struct st_cache_field *copy);
virtual bool get_date(MYSQL_TIME *ltime,uint fuzzydate);
- virtual bool get_time(MYSQL_TIME *ltime);
+ bool get_time(MYSQL_TIME *ltime) { return get_date(ltime, TIME_TIME_ONLY); }
virtual CHARSET_INFO *charset(void) const { return &my_charset_bin; }
virtual CHARSET_INFO *sort_charset(void) const { return charset(); }
virtual bool has_charset(void) const { return FALSE; }
@@ -455,16 +452,12 @@ public:
virtual enum Derivation derivation(void) const
{ return DERIVATION_IMPLICIT; }
virtual void set_derivation(enum Derivation derivation_arg) { }
+ virtual int set_time() { return 1; }
bool set_warning(MYSQL_ERROR::enum_warning_level, unsigned int code,
int cuted_increment);
void set_datetime_warning(MYSQL_ERROR::enum_warning_level, uint code,
- const char *str, uint str_len,
- timestamp_type ts_type, int cuted_increment);
- void set_datetime_warning(MYSQL_ERROR::enum_warning_level, uint code,
- longlong nr, timestamp_type ts_type,
+ const Lazy_string *str, timestamp_type ts_type,
int cuted_increment);
- void set_datetime_warning(MYSQL_ERROR::enum_warning_level, const uint code,
- double nr, timestamp_type ts_type);
inline bool check_overflow(int op_result)
{
return (op_result == E_DEC_OVERFLOW);
@@ -555,18 +548,14 @@ protected:
bool low_byte_first_from, bool low_byte_first_to)
{
int32 val;
-#ifdef WORDS_BIGENDIAN
- if (low_byte_first_from)
+ if (BIGENDIAN && low_byte_first_from)
val = sint4korr(from);
else
-#endif
longget(val, from);
-#ifdef WORDS_BIGENDIAN
- if (low_byte_first_to)
+ if (BIGENDIAN && low_byte_first_to)
int4store(to, val);
else
-#endif
longstore(to, val);
}
@@ -577,18 +566,14 @@ protected:
bool low_byte_first_from, bool low_byte_first_to)
{
int64 val;
-#ifdef WORDS_BIGENDIAN
- if (low_byte_first_from)
+ if (BIGENDIAN && low_byte_first_from)
val = sint8korr(from);
else
-#endif
longlongget(val, from);
-#ifdef WORDS_BIGENDIAN
- if (low_byte_first_to)
+ if (BIGENDIAN && low_byte_first_to)
int8store(to, val);
else
-#endif
longlongstore(to, val);
}
@@ -681,7 +666,6 @@ public:
uint is_equal(Create_field *new_field);
};
-
/* base class for Field_string, Field_varstring and Field_blob */
class Field_longstr :public Field_str
@@ -899,18 +883,14 @@ public:
uint max_length, bool low_byte_first)
{
int16 val;
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
+ if (BIGENDIAN && table->s->db_low_byte_first)
val = sint2korr(from);
else
-#endif
shortget(val, from);
-#ifdef WORDS_BIGENDIAN
- if (low_byte_first)
+ if (BIGENDIAN && low_byte_first)
int2store(to, val);
else
-#endif
shortstore(to, val);
return to + sizeof(val);
}
@@ -919,18 +899,14 @@ public:
uint param_data, bool low_byte_first)
{
int16 val;
-#ifdef WORDS_BIGENDIAN
- if (low_byte_first)
+ if (BIGENDIAN && low_byte_first)
val = sint2korr(from);
else
-#endif
shortget(val, from);
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
+ if (BIGENDIAN && table->s->db_low_byte_first)
int2store(to, val);
else
-#endif
shortstore(to, val);
return from + sizeof(val);
}
@@ -1025,7 +1001,6 @@ public:
};
-#ifdef HAVE_LONG_LONG
class Field_longlong :public Field_num {
public:
Field_longlong(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
@@ -1062,7 +1037,6 @@ public:
void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return 8; }
void sql_type(String &str) const;
- bool can_be_compared_as_longlong() const { return TRUE; }
uint32 max_display_length() { return 20; }
virtual uchar *pack(uchar* to, const uchar *from,
uint max_length __attribute__((unused)),
@@ -1077,7 +1051,6 @@ public:
return unpack_int64(to, from, low_byte_first);
}
};
-#endif
class Field_float :public Field_real {
@@ -1188,6 +1161,8 @@ public:
class Field_timestamp :public Field_str {
+ int store_TIME_with_warning(THD *, MYSQL_TIME *, const Lazy_string *,
+ bool, bool);
public:
Field_timestamp(uchar *ptr_arg, uint32 len_arg,
uchar *null_ptr_arg, uchar null_bit_arg,
@@ -1197,11 +1172,11 @@ public:
CHARSET_INFO *cs);
enum_field_types type() const { return MYSQL_TYPE_TIMESTAMP;}
enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONG_INT; }
- enum Item_result cmp_type () const { return INT_RESULT; }
+ enum Item_result cmp_type () const { return TIME_RESULT; }
int store(const char *to,uint length,CHARSET_INFO *charset);
int store(double nr);
int store(longlong nr, bool unsigned_val);
- int reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=0; return 0; }
+ int store_time(MYSQL_TIME *ltime, timestamp_type type);
double val_real(void);
longlong val_int(void);
String *val_str(String*,String *);
@@ -1210,9 +1185,9 @@ public:
void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return 4; }
void sql_type(String &str) const;
- bool can_be_compared_as_longlong() const { return TRUE; }
bool zero_pack() const { return 0; }
- void set_time();
+ uint decimals() const { return 0; }
+ virtual int set_time();
virtual void set_default()
{
if (table->timestamp_field == this &&
@@ -1222,31 +1197,15 @@ public:
Field::set_default();
}
/* Get TIMESTAMP field value as seconds since begging of Unix Epoch */
- inline long get_timestamp(my_bool *null_value)
+ virtual long get_timestamp(ulong *sec_part) const;
+ virtual void store_TIME(my_time_t timestamp, ulong sec_part)
{
- if ((*null_value= is_null()))
- return 0;
-#ifdef WORDS_BIGENDIAN
- if (table && table->s->db_low_byte_first)
- return sint4korr(ptr);
-#endif
- long tmp;
- longget(tmp,ptr);
- return tmp;
- }
- inline void store_timestamp(my_time_t timestamp)
- {
-#ifdef WORDS_BIGENDIAN
- if (table && table->s->db_low_byte_first)
- {
+ if (BIGENDIAN && table && table->s->db_low_byte_first)
int4store(ptr,timestamp);
- }
else
-#endif
longstore(ptr,(uint32) timestamp);
}
bool get_date(MYSQL_TIME *ltime,uint fuzzydate);
- bool get_time(MYSQL_TIME *ltime);
timestamp_auto_set_type get_auto_set_type() const;
uchar *pack(uchar *to, const uchar *from,
uint max_length __attribute__((unused)), bool low_byte_first)
@@ -1262,6 +1221,43 @@ public:
};
+class Field_timestamp_hires :public Field_timestamp {
+ uint dec;
+public:
+ Field_timestamp_hires(uchar *ptr_arg,
+ uchar *null_ptr_arg, uchar null_bit_arg,
+ enum utype unireg_check_arg, const char *field_name_arg,
+ TABLE_SHARE *share, uint dec_arg, CHARSET_INFO *cs) :
+ Field_timestamp(ptr_arg, MAX_DATETIME_WIDTH + dec_arg + 1, null_ptr_arg,
+ null_bit_arg, unireg_check_arg, field_name_arg, share, cs),
+ dec(dec_arg)
+ {
+ DBUG_ASSERT(dec);
+ DBUG_ASSERT(dec <= MAX_SEC_PART_DIGITS);
+ }
+ void sql_type(String &str) const;
+ long get_timestamp(ulong *sec_part) const;
+ void store_TIME(my_time_t timestamp, ulong sec_part);
+ int store_decimal(const my_decimal *d);
+ double val_real(void);
+ String *val_str(String*,String *);
+ bool send_binary(Protocol *protocol);
+ int cmp(const uchar *,const uchar *);
+ void sort_string(uchar *buff,uint length);
+ uint decimals() const { return dec; }
+ int set_time();
+ enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; }
+ void make_field(Send_field *field);
+ uint32 pack_length() const;
+ uchar *pack(uchar *to, const uchar *from,
+ uint max_length, bool low_byte_first)
+ { return Field::pack(to, from, max_length, low_byte_first); }
+ const uchar *unpack(uchar* to, const uchar *from, uint param_data,
+ bool low_byte_first)
+ { return Field::unpack(to, from, param_data, low_byte_first); }
+};
+
+
class Field_year :public Field_tiny {
public:
Field_year(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
@@ -1279,39 +1275,51 @@ public:
String *val_str(String*,String *);
bool send_binary(Protocol *protocol);
void sql_type(String &str) const;
- bool can_be_compared_as_longlong() const { return TRUE; }
};
-class Field_date :public Field_str {
+class Field_temporal: public Field_str {
+protected:
+ int store_TIME_with_warning(MYSQL_TIME *ltime, const Lazy_string *str,
+ int was_cut, int have_smth_to_conv);
+ virtual void store_TIME(MYSQL_TIME *ltime) = 0;
+ virtual timestamp_type temporal_type() = 0;
+public:
+ Field_temporal(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
+ uchar null_bit_arg, utype unireg_check_arg,
+ const char *field_name_arg, CHARSET_INFO *charset_arg)
+ :Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg,
+ field_name_arg, charset_arg) { }
+ enum Item_result cmp_type () const { return TIME_RESULT; }
+ int store(const char *to,uint length,CHARSET_INFO *charset);
+ int store(double nr);
+ int store(longlong nr, bool unsigned_val);
+ int store_time(MYSQL_TIME *ltime, timestamp_type type);
+};
+
+class Field_date :public Field_temporal {
+ void store_TIME(MYSQL_TIME *ltime);
+ timestamp_type temporal_type()
+ { return MYSQL_TIMESTAMP_DATE; }
public:
Field_date(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
CHARSET_INFO *cs)
- :Field_str(ptr_arg, MAX_DATE_WIDTH, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg, cs)
+ :Field_temporal(ptr_arg, MAX_DATE_WIDTH, null_ptr_arg, null_bit_arg,
+ unireg_check_arg, field_name_arg, cs)
{}
- Field_date(bool maybe_null_arg, const char *field_name_arg,
- CHARSET_INFO *cs)
- :Field_str((uchar*) 0, MAX_DATE_WIDTH, maybe_null_arg ? (uchar*) "": 0,0,
- NONE, field_name_arg, cs) {}
enum_field_types type() const { return MYSQL_TYPE_DATE;}
enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONG_INT; }
- enum Item_result cmp_type () const { return INT_RESULT; }
- int store(const char *to,uint length,CHARSET_INFO *charset);
- int store(double nr);
- int store(longlong nr, bool unsigned_val);
int reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=0; return 0; }
double val_real(void);
longlong val_int(void);
String *val_str(String*,String *);
- bool get_time(MYSQL_TIME *ltime);
+ uint decimals() const { return 0; }
bool send_binary(Protocol *protocol);
int cmp(const uchar *,const uchar *);
void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return 4; }
void sql_type(String &str) const;
- bool can_be_compared_as_longlong() const { return TRUE; }
bool zero_pack() const { return 1; }
uchar *pack(uchar* to, const uchar *from,
uint max_length __attribute__((unused)), bool low_byte_first)
@@ -1327,27 +1335,21 @@ public:
};
-class Field_newdate :public Field_str {
+class Field_newdate :public Field_temporal {
+ void store_TIME(MYSQL_TIME *ltime);
+ timestamp_type temporal_type() { return MYSQL_TIMESTAMP_DATE; }
public:
Field_newdate(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
CHARSET_INFO *cs)
- :Field_str(ptr_arg, 10, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg, cs)
+ :Field_temporal(ptr_arg, MAX_DATE_WIDTH, null_ptr_arg, null_bit_arg,
+ unireg_check_arg, field_name_arg, cs)
{}
- Field_newdate(bool maybe_null_arg, const char *field_name_arg,
- CHARSET_INFO *cs)
- :Field_str((uchar*) 0,10, maybe_null_arg ? (uchar*) "": 0,0,
- NONE, field_name_arg, cs) {}
enum_field_types type() const { return MYSQL_TYPE_DATE;}
enum_field_types real_type() const { return MYSQL_TYPE_NEWDATE; }
enum ha_base_keytype key_type() const { return HA_KEYTYPE_UINT24; }
- enum Item_result cmp_type () const { return INT_RESULT; }
- int store(const char *to,uint length,CHARSET_INFO *charset);
- int store(double nr);
- int store(longlong nr, bool unsigned_val);
- int store_time(MYSQL_TIME *ltime, timestamp_type type);
int reset(void) { ptr[0]=ptr[1]=ptr[2]=0; return 0; }
+ uint decimals() const { return 0; }
double val_real(void);
longlong val_int(void);
String *val_str(String*,String *);
@@ -1356,75 +1358,84 @@ public:
void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return 3; }
void sql_type(String &str) const;
- bool can_be_compared_as_longlong() const { return TRUE; }
bool zero_pack() const { return 1; }
bool get_date(MYSQL_TIME *ltime,uint fuzzydate);
- bool get_time(MYSQL_TIME *ltime);
};
-class Field_time :public Field_str {
+class Field_time :public Field_temporal {
+ void store_TIME(MYSQL_TIME *ltime);
+ timestamp_type temporal_type()
+ { return MYSQL_TIMESTAMP_TIME; }
public:
- Field_time(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
- enum utype unireg_check_arg, const char *field_name_arg,
- CHARSET_INFO *cs)
- :Field_str(ptr_arg, 8, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg, cs)
+ Field_time(uchar *ptr_arg, uint length_arg, uchar *null_ptr_arg,
+ uchar null_bit_arg, enum utype unireg_check_arg,
+ const char *field_name_arg, CHARSET_INFO *cs)
+ :Field_temporal(ptr_arg, length_arg, null_ptr_arg, null_bit_arg,
+ unireg_check_arg, field_name_arg, cs)
{}
- Field_time(bool maybe_null_arg, const char *field_name_arg,
- CHARSET_INFO *cs)
- :Field_str((uchar*) 0,8, maybe_null_arg ? (uchar*) "": 0,0,
- NONE, field_name_arg, cs) {}
enum_field_types type() const { return MYSQL_TYPE_TIME;}
enum ha_base_keytype key_type() const { return HA_KEYTYPE_INT24; }
- enum Item_result cmp_type () const { return INT_RESULT; }
int store_time(MYSQL_TIME *ltime, timestamp_type type);
int store(const char *to,uint length,CHARSET_INFO *charset);
int store(double nr);
int store(longlong nr, bool unsigned_val);
- int reset(void) { ptr[0]=ptr[1]=ptr[2]=0; return 0; }
+ uint decimals() const { return 0; }
double val_real(void);
longlong val_int(void);
String *val_str(String*,String *);
bool get_date(MYSQL_TIME *ltime, uint fuzzydate);
bool send_binary(Protocol *protocol);
- bool get_time(MYSQL_TIME *ltime);
int cmp(const uchar *,const uchar *);
void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return 3; }
void sql_type(String &str) const;
- bool can_be_compared_as_longlong() const { return TRUE; }
bool zero_pack() const { return 1; }
};
+class Field_time_hires :public Field_time {
+ uint dec;
+ void store_TIME(MYSQL_TIME *ltime);
+public:
+ Field_time_hires(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
+ enum utype unireg_check_arg, const char *field_name_arg,
+ uint dec_arg, CHARSET_INFO *cs)
+ :Field_time(ptr_arg, MIN_TIME_WIDTH + dec_arg + 1, null_ptr_arg,
+ null_bit_arg, unireg_check_arg, field_name_arg, cs),
+ dec(dec_arg)
+ {
+ DBUG_ASSERT(dec);
+ DBUG_ASSERT(dec <= MAX_SEC_PART_DIGITS);
+ }
+ enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; }
+ uint decimals() const { return dec; }
+ longlong val_int(void) { return (longlong)floor(val_real()); }
+ double val_real(void);
+ String *val_str(String*,String *);
+ bool get_date(MYSQL_TIME *ltime, uint fuzzydate);
+ bool send_binary(Protocol *protocol);
+ int cmp(const uchar *,const uchar *);
+ void sort_string(uchar *buff,uint length);
+ uint32 pack_length() const;
+ void sql_type(String &str) const;
+ void make_field(Send_field *);
+};
-class Field_datetime :public Field_str {
+class Field_datetime :public Field_temporal {
+ void store_TIME(MYSQL_TIME *ltime);
+ timestamp_type temporal_type()
+ { return MYSQL_TIMESTAMP_DATETIME; }
public:
- Field_datetime(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
- enum utype unireg_check_arg, const char *field_name_arg,
- CHARSET_INFO *cs)
- :Field_str(ptr_arg, MAX_DATETIME_WIDTH, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg, cs)
+ Field_datetime(uchar *ptr_arg, uint length_arg, uchar *null_ptr_arg,
+ uchar null_bit_arg, enum utype unireg_check_arg,
+ const char *field_name_arg, CHARSET_INFO *cs)
+ :Field_temporal(ptr_arg, length_arg, null_ptr_arg, null_bit_arg,
+ unireg_check_arg, field_name_arg, cs)
{}
- Field_datetime(bool maybe_null_arg, const char *field_name_arg,
- CHARSET_INFO *cs)
- :Field_str((uchar*) 0, MAX_DATETIME_WIDTH, maybe_null_arg ? (uchar*) "": 0,0,
- NONE, field_name_arg, cs) {}
enum_field_types type() const { return MYSQL_TYPE_DATETIME;}
-#ifdef HAVE_LONG_LONG
enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONGLONG; }
-#endif
- enum Item_result cmp_type () const { return INT_RESULT; }
- uint decimals() const { return DATETIME_DEC; }
- int store(const char *to,uint length,CHARSET_INFO *charset);
- int store(double nr);
- int store(longlong nr, bool unsigned_val);
- int store_time(MYSQL_TIME *ltime, timestamp_type type);
- int reset(void)
- {
- ptr[0]=ptr[1]=ptr[2]=ptr[3]=ptr[4]=ptr[5]=ptr[6]=ptr[7]=0;
- return 0;
- }
+ enum Item_result cmp_type () const { return TIME_RESULT; }
+ uint decimals() const { return 0; }
double val_real(void);
longlong val_int(void);
String *val_str(String*,String *);
@@ -1433,10 +1444,8 @@ public:
void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return 8; }
void sql_type(String &str) const;
- bool can_be_compared_as_longlong() const { return TRUE; }
bool zero_pack() const { return 1; }
bool get_date(MYSQL_TIME *ltime,uint fuzzydate);
- bool get_time(MYSQL_TIME *ltime);
uchar *pack(uchar* to, const uchar *from,
uint max_length __attribute__((unused)), bool low_byte_first)
{
@@ -1451,6 +1460,81 @@ public:
};
+class Field_datetime_hires :public Field_datetime {
+ void store_TIME(MYSQL_TIME *ltime);
+ uint dec;
+public:
+ Field_datetime_hires(uchar *ptr_arg, uchar *null_ptr_arg,
+ uchar null_bit_arg, enum utype unireg_check_arg,
+ const char *field_name_arg, uint dec_arg,
+ CHARSET_INFO *cs)
+ :Field_datetime(ptr_arg, MAX_DATETIME_WIDTH + dec_arg + 1,
+ null_ptr_arg, null_bit_arg, unireg_check_arg,
+ field_name_arg, cs), dec(dec_arg)
+ {
+ DBUG_ASSERT(dec);
+ DBUG_ASSERT(dec <= MAX_SEC_PART_DIGITS);
+ }
+ enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; }
+ int store_decimal(const my_decimal *d);
+ uint decimals() const { return dec; }
+ void make_field(Send_field *field);
+ double val_real(void);
+ longlong val_int(void);
+ String *val_str(String*,String *);
+ bool send_binary(Protocol *protocol);
+ int cmp(const uchar *,const uchar *);
+ void sort_string(uchar *buff,uint length);
+ uint32 pack_length() const;
+ void sql_type(String &str) const;
+ bool get_date(MYSQL_TIME *ltime,uint fuzzydate);
+ uchar *pack(uchar *to, const uchar *from,
+ uint max_length, bool low_byte_first)
+ { return Field::pack(to, from, max_length, low_byte_first); }
+ const uchar *unpack(uchar* to, const uchar *from, uint param_data,
+ bool low_byte_first)
+ { return Field::unpack(to, from, param_data, low_byte_first); }
+};
+
+static inline Field_timestamp *
+new_Field_timestamp(uchar *ptr, uchar *null_ptr, uchar null_bit,
+ enum Field::utype unireg_check, const char *field_name,
+ TABLE_SHARE *share, uint dec, CHARSET_INFO *cs)
+{
+ if (dec==0 || dec == NOT_FIXED_DEC)
+ return new Field_timestamp(ptr, MAX_DATETIME_WIDTH, null_ptr, null_bit,
+ unireg_check, field_name, share, cs);
+ else
+ return new Field_timestamp_hires(ptr, null_ptr, null_bit, unireg_check,
+ field_name, share, dec, cs);
+}
+
+static inline Field_time *
+new_Field_time(uchar *ptr, uchar *null_ptr, uchar null_bit,
+ enum Field::utype unireg_check, const char *field_name,
+ uint dec, CHARSET_INFO *cs)
+{
+ if (dec == 0 || dec == NOT_FIXED_DEC)
+ return new Field_time(ptr, MIN_TIME_WIDTH, null_ptr, null_bit,
+ unireg_check, field_name, cs);
+ else
+ return new Field_time_hires(ptr, null_ptr, null_bit,
+ unireg_check, field_name, dec, cs);
+}
+
+static inline Field_datetime *
+new_Field_datetime(uchar *ptr, uchar *null_ptr, uchar null_bit,
+ enum Field::utype unireg_check,
+ const char *field_name, uint dec, CHARSET_INFO *cs)
+{
+ if (dec == 0 || dec == NOT_FIXED_DEC)
+ return new Field_datetime(ptr, MAX_DATETIME_WIDTH, null_ptr, null_bit,
+ unireg_check, field_name, cs);
+ else
+ return new Field_datetime_hires(ptr, null_ptr, null_bit,
+ unireg_check, field_name, dec, cs);
+}
+
class Field_string :public Field_longstr {
public:
bool can_alter_field_type;
@@ -1698,9 +1782,6 @@ public:
int reset(void) { bzero(ptr, packlength+sizeof(uchar*)); return 0; }
void reset_fields() { bzero((uchar*) &value,sizeof(value)); }
uint32 get_field_buffer_size(void) { return value.alloced_length(); }
-#ifndef WORDS_BIGENDIAN
- static
-#endif
void store_length(uchar *i_ptr, uint i_packlength, uint32 i_number, bool low_byte_first);
void store_length(uchar *i_ptr, uint i_packlength, uint32 i_number)
{
@@ -1727,7 +1808,6 @@ public:
uint32 get_length(const uchar *ptr, uint packlength, bool low_byte_first);
uint32 get_length(const uchar *ptr_arg)
{ return get_length(ptr_arg, this->packlength, table->s->db_low_byte_first); }
- void put_length(uchar *pos, uint32 length);
inline void get_ptr(uchar **str)
{
memcpy_fixed((uchar*) str,ptr+packlength,sizeof(uchar*));
diff --git a/sql/filesort.cc b/sql/filesort.cc
index 021cbdd2aad..236a628cce6 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -842,25 +842,26 @@ static void make_sortkey(register SORTPARAM *param,
break;
}
case INT_RESULT:
+ case TIME_RESULT:
{
- longlong value= item->val_int_result();
+ longlong value;
+ if (sort_field->result_type == INT_RESULT)
+ value= item->val_int_result();
+ else
+ {
+ MYSQL_TIME buf;
+ item->get_date_result(&buf, TIME_FUZZY_DATE | TIME_INVALID_DATES);
+ value= pack_time(&buf);
+ }
if (maybe_null)
{
- *to++=1; /* purecov: inspected */
if (item->null_value)
{
- if (maybe_null)
- bzero((char*) to-1,sort_field->length+1);
- else
- {
- DBUG_PRINT("warning",
- ("Got null on something that shouldn't be null"));
- bzero((char*) to,sort_field->length);
- }
+ bzero((char*) to++, sort_field->length+1);
break;
}
+ *to++=1; /* purecov: inspected */
}
-#if SIZEOF_LONG_LONG > 4
to[7]= (uchar) value;
to[6]= (uchar) (value >> 8);
to[5]= (uchar) (value >> 16);
@@ -872,15 +873,6 @@ static void make_sortkey(register SORTPARAM *param,
to[0]= (uchar) (value >> 56);
else
to[0]= (uchar) (value >> 56) ^ 128; /* Reverse signbit */
-#else
- to[3]= (uchar) value;
- to[2]= (uchar) (value >> 8);
- to[1]= (uchar) (value >> 16);
- if (item->unsigned_flag) /* Fix sign */
- to[0]= (uchar) (value >> 24);
- else
- to[0]= (uchar) (value >> 24) ^ 128; /* Reverse signbit */
-#endif
break;
}
case DECIMAL_RESULT:
@@ -890,8 +882,7 @@ static void make_sortkey(register SORTPARAM *param,
{
if (item->null_value)
{
- bzero((char*)to, sort_field->length+1);
- to++;
+ bzero((char*) to++, sort_field->length+1);
break;
}
*to++=1;
@@ -1462,9 +1453,7 @@ sortlength(THD *thd, SORT_FIELD *sortorder, uint s_length,
}
else
{
- sortorder->result_type= sortorder->item->result_type();
- if (sortorder->item->result_as_longlong())
- sortorder->result_type= INT_RESULT;
+ sortorder->result_type= sortorder->item->cmp_type();
switch (sortorder->result_type) {
case STRING_RESULT:
sortorder->length=sortorder->item->max_length;
@@ -1482,12 +1471,9 @@ sortlength(THD *thd, SORT_FIELD *sortorder, uint s_length,
sortorder->length+= sortorder->suffix_length;
}
break;
+ case TIME_RESULT:
case INT_RESULT:
-#if SIZEOF_LONG_LONG > 4
sortorder->length=8; // Size of intern longlong
-#else
- sortorder->length=4;
-#endif
break;
case DECIMAL_RESULT:
sortorder->length=
@@ -1562,6 +1548,7 @@ get_addon_fields(THD *thd, Field **ptabfield, uint sortlength, uint *plength)
Actually we need only the fields referred in the
result set. And for some of them it makes sense to use
the values directly from sorted fields.
+ But beware the case when item->cmp_type() != item->result_type()
*/
*plength= 0;
diff --git a/sql/item.cc b/sql/item.cc
index d88a6e80bfe..7f7e39c9dac 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -461,6 +461,34 @@ void Item::print_item_w_name(String *str, enum_query_type query_type)
}
+void Item::print_value(String *str)
+{
+ char buff[MAX_FIELD_WIDTH];
+ String *ptr, tmp(buff,sizeof(buff),str->charset());
+ ptr= val_str(&tmp);
+ if (!ptr)
+ str->append("NULL");
+ else
+ {
+ switch (result_type())
+ {
+ default:
+ DBUG_ASSERT(0);
+ case STRING_RESULT:
+ str->append('\'');
+ str->append(*ptr);
+ str->append('\'');
+ break;
+ case DECIMAL_RESULT:
+ case REAL_RESULT:
+ case INT_RESULT:
+ str->append(*ptr);
+ break;
+ }
+ }
+}
+
+
void Item::cleanup()
{
DBUG_ENTER("Item::cleanup");
@@ -503,6 +531,45 @@ void Item::rename(char *new_name)
name= new_name;
}
+Item_result Item::cmp_type() const
+{
+ switch(field_type()) {
+ case MYSQL_TYPE_DECIMAL:
+ case MYSQL_TYPE_NEWDECIMAL:
+ return DECIMAL_RESULT;
+ case MYSQL_TYPE_TINY:
+ case MYSQL_TYPE_SHORT:
+ case MYSQL_TYPE_LONG:
+ case MYSQL_TYPE_LONGLONG:
+ case MYSQL_TYPE_INT24:
+ case MYSQL_TYPE_YEAR:
+ case MYSQL_TYPE_BIT:
+ case MYSQL_TYPE_ENUM:
+ case MYSQL_TYPE_SET:
+ return INT_RESULT;
+ case MYSQL_TYPE_FLOAT:
+ case MYSQL_TYPE_DOUBLE:
+ return REAL_RESULT;
+ case MYSQL_TYPE_NULL:
+ case MYSQL_TYPE_VARCHAR:
+ case MYSQL_TYPE_TINY_BLOB:
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ case MYSQL_TYPE_LONG_BLOB:
+ case MYSQL_TYPE_BLOB:
+ case MYSQL_TYPE_VAR_STRING:
+ case MYSQL_TYPE_STRING:
+ case MYSQL_TYPE_GEOMETRY:
+ return STRING_RESULT;
+ case MYSQL_TYPE_TIMESTAMP:
+ case MYSQL_TYPE_DATE:
+ case MYSQL_TYPE_TIME:
+ case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_NEWDATE:
+ return TIME_RESULT;
+ };
+ DBUG_ASSERT(0);
+ return (Item_result)-1;
+}
/**
Traverse item tree possibly transforming it (replacing items).
@@ -915,13 +982,15 @@ bool Item_string::eq(const Item *item, bool binary_cmp) const
bool Item::get_date(MYSQL_TIME *ltime,uint fuzzydate)
{
- if (result_type() == STRING_RESULT)
+ if (field_type() == MYSQL_TYPE_TIME)
+ fuzzydate|= TIME_TIME_ONLY;
+ if (result_type() == STRING_RESULT || fuzzydate & TIME_TIME_ONLY)
{
char buff[40];
String tmp(buff,sizeof(buff), &my_charset_bin),*res;
if (!(res=val_str(&tmp)) ||
- str_to_datetime_with_warn(res->ptr(), res->length(),
- ltime, fuzzydate) <= MYSQL_TIMESTAMP_ERROR)
+ str_to_datetime_with_warn(res->ptr(), res->length(), ltime,
+ fuzzydate) <= MYSQL_TIMESTAMP_ERROR)
goto err;
}
else
@@ -946,22 +1015,14 @@ err:
}
/**
- Get time of first argument.\
+ Get time of first argument.
As a extra convenience the time structure is reset on error!
*/
bool Item::get_time(MYSQL_TIME *ltime)
{
- char buff[40];
- String tmp(buff,sizeof(buff),&my_charset_bin),*res;
- if (!(res=val_str(&tmp)) ||
- str_to_time_with_warn(res->ptr(), res->length(), ltime))
- {
- bzero((char*) ltime,sizeof(*ltime));
- return 1;
- }
- return 0;
+ return get_date(ltime, TIME_TIME_ONLY);
}
CHARSET_INFO *Item::default_charset()
@@ -987,6 +1048,7 @@ int Item::save_in_field_no_warnings(Field *field, bool no_conversions)
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
ulong sql_mode= thd->variables.sql_mode;
thd->variables.sql_mode&= ~(MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE);
+ thd->variables.sql_mode|= MODE_INVALID_DATES;
thd->count_cuted_fields= CHECK_FIELD_IGNORE;
res= save_in_field(field, no_conversions);
thd->count_cuted_fields= tmp;
@@ -2085,16 +2147,6 @@ bool Item_field::get_date_result(MYSQL_TIME *ltime,uint fuzzydate)
return 0;
}
-bool Item_field::get_time(MYSQL_TIME *ltime)
-{
- if ((null_value=field->is_null()) || field->get_time(ltime))
- {
- bzero((char*) ltime,sizeof(*ltime));
- return 1;
- }
- return 0;
-}
-
double Item_field::val_result()
{
if ((null_value=result_field->is_null()))
@@ -2698,13 +2750,16 @@ void Item_param::set_time(MYSQL_TIME *tm, timestamp_type time_type,
value.time= *tm;
value.time.time_type= time_type;
+ decimals= value.time.second_part > 0 ? MAX_SEC_PART_DIGITS : 0;
+
if (value.time.year > 9999 || value.time.month > 12 ||
value.time.day > 31 ||
(time_type != MYSQL_TIMESTAMP_TIME && value.time.hour > 23) ||
- value.time.minute > 59 || value.time.second > 59)
+ value.time.minute > 59 || value.time.second > 59 ||
+ value.time.second_part >= MAX_SEC_PART_VALUE)
{
char buff[MAX_DATE_STRING_REP_LENGTH];
- uint length= my_TIME_to_str(&value.time, buff);
+ uint length= my_TIME_to_str(&value.time, buff, decimals);
make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
buff, length, time_type, 0);
set_zero_time(&value.time, MYSQL_TIMESTAMP_ERROR);
@@ -2713,7 +2768,6 @@ void Item_param::set_time(MYSQL_TIME *tm, timestamp_type time_type,
state= TIME_VALUE;
maybe_null= 0;
max_length= max_length_arg;
- decimals= 0;
DBUG_VOID_RETURN;
}
@@ -2790,10 +2844,12 @@ bool Item_param::set_from_user_var(THD *thd, const user_var_entry *entry)
case REAL_RESULT:
set_double(*(double*)entry->value);
item_type= Item::REAL_ITEM;
+ param_type= MYSQL_TYPE_DOUBLE;
break;
case INT_RESULT:
set_int(*(longlong*)entry->value, MY_INT64_NUM_DECIMAL_DIGITS);
item_type= Item::INT_ITEM;
+ param_type= MYSQL_TYPE_LONGLONG;
break;
case STRING_RESULT:
{
@@ -2816,6 +2872,7 @@ bool Item_param::set_from_user_var(THD *thd, const user_var_entry *entry)
charset of connection, so we have to set it later.
*/
item_type= Item::STRING_ITEM;
+ param_type= MYSQL_TYPE_VARCHAR;
if (set_str((const char *)entry->value, entry->length))
DBUG_RETURN(1);
@@ -2831,6 +2888,7 @@ bool Item_param::set_from_user_var(THD *thd, const user_var_entry *entry)
my_decimal_precision_to_length_no_truncation(ent_value->precision(),
decimals, unsigned_flag);
item_type= Item::DECIMAL_ITEM;
+ param_type= MYSQL_TYPE_NEWDECIMAL;
break;
}
default:
@@ -2911,21 +2969,6 @@ int Item_param::save_in_field(Field *field, bool no_conversions)
}
-bool Item_param::get_time(MYSQL_TIME *res)
-{
- if (state == TIME_VALUE)
- {
- *res= value.time;
- return 0;
- }
- /*
- If parameter value isn't supplied assertion will fire in val_str()
- which is called from Item::get_time().
- */
- return Item::get_time(res);
-}
-
-
bool Item_param::get_date(MYSQL_TIME *res, uint fuzzydate)
{
if (state == TIME_VALUE)
@@ -3055,7 +3098,8 @@ String *Item_param::val_str(String* str)
{
if (str->reserve(MAX_DATE_STRING_REP_LENGTH))
break;
- str->length((uint) my_TIME_to_str(&value.time, (char*) str->ptr()));
+ str->length((uint) my_TIME_to_str(&value.time, (char*) str->ptr(),
+ decimals));
str->set_charset(&my_charset_bin);
return str;
}
@@ -3107,7 +3151,7 @@ const String *Item_param::query_val_str(String* str) const
buf= str->c_ptr_quick();
ptr= buf;
*ptr++= '\'';
- ptr+= (uint) my_TIME_to_str(&value.time, ptr);
+ ptr+= (uint) my_TIME_to_str(&value.time, ptr, decimals);
*ptr++= '\'';
str->length((uint32) (ptr - buf));
break;
@@ -3387,8 +3431,7 @@ void Item_copy_int::copy()
null_value=item->null_value;
}
-static int save_int_value_in_field (Field *field, longlong nr,
- bool null_value, bool unsigned_flag);
+static int save_int_value_in_field (Field *, longlong, bool, bool);
int Item_copy_int::save_in_field(Field *field, bool no_conversions)
{
@@ -4651,12 +4694,7 @@ Item *Item_field::equal_fields_propagator(uchar *arg)
item= this;
else if (field && (field->flags & ZEROFILL_FLAG) && IS_NUM(field->type()))
{
- /*
- We don't need to zero-fill timestamp columns here because they will be
- first converted to a string (in date/time format) and compared as such if
- compared with another string.
- */
- if (item && field->type() != FIELD_TYPE_TIMESTAMP && cmp_context != INT_RESULT)
+ if (item && (cmp_context == STRING_RESULT || cmp_context == (Item_result)-1))
convert_zerofill_number_to_string(&item, (Field_num *)field);
else
item= this;
@@ -4782,21 +4820,6 @@ enum_field_types Item::field_type() const
}
-bool Item::is_datetime()
-{
- switch (field_type())
- {
- case MYSQL_TYPE_DATE:
- case MYSQL_TYPE_DATETIME:
- case MYSQL_TYPE_TIMESTAMP:
- return TRUE;
- default:
- break;
- }
- return FALSE;
-}
-
-
String *Item::check_well_formed_result(String *str, bool send_error)
{
/* Check whether we got a well-formed string */
@@ -4973,16 +4996,19 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table, bool fixed_length)
break;
case MYSQL_TYPE_NEWDATE:
case MYSQL_TYPE_DATE:
- field= new Field_newdate(maybe_null, name, &my_charset_bin);
+ field= new Field_newdate(0, null_ptr, 0, Field::NONE, name, &my_charset_bin);
break;
case MYSQL_TYPE_TIME:
- field= new Field_time(maybe_null, name, &my_charset_bin);
+ field= new_Field_time(0, null_ptr, 0, Field::NONE, name,
+ decimals, &my_charset_bin);
break;
case MYSQL_TYPE_TIMESTAMP:
- field= new Field_timestamp(maybe_null, name, &my_charset_bin);
+ field= new_Field_timestamp(0, null_ptr, 0,
+ Field::NONE, name, 0, decimals, &my_charset_bin);
break;
case MYSQL_TYPE_DATETIME:
- field= new Field_datetime(maybe_null, name, &my_charset_bin);
+ field= new_Field_datetime(0, null_ptr, 0, Field::NONE, name,
+ decimals, &my_charset_bin);
break;
case MYSQL_TYPE_YEAR:
field= new Field_year((uchar*) 0, max_length, null_ptr, 0, Field::NONE,
@@ -5197,12 +5223,6 @@ int Item_string::save_in_field(Field *field, bool no_conversions)
}
-int Item_uint::save_in_field(Field *field, bool no_conversions)
-{
- /* Item_int::save_in_field handles both signed and unsigned. */
- return Item_int::save_in_field(field, no_conversions);
-}
-
static int save_int_value_in_field (Field *field, longlong nr,
bool null_value, bool unsigned_flag)
{
@@ -5219,6 +5239,22 @@ int Item_int::save_in_field(Field *field, bool no_conversions)
}
+void Item_datetime::set(longlong packed)
+{
+ unpack_time(packed, &ltime);
+}
+
+int Item_datetime::save_in_field(Field *field, bool no_conversions)
+{
+ field->set_notnull();
+ return field->store_time(&ltime, ltime.time_type);
+}
+
+longlong Item_datetime::val_int()
+{
+ return TIME_to_ulonglong(&ltime);
+}
+
int Item_decimal::save_in_field(Field *field, bool no_conversions)
{
field->set_notnull();
@@ -5643,7 +5679,7 @@ bool Item::send(Protocol *protocol, String *buffer)
if (f_type == MYSQL_TYPE_DATE)
return protocol->store_date(&tm);
else
- result= protocol->store(&tm);
+ result= protocol->store(&tm, decimals);
}
break;
}
@@ -5652,7 +5688,7 @@ bool Item::send(Protocol *protocol, String *buffer)
MYSQL_TIME tm;
get_time(&tm);
if (!null_value)
- result= protocol->store_time(&tm);
+ result= protocol->store_time(&tm, decimals);
break;
}
}
@@ -5733,17 +5769,7 @@ void Item_field::print(String *str, enum_query_type query_type)
{
if (field && field->table->const_table)
{
- char buff[MAX_FIELD_WIDTH];
- String tmp(buff,sizeof(buff),str->charset());
- field->val_str(&tmp);
- if (field->is_null())
- str->append("NULL");
- else
- {
- str->append('\'');
- str->append(tmp);
- str->append('\'');
- }
+ print_value(str);
return;
}
Item_ident::print(str, query_type);
@@ -6839,6 +6865,8 @@ Item_result item_cmp_type(Item_result a,Item_result b)
return INT_RESULT;
else if (a == ROW_RESULT || b == ROW_RESULT)
return ROW_RESULT;
+ else if (a == TIME_RESULT || b == TIME_RESULT)
+ return TIME_RESULT;
if ((a == INT_RESULT || a == DECIMAL_RESULT) &&
(b == INT_RESULT || b == DECIMAL_RESULT))
return DECIMAL_RESULT;
@@ -6952,6 +6980,9 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item)
@note We only use this on the range optimizer/partition pruning,
because in some cases we can't store the value in the field
without some precision/character loss.
+
+ @todo rewrite it to use Arg_comparator (currently it's a simplified and
+ incomplete version of it)
*/
int stored_field_cmp_to_item(THD *thd, Field *field, Item *item)
@@ -7009,6 +7040,21 @@ int stored_field_cmp_to_item(THD *thd, Field *field, Item *item)
field_val= field->val_decimal(&field_buf);
return my_decimal_cmp(item_val, field_val);
}
+ if (field->cmp_type() == TIME_RESULT)
+ {
+ MYSQL_TIME field_time, item_time;
+ if (field->type() == MYSQL_TYPE_TIME)
+ {
+ field->get_time(&field_time);
+ item->get_time(&item_time);
+ }
+ else
+ {
+ field->get_date(&field_time, TIME_FUZZY_DATE | TIME_INVALID_DATES);
+ item->get_date(&item_time, TIME_FUZZY_DATE | TIME_INVALID_DATES);
+ }
+ return my_time_compare(&field_time, &item_time);
+ }
double result= item->val_real();
if (item->null_value)
return 0;
@@ -7048,6 +7094,8 @@ Item_cache* Item_cache::get_cache(const Item *item, const Item_result type)
return new Item_cache_str(item);
case ROW_RESULT:
return new Item_cache_row();
+ case TIME_RESULT:
+ return new Item_cache_int(MYSQL_TYPE_DATETIME);
default:
// should never be in real life
DBUG_ASSERT(0);
@@ -7065,6 +7113,11 @@ void Item_cache::store(Item *item)
void Item_cache::print(String *str, enum_query_type query_type)
{
+ if (value_cached)
+ {
+ print_value(str);
+ return;
+ }
str->append(STRING_WITH_LEN("<cache>("));
if (example)
example->print(str, query_type);
@@ -7100,7 +7153,7 @@ String *Item_cache_int::val_str(String *str)
DBUG_ASSERT(fixed == 1);
if (!value_cached && !cache_value())
return NULL;
- str->set(value, default_charset());
+ str->set_int(value, unsigned_flag, default_charset());
return str;
}
@@ -7466,7 +7519,7 @@ enum_field_types Item_type_holder::get_real_type(Item *item)
case FIELD_ITEM:
{
/*
- Item_fields::field_type ask Field_type() but sometimes field return
+ Item_field::field_type ask Field_type() but sometimes field return
a different type, like for enum/set, so we need to ask real type.
*/
Field *field= ((Item_field *) item)->field;
diff --git a/sql/item.h b/sql/item.h
index 57abb43010e..0be8312750d 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -569,7 +569,8 @@ public:
virtual bool send(Protocol *protocol, String *str);
virtual bool eq(const Item *, bool binary_cmp) const;
virtual Item_result result_type() const { return REAL_RESULT; }
- virtual Item_result cast_to_int_type() const { return result_type(); }
+ virtual Item_result cmp_type() const;
+ virtual Item_result cast_to_int_type() const { return cmp_type(); }
virtual enum_field_types string_field_type() const;
virtual enum_field_types field_type() const;
virtual enum Type type() const =0;
@@ -801,6 +802,7 @@ public:
}
void print_item_w_name(String *, enum_query_type query_type);
+ void print_value(String *);
virtual void update_used_tables() {}
virtual void split_sum_func(THD *thd, Item **ref_pointer_array,
List<Item> &fields) {}
@@ -808,7 +810,7 @@ public:
void split_sum_func2(THD *thd, Item **ref_pointer_array, List<Item> &fields,
Item **ref, bool skip_registered);
virtual bool get_date(MYSQL_TIME *ltime,uint fuzzydate);
- virtual bool get_time(MYSQL_TIME *ltime);
+ bool get_time(MYSQL_TIME *ltime);
virtual bool get_date_result(MYSQL_TIME *ltime,uint fuzzydate)
{ return get_date(ltime,fuzzydate); }
/*
@@ -1037,15 +1039,6 @@ public:
{
return 0;
}
- /*
- result_as_longlong() must return TRUE for Items representing DATE/TIME
- functions and DATE/TIME table fields.
- Those Items have result_type()==STRING_RESULT (and not INT_RESULT), but
- their values should be compared as integers (because the integer
- representation is more precise than the string one).
- */
- virtual bool result_as_longlong() { return FALSE; }
- bool is_datetime();
virtual Field::geometry_type get_geometry_type() const
{ return Field::GEOM_GEOMETRY; };
String *check_well_formed_result(String *str, bool send_error= 0);
@@ -1514,7 +1507,6 @@ public:
Field *tmp_table_field(TABLE *t_arg) { return result_field; }
bool get_date(MYSQL_TIME *ltime,uint fuzzydate);
bool get_date_result(MYSQL_TIME *ltime,uint fuzzydate);
- bool get_time(MYSQL_TIME *ltime);
bool is_null() { return field->is_null(); }
void update_null_value();
Item *get_tmp_table_item(THD *thd);
@@ -1523,10 +1515,6 @@ public:
bool register_field_in_read_map(uchar *arg);
bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
void cleanup();
- bool result_as_longlong()
- {
- return field->can_be_compared_as_longlong();
- }
Item_equal *find_item_equal(COND_EQUAL *cond_equal);
bool subst_argument_checker(uchar **arg);
Item *equal_fields_propagator(uchar *arg);
@@ -1671,6 +1659,7 @@ public:
Item_param(uint pos_in_query_arg);
enum Item_result result_type () const { return item_result_type; }
+ enum Item_result cast_to_int_type() const { return item_result_type; }
enum Type type() const { return item_type; }
enum_field_types field_type() const { return param_type; }
@@ -1678,7 +1667,6 @@ public:
longlong val_int();
my_decimal *val_decimal(my_decimal*);
String *val_str(String*);
- bool get_time(MYSQL_TIME *tm);
bool get_date(MYSQL_TIME *tm, uint fuzzydate);
int save_in_field(Field *field, bool no_conversions);
@@ -1777,13 +1765,12 @@ class Item_uint :public Item_int
{
public:
Item_uint(const char *str_arg, uint length);
- Item_uint(ulonglong i) :Item_int((ulonglong) i, 10) {}
+ Item_uint(ulonglong i) :Item_int(i, 10) {}
Item_uint(const char *str_arg, longlong i, uint length);
double val_real()
{ DBUG_ASSERT(fixed == 1); return ulonglong2double((ulonglong)value); }
String *val_str(String*);
Item *clone_item() { return new Item_uint(name, value, max_length); }
- int save_in_field(Field *field, bool no_conversions);
virtual void print(String *str, enum_query_type query_type);
Item_num *neg ();
uint decimal_precision() const { return max_length; }
@@ -1791,6 +1778,19 @@ public:
};
+class Item_datetime :public Item_int
+{
+protected:
+ MYSQL_TIME ltime;
+public:
+ Item_datetime() :Item_int(0) { unsigned_flag=0; }
+ int save_in_field(Field *field, bool no_conversions);
+ longlong val_int();
+ double val_real() { return val_int(); }
+ void set(longlong packed);
+};
+
+
/* decimal (fixed point) constant */
class Item_decimal :public Item_num
{
@@ -2071,8 +2071,9 @@ class Item_return_date_time :public Item_partition_func_safe_string
{
enum_field_types date_time_field_type;
public:
- Item_return_date_time(const char *name_arg, enum_field_types field_type_arg)
- :Item_partition_func_safe_string(name_arg, 0, &my_charset_bin),
+ Item_return_date_time(const char *name_arg, uint length_arg,
+ enum_field_types field_type_arg)
+ :Item_partition_func_safe_string(name_arg, length_arg, &my_charset_bin),
date_time_field_type(field_type_arg)
{ }
enum_field_types field_type() const { return date_time_field_type; }
@@ -2286,10 +2287,6 @@ public:
(this->*processor)(arg);
}
virtual void print(String *str, enum_query_type query_type);
- bool result_as_longlong()
- {
- return (*ref)->result_as_longlong();
- }
void cleanup();
Item_field *filed_for_view_update()
{ return (*ref)->filed_for_view_update(); }
@@ -2322,12 +2319,6 @@ public:
if (ref && result_type() == ROW_RESULT)
(*ref)->bring_value();
}
- bool get_time(MYSQL_TIME *ltime)
- {
- DBUG_ASSERT(fixed);
- return (*ref)->get_time(ltime);
- }
-
};
@@ -3031,7 +3022,7 @@ class Item_cache_int: public Item_cache
protected:
longlong value;
public:
- Item_cache_int(): Item_cache(),
+ Item_cache_int(): Item_cache(MYSQL_TYPE_LONGLONG),
value(0) {}
Item_cache_int(enum_field_types field_type_arg):
Item_cache(field_type_arg), value(0) {}
@@ -3043,7 +3034,6 @@ public:
String* val_str(String *str);
my_decimal *val_decimal(my_decimal *);
enum Item_result result_type() const { return INT_RESULT; }
- bool result_as_longlong() { return TRUE; }
bool cache_value();
};
@@ -3052,7 +3042,7 @@ class Item_cache_real: public Item_cache
{
double value;
public:
- Item_cache_real(): Item_cache(),
+ Item_cache_real(): Item_cache(MYSQL_TYPE_DOUBLE),
value(0) {}
double val_real();
@@ -3069,7 +3059,7 @@ class Item_cache_decimal: public Item_cache
protected:
my_decimal decimal_value;
public:
- Item_cache_decimal(): Item_cache() {}
+ Item_cache_decimal(): Item_cache(MYSQL_TYPE_NEWDECIMAL) {}
double val_real();
longlong val_int();
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 5302406e270..f2935137de7 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -30,9 +30,6 @@
#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)
@@ -138,10 +135,10 @@ static int cmp_row_type(Item* item1, Item* item2)
static int agg_cmp_type(Item_result *type, Item **items, uint nitems)
{
uint i;
- type[0]= items[0]->result_type();
+ type[0]= items[0]->cmp_type();
for (i= 1 ; i < nitems ; i++)
{
- type[0]= item_cmp_type(type[0], items[i]->result_type());
+ type[0]= item_cmp_type(type[0], items[i]->cmp_type());
/*
When aggregating types of two row expressions we have to check
that they have the same cardinality and that each component
@@ -488,48 +485,27 @@ void Item_bool_func2::fix_length_and_dec()
args[0]->cmp_context= args[1]->cmp_context=
item_cmp_type(args[0]->result_type(), args[1]->result_type());
- // Make a special case of compare with fields to get nicer DATE comparisons
- if (functype() == LIKE_FUNC) // Disable conversion in case of LIKE function.
- {
- set_cmp_func();
- return;
- }
+ /*
+ Make a special case of compare with fields to get nicer comparisons
+ of numbers with constant string.
+ This directly contradicts the manual (number and a string should
+ be compared as doubles), but seems to provide more
+ "intuitive" behavior in some cases (but less intuitive in others).
+ But disable conversion in case of LIKE function.
+ */
thd= current_thd;
- if (!thd->is_context_analysis_only())
+ if (functype() != LIKE_FUNC && !thd->is_context_analysis_only())
{
- if (args[0]->real_item()->type() == FIELD_ITEM)
- {
- Item_field *field_item= (Item_field*) (args[0]->real_item());
- if (field_item->field->can_be_compared_as_longlong() &&
- !(field_item->is_datetime() &&
- args[1]->result_type() == STRING_RESULT))
- {
- if (convert_constant_item(thd, field_item, &args[1]))
- {
- cmp.set_cmp_func(this, tmp_arg, tmp_arg+1,
- INT_RESULT); // Works for all types.
- args[0]->cmp_context= args[1]->cmp_context= INT_RESULT;
- return;
- }
- }
- }
- if (args[1]->real_item()->type() == FIELD_ITEM)
+ int field;
+ if (args[field= 0]->real_item()->type() == FIELD_ITEM ||
+ args[field= 1]->real_item()->type() == FIELD_ITEM)
{
- Item_field *field_item= (Item_field*) (args[1]->real_item());
- if (field_item->field->can_be_compared_as_longlong() &&
- !(field_item->is_datetime() &&
- args[0]->result_type() == STRING_RESULT))
- {
- if (convert_constant_item(thd, field_item, &args[0]))
- {
- cmp.set_cmp_func(this, tmp_arg, tmp_arg+1,
- INT_RESULT); // Works for all types.
- args[0]->cmp_context= args[1]->cmp_context= INT_RESULT;
- return;
- }
- }
+ Item_field *field_item= (Item_field*) (args[field]->real_item());
+ if (field_item->cmp_type() == INT_RESULT &&
+ convert_constant_item(thd, field_item, &args[!field]))
+ args[0]->cmp_context= args[1]->cmp_context= INT_RESULT;
}
}
set_cmp_func();
@@ -543,6 +519,8 @@ int Arg_comparator::set_compare_func(Item_result_field *item, Item_result type)
[is_owner_equal_func()];
switch (type) {
+ case TIME_RESULT:
+ break;
case ROW_RESULT:
{
uint n= (*a)->cols();
@@ -669,16 +647,17 @@ bool get_mysql_time_from_str(THD *thd, String *str, timestamp_type warn_type,
bool value;
int error;
enum_mysql_timestamp_type timestamp_type;
+ int flags= TIME_FUZZY_DATE | MODE_INVALID_DATES;
+
+ flags|= thd->variables.sql_mode & (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE);
+
+ if (warn_type == MYSQL_TIMESTAMP_TIME)
+ flags|= TIME_TIME_ONLY;
timestamp_type=
- str_to_datetime(str->ptr(), str->length(), l_time,
- (TIME_FUZZY_DATE | MODE_INVALID_DATES |
- (thd->variables.sql_mode &
- (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE))),
- &error);
-
- if (timestamp_type == MYSQL_TIMESTAMP_DATETIME ||
- timestamp_type == MYSQL_TIMESTAMP_DATE)
+ str_to_datetime(str->ptr(), str->length(), l_time, flags, &error);
+
+ if (timestamp_type > MYSQL_TIMESTAMP_ERROR)
/*
Do not return yet, we may still want to throw a "trailing garbage"
warning.
@@ -726,164 +705,7 @@ static ulonglong get_date_from_str(THD *thd, String *str,
if (*error_arg)
return 0;
- return TIME_to_ulonglong_datetime(&l_time);
-}
-
-
-/*
- Check whether compare_datetime() can be used to compare items.
-
- SYNOPSIS
- Arg_comparator::can_compare_as_dates()
- a, b [in] items to be compared
- const_value [out] converted value of the string constant, if any
-
- DESCRIPTION
- Check several cases when the DATE/DATETIME comparator should be used.
- The following cases are checked:
- 1. Both a and b is a DATE/DATETIME field/function returning string or
- int result.
- 2. Only a or b is a DATE/DATETIME field/function returning string or
- int result and the other item (b or a) is an item with string result.
- If the second item is a constant one then it's checked to be
- convertible to the DATE/DATETIME type. If the constant can't be
- converted to a DATE/DATETIME then the compare_datetime() comparator
- isn't used and the warning about wrong DATE/DATETIME value is issued.
- In all other cases (date-[int|real|decimal]/[int|real|decimal]-date)
- the comparison is handled by other comparators.
- If the datetime comparator can be used and one the operands of the
- comparison is a string constant that was successfully converted to a
- DATE/DATETIME type then the result of the conversion is returned in the
- const_value if it is provided. If there is no constant or
- compare_datetime() isn't applicable then the *const_value remains
- unchanged.
-
- RETURN
- the found type of date comparison
-*/
-
-enum Arg_comparator::enum_date_cmp_type
-Arg_comparator::can_compare_as_dates(Item *a, Item *b, ulonglong *const_value)
-{
- enum enum_date_cmp_type cmp_type= CMP_DATE_DFLT;
- Item *str_arg= 0, *date_arg= 0;
-
- if (a->type() == Item::ROW_ITEM || b->type() == Item::ROW_ITEM)
- return CMP_DATE_DFLT;
-
- if (a->is_datetime())
- {
- if (b->is_datetime())
- cmp_type= CMP_DATE_WITH_DATE;
- else if (b->result_type() == STRING_RESULT)
- {
- cmp_type= CMP_DATE_WITH_STR;
- date_arg= a;
- str_arg= b;
- }
- }
- else if (b->is_datetime() && a->result_type() == STRING_RESULT)
- {
- cmp_type= CMP_STR_WITH_DATE;
- date_arg= b;
- str_arg= a;
- }
-
- if (cmp_type != CMP_DATE_DFLT)
- {
- THD *thd= current_thd;
- /*
- Do not cache GET_USER_VAR() function as its const_item() may return TRUE
- for the current thread but it still may change during the execution.
- Don't use cache while in the context analysis mode only (i.e. for
- EXPLAIN/CREATE VIEW and similar queries). Cache is useless in such
- cases and can cause problems. For example evaluating subqueries can
- confuse storage engines since in context analysis mode tables
- aren't locked.
- */
- if (!thd->is_context_analysis_only() &&
- cmp_type != CMP_DATE_WITH_DATE && str_arg->const_item() &&
- (str_arg->type() != Item::FUNC_ITEM ||
- ((Item_func*)str_arg)->functype() != Item_func::GUSERVAR_FUNC))
- {
- ulonglong value;
- bool error;
- String tmp, *str_val= 0;
- timestamp_type t_type= (date_arg->field_type() == MYSQL_TYPE_DATE ?
- MYSQL_TIMESTAMP_DATE : MYSQL_TIMESTAMP_DATETIME);
-
- str_val= str_arg->val_str(&tmp);
- if (str_arg->null_value)
- return CMP_DATE_DFLT;
- value= get_date_from_str(thd, str_val, t_type, date_arg->name, &error);
- if (error)
- return CMP_DATE_DFLT;
- if (const_value)
- *const_value= value;
- }
- }
- return cmp_type;
-}
-
-
-/*
- Retrieves correct TIME value from the given item.
-
- SYNOPSIS
- get_time_value()
- thd thread handle
- item_arg [in/out] item to retrieve TIME value from
- cache_arg [in/out] pointer to place to store the cache item to
- warn_item [in] unused
- is_null [out] TRUE <=> the item_arg is null
-
- DESCRIPTION
- Retrieves the correct TIME value from given item for comparison by the
- compare_datetime() function.
- If item's result can be compared as longlong then its int value is used
- and a value returned by get_time function is used otherwise.
- If an item is a constant one then its value is cached and it isn't
- get parsed again. An Item_cache_int object is used for for cached values.
- It seamlessly substitutes the original item. The cache item is marked as
- non-constant to prevent re-caching it again.
-
- RETURN
- obtained value
-*/
-
-longlong
-get_time_value(THD *thd, Item ***item_arg, Item **cache_arg,
- Item *warn_item, bool *is_null)
-{
- longlong value;
- Item *item= **item_arg;
- MYSQL_TIME ltime;
-
- if (item->result_as_longlong())
- {
- value= item->val_int();
- *is_null= item->null_value;
- }
- else
- {
- *is_null= item->get_time(&ltime);
- value= !*is_null ? (longlong) TIME_to_ulonglong_datetime(&ltime) : 0;
- }
- /*
- Do not cache GET_USER_VAR() function as its const_item() may return TRUE
- for the current thread but it still may change during the execution.
- */
- if (item->const_item() && cache_arg && (item->type() != Item::FUNC_ITEM ||
- ((Item_func*)item)->functype() != Item_func::GUSERVAR_FUNC))
- {
- Item_cache_int *cache= new Item_cache_int();
- /* Mark the cache as non-const to prevent re-caching. */
- cache->set_used_tables(1);
- cache->store(item, value);
- *cache_arg= cache;
- *item_arg= cache_arg;
- }
- return value;
+ return pack_time(&l_time);
}
@@ -891,65 +713,15 @@ int Arg_comparator::set_cmp_func(Item_result_field *owner_arg,
Item **a1, Item **a2,
Item_result type)
{
- enum enum_date_cmp_type cmp_type;
- ulonglong const_value= (ulonglong)-1;
thd= current_thd;
owner= owner_arg;
set_null= set_null && owner_arg;
a= a1;
b= a2;
- thd= current_thd;
-
- if ((cmp_type= can_compare_as_dates(*a, *b, &const_value)))
- {
- a_type= (*a)->field_type();
- b_type= (*b)->field_type();
- a_cache= 0;
- b_cache= 0;
- if (const_value != (ulonglong)-1)
- {
- /*
- cache_converted_constant can't be used here because it can't
- correctly convert a DATETIME value from string to int representation.
- */
- Item_cache_int *cache= new Item_cache_int();
- /* Mark the cache as non-const to prevent re-caching. */
- cache->set_used_tables(1);
- if (!(*a)->is_datetime())
- {
- cache->store((*a), const_value);
- a_cache= cache;
- a= (Item **)&a_cache;
- }
- else
- {
- cache->store((*b), const_value);
- b_cache= cache;
- b= (Item **)&b_cache;
- }
- }
- is_nulls_eq= is_owner_equal_func();
- func= &Arg_comparator::compare_datetime;
- 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 &&
- (*b)->field_type() == MYSQL_TYPE_TIME)
- {
- /* Compare TIME values as integers. */
- a_cache= 0;
- b_cache= 0;
- is_nulls_eq= is_owner_equal_func();
- func= &Arg_comparator::compare_datetime;
- get_value_a_func= &get_time_value;
- get_value_b_func= &get_time_value;
- return 0;
- }
- else if (type == STRING_RESULT &&
- (*a)->result_type() == STRING_RESULT &&
- (*b)->result_type() == STRING_RESULT)
+ if (type == STRING_RESULT &&
+ (*a)->result_type() == STRING_RESULT &&
+ (*b)->result_type() == STRING_RESULT)
{
DTCollation coll;
coll.set((*a)->collation.collation);
@@ -957,8 +729,10 @@ int Arg_comparator::set_cmp_func(Item_result_field *owner_arg,
b, 1, MY_COLL_CMP_CONV, 1))
return 1;
}
- else if (try_year_cmp_func(type))
- return 0;
+ if (type == INT_RESULT &&
+ (*a)->field_type() == MYSQL_TYPE_YEAR &&
+ (*b)->field_type() == MYSQL_TYPE_YEAR)
+ type= TIME_RESULT;
a= cache_converted_constant(thd, a, &a_cache, type);
b= cache_converted_constant(thd, b, &b_cache, type);
@@ -966,45 +740,6 @@ int Arg_comparator::set_cmp_func(Item_result_field *owner_arg,
}
-/*
- Helper function to call from Arg_comparator::set_cmp_func()
-*/
-
-bool Arg_comparator::try_year_cmp_func(Item_result type)
-{
- if (type == ROW_RESULT)
- return FALSE;
-
- bool a_is_year= (*a)->field_type() == MYSQL_TYPE_YEAR;
- bool b_is_year= (*b)->field_type() == MYSQL_TYPE_YEAR;
-
- if (!a_is_year && !b_is_year)
- return FALSE;
-
- if (a_is_year && b_is_year)
- {
- get_value_a_func= &get_year_value;
- get_value_b_func= &get_year_value;
- }
- else if (a_is_year && (*b)->is_datetime())
- {
- get_value_a_func= &get_year_value;
- get_value_b_func= &get_datetime_value;
- }
- else if (b_is_year && (*a)->is_datetime())
- {
- get_value_b_func= &get_year_value;
- get_value_a_func= &get_datetime_value;
- }
- else
- return FALSE;
-
- is_nulls_eq= is_owner_equal_func();
- func= &Arg_comparator::compare_datetime;
-
- return TRUE;
-}
-
/**
Convert and cache a constant.
@@ -1026,9 +761,14 @@ Item** Arg_comparator::cache_converted_constant(THD *thd_arg, Item **value,
Item **cache_item,
Item_result type)
{
- /* Don't need cache if doing context analysis only. */
+ /*
+ Don't need cache if doing context analysis only.
+ Also, get_datetime_value creates Item_cache internally.
+ Unless fixed, we should not do it here.
+ */
if (!thd_arg->is_context_analysis_only() &&
- (*value)->const_item() && type != (*value)->result_type())
+ (*value)->const_item() && type != (*value)->result_type() &&
+ type != TIME_RESULT)
{
Item_cache *cache= Item_cache::get_cache(*value, type);
cache->setup(*value);
@@ -1046,14 +786,9 @@ void Arg_comparator::set_datetime_cmp_func(Item_result_field *owner_arg,
owner= owner_arg;
a= a1;
b= b1;
- a_type= (*a)->field_type();
- b_type= (*b)->field_type();
a_cache= 0;
b_cache= 0;
- is_nulls_eq= FALSE;
- func= &Arg_comparator::compare_datetime;
- get_value_a_func= &get_datetime_value;
- get_value_b_func= &get_datetime_value;
+ func= comparator_matrix[TIME_RESULT][is_owner_equal_func()];
}
@@ -1071,81 +806,113 @@ void Arg_comparator::set_datetime_cmp_func(Item_result_field *owner_arg,
DESCRIPTION
Retrieves the correct DATETIME value from given item for comparison by the
compare_datetime() function.
- If item's result can be compared as longlong then its int value is used
- and its string value is used otherwise. Strings are always parsed and
- converted to int values by the get_date_from_str() function.
- This allows us to compare correctly string dates with missed insignificant
- zeros. If an item is a constant one then its value is cached and it isn't
- get parsed again. An Item_cache_int object is used for caching values. It
- seamlessly substitutes the original item. The cache item is marked as
- non-constant to prevent re-caching it again. In order to compare
- correctly DATE and DATETIME items the result of the former are treated as
- a DATETIME with zero time (00:00:00).
+
+ If the value should be compared as time (TIME_RESULT), it's retrieved as
+ MYSQL_TIME. Otherwise it's read as a number/string and converted to time.
+ Constant items are cached, so the convertion is only done once for them.
+
+ Note the f_type behavior: if the item can be compared as time, then
+ f_type is this item's field_type(). Otherwise it's field_type() of
+ warn_item (which is the other operand of the comparison operator).
+ This logic provides correct string/number to date/time conversion
+ depending on the other operand (when comparing a string with a date, it's
+ parsed as a date, when comparing a string with a time it's parsed as a time)
RETURN
- obtained value
+ MYSQL_TIME value, packed in a longlong, suitable for comparison.
*/
longlong
get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg,
Item *warn_item, bool *is_null)
{
- longlong value= 0;
- String buf, *str= 0;
+ longlong UNINIT_VAR(value);
Item *item= **item_arg;
-
- if (item->result_as_longlong())
- {
+ enum_field_types f_type= warn_item->field_type();
+ timestamp_type t_type=
+ f_type == MYSQL_TYPE_DATE ? MYSQL_TIMESTAMP_DATE :
+ f_type == MYSQL_TYPE_TIME ? MYSQL_TIMESTAMP_TIME :
+ MYSQL_TIMESTAMP_DATETIME;
+
+ switch (item->cmp_type()) {
+ case TIME_RESULT:
+ /* if it's our Item_cache_int, as created below, we simply use the value */
+ if (item->result_type() == INT_RESULT)
+ value= item->val_int();
+ else
+ {
+ MYSQL_TIME buf;
+ item->get_date_result(&buf, TIME_FUZZY_DATE | TIME_INVALID_DATES);
+ value= pack_time(&buf);
+ f_type= item->field_type(); // for Item_cache_int below.
+ }
+ break;
+ case INT_RESULT:
value= item->val_int();
- *is_null= item->null_value;
- enum_field_types f_type= item->field_type();
- /*
- Item_date_add_interval may return MYSQL_TYPE_STRING as the result
- field type. To detect that the DATE value has been returned we
- compare it with 100000000L - any DATE value should be less than it.
- Don't shift cached DATETIME values up for the second time.
- */
- if (f_type == MYSQL_TYPE_DATE ||
- (f_type != MYSQL_TYPE_DATETIME && value < 100000000L))
- value*= 1000000L;
- }
- else
- {
- str= item->val_str(&buf);
- *is_null= item->null_value;
+
+ if (item->field_type() == MYSQL_TYPE_YEAR)
+ {
+ Item *real_item= item->real_item();
+ if (!(real_item->type() == Item::FIELD_ITEM &&
+ ((Item_field *)real_item)->field->type() == MYSQL_TYPE_YEAR &&
+ ((Item_field *)real_item)->field->field_length == 4))
+ {
+ if (value < 70)
+ value+= 100;
+ if (value <= 1900)
+ value+= 1900;
+ }
+ value*= 13ULL * 32ULL * 24ULL * 60ULL * 60ULL * 1000000ULL;
+ }
+ else
+ {
+ MYSQL_TIME buf;
+ int was_cut;
+
+ if (number_to_datetime(value, &buf, TIME_INVALID_DATES|TIME_FUZZY_DATE,
+ &was_cut) == -1)
+ {
+ const Lazy_string_num str(value);
+ make_truncated_value_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ &str, t_type, warn_item->name);
+ value= 0;
+ }
+ else
+ value= pack_time(&buf);
+ }
+ break;
+ case STRING_RESULT:
+ case DECIMAL_RESULT:
+ case REAL_RESULT:
+ {
+ char strbuf[MAX_DATETIME_FULL_WIDTH];
+ String buf(strbuf, sizeof(strbuf), &my_charset_bin), *str;
+ if ((str= item->val_str(&buf)))
+ {
+ /*
+ Convert strings to the integer DATE/DATETIME representation.
+ Even if both dates provided in strings we can't compare them directly as
+ strings as there is no warranty that they are correct and do not miss
+ some insignificant zeros.
+ */
+ bool error;
+ value= (longlong) get_date_from_str(thd, str, t_type, warn_item->name, &error);
+ /*
+ If str did not contain a valid date according to the current
+ SQL_MODE, get_date_from_str() has already thrown a warning,
+ and we don't want to throw NULL on invalid date (see 5.2.6
+ "SQL modes" in the manual), so we're done here.
+ */
+ }
+ break;
+ }
+ default: DBUG_ASSERT(0);
}
- if (*is_null)
+ if ((*is_null= item->null_value))
return ~(ulonglong) 0;
- /*
- Convert strings to the integer DATE/DATETIME representation.
- Even if both dates provided in strings we can't compare them directly as
- strings as there is no warranty that they are correct and do not miss
- some insignificant zeros.
- */
- if (str)
- {
- bool error;
- enum_field_types f_type= warn_item->field_type();
- timestamp_type t_type= f_type ==
- MYSQL_TYPE_DATE ? MYSQL_TIMESTAMP_DATE : MYSQL_TIMESTAMP_DATETIME;
- value= (longlong) get_date_from_str(thd, str, t_type, warn_item->name, &error);
- /*
- If str did not contain a valid date according to the current
- SQL_MODE, get_date_from_str() has already thrown a warning,
- and we don't want to throw NULL on invalid date (see 5.2.6
- "SQL modes" in the manual), so we're done here.
- */
- }
- /*
- Do not cache GET_USER_VAR() function as its const_item() may return TRUE
- for the current thread but it still may change during the execution.
- */
- if (item->const_item() && cache_arg && (item->type() != Item::FUNC_ITEM ||
- ((Item_func*)item)->functype() != Item_func::GUSERVAR_FUNC))
+ if (cache_arg && item->const_item() && item->type() != Item::CACHE_ITEM)
{
- Item_cache_int *cache= new Item_cache_int(MYSQL_TYPE_DATETIME);
- /* Mark the cache as non-const to prevent re-caching. */
- cache->set_used_tables(1);
+ Item_cache_int *cache= new Item_cache_int(f_type);
cache->store(item, value);
*cache_arg= cache;
*item_arg= cache_arg;
@@ -1155,64 +922,6 @@ get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg,
/*
- Retrieves YEAR value of 19XX-00-00 00:00:00 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_datetime() function.
- Converts year to DATETIME of form YYYY-00-00 00:00:00 for the compatibility
- with the get_datetime_value function result.
-
- 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.
- Here we are converting all item values but YEAR(4) fields since
- 1) YEAR(4) already has a regular YYYY form and
- 2) we don't want to convert zero/bad YEAR(4) values to the
- value of 2000.
- */
- Item *real_item= item->real_item();
- if (!(real_item->type() == Item::FIELD_ITEM &&
- ((Item_field *)real_item)->field->type() == MYSQL_TYPE_YEAR &&
- ((Item_field *)real_item)->field->field_length == 4))
- {
- if (value < 70)
- value+= 100;
- if (value <= 1900)
- value+= 1900;
- }
- /* Convert year to DATETIME of form YYYY-00-00 00:00:00 (YYYY0000000000). */
- value*= 10000000000LL;
-
- return value;
-}
-
-
-/*
Compare items values as dates.
SYNOPSIS
@@ -1224,18 +933,9 @@ get_year_value(THD *thd, Item ***item_arg, Item **cache_arg,
with help of the get_datetime_value() function.
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 or at least one item is null
0 a == b
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|-1 |-1 |-1 |-1/0/1|
*/
int Arg_comparator::compare_datetime()
@@ -1243,34 +943,43 @@ int Arg_comparator::compare_datetime()
bool a_is_null, b_is_null;
longlong a_value, b_value;
+ if (set_null)
+ owner->null_value= 1;
+
/* Get DATE/DATETIME/TIME value of the 'a' item. */
- a_value= (*get_value_a_func)(thd, &a, &a_cache, *b, &a_is_null);
- if (!is_nulls_eq && a_is_null)
- {
- if (set_null)
- owner->null_value= 1;
+ a_value= get_datetime_value(thd, &a, &a_cache, *b, &a_is_null);
+ if (a_is_null)
return -1;
- }
/* Get DATE/DATETIME/TIME value of the 'b' item. */
- b_value= (*get_value_b_func)(thd, &b, &b_cache, *a, &b_is_null);
- if (a_is_null || b_is_null)
- {
- if (set_null)
- owner->null_value= is_nulls_eq ? 0 : 1;
- return is_nulls_eq ? (a_is_null == b_is_null) : -1;
- }
+ b_value= get_datetime_value(thd, &b, &b_cache, *a, &b_is_null);
+ if (b_is_null)
+ return -1;
/* Here we have two not-NULL values. */
if (set_null)
owner->null_value= 0;
/* Compare values. */
- if (is_nulls_eq)
- return (a_value == b_value);
- return a_value < b_value ? -1 : (a_value > b_value ? 1 : 0);
+ return a_value < b_value ? -1 : a_value > b_value ? 1 : 0;
}
+int Arg_comparator::compare_e_datetime()
+{
+ bool a_is_null, b_is_null;
+ longlong a_value, b_value;
+
+ if (set_null)
+ owner->null_value= 0;
+
+ /* Get DATE/DATETIME/TIME value of the 'a' item. */
+ a_value= get_datetime_value(thd, &a, &a_cache, *b, &a_is_null);
+
+ /* Get DATE/DATETIME/TIME value of the 'b' item. */
+ b_value= get_datetime_value(thd, &b, &b_cache, *a, &b_is_null);
+ return a_is_null || b_is_null ? a_is_null == b_is_null
+ : a_value == b_value;
+}
int Arg_comparator::compare_string()
{
@@ -2247,9 +1956,7 @@ void Item_func_between::fix_length_and_dec()
{
max_length= 1;
int i;
- bool datetime_found= FALSE;
- int time_items_found= 0;
- compare_as_dates= TRUE;
+ compare_as_dates= 0;
THD *thd= current_thd;
/*
@@ -2265,43 +1972,33 @@ void Item_func_between::fix_length_and_dec()
return;
/*
- Detect the comparison of DATE/DATETIME items.
- At least one of items should be a DATE/DATETIME item and other items
- should return the STRING result.
+ When comparing as date/time, we need to convert non-temporal values
+ (e.g. strings) to MYSQL_TIME. get_datetime_value() doees it
+ automatically when one of the operands is a date/time. But here we
+ may need to compare two strings as dates (str1 BETWEEN str2 AND date).
+ For this to work, we need to know what date/time type we compare
+ strings as.
*/
- if (cmp_type == STRING_RESULT)
+ if (cmp_type == TIME_RESULT)
{
for (i= 0; i < 3; i++)
{
- if (args[i]->is_datetime())
+ if (args[i]->cmp_type() == TIME_RESULT)
{
- datetime_found= TRUE;
+ if (args[i]->field_type() != MYSQL_TYPE_TIME ||
+ (args[i]->field_type() == MYSQL_TYPE_TIME && compare_as_dates==0))
+ compare_as_dates= args[i];
continue;
}
- if (args[i]->field_type() == MYSQL_TYPE_TIME &&
- args[i]->result_as_longlong())
- time_items_found++;
}
}
- if (!datetime_found)
- compare_as_dates= FALSE;
- if (compare_as_dates)
- {
- 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)
- {
- /* Compare TIME items as integers. */
- cmp_type= INT_RESULT;
- }
- else if (args[0]->real_item()->type() == FIELD_ITEM &&
- thd->lex->sql_command != SQLCOM_CREATE_VIEW &&
- thd->lex->sql_command != SQLCOM_SHOW_CREATE)
+ /* See the comment about the similar block in Item_bool_func2 */
+ if (args[0]->real_item()->type() == FIELD_ITEM &&
+ !thd->is_context_analysis_only())
{
Item_field *field_item= (Item_field*) (args[0]->real_item());
- if (field_item->field->can_be_compared_as_longlong())
+ if (field_item->cmp_type() == INT_RESULT)
{
/*
The following can't be recoded with || as convert_constant_item
@@ -2319,27 +2016,46 @@ void Item_func_between::fix_length_and_dec()
longlong Item_func_between::val_int()
{ // ANSI BETWEEN
DBUG_ASSERT(fixed == 1);
- if (compare_as_dates)
+
+ switch (cmp_type) {
+ case TIME_RESULT:
{
- int ge_res, le_res;
+ THD *thd= current_thd;
+ longlong value, a, b;
+ Item *cache, **ptr;
+ bool value_is_null, a_is_null, b_is_null;
+
+ ptr= &args[0];
+ value= get_datetime_value(thd, &ptr, &cache, compare_as_dates,
+ &value_is_null);
+ if (ptr != &args[0])
+ thd->change_item_tree(&args[0], *ptr);
- ge_res= ge_cmp.compare();
- if ((null_value= args[0]->null_value))
+ if ((null_value= value_is_null))
return 0;
- le_res= le_cmp.compare();
- if (!args[1]->null_value && !args[2]->null_value)
- return (longlong) ((ge_res >= 0 && le_res <=0) != negated);
- else if (args[1]->null_value)
- {
- null_value= le_res > 0; // not null if false range.
- }
+ ptr= &args[1];
+ a= get_datetime_value(thd, &ptr, &cache, compare_as_dates, &a_is_null);
+ if (ptr != &args[1])
+ thd->change_item_tree(&args[1], *ptr);
+
+ ptr= &args[2];
+ b= get_datetime_value(thd, &ptr, &cache, compare_as_dates, &b_is_null);
+ if (ptr != &args[2])
+ thd->change_item_tree(&args[2], *ptr);
+
+ if (!a_is_null && !b_is_null)
+ return (longlong) ((value >= a && value <= b) != negated);
+ if (a_is_null && b_is_null)
+ null_value=1;
+ else if (a_is_null)
+ null_value= value <= b; // not null if false range.
else
- {
- null_value= ge_res < 0;
- }
+ null_value= value >= a;
+ break;
}
- else if (cmp_type == STRING_RESULT)
+
+ case STRING_RESULT:
{
String *value,*a,*b;
value=args[0]->val_str(&value0);
@@ -2363,8 +2079,9 @@ longlong Item_func_between::val_int()
// Set to not null if false range.
null_value= sortcmp(value,a,cmp_collation.collation) >= 0;
}
+ break;
}
- else if (cmp_type == INT_RESULT)
+ case INT_RESULT:
{
longlong value=args[0]->val_int(), a, b;
if ((null_value=args[0]->null_value))
@@ -2383,8 +2100,9 @@ longlong Item_func_between::val_int()
{
null_value= value >= a;
}
+ break;
}
- else if (cmp_type == DECIMAL_RESULT)
+ case DECIMAL_RESULT:
{
my_decimal dec_buf, *dec= args[0]->val_decimal(&dec_buf),
a_buf, *a_dec, b_buf, *b_dec;
@@ -2401,8 +2119,9 @@ longlong Item_func_between::val_int()
null_value= (my_decimal_cmp(dec, b_dec) <= 0);
else
null_value= (my_decimal_cmp(dec, a_dec) >= 0);
+ break;
}
- else
+ case REAL_RESULT:
{
double value= args[0]->val_real(),a,b;
if ((null_value=args[0]->null_value))
@@ -2421,6 +2140,12 @@ longlong Item_func_between::val_int()
{
null_value= value >= a;
}
+ break;
+ }
+ default:
+ DBUG_ASSERT(0);
+ null_value= 1;
+ return 0;
}
return (longlong) (!null_value && negated);
}
@@ -3890,7 +3615,7 @@ void Item_func_in::fix_length_and_dec()
skip_column= TRUE;
break;
}
- else if (itm->is_datetime())
+ else if (itm->cmp_type() == TIME_RESULT)
{
datetime_found= TRUE;
/*
@@ -3946,14 +3671,14 @@ void Item_func_in::fix_length_and_dec()
So we must check here if the column on the left and all the constant
values on the right can be compared as integers and adjust the
comparison type accordingly.
+
+ See the comment about the similar block in Item_bool_func2
*/
if (args[0]->real_item()->type() == FIELD_ITEM &&
- thd->lex->sql_command != SQLCOM_CREATE_VIEW &&
- thd->lex->sql_command != SQLCOM_SHOW_CREATE &&
- cmp_type != INT_RESULT)
+ !thd->is_context_analysis_only() && cmp_type != INT_RESULT)
{
Item_field *field_item= (Item_field*) (args[0]->real_item());
- if (field_item->field->can_be_compared_as_longlong())
+ if (field_item->cmp_type() == INT_RESULT)
{
bool all_converted= TRUE;
for (arg=args+1, arg_end=args+arg_count; arg != arg_end ; arg++)
@@ -5359,7 +5084,7 @@ Item_equal::Item_equal(Item *c, Item_field *f)
const_item_cache= 0;
fields.push_back(f);
const_item= c;
- compare_as_dates= f->is_datetime();
+ compare_as_dates= f->cmp_type() == TIME_RESULT;
}
@@ -5406,7 +5131,7 @@ void Item_equal::add(Item *c, Item_field *f)
{
DBUG_ASSERT(f);
const_item= c;
- compare_as_dates= f->is_datetime();
+ compare_as_dates= f->cmp_type() == TIME_RESULT;
return;
}
compare_const(c);
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 506de05f0ea..ec5ba8bb616 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -33,32 +33,22 @@ class Arg_comparator: public Sql_alloc
Item **a, **b;
arg_cmp_func func;
Item_result_field *owner;
+ bool set_null; // TRUE <=> set owner->null_value
Arg_comparator *comparators; // used only for compare_row()
double precision;
/* Fields used in DATE/DATETIME comparison. */
THD *thd;
- 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.
- enum enum_date_cmp_type { CMP_DATE_DFLT= 0, CMP_DATE_WITH_DATE,
- CMP_DATE_WITH_STR, CMP_STR_WITH_DATE };
- 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);
- bool try_year_cmp_func(Item_result type);
public:
DTCollation cmp_collation;
/* Allow owner function to use string buffers. */
String value1, value2;
- Arg_comparator(): comparators(0), thd(0), a_cache(0), b_cache(0), set_null(TRUE),
- get_value_a_func(0), get_value_b_func(0) {};
- Arg_comparator(Item **a1, Item **a2): a(a1), b(a2), comparators(0), thd(0),
- a_cache(0), b_cache(0), set_null(TRUE),
- get_value_a_func(0), get_value_b_func(0) {};
+ Arg_comparator(): set_null(TRUE), comparators(0), thd(0),
+ a_cache(0), b_cache(0) {};
+ Arg_comparator(Item **a1, Item **a2): a(a1), b(a2), set_null(TRUE),
+ comparators(0), thd(0), a_cache(0), b_cache(0) {};
int set_compare_func(Item_result_field *owner, Item_result type);
inline int set_compare_func(Item_result_field *owner_arg)
@@ -75,8 +65,8 @@ public:
{
set_null= set_null_arg;
return set_cmp_func(owner_arg, a1, a2,
- item_cmp_type((*a1)->result_type(),
- (*a2)->result_type()));
+ item_cmp_type((*a1)->cmp_type(),
+ (*a2)->cmp_type()));
}
inline int compare() { return (this->*func)(); }
@@ -99,14 +89,12 @@ public:
int compare_real_fixed();
int compare_e_real_fixed();
int compare_datetime(); // compare args[0] & args[1] as DATETIMEs
-
- static enum enum_date_cmp_type can_compare_as_dates(Item *a, Item *b,
- ulonglong *const_val_arg);
+ int compare_e_datetime();
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];
+ static arg_cmp_func comparator_matrix [6][2];
inline bool is_owner_equal_func()
{
return (owner->type() == Item::FUNC_ITEM &&
@@ -614,9 +602,7 @@ public:
Item_result cmp_type;
String value0,value1,value2;
/* TRUE <=> arguments will be compared as dates. */
- bool compare_as_dates;
- /* Comparators used for DATE/DATETIME comparison. */
- Arg_comparator ge_cmp, le_cmp;
+ Item *compare_as_dates;
Item_func_between(Item *a, Item *b, Item *c)
:Item_func_opt_neg(a, b, c), compare_as_dates(FALSE) {}
longlong val_int();
@@ -894,6 +880,16 @@ public:
lval_cache(0) {};
void set(uint pos,Item *item);
uchar *get_value(Item *item);
+ Item* create_item()
+ {
+ return new Item_datetime();
+ }
+ void value_to_item(uint pos, Item *item)
+ {
+ packed_longlong *val= reinterpret_cast<packed_longlong*>(base)+pos;
+ Item_datetime *dt= reinterpret_cast<Item_datetime*>(item);
+ dt->set(val->val);
+ }
friend int cmp_longlong(void *cmp_arg, packed_longlong *a,packed_longlong *b);
};
diff --git a/sql/item_create.cc b/sql/item_create.cc
index 5726e987ef6..ac1102fabbb 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -5044,6 +5044,14 @@ find_qualified_function_builder(THD *thd)
return & Create_sp_func::s_singleton;
}
+static inline const char* item_name(Item *a, String *str)
+{
+ if (a->name)
+ return a->name;
+ str->length(0);
+ a->print(str, QT_ORDINARY);
+ return str->c_ptr_safe();
+}
Item *
create_func_cast(THD *thd, Item *a, Cast_target cast_type,
@@ -5051,6 +5059,8 @@ create_func_cast(THD *thd, Item *a, Cast_target cast_type,
CHARSET_INFO *cs)
{
Item *UNINIT_VAR(res);
+ char buff[1024];
+ String buf(buff, sizeof(buff), system_charset_info);
switch (cast_type) {
case ITEM_CAST_BINARY:
@@ -5066,11 +5076,29 @@ create_func_cast(THD *thd, Item *a, Cast_target cast_type,
res= new (thd->mem_root) Item_date_typecast(a);
break;
case ITEM_CAST_TIME:
- res= new (thd->mem_root) Item_time_typecast(a);
- break;
case ITEM_CAST_DATETIME:
- res= new (thd->mem_root) Item_datetime_typecast(a);
+ {
+ uint len;
+ if (c_len)
+ {
+ errno= 0;
+ len= strtoul(c_len, NULL, 10);
+ if (errno != 0 || len > MAX_DATETIME_PRECISION)
+ {
+ my_error(ER_TOO_BIG_PRECISION, MYF(0), len,
+ item_name(a, &buf), MAX_DATETIME_PRECISION);
+ return NULL;
+ }
+ }
+ else
+ len= NOT_FIXED_DEC;
+
+ if (cast_type == ITEM_CAST_TIME)
+ res= new (thd->mem_root) Item_time_typecast(a, len);
+ else
+ res= new (thd->mem_root) Item_datetime_typecast(a, len);
break;
+ }
case ITEM_CAST_DECIMAL:
{
ulong len= 0;
@@ -5083,8 +5111,8 @@ create_func_cast(THD *thd, Item *a, Cast_target cast_type,
decoded_size= strtoul(c_len, NULL, 10);
if (errno != 0)
{
- my_error(ER_TOO_BIG_PRECISION, MYF(0), c_len, a->name,
- DECIMAL_MAX_PRECISION);
+ my_error(ER_TOO_BIG_PRECISION, MYF(0), decoded_size,
+ item_name(a, &buf), DECIMAL_MAX_PRECISION);
return NULL;
}
len= decoded_size;
@@ -5097,8 +5125,8 @@ create_func_cast(THD *thd, Item *a, Cast_target cast_type,
decoded_size= strtoul(c_dec, NULL, 10);
if ((errno != 0) || (decoded_size > UINT_MAX))
{
- my_error(ER_TOO_BIG_SCALE, MYF(0), c_dec, a->name,
- DECIMAL_MAX_SCALE);
+ my_error(ER_TOO_BIG_SCALE, MYF(0), decoded_size,
+ item_name(a, &buf), DECIMAL_MAX_SCALE);
return NULL;
}
dec= decoded_size;
@@ -5111,13 +5139,13 @@ create_func_cast(THD *thd, Item *a, Cast_target cast_type,
}
if (len > DECIMAL_MAX_PRECISION)
{
- my_error(ER_TOO_BIG_PRECISION, MYF(0), len, a->name,
- DECIMAL_MAX_PRECISION);
+ my_error(ER_TOO_BIG_PRECISION, MYF(0), len,
+ item_name(a, &buf), DECIMAL_MAX_PRECISION);
return 0;
}
if (dec > DECIMAL_MAX_SCALE)
{
- my_error(ER_TOO_BIG_SCALE, MYF(0), dec, a->name,
+ my_error(ER_TOO_BIG_SCALE, MYF(0), dec, item_name(a, &buf),
DECIMAL_MAX_SCALE);
return 0;
}
@@ -5135,7 +5163,7 @@ create_func_cast(THD *thd, Item *a, Cast_target cast_type,
decoded_size= strtoul(c_len, NULL, 10);
if ((errno != 0) || (decoded_size > MAX_FIELD_BLOBLENGTH))
{
- my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), "cast as char", MAX_FIELD_BLOBLENGTH);
+ my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), "cast as char", MAX_FIELD_BLOBLENGTH);
return NULL;
}
len= (int) decoded_size;
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 8bb1009ac2c..b37156efa02 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -940,8 +940,7 @@ longlong Item_func_signed::val_int()
longlong value;
int error;
- if (args[0]->cast_to_int_type() != STRING_RESULT ||
- args[0]->result_as_longlong())
+ if (args[0]->cast_to_int_type() != STRING_RESULT)
{
value= args[0]->val_int();
null_value= args[0]->null_value;
@@ -982,8 +981,7 @@ longlong Item_func_unsigned::val_int()
value= 0;
return value;
}
- else if (args[0]->cast_to_int_type() != STRING_RESULT ||
- args[0]->result_as_longlong())
+ else if (args[0]->cast_to_int_type() != STRING_RESULT)
{
value= args[0]->val_int();
null_value= args[0]->null_value;
@@ -2220,7 +2218,6 @@ double Item_func_units::val_real()
void Item_func_min_max::fix_length_and_dec()
{
int max_int_part=0;
- bool datetime_found= FALSE;
decimals=0;
max_length=0;
maybe_null=0;
@@ -2234,21 +2231,17 @@ void Item_func_min_max::fix_length_and_dec()
if (args[i]->maybe_null)
maybe_null=1;
cmp_type=item_cmp_type(cmp_type,args[i]->result_type());
- if (args[i]->result_type() != ROW_RESULT && args[i]->is_datetime())
+ if (args[i]->cmp_type() == TIME_RESULT)
{
- datetime_found= TRUE;
- if (!datetime_item || args[i]->field_type() == MYSQL_TYPE_DATETIME)
- datetime_item= args[i];
+ if (!compare_as_dates || args[i]->field_type() == MYSQL_TYPE_DATETIME)
+ compare_as_dates= args[i];
}
}
if (cmp_type == STRING_RESULT)
{
agg_arg_charsets(collation, args, arg_count, MY_COLL_CMP_CONV, 1);
- if (datetime_found)
- {
+ if (compare_as_dates)
thd= current_thd;
- compare_as_dates= TRUE;
- }
}
else if ((cmp_type == DECIMAL_RESULT) || (cmp_type == INT_RESULT))
max_length= my_decimal_precision_to_length_no_truncation(max_int_part +
@@ -2256,7 +2249,11 @@ void Item_func_min_max::fix_length_and_dec()
unsigned_flag);
else if (cmp_type == REAL_RESULT)
max_length= float_length(decimals);
- cached_field_type= agg_field_type(args, arg_count);
+
+ if (compare_as_dates)
+ cached_field_type= compare_as_dates->field_type();
+ else
+ cached_field_type= agg_field_type(args, arg_count);
}
@@ -2265,52 +2262,45 @@ void Item_func_min_max::fix_length_and_dec()
SYNOPSIS
cmp_datetimes()
- value [out] found least/greatest DATE/DATETIME value
DESCRIPTION
Compare item arguments as DATETIME values and return the index of the
least/greatest argument in the arguments array.
- The correct integer DATE/DATETIME value of the found argument is
+ The correct DATE/DATETIME value of the found argument is
stored to the value pointer, if latter is provided.
RETURN
- 0 If one of arguments is NULL or there was a execution error
- # index of the least/greatest argument
+ 1 If one of arguments is NULL or there was a execution error
+ 0 Otherwise
*/
-uint Item_func_min_max::cmp_datetimes(ulonglong *value)
+bool Item_func_min_max::cmp_datetimes(MYSQL_TIME *ltime)
{
longlong UNINIT_VAR(min_max);
- uint min_max_idx= 0;
for (uint i=0; i < arg_count ; i++)
{
Item **arg= args + i;
bool is_null;
- longlong res= get_datetime_value(thd, &arg, 0, datetime_item, &is_null);
+ longlong res= get_datetime_value(thd, &arg, 0, compare_as_dates, &is_null);
/* Check if we need to stop (because of error or KILL) and stop the loop */
if (thd->is_error())
{
null_value= 1;
- return 0;
+ return 1;
}
if ((null_value= args[i]->null_value))
- return 0;
+ return 1;
if (i == 0 || (res < min_max ? cmp_sign : -cmp_sign) > 0)
- {
min_max= res;
- min_max_idx= i;
- }
}
- if (value)
- {
- *value= min_max;
- if (datetime_item->field_type() == MYSQL_TYPE_DATE)
- *value/= 1000000L;
- }
- return min_max_idx;
+ unpack_time(min_max, ltime);
+ if (compare_as_dates->field_type() == MYSQL_TYPE_DATE)
+ ltime->time_type= MYSQL_TIMESTAMP_DATE;
+
+ return 0;
}
@@ -2319,19 +2309,14 @@ String *Item_func_min_max::val_str(String *str)
DBUG_ASSERT(fixed == 1);
if (compare_as_dates)
{
- String *str_res;
- uint min_max_idx= cmp_datetimes(NULL);
- if (null_value)
+ MYSQL_TIME ltime;
+ if (cmp_datetimes(&ltime))
return 0;
- str_res= args[min_max_idx]->val_str(str);
- if (args[min_max_idx]->null_value)
- {
- // check if the call to val_str() above returns a NULL value
- null_value= 1;
- return NULL;
- }
- str_res->set_charset(collation.collation);
- return str_res;
+
+ char buf[MAX_DATE_STRING_REP_LENGTH];
+ int len= my_TIME_to_str(&ltime, buf, decimals);
+ str->copy(buf, len, collation.collation);
+ return str;
}
switch (cmp_type) {
case INT_RESULT:
@@ -2398,9 +2383,11 @@ double Item_func_min_max::val_real()
double value=0.0;
if (compare_as_dates)
{
- ulonglong result= 0;
- (void)cmp_datetimes(&result);
- return (double)result;
+ MYSQL_TIME ltime;
+ if (cmp_datetimes(&ltime))
+ return 0;
+
+ return TIME_to_double(&ltime);
}
for (uint i=0; i < arg_count ; i++)
{
@@ -2425,9 +2412,11 @@ longlong Item_func_min_max::val_int()
longlong value=0;
if (compare_as_dates)
{
- ulonglong result= 0;
- (void)cmp_datetimes(&result);
- return (longlong)result;
+ MYSQL_TIME ltime;
+ if (cmp_datetimes(&ltime))
+ return 0;
+
+ return TIME_to_ulonglong(&ltime);
}
for (uint i=0; i < arg_count ; i++)
{
@@ -2453,10 +2442,11 @@ my_decimal *Item_func_min_max::val_decimal(my_decimal *dec)
if (compare_as_dates)
{
- ulonglong value= 0;
- (void)cmp_datetimes(&value);
- ulonglong2decimal(value, dec);
- return dec;
+ MYSQL_TIME ltime;
+ if (cmp_datetimes(&ltime))
+ return 0;
+
+ return date2my_decimal(&ltime, dec);
}
for (uint i=0; i < arg_count ; i++)
{
@@ -3979,7 +3969,7 @@ double user_var_entry::val_real(my_bool *null_value)
}
case STRING_RESULT:
return my_atof(value); // This is null terminated
- case ROW_RESULT:
+ default:
DBUG_ASSERT(1); // Impossible
break;
}
@@ -4010,7 +4000,7 @@ longlong user_var_entry::val_int(my_bool *null_value) const
int error;
return my_strtoll10(value, (char**) 0, &error);// String is null terminated
}
- case ROW_RESULT:
+ default:
DBUG_ASSERT(1); // Impossible
break;
}
@@ -4042,7 +4032,7 @@ String *user_var_entry::val_str(my_bool *null_value, String *str,
case STRING_RESULT:
if (str->copy(value, length, collation.collation))
str= 0; // EOM error
- case ROW_RESULT:
+ default:
DBUG_ASSERT(1); // Impossible
break;
}
@@ -4069,7 +4059,7 @@ my_decimal *user_var_entry::val_decimal(my_bool *null_value, my_decimal *val)
case STRING_RESULT:
str2my_decimal(E_DEC_FATAL_ERROR, value, length, collation.collation, val);
break;
- case ROW_RESULT:
+ default:
DBUG_ASSERT(1); // Impossible
break;
}
diff --git a/sql/item_func.h b/sql/item_func.h
index 26a7e033692..d0f5d8d8d8f 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -757,25 +757,21 @@ class Item_func_min_max :public Item_func
Item_result cmp_type;
String tmp_value;
int cmp_sign;
- /* TRUE <=> arguments should be compared in the DATETIME context. */
- bool compare_as_dates;
/* An item used for issuing warnings while string to DATETIME conversion. */
- Item *datetime_item;
+ Item *compare_as_dates;
THD *thd;
protected:
enum_field_types cached_field_type;
public:
Item_func_min_max(List<Item> &list,int cmp_sign_arg) :Item_func(list),
- cmp_type(INT_RESULT), cmp_sign(cmp_sign_arg), compare_as_dates(FALSE),
- datetime_item(0) {}
+ cmp_type(INT_RESULT), cmp_sign(cmp_sign_arg), compare_as_dates(FALSE) {}
double val_real();
longlong val_int();
String *val_str(String *);
my_decimal *val_decimal(my_decimal *);
void fix_length_and_dec();
enum Item_result result_type () const { return cmp_type; }
- bool result_as_longlong() { return compare_as_dates; };
- uint cmp_datetimes(ulonglong *value);
+ bool cmp_datetimes(MYSQL_TIME *ltime);
enum_field_types field_type() const { return cached_field_type; }
};
diff --git a/sql/item_row.h b/sql/item_row.h
index 76d1c875e7d..0b8c09f6c5d 100644
--- a/sql/item_row.h
+++ b/sql/item_row.h
@@ -65,6 +65,7 @@ public:
table_map used_tables() const { return used_tables_cache; };
bool const_item() const { return const_item_cache; };
enum Item_result result_type() const { return ROW_RESULT; }
+ Item_result cmp_type() const { return ROW_RESULT; }
void update_used_tables();
table_map not_null_tables() const { return not_null_tables_cache; }
virtual void print(String *str, enum_query_type query_type);
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 65f8222d38b..d2fd0c4b0eb 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -692,14 +692,17 @@ Field *Item_sum_hybrid::create_tmp_field(bool group, TABLE *table,
*/
switch (args[0]->field_type()) {
case MYSQL_TYPE_DATE:
- field= new Field_newdate(maybe_null, name, collation.collation);
+ field= new Field_newdate(0, maybe_null ? (uchar*)"" : 0, 0, Field::NONE,
+ name, collation.collation);
break;
case MYSQL_TYPE_TIME:
- field= new Field_time(maybe_null, name, collation.collation);
+ field= new_Field_time(0, maybe_null ? (uchar*)"" : 0, 0, Field::NONE,
+ name, decimals, collation.collation);
break;
case MYSQL_TYPE_TIMESTAMP:
case MYSQL_TYPE_DATETIME:
- field= new Field_datetime(maybe_null, name, collation.collation);
+ field= new_Field_datetime(0, maybe_null ? (uchar*)"" : 0, 0, Field::NONE,
+ name, decimals, collation.collation);
break;
default:
return Item_sum::create_tmp_field(group, table, convert_blob_length);
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 6335199b8de..aa42d869df5 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -35,128 +35,12 @@
/** Day number for Dec 31st, 9999. */
#define MAX_DAY_NUMBER 3652424L
-/**
- @todo
- OPTIMIZATION
- - Replace the switch with a function that should be called for each
- date type.
- - Remove sprintf and opencode the conversion, like we do in
- Field_datetime.
-
- The reason for this functions existence is that as we don't have a
- way to know if a datetime/time value has microseconds in them
- we are now only adding microseconds to the output if the
- value has microseconds.
-
- We can't use a standard make_date_time() for this as we don't know
- if someone will use %f in the format specifier in which case we would get
- the microseconds twice.
-*/
-
-static bool make_datetime(date_time_format_types format, MYSQL_TIME *ltime,
- String *str)
-{
- char *buff;
- CHARSET_INFO *cs= &my_charset_bin;
- uint length= MAX_DATE_STRING_REP_LENGTH;
-
- if (str->alloc(length))
- return 1;
- buff= (char*) str->ptr();
-
- switch (format) {
- case TIME_ONLY:
- length= cs->cset->snprintf(cs, buff, length, "%s%02d:%02d:%02d",
- ltime->neg ? "-" : "",
- ltime->hour, ltime->minute, ltime->second);
- break;
- case TIME_MICROSECOND:
- length= cs->cset->snprintf(cs, buff, length, "%s%02d:%02d:%02d.%06ld",
- ltime->neg ? "-" : "",
- ltime->hour, ltime->minute, ltime->second,
- ltime->second_part);
- break;
- case DATE_ONLY:
- length= cs->cset->snprintf(cs, buff, length, "%04d-%02d-%02d",
- ltime->year, ltime->month, ltime->day);
- break;
- case DATE_TIME:
- length= cs->cset->snprintf(cs, buff, length,
- "%04d-%02d-%02d %02d:%02d:%02d",
- ltime->year, ltime->month, ltime->day,
- ltime->hour, ltime->minute, ltime->second);
- break;
- case DATE_TIME_MICROSECOND:
- length= cs->cset->snprintf(cs, buff, length,
- "%04d-%02d-%02d %02d:%02d:%02d.%06ld",
- ltime->year, ltime->month, ltime->day,
- ltime->hour, ltime->minute, ltime->second,
- ltime->second_part);
- break;
- }
-
- str->length(length);
- str->set_charset(cs);
- return 0;
-}
-
-
-/*
- Wrapper over make_datetime() with validation of the input MYSQL_TIME value
-
- NOTE
- see make_datetime() for more information
-
- RETURN
- 1 if there was an error during converion
- 0 otherwise
-*/
-
-static bool make_datetime_with_warn(date_time_format_types format, MYSQL_TIME *ltime,
- String *str)
+static bool make_datetime(MYSQL_TIME *ltime, String *str, uint decimals)
{
- int warning= 0;
-
- if (make_datetime(format, ltime, str))
- return 1;
- if (check_time_range(ltime, &warning))
- return 1;
- if (!warning)
- return 0;
-
- make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- str->ptr(), str->length(),
- MYSQL_TIMESTAMP_TIME, NullS);
- return make_datetime(format, ltime, str);
-}
-
-
-/*
- Wrapper over make_time() with validation of the input MYSQL_TIME value
-
- NOTE
- see make_time() for more info
-
- RETURN
- 1 if there was an error during conversion
- 0 otherwise
-*/
-
-static bool make_time_with_warn(const DATE_TIME_FORMAT *format,
- MYSQL_TIME *l_time, String *str)
-{
- int warning= 0;
- make_time(format, l_time, str);
- if (check_time_range(l_time, &warning))
+ if (str->alloc(MAX_DATE_STRING_REP_LENGTH))
return 1;
- if (warning)
- {
- make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- str->ptr(), str->length(),
- MYSQL_TIMESTAMP_TIME, NullS);
- make_time(format, l_time, str);
- }
-
+ str->length(my_TIME_to_str(ltime, const_cast<char*>(str->ptr()), decimals));
+ str->set_charset(&my_charset_bin);
return 0;
}
@@ -167,7 +51,6 @@ static bool make_time_with_warn(const DATE_TIME_FORMAT *format,
SYNOPSIS:
sec_to_time()
seconds number of seconds
- unsigned_flag 1, if 'seconds' is unsigned, 0, otherwise
ltime output MYSQL_TIME value
DESCRIPTION
@@ -181,16 +64,16 @@ static bool make_time_with_warn(const DATE_TIME_FORMAT *format,
0 otherwise
*/
-static bool sec_to_time(longlong seconds, bool unsigned_flag, MYSQL_TIME *ltime)
+static bool sec_to_time(double seconds, MYSQL_TIME *ltime)
{
uint sec;
bzero((char *)ltime, sizeof(*ltime));
+
+ ltime->time_type= MYSQL_TIMESTAMP_TIME;
if (seconds < 0)
{
- if (unsigned_flag)
- goto overflow;
ltime->neg= 1;
if (seconds < -3020399)
goto overflow;
@@ -203,6 +86,7 @@ static bool sec_to_time(longlong seconds, bool unsigned_flag, MYSQL_TIME *ltime)
ltime->hour= (uint) (seconds/3600);
ltime->minute= sec/60;
ltime->second= sec % 60;
+ ltime->second_part= (ulong)((seconds - trunc(seconds))*1e6);
return 0;
@@ -211,9 +95,8 @@ overflow:
ltime->minute= TIME_MAX_MINUTE;
ltime->second= TIME_MAX_SECOND;
- char buf[22];
- int len= (int)(longlong10_to_str(seconds, buf, unsigned_flag ? 10 : -10)
- - buf);
+ char buf[100];
+ uint len= snprintf(buf, sizeof(buf), "%.80g", ltime->neg ? -seconds: seconds);
make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
buf, len, MYSQL_TIMESTAMP_TIME,
NullS);
@@ -270,7 +153,8 @@ static bool extract_date_time(DATE_TIME_FORMAT *format,
const char *val, uint length, MYSQL_TIME *l_time,
timestamp_type cached_timestamp_type,
const char **sub_pattern_end,
- const char *date_time_type)
+ const char *date_time_type,
+ uint fuzzy_date)
{
int weekday= 0, yearday= 0, daypart= 0;
int week_number= -1;
@@ -291,6 +175,8 @@ static bool extract_date_time(DATE_TIME_FORMAT *format,
if (!sub_pattern_end)
bzero((char*) l_time, sizeof(*l_time));
+ l_time->time_type= cached_timestamp_type;
+
for (; ptr != end && val != val_end; ptr++)
{
/* Skip pre-space between each argument */
@@ -464,7 +350,7 @@ static bool extract_date_time(DATE_TIME_FORMAT *format,
*/
if (extract_date_time(&time_ampm_format, val,
(uint)(val_end - val), l_time,
- cached_timestamp_type, &val, "time"))
+ cached_timestamp_type, &val, "time", fuzzy_date))
DBUG_RETURN(1);
break;
@@ -472,7 +358,7 @@ static bool extract_date_time(DATE_TIME_FORMAT *format,
case 'T':
if (extract_date_time(&time_24hrs_format, val,
(uint)(val_end - val), l_time,
- cached_timestamp_type, &val, "time"))
+ cached_timestamp_type, &val, "time", fuzzy_date))
DBUG_RETURN(1);
break;
@@ -578,6 +464,10 @@ static bool extract_date_time(DATE_TIME_FORMAT *format,
l_time->minute > 59 || l_time->second > 59)
goto err;
+ if ((fuzzy_date & TIME_NO_ZERO_DATE) &&
+ (l_time->year == 0 || l_time->month == 0 || l_time->day == 0))
+ goto err;
+
if (val != val_end)
{
do
@@ -1299,7 +1189,12 @@ longlong Item_func_unix_timestamp::val_int()
{ // Optimize timestamp field
Field *field=((Item_field*) args[0])->field;
if (field->type() == MYSQL_TYPE_TIMESTAMP)
- return ((Field_timestamp*) field)->get_timestamp(&null_value);
+ {
+ if ((null_value= field->is_null()))
+ return 0;
+ ulong unused;
+ return ((Field_timestamp*) field)->get_timestamp(&unused);
+ }
}
if (get_arg0_date(&ltime, 0))
@@ -1317,13 +1212,13 @@ longlong Item_func_unix_timestamp::val_int()
}
-longlong Item_func_time_to_sec::val_int()
+double Item_func_time_to_sec::val_real()
{
DBUG_ASSERT(fixed == 1);
MYSQL_TIME ltime;
- longlong seconds;
+ double seconds;
(void) get_arg0_time(&ltime);
- seconds=ltime.hour*3600L+ltime.minute*60+ltime.second;
+ seconds=ltime.hour*3600L+ltime.minute*60+ltime.second+ltime.second_part/1e6;
return ltime.neg ? -seconds : seconds;
}
@@ -1486,29 +1381,38 @@ bool get_interval_value(Item *args,interval_type int_type,
}
-String *Item_date::val_str(String *str)
+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 (str->alloc(MAX_DATE_STRING_REP_LENGTH))
+ if (make_datetime(&ltime, str, decimals))
{
null_value= 1;
return (String *) 0;
}
- make_date((DATE_TIME_FORMAT *) 0, &ltime, str);
return str;
}
-longlong Item_date::val_int()
+longlong Item_temporal_func::val_int()
+{
+ DBUG_ASSERT(fixed == 1);
+ MYSQL_TIME ltime;
+ if (get_date(&ltime, TIME_FUZZY_DATE))
+ return 0;
+ return (longlong)TIME_to_ulonglong(&ltime);
+}
+
+
+double Item_temporal_func::val_real()
{
DBUG_ASSERT(fixed == 1);
MYSQL_TIME ltime;
if (get_date(&ltime, TIME_FUZZY_DATE))
return 0;
- return (longlong) (ltime.year*10000L+ltime.month*100+ltime.day);
+ return TIME_to_double(&ltime);
}
@@ -1535,19 +1439,6 @@ void Item_func_curdate::fix_length_and_dec()
/* We don't need to set second_part and neg because they already 0 */
ltime.hour= ltime.minute= ltime.second= 0;
ltime.time_type= MYSQL_TIMESTAMP_DATE;
- value= (longlong) TIME_to_ulonglong_date(&ltime);
-}
-
-String *Item_func_curdate::val_str(String *str)
-{
- DBUG_ASSERT(fixed == 1);
- if (str->alloc(MAX_DATE_STRING_REP_LENGTH))
- {
- null_value= 1;
- return (String *) 0;
- }
- make_date((DATE_TIME_FORMAT *) 0, &ltime, str);
- return str;
}
/**
@@ -1557,8 +1448,7 @@ String *Item_func_curdate::val_str(String *str)
void Item_func_curdate_local::store_now_in_TIME(MYSQL_TIME *now_time)
{
THD *thd= current_thd;
- thd->variables.time_zone->gmt_sec_to_TIME(now_time,
- (my_time_t)thd->query_start());
+ thd->variables.time_zone->gmt_sec_to_TIME(now_time, thd->query_start());
thd->time_zone_used= 1;
}
@@ -1569,8 +1459,9 @@ void Item_func_curdate_local::store_now_in_TIME(MYSQL_TIME *now_time)
*/
void Item_func_curdate_utc::store_now_in_TIME(MYSQL_TIME *now_time)
{
- my_tz_UTC->gmt_sec_to_TIME(now_time,
- (my_time_t)(current_thd->query_start()));
+ THD *thd= current_thd;
+ my_tz_UTC->gmt_sec_to_TIME(now_time, thd->query_start());
+ thd->time_zone_used= 1;
/*
We are not flagging this query as using time zone, since it uses fixed
UTC-SYSTEM time-zone.
@@ -1586,26 +1477,42 @@ bool Item_func_curdate::get_date(MYSQL_TIME *res,
}
-String *Item_func_curtime::val_str(String *str)
+bool Item_func_curtime::fix_fields(THD *thd, Item **items)
{
- DBUG_ASSERT(fixed == 1);
- str_value.set(buff, buff_length, &my_charset_bin);
- return &str_value;
+ if (decimals > MAX_SEC_PART_DIGITS)
+ {
+ my_error(ER_WRONG_ARGUMENTS, MYF(0), func_name());
+ return 1;
+ }
+ return Item_timefunc::fix_fields(thd, items);
}
-
void Item_func_curtime::fix_length_and_dec()
{
- MYSQL_TIME ltime;
-
- decimals= DATETIME_DEC;
collation.set(&my_charset_bin);
store_now_in_TIME(&ltime);
- value= TIME_to_ulonglong_time(&ltime);
- buff_length= (uint) my_time_to_str(&ltime, buff);
- max_length= buff_length;
+ max_length= MAX_TIME_WIDTH +
+ (decimals ? min(decimals, MAX_SEC_PART_DIGITS)+1 : 0);
}
+bool Item_func_curtime::get_date(MYSQL_TIME *res,
+ uint fuzzy_date __attribute__((unused)))
+{
+ *res= ltime;
+ return 0;
+}
+
+static void set_sec_part(ulong sec_part, MYSQL_TIME *ltime, Item *item)
+{
+ DBUG_ASSERT(item->decimals == AUTO_SEC_PART_DIGITS ||
+ item->decimals <= MAX_SEC_PART_DIGITS);
+ if (item->decimals)
+ {
+ ltime->second_part= sec_part;
+ if (item->decimals < MAX_SEC_PART_DIGITS)
+ ltime->second_part= sec_part_truncate(ltime->second_part, item->decimals);
+ }
+}
/**
Converts current time in my_time_t to MYSQL_TIME represenatation for local
@@ -1614,8 +1521,10 @@ void Item_func_curtime::fix_length_and_dec()
void Item_func_curtime_local::store_now_in_TIME(MYSQL_TIME *now_time)
{
THD *thd= current_thd;
- thd->variables.time_zone->gmt_sec_to_TIME(now_time,
- (my_time_t)thd->query_start());
+ thd->variables.time_zone->gmt_sec_to_TIME(now_time, thd->query_start());
+ now_time->year= now_time->month= now_time->day= 0;
+ now_time->time_type= MYSQL_TIMESTAMP_TIME;
+ set_sec_part(thd->query_start_sec_part(), now_time, this);
thd->time_zone_used= 1;
}
@@ -1626,33 +1535,33 @@ void Item_func_curtime_local::store_now_in_TIME(MYSQL_TIME *now_time)
*/
void Item_func_curtime_utc::store_now_in_TIME(MYSQL_TIME *now_time)
{
- my_tz_UTC->gmt_sec_to_TIME(now_time,
- (my_time_t)(current_thd->query_start()));
+ THD *thd= current_thd;
+ my_tz_UTC->gmt_sec_to_TIME(now_time, thd->query_start());
+ now_time->year= now_time->month= now_time->day= 0;
+ now_time->time_type= MYSQL_TIMESTAMP_TIME;
+ set_sec_part(thd->query_start_sec_part(), now_time, this);
/*
We are not flagging this query as using time zone, since it uses fixed
UTC-SYSTEM time-zone.
*/
}
-
-String *Item_func_now::val_str(String *str)
+bool Item_func_now::fix_fields(THD *thd, Item **items)
{
- DBUG_ASSERT(fixed == 1);
- str_value.set(buff,buff_length, &my_charset_bin);
- return &str_value;
+ if (decimals > MAX_SEC_PART_DIGITS)
+ {
+ my_error(ER_WRONG_ARGUMENTS, MYF(0), func_name());
+ return 1;
+ }
+ return Item_temporal_func::fix_fields(thd, items);
}
-
void Item_func_now::fix_length_and_dec()
{
- decimals= DATETIME_DEC;
collation.set(&my_charset_bin);
-
store_now_in_TIME(&ltime);
- value= (longlong) TIME_to_ulonglong_datetime(&ltime);
-
- buff_length= (uint) my_datetime_to_str(&ltime, buff);
- max_length= buff_length;
+ max_length= MAX_DATETIME_WIDTH +
+ (decimals ? min(decimals, MAX_SEC_PART_DIGITS)+1 : 0);
}
@@ -1663,8 +1572,8 @@ void Item_func_now::fix_length_and_dec()
void Item_func_now_local::store_now_in_TIME(MYSQL_TIME *now_time)
{
THD *thd= current_thd;
- thd->variables.time_zone->gmt_sec_to_TIME(now_time,
- (my_time_t)thd->query_start());
+ thd->variables.time_zone->gmt_sec_to_TIME(now_time, thd->query_start());
+ set_sec_part(thd->query_start_sec_part(), now_time, this);
thd->time_zone_used= 1;
}
@@ -1675,8 +1584,9 @@ void Item_func_now_local::store_now_in_TIME(MYSQL_TIME *now_time)
*/
void Item_func_now_utc::store_now_in_TIME(MYSQL_TIME *now_time)
{
- my_tz_UTC->gmt_sec_to_TIME(now_time,
- (my_time_t)(current_thd->query_start()));
+ THD *thd= current_thd;
+ my_tz_UTC->gmt_sec_to_TIME(now_time, thd->query_start());
+ set_sec_part(thd->query_start_sec_part(), now_time, this);
/*
We are not flagging this query as using time zone, since it uses fixed
UTC-SYSTEM time-zone.
@@ -1692,13 +1602,6 @@ bool Item_func_now::get_date(MYSQL_TIME *res,
}
-int Item_func_now::save_in_field(Field *to, bool no_conversions)
-{
- to->set_notnull();
- return to->store_time(&ltime, MYSQL_TIMESTAMP_DATETIME);
-}
-
-
/**
Converts current time in my_time_t to MYSQL_TIME represenatation for local
time zone. Defines time zone (local) used for whole SYSDATE function.
@@ -1706,99 +1609,36 @@ int Item_func_now::save_in_field(Field *to, bool no_conversions)
void Item_func_sysdate_local::store_now_in_TIME(MYSQL_TIME *now_time)
{
THD *thd= current_thd;
- thd->variables.time_zone->gmt_sec_to_TIME(now_time, (my_time_t) my_time(0));
+ my_hrtime_t now= my_hrtime();
+ thd->variables.time_zone->gmt_sec_to_TIME(now_time, hrtime_to_time(now));
+ set_sec_part(hrtime_sec_part(now), now_time, this);
thd->time_zone_used= 1;
}
-String *Item_func_sysdate_local::val_str(String *str)
-{
- DBUG_ASSERT(fixed == 1);
- store_now_in_TIME(&ltime);
- buff_length= (uint) my_datetime_to_str(&ltime, buff);
- str_value.set(buff, buff_length, &my_charset_bin);
- return &str_value;
-}
-
-
-longlong Item_func_sysdate_local::val_int()
-{
- DBUG_ASSERT(fixed == 1);
- store_now_in_TIME(&ltime);
- return (longlong) TIME_to_ulonglong_datetime(&ltime);
-}
-
-
-double Item_func_sysdate_local::val_real()
-{
- DBUG_ASSERT(fixed == 1);
- store_now_in_TIME(&ltime);
- return ulonglong2double(TIME_to_ulonglong_datetime(&ltime));
-}
-
-
-void Item_func_sysdate_local::fix_length_and_dec()
-{
- decimals= 0;
- collation.set(&my_charset_bin);
- max_length= MAX_DATETIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
-}
-
-
bool Item_func_sysdate_local::get_date(MYSQL_TIME *res,
uint fuzzy_date __attribute__((unused)))
{
+ MYSQL_TIME ltime;
store_now_in_TIME(&ltime);
*res= ltime;
return 0;
}
-int Item_func_sysdate_local::save_in_field(Field *to, bool no_conversions)
-{
- store_now_in_TIME(&ltime);
- to->set_notnull();
- to->store_time(&ltime, MYSQL_TIMESTAMP_DATETIME);
- return 0;
-}
-
-
-String *Item_func_sec_to_time::val_str(String *str)
+bool Item_func_sec_to_time::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
{
DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
- longlong arg_val= args[0]->val_int();
-
- if ((null_value=args[0]->null_value) ||
- str->alloc(MAX_DATE_STRING_REP_LENGTH))
- {
- null_value= 1;
- return (String*) 0;
- }
-
- sec_to_time(arg_val, args[0]->unsigned_flag, &ltime);
+ double arg_val= args[0]->val_real();
- make_time((DATE_TIME_FORMAT *) 0, &ltime, str);
- return str;
-}
-
+ if ((null_value= args[0]->null_value))
+ return 1;
-longlong Item_func_sec_to_time::val_int()
-{
- DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
- longlong arg_val= args[0]->val_int();
+ sec_to_time(arg_val, ltime);
- if ((null_value=args[0]->null_value))
- return 0;
-
- sec_to_time(arg_val, args[0]->unsigned_flag, &ltime);
-
- return (ltime.neg ? -1 : 1) *
- ((ltime.hour)*10000 + ltime.minute*100 + ltime.second);
+ return 0;
}
-
void Item_func_date_format::fix_length_and_dec()
{
THD* thd= current_thd;
@@ -1934,23 +1774,11 @@ String *Item_func_date_format::val_str(String *str)
String *format;
MYSQL_TIME l_time;
uint size;
+ int is_time_flag = is_time_format ? TIME_TIME_ONLY : 0;
DBUG_ASSERT(fixed == 1);
- if (!is_time_format)
- {
- if (get_arg0_date(&l_time, TIME_FUZZY_DATE))
- return 0;
- }
- else
- {
- String *res;
- if (!(res=args[0]->val_str(str)) ||
- (str_to_time_with_warn(res->ptr(), res->length(), &l_time)))
- goto null_date;
-
- l_time.year=l_time.month=l_time.day=0;
- null_value=0;
- }
+ if (get_arg0_date(&l_time, TIME_FUZZY_DATE | is_time_flag))
+ return 0;
if (!(format = args[1]->val_str(str)) || !format->length())
goto null_date;
@@ -1990,46 +1818,13 @@ void Item_func_from_unixtime::fix_length_and_dec()
{
thd= current_thd;
collation.set(&my_charset_bin);
- decimals= DATETIME_DEC;
+ decimals= 0;
max_length=MAX_DATETIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
maybe_null= 1;
thd->time_zone_used= 1;
}
-String *Item_func_from_unixtime::val_str(String *str)
-{
- MYSQL_TIME time_tmp;
-
- DBUG_ASSERT(fixed == 1);
-
- if (get_date(&time_tmp, 0))
- return 0;
-
- if (str->alloc(MAX_DATE_STRING_REP_LENGTH))
- {
- null_value= 1;
- return 0;
- }
-
- make_datetime((DATE_TIME_FORMAT *) 0, &time_tmp, str);
-
- return str;
-}
-
-
-longlong Item_func_from_unixtime::val_int()
-{
- MYSQL_TIME time_tmp;
-
- DBUG_ASSERT(fixed == 1);
-
- if (get_date(&time_tmp, 0))
- return 0;
-
- return (longlong) TIME_to_ulonglong_datetime(&time_tmp);
-}
-
bool Item_func_from_unixtime::get_date(MYSQL_TIME *ltime,
uint fuzzy_date __attribute__((unused)))
{
@@ -2050,42 +1845,14 @@ bool Item_func_from_unixtime::get_date(MYSQL_TIME *ltime,
void Item_func_convert_tz::fix_length_and_dec()
{
collation.set(&my_charset_bin);
- decimals= 0;
- max_length= MAX_DATETIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
+ max_length= MAX_DATETIME_WIDTH;
+ decimals= args[0]->decimals;
+ if (decimals && decimals != NOT_FIXED_DEC)
+ max_length+= min(decimals, MAX_SEC_PART_DIGITS) + 1;
maybe_null= 1;
}
-String *Item_func_convert_tz::val_str(String *str)
-{
- MYSQL_TIME time_tmp;
-
- if (get_date(&time_tmp, 0))
- return 0;
-
- if (str->alloc(MAX_DATE_STRING_REP_LENGTH))
- {
- null_value= 1;
- return 0;
- }
-
- make_datetime((DATE_TIME_FORMAT *) 0, &time_tmp, str);
-
- return str;
-}
-
-
-longlong Item_func_convert_tz::val_int()
-{
- MYSQL_TIME time_tmp;
-
- if (get_date(&time_tmp, 0))
- return 0;
-
- return (longlong)TIME_to_ulonglong_datetime(&time_tmp);
-}
-
-
bool Item_func_convert_tz::get_date(MYSQL_TIME *ltime,
uint fuzzy_date __attribute__((unused)))
{
@@ -2114,9 +1881,12 @@ bool Item_func_convert_tz::get_date(MYSQL_TIME *ltime,
{
my_bool not_used;
my_time_tmp= from_tz->TIME_to_gmt_sec(ltime, &not_used);
+ ulong sec_part= ltime->second_part;
/* my_time_tmp is guranteed to be in the allowed range */
if (my_time_tmp)
to_tz->gmt_sec_to_TIME(ltime, my_time_tmp);
+ /* we rely on the fact that no timezone conversion can change sec_part */
+ ltime->second_part= sec_part;
}
null_value= 0;
@@ -2127,7 +1897,7 @@ bool Item_func_convert_tz::get_date(MYSQL_TIME *ltime,
void Item_func_convert_tz::cleanup()
{
from_tz_cached= to_tz_cached= 0;
- Item_date_func::cleanup();
+ Item_temporal_func::cleanup();
}
@@ -2137,8 +1907,7 @@ void Item_date_add_interval::fix_length_and_dec()
collation.set(&my_charset_bin);
maybe_null=1;
- max_length=MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
- value.alloc(max_length);
+ max_length=MAX_DATETIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
/*
The field type for the result of an Item_date function is defined as
@@ -2146,7 +1915,11 @@ void Item_date_add_interval::fix_length_and_dec()
- If first arg is a MYSQL_TYPE_DATETIME result is MYSQL_TYPE_DATETIME
- If first arg is a MYSQL_TYPE_DATE and the interval type uses hours,
- minutes or seconds then type is MYSQL_TYPE_DATETIME.
+ minutes or seconds then type is MYSQL_TYPE_DATETIME
+ otherwise it's MYSQL_TYPE_DATE
+ - if first arg is a MYSQL_TYPE_TIME and the interval type isn't using
+ anything larger than days, then the result is MYSQL_TYPE_TIME,
+ otherwise - MYSQL_TYPE_DATETIME.
- Otherwise the result is MYSQL_TYPE_STRING
(This is because you can't know if the string contains a DATE, MYSQL_TIME or
DATETIME argument)
@@ -2163,6 +1936,20 @@ void Item_date_add_interval::fix_length_and_dec()
else
cached_field_type= MYSQL_TYPE_DATETIME;
}
+ else if (arg0_field_type == MYSQL_TYPE_TIME)
+ {
+ if (int_type >= INTERVAL_DAY && int_type != INTERVAL_YEAR_MONTH)
+ cached_field_type= arg0_field_type;
+ else
+ cached_field_type= MYSQL_TYPE_DATETIME;
+ }
+ if (int_type == INTERVAL_MICROSECOND || int_type >= INTERVAL_DAY_MICROSECOND)
+ decimals= 6;
+ else
+ decimals= args[0]->decimals;
+ if (decimals)
+ max_length+= min(decimals, MAX_SEC_PART_DIGITS) + 1;
+ value.alloc(max_length);
}
@@ -2172,7 +1959,7 @@ bool Item_date_add_interval::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
{
INTERVAL interval;
- if (args[0]->get_date(ltime, TIME_NO_ZERO_DATE) ||
+ if (args[0]->get_date(ltime, TIME_NO_ZERO_DATE|TIME_FUZZY_DATE) ||
get_interval_value(args[1], int_type, &value, &interval))
return (null_value=1);
@@ -2185,44 +1972,6 @@ bool Item_date_add_interval::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
}
-String *Item_date_add_interval::val_str(String *str)
-{
- DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
- enum date_time_format_types format;
-
- if (Item_date_add_interval::get_date(&ltime, TIME_NO_ZERO_DATE))
- return 0;
-
- if (ltime.time_type == MYSQL_TIMESTAMP_DATE)
- format= DATE_ONLY;
- else if (ltime.second_part)
- format= DATE_TIME_MICROSECOND;
- else
- format= DATE_TIME;
-
- if (!make_datetime(format, &ltime, str))
- return str;
-
- null_value=1;
- return 0;
-}
-
-
-longlong Item_date_add_interval::val_int()
-{
- DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
- longlong date;
- if (Item_date_add_interval::get_date(&ltime, TIME_NO_ZERO_DATE))
- return (longlong) 0;
- date = (ltime.year*100L + ltime.month)*100L + ltime.day;
- return ltime.time_type == MYSQL_TIMESTAMP_DATE ? date :
- ((date*100L + ltime.hour)*100L+ ltime.minute)*100L + ltime.second;
-}
-
-
-
bool Item_date_add_interval::eq(const Item *item, bool binary_cmp) const
{
Item_date_add_interval *other= (Item_date_add_interval*) item;
@@ -2304,25 +2053,12 @@ longlong Item_extract::val_int()
uint year;
ulong week_format;
long neg;
- if (date_value)
- {
- if (get_arg0_date(&ltime, TIME_FUZZY_DATE))
- return 0;
- neg=1;
- }
- else
- {
- char buf[40];
- String value(buf, sizeof(buf), &my_charset_bin);;
- String *res= args[0]->val_str(&value);
- if (!res || str_to_time_with_warn(res->ptr(), res->length(), &ltime))
- {
- null_value=1;
- return 0;
- }
- neg= ltime.neg ? -1 : 1;
- null_value=0;
- }
+ int is_time_flag = date_value ? 0 : TIME_TIME_ONLY;
+
+ if (get_arg0_date(&ltime, TIME_FUZZY_DATE | is_time_flag))
+ return 0;
+ neg= ltime.neg ? -1 : 1;
+
switch (int_type) {
case INTERVAL_YEAR: return ltime.year;
case INTERVAL_YEAR_MONTH: return ltime.year*100L+ltime.month;
@@ -2405,7 +2141,7 @@ bool Item_char_typecast::eq(const Item *item, bool binary_cmp) const
return 1;
}
-void Item_typecast::print(String *str, enum_query_type query_type)
+void Item_temporal_typecast::print(String *str, enum_query_type query_type)
{
str->append(STRING_WITH_LEN("cast("));
args[0]->print(str, query_type);
@@ -2555,75 +2291,20 @@ void Item_char_typecast::fix_length_and_dec()
}
-String *Item_datetime_typecast::val_str(String *str)
-{
- DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
-
- if (!get_arg0_date(&ltime, TIME_FUZZY_DATE) &&
- !make_datetime(ltime.second_part ? DATE_TIME_MICROSECOND : DATE_TIME,
- &ltime, str))
- return str;
-
- null_value=1;
- return 0;
-}
-
-
-longlong Item_datetime_typecast::val_int()
-{
- DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
- if (get_arg0_date(&ltime,1))
- {
- null_value= 1;
- return 0;
- }
-
- return TIME_to_ulonglong_datetime(&ltime);
-}
-
-
-bool Item_time_typecast::get_time(MYSQL_TIME *ltime)
+bool Item_time_typecast::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
{
bool res= get_arg0_time(ltime);
/*
- For MYSQL_TIMESTAMP_TIME value we can have non-zero day part,
+ MYSQL_TIMESTAMP_TIME value can have non-zero day part,
which we should not lose.
*/
- if (ltime->time_type == MYSQL_TIMESTAMP_DATETIME)
+ if (ltime->time_type != MYSQL_TIMESTAMP_TIME)
ltime->year= ltime->month= ltime->day= 0;
ltime->time_type= MYSQL_TIMESTAMP_TIME;
return res;
}
-longlong Item_time_typecast::val_int()
-{
- MYSQL_TIME ltime;
- if (get_time(&ltime))
- {
- null_value= 1;
- return 0;
- }
- return ltime.hour * 10000L + ltime.minute * 100 + ltime.second;
-}
-
-String *Item_time_typecast::val_str(String *str)
-{
- DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
-
- if (!get_arg0_time(&ltime) &&
- !make_datetime(ltime.second_part ? TIME_MICROSECOND : TIME_ONLY,
- &ltime, str))
- return str;
-
- null_value=1;
- return 0;
-}
-
-
bool Item_date_typecast::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
{
bool res= get_arg0_date(ltime, TIME_FUZZY_DATE);
@@ -2632,39 +2313,27 @@ bool Item_date_typecast::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
return res;
}
-
-bool Item_date_typecast::get_time(MYSQL_TIME *ltime)
-{
- bzero((char *)ltime, sizeof(MYSQL_TIME));
- return args[0]->null_value;
-}
-
-
-String *Item_date_typecast::val_str(String *str)
+bool Item_datetime_typecast::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
{
- DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
+ if (get_arg0_date(ltime, TIME_FUZZY_DATE))
+ return 1;
- if (!get_arg0_date(&ltime, TIME_FUZZY_DATE) &&
- !str->alloc(MAX_DATE_STRING_REP_LENGTH))
+ /*
+ ltime is valid MYSQL_TYPE_TIME ( according to fuzzy_date).
+ But not every valid TIME value is a valid DATETIME value!
+ */
+ if (ltime->time_type == MYSQL_TIMESTAMP_TIME && ltime->hour >= 24)
{
- make_date((DATE_TIME_FORMAT *) 0, &ltime, str);
- return str;
+ Lazy_string_time str(ltime);
+ make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ &str, MYSQL_TIMESTAMP_DATETIME, 0);
+ return (null_value= 1);
}
- null_value=1;
+ ltime->time_type= MYSQL_TIMESTAMP_DATETIME;
return 0;
}
-longlong Item_date_typecast::val_int()
-{
- DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
- if ((null_value= args[0]->get_date(&ltime, TIME_FUZZY_DATE)))
- return 0;
- return (longlong) (ltime.year * 10000L + ltime.month * 100 + ltime.day);
-}
-
/**
MAKEDATE(a,b) is a date function that creates a date value
from a year and day value.
@@ -2675,10 +2344,9 @@ longlong Item_date_typecast::val_int()
for dates between 0000-01-01 and 0099-12-31
*/
-String *Item_func_makedate::val_str(String *str)
+bool Item_func_makedate::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
{
DBUG_ASSERT(fixed == 1);
- MYSQL_TIME l_time;
long daynr= (long) args[1]->val_int();
long year= (long) args[0]->val_int();
long days;
@@ -2694,65 +2362,22 @@ String *Item_func_makedate::val_str(String *str)
/* Day number from year 0 to 9999-12-31 */
if (days >= 0 && days <= MAX_DAY_NUMBER)
{
- null_value=0;
- get_date_from_daynr(days,&l_time.year,&l_time.month,&l_time.day);
- if (str->alloc(MAX_DATE_STRING_REP_LENGTH))
- goto err;
- make_date((DATE_TIME_FORMAT *) 0, &l_time, str);
- return str;
- }
-
-err:
- null_value=1;
- return 0;
-}
-
-
-/*
- MAKEDATE(a,b) is a date function that creates a date value
- from a year and day value.
-
- NOTES:
- As arguments are integers, we can't know if the year is a 2 digit or 4 digit year.
- In this case we treat all years < 100 as 2 digit years. Ie, this is not safe
- for dates between 0000-01-01 and 0099-12-31
-*/
-
-longlong Item_func_makedate::val_int()
-{
- DBUG_ASSERT(fixed == 1);
- MYSQL_TIME l_time;
- long daynr= (long) args[1]->val_int();
- long year= (long) args[0]->val_int();
- long days;
-
- if (args[0]->null_value || args[1]->null_value ||
- year < 0 || daynr <= 0)
- goto err;
-
- if (year < 100)
- year= year_2000_handling(year);
-
- days= calc_daynr(year,1,1) + daynr - 1;
- /* Day number from year 0 to 9999-12-31 */
- if (days >= 0 && days < MAX_DAY_NUMBER)
- {
- null_value=0;
- get_date_from_daynr(days,&l_time.year,&l_time.month,&l_time.day);
- return (longlong) (l_time.year * 10000L + l_time.month * 100 + l_time.day);
+ bzero(ltime, sizeof(*ltime));
+ ltime->time_type= MYSQL_TIMESTAMP_DATE;
+ get_date_from_daynr(days, &ltime->year, &ltime->month, &ltime->day);
+ return (null_value= 0);
}
err:
- null_value= 1;
- return 0;
+ return (null_value= 1);
}
void Item_func_add_time::fix_length_and_dec()
{
enum_field_types arg0_field_type;
- decimals=0;
- max_length=MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
+ max_length= MAX_DATETIME_WIDTH;
+ decimals= NOT_FIXED_DEC;
maybe_null= 1;
/*
@@ -2773,6 +2398,8 @@ void Item_func_add_time::fix_length_and_dec()
cached_field_type= MYSQL_TYPE_DATETIME;
else if (arg0_field_type == MYSQL_TYPE_TIME)
cached_field_type= MYSQL_TYPE_TIME;
+ if (decimals)
+ max_length+= min(decimals, MAX_SEC_PART_DIGITS) + 1;
}
/**
@@ -2785,38 +2412,38 @@ void Item_func_add_time::fix_length_and_dec()
Result: Time value or datetime value
*/
-String *Item_func_add_time::val_str(String *str)
+bool Item_func_add_time::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
{
DBUG_ASSERT(fixed == 1);
- MYSQL_TIME l_time1, l_time2, l_time3;
+ MYSQL_TIME l_time1, l_time2;
bool is_time= 0;
long days, microseconds;
longlong seconds;
- int l_sign= sign;
+ int l_sign= sign, was_cut= 0;
+ uint dec= decimals;
- null_value=0;
if (is_date) // TIMESTAMP function
{
if (get_arg0_date(&l_time1, TIME_FUZZY_DATE) ||
args[1]->get_time(&l_time2) ||
l_time1.time_type == MYSQL_TIMESTAMP_TIME ||
l_time2.time_type != MYSQL_TIMESTAMP_TIME)
- goto null_date;
+ return (null_value= 1);
}
else // ADDTIME function
{
if (args[0]->get_time(&l_time1) ||
args[1]->get_time(&l_time2) ||
l_time2.time_type == MYSQL_TIMESTAMP_DATETIME)
- goto null_date;
+ return (null_value= 1);
is_time= (l_time1.time_type == MYSQL_TIMESTAMP_TIME);
}
if (l_time1.neg != l_time2.neg)
l_sign= -l_sign;
- bzero((char *)&l_time3, sizeof(l_time3));
+ bzero(ltime, sizeof(*ltime));
- l_time3.neg= calc_time_diff(&l_time1, &l_time2, -l_sign,
+ ltime->neg= calc_time_diff(&l_time1, &l_time2, -l_sign,
&seconds, &microseconds);
/*
@@ -2824,35 +2451,40 @@ String *Item_func_add_time::val_str(String *str)
is non-zero we need to swap sign to get proper result.
*/
if (l_time1.neg && (seconds || microseconds))
- l_time3.neg= 1-l_time3.neg; // Swap sign of result
+ ltime->neg= 1-ltime->neg; // Swap sign of result
- if (!is_time && l_time3.neg)
- goto null_date;
+ if (!is_time && ltime->neg)
+ return (null_value= 1);
days= (long)(seconds/86400L);
- calc_time_from_sec(&l_time3, (long)(seconds%86400L), microseconds);
+ calc_time_from_sec(ltime, (long)(seconds%86400L), microseconds);
+
+ ltime->time_type= is_time ? MYSQL_TIMESTAMP_TIME : MYSQL_TIMESTAMP_DATETIME;
+
+ if (cached_field_type == MYSQL_TYPE_STRING &&
+ (l_time1.second_part || l_time2.second_part))
+ dec= MAX_SEC_PART_DIGITS;
if (!is_time)
{
- get_date_from_daynr(days,&l_time3.year,&l_time3.month,&l_time3.day);
- if (l_time3.day &&
- !make_datetime(l_time1.second_part || l_time2.second_part ?
- DATE_TIME_MICROSECOND : DATE_TIME,
- &l_time3, str))
- return str;
- goto null_date;
+ get_date_from_daynr(days,&ltime->year,&ltime->month,&ltime->day);
+ if (!ltime->day)
+ return (null_value= 1);
+ return (null_value= 0);
}
- l_time3.hour+= days*24;
- if (!make_datetime_with_warn(l_time1.second_part || l_time2.second_part ?
- TIME_MICROSECOND : TIME_ONLY,
- &l_time3, str))
- return str;
+ ltime->hour+= days*24;
-null_date:
- null_value=1;
- return 0;
+ MYSQL_TIME copy= *ltime;
+ Lazy_string_time str(&copy);
+
+ check_time_range(ltime, &was_cut);
+ if (was_cut)
+ make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ &str, MYSQL_TIMESTAMP_TIME, NullS);
+
+ return (null_value= 0);
}
@@ -2885,13 +2517,14 @@ void Item_func_add_time::print(String *str, enum_query_type query_type)
Result: Time value
*/
-String *Item_func_timediff::val_str(String *str)
+bool Item_func_timediff::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
{
DBUG_ASSERT(fixed == 1);
longlong seconds;
long microseconds;
- int l_sign= 1;
- MYSQL_TIME l_time1 ,l_time2, l_time3;
+ int l_sign= 1, was_cut= 0;
+ MYSQL_TIME l_time1,l_time2,l_time3;
+ Lazy_string_time str(&l_time3);
null_value= 0;
if (args[0]->get_time(&l_time1) ||
@@ -2917,14 +2550,16 @@ String *Item_func_timediff::val_str(String *str)
calc_time_from_sec(&l_time3, (long) seconds, microseconds);
- if (!make_datetime_with_warn(l_time1.second_part || l_time2.second_part ?
- TIME_MICROSECOND : TIME_ONLY,
- &l_time3, str))
- return str;
+ *ltime= l_time3;
+ check_time_range(ltime, &was_cut);
+
+ if (was_cut)
+ make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ &str, MYSQL_TIMESTAMP_TIME, NullS);
+ return (null_value= 0);
null_date:
- null_value=1;
- return 0;
+ return (null_value= 1);
}
/**
@@ -2933,10 +2568,9 @@ null_date:
Result: Time value
*/
-String *Item_func_maketime::val_str(String *str)
+bool Item_func_maketime::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
{
DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
bool overflow= 0;
longlong hour= args[0]->val_int();
@@ -2947,12 +2581,11 @@ String *Item_func_maketime::val_str(String *str)
args[1]->null_value ||
args[2]->null_value ||
minute < 0 || minute > 59 ||
- second < 0 || second > 59 ||
- str->alloc(MAX_DATE_STRING_REP_LENGTH))))
+ second < 0 || second > 59)))
return 0;
- bzero((char *)&ltime, sizeof(ltime));
- ltime.neg= 0;
+ bzero(ltime, sizeof(*ltime));
+ ltime->time_type= MYSQL_TIMESTAMP_TIME;
/* Check for integer overflows */
if (hour < 0)
@@ -2960,22 +2593,22 @@ String *Item_func_maketime::val_str(String *str)
if (args[0]->unsigned_flag)
overflow= 1;
else
- ltime.neg= 1;
+ ltime->neg= 1;
}
- if (-hour > UINT_MAX || hour > UINT_MAX)
+ if (-hour > TIME_MAX_HOUR || hour > TIME_MAX_HOUR)
overflow= 1;
if (!overflow)
{
- ltime.hour= (uint) ((hour < 0 ? -hour : hour));
- ltime.minute= (uint) minute;
- ltime.second= (uint) second;
+ ltime->hour= (uint) ((hour < 0 ? -hour : hour));
+ ltime->minute= (uint) minute;
+ ltime->second= (uint) second;
}
else
{
- ltime.hour= TIME_MAX_HOUR;
- ltime.minute= TIME_MAX_MINUTE;
- ltime.second= TIME_MAX_SECOND;
+ ltime->hour= TIME_MAX_HOUR;
+ ltime->minute= TIME_MAX_MINUTE;
+ ltime->second= TIME_MAX_SECOND;
char buf[28];
char *ptr= longlong10_to_str(hour, buf, args[0]->unsigned_flag ? 10 : -10);
int len = (int)(ptr - buf) +
@@ -2985,12 +2618,7 @@ String *Item_func_maketime::val_str(String *str)
NullS);
}
- if (make_time_with_warn((DATE_TIME_FORMAT *) 0, &ltime, str))
- {
- null_value= 1;
- return 0;
- }
- return str;
+ return 0;
}
@@ -3272,9 +2900,9 @@ get_date_time_result_type(const char *format, uint length)
have all types of date-time components and can end our search.
*/
return DATE_TIME_MICROSECOND;
+ }
}
}
- }
/* We don't have all three types of date-time components */
if (frac_second_used)
@@ -3292,36 +2920,45 @@ get_date_time_result_type(const char *format, uint length)
void Item_func_str_to_date::fix_length_and_dec()
{
maybe_null= 1;
- decimals=0;
cached_field_type= MYSQL_TYPE_DATETIME;
- max_length= MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
- cached_timestamp_type= MYSQL_TIMESTAMP_NONE;
+ max_length= MAX_DATETIME_WIDTH+MAX_SEC_PART_DIGITS;
+ cached_timestamp_type= MYSQL_TIMESTAMP_DATETIME;
+ decimals= AUTO_SEC_PART_DIGITS;
if ((const_item= args[1]->const_item()))
{
char format_buff[64];
String format_str(format_buff, sizeof(format_buff), &my_charset_bin);
String *format= args[1]->val_str(&format_str);
+ decimals= 0;
if (!args[1]->null_value)
{
- cached_format_type= get_date_time_result_type(format->ptr(),
- format->length());
+ date_time_format_types cached_format_type=
+ get_date_time_result_type(format->ptr(), format->length());
switch (cached_format_type) {
case DATE_ONLY:
cached_timestamp_type= MYSQL_TIMESTAMP_DATE;
cached_field_type= MYSQL_TYPE_DATE;
max_length= MAX_DATE_WIDTH * MY_CHARSET_BIN_MB_MAXLEN;
break;
- case TIME_ONLY:
case TIME_MICROSECOND:
+ decimals= 6;
+ /* fall through */
+ case TIME_ONLY:
cached_timestamp_type= MYSQL_TIMESTAMP_TIME;
cached_field_type= MYSQL_TYPE_TIME;
max_length= MAX_TIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN;
break;
- default:
+ case DATE_TIME_MICROSECOND:
+ decimals= 6;
+ /* fall through */
+ case DATE_TIME:
cached_timestamp_type= MYSQL_TIMESTAMP_DATETIME;
cached_field_type= MYSQL_TYPE_DATETIME;
+ max_length= MAX_DATETIME_WIDTH;
break;
}
+ if (decimals)
+ max_length+= decimals + 1;
}
}
}
@@ -3339,14 +2976,11 @@ bool Item_func_str_to_date::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
if (args[0]->null_value || args[1]->null_value)
goto null_date;
- null_value= 0;
- bzero((char*) ltime, sizeof(*ltime));
date_time_format.format.str= (char*) format->ptr();
date_time_format.format.length= format->length();
if (extract_date_time(&date_time_format, val->ptr(), val->length(),
- ltime, cached_timestamp_type, 0, "datetime") ||
- ((fuzzy_date & TIME_NO_ZERO_DATE) &&
- (ltime->year == 0 || ltime->month == 0 || ltime->day == 0)))
+ ltime, cached_timestamp_type, 0, "datetime",
+ fuzzy_date))
goto null_date;
if (cached_timestamp_type == MYSQL_TIMESTAMP_TIME && ltime->day)
{
@@ -3358,6 +2992,7 @@ bool Item_func_str_to_date::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
ltime->hour+= ltime->day*24;
ltime->day= 0;
}
+ null_value= 0;
return 0;
null_date:
@@ -3365,22 +3000,6 @@ null_date:
}
-String *Item_func_str_to_date::val_str(String *str)
-{
- DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
-
- if (Item_func_str_to_date::get_date(&ltime, TIME_FUZZY_DATE))
- return 0;
-
- if (!make_datetime((const_item ? cached_format_type :
- (ltime.second_part ? DATE_TIME_MICROSECOND : DATE_TIME)),
- &ltime, str))
- return str;
- return 0;
-}
-
-
bool Item_func_last_day::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
{
if (get_arg0_date(ltime, fuzzy_date & ~TIME_FUZZY_DATE) ||
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
index 47bb9509582..e2e65142902 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -323,147 +323,100 @@ public:
};
-class Item_func_time_to_sec :public Item_int_func
+class Item_func_time_to_sec :public Item_real_func
{
public:
- Item_func_time_to_sec(Item *item) :Item_int_func(item) {}
- longlong val_int();
+ Item_func_time_to_sec(Item *item) :Item_real_func(item) {}
const char *func_name() const { return "time_to_sec"; }
+ double val_real();
void fix_length_and_dec()
{
maybe_null= TRUE;
- decimals=0;
- max_length=10*MY_CHARSET_BIN_MB_MAXLEN;
+ decimals=args[0]->decimals;
+ max_length=17;
}
bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
-/*
- This can't be a Item_str_func, because the val_real() functions are special
-*/
-
-class Item_date :public Item_func
+class Item_temporal_func: public Item_func
{
public:
- Item_date() :Item_func() {}
- Item_date(Item *a) :Item_func(a) {}
+ Item_temporal_func() :Item_func() {}
+ Item_temporal_func(Item *a) :Item_func(a) {}
+ Item_temporal_func(Item *a, Item *b) :Item_func(a,b) {}
+ Item_temporal_func(Item *a, Item *b, Item *c) :Item_func(a,b,c) {}
enum Item_result result_type () const { return STRING_RESULT; }
- enum_field_types field_type() const { return MYSQL_TYPE_DATE; }
+ enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; }
String *val_str(String *str);
longlong val_int();
- double val_real() { return val_real_from_decimal(); }
- const char *func_name() const { return "date"; }
- void fix_length_and_dec()
- {
- collation.set(&my_charset_bin);
- decimals=0;
- max_length=MAX_DATE_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
- }
- Field *tmp_table_field(TABLE *table)
- {
- return tmp_table_field_from_field_type(table, 0);
- }
- bool result_as_longlong() { return TRUE; }
+ double val_real();
+ bool get_date(MYSQL_TIME *res, uint fuzzy_date) { DBUG_ASSERT(0); return 1; }
my_decimal *val_decimal(my_decimal *decimal_value)
- {
- DBUG_ASSERT(fixed == 1);
- return val_decimal_from_date(decimal_value);
- }
+ { return val_decimal_from_date(decimal_value); }
+ Field *tmp_table_field(TABLE *table)
+ { return tmp_table_field_from_field_type(table, 0); }
int save_in_field(Field *field, bool no_conversions)
- {
- return save_date_in_field(field);
- }
+ { return save_date_in_field(field); }
};
-
-class Item_date_func :public Item_str_func
+class Item_datefunc :public Item_temporal_func
{
public:
- Item_date_func() :Item_str_func() {}
- Item_date_func(Item *a) :Item_str_func(a) {}
- Item_date_func(Item *a,Item *b) :Item_str_func(a,b) {}
- Item_date_func(Item *a,Item *b, Item *c) :Item_str_func(a,b,c) {}
- enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; }
- Field *tmp_table_field(TABLE *table)
- {
- return tmp_table_field_from_field_type(table, 0);
- }
- bool result_as_longlong() { return TRUE; }
- double val_real() { return (double) val_int(); }
- my_decimal *val_decimal(my_decimal *decimal_value)
- {
- DBUG_ASSERT(fixed == 1);
- return val_decimal_from_date(decimal_value);
- }
- int save_in_field(Field *field, bool no_conversions)
- {
- return save_date_in_field(field);
+ Item_datefunc() :Item_temporal_func() {}
+ Item_datefunc(Item *a) :Item_temporal_func(a) {}
+ enum_field_types field_type() const { return MYSQL_TYPE_DATE; }
+ const char *func_name() const { return "date"; }
+ bool get_date(MYSQL_TIME *res, uint fuzzy_date)
+ { return get_arg0_date(res, fuzzy_date); }
+ void fix_length_and_dec()
+ {
+ collation.set(&my_charset_bin);
+ decimals=0;
+ max_length=MAX_DATE_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
}
};
-class Item_str_timefunc :public Item_str_func
+class Item_timefunc :public Item_temporal_func
{
public:
- Item_str_timefunc() :Item_str_func() {}
- Item_str_timefunc(Item *a) :Item_str_func(a) {}
- Item_str_timefunc(Item *a,Item *b) :Item_str_func(a,b) {}
- Item_str_timefunc(Item *a, Item *b, Item *c) :Item_str_func(a, b ,c) {}
+ Item_timefunc() :Item_temporal_func() {}
+ Item_timefunc(Item *a) :Item_temporal_func(a) {}
+ Item_timefunc(Item *a,Item *b) :Item_temporal_func(a,b) {}
+ Item_timefunc(Item *a, Item *b, Item *c) :Item_temporal_func(a, b ,c) {}
enum_field_types field_type() const { return MYSQL_TYPE_TIME; }
void fix_length_and_dec()
{
- decimals= DATETIME_DEC;
- max_length=MAX_TIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
- }
- Field *tmp_table_field(TABLE *table)
- {
- return tmp_table_field_from_field_type(table, 0);
+ max_length= MAX_TIME_WIDTH +
+ (decimals ? min(decimals, MAX_SEC_PART_DIGITS)+1 : 0);
}
- double val_real() { return val_real_from_decimal(); }
- my_decimal *val_decimal(my_decimal *decimal_value)
- {
- DBUG_ASSERT(fixed == 1);
- return val_decimal_from_time(decimal_value);
- }
- int save_in_field(Field *field, bool no_conversions)
- {
- return save_time_in_field(field);
- }
- longlong val_int() { return val_int_from_decimal(); }
- bool result_as_longlong() { return TRUE; }
};
/* Abstract CURTIME function. Children should define what time zone is used */
-class Item_func_curtime :public Item_str_timefunc
+class Item_func_curtime :public Item_timefunc
{
- longlong value;
- char buff[9*2+32];
- uint buff_length;
+ MYSQL_TIME ltime;
public:
- Item_func_curtime() :Item_str_timefunc() {}
- Item_func_curtime(Item *a) :Item_str_timefunc(a) {}
- double val_real() { DBUG_ASSERT(fixed == 1); return (double) value; }
- longlong val_int() { DBUG_ASSERT(fixed == 1); return value; }
- String *val_str(String *str);
+ Item_func_curtime(uint dec) :Item_timefunc() { decimals= dec; }
+ bool fix_fields(THD *, Item **);
void fix_length_and_dec();
+ bool get_date(MYSQL_TIME *res, uint fuzzy_date);
/*
Abstract method that defines which time zone is used for conversion.
Converts time current time in my_time_t representation to broken-down
MYSQL_TIME representation using UTC-SYSTEM or per-thread time zone.
*/
virtual void store_now_in_TIME(MYSQL_TIME *now_time)=0;
- bool result_as_longlong() { return TRUE; }
};
class Item_func_curtime_local :public Item_func_curtime
{
public:
- Item_func_curtime_local() :Item_func_curtime() {}
- Item_func_curtime_local(Item *a) :Item_func_curtime(a) {}
+ Item_func_curtime_local(uint dec) :Item_func_curtime(dec) {}
const char *func_name() const { return "curtime"; }
virtual void store_now_in_TIME(MYSQL_TIME *now_time);
};
@@ -472,8 +425,7 @@ public:
class Item_func_curtime_utc :public Item_func_curtime
{
public:
- Item_func_curtime_utc() :Item_func_curtime() {}
- Item_func_curtime_utc(Item *a) :Item_func_curtime(a) {}
+ Item_func_curtime_utc(uint dec) :Item_func_curtime(dec) {}
const char *func_name() const { return "utc_time"; }
virtual void store_now_in_TIME(MYSQL_TIME *now_time);
};
@@ -481,14 +433,11 @@ public:
/* Abstract CURDATE function. See also Item_func_curtime. */
-class Item_func_curdate :public Item_date
+class Item_func_curdate :public Item_datefunc
{
- longlong value;
MYSQL_TIME ltime;
public:
- Item_func_curdate() :Item_date() {}
- longlong val_int() { DBUG_ASSERT(fixed == 1); return (value) ; }
- String *val_str(String *str);
+ Item_func_curdate() :Item_datefunc() {}
void fix_length_and_dec();
bool get_date(MYSQL_TIME *res, uint fuzzy_date);
virtual void store_now_in_TIME(MYSQL_TIME *now_time)=0;
@@ -515,20 +464,12 @@ public:
/* Abstract CURRENT_TIMESTAMP function. See also Item_func_curtime */
-class Item_func_now :public Item_date_func
+class Item_func_now :public Item_temporal_func
{
-protected:
- longlong value;
- char buff[20*2+32]; // +32 to make my_snprintf_{8bit|ucs2} happy
- uint buff_length;
MYSQL_TIME ltime;
public:
- Item_func_now() :Item_date_func() {}
- Item_func_now(Item *a) :Item_date_func(a) {}
- enum Item_result result_type () const { return STRING_RESULT; }
- longlong val_int() { DBUG_ASSERT(fixed == 1); return value; }
- int save_in_field(Field *to, bool no_conversions);
- String *val_str(String *str);
+ Item_func_now(uint dec) :Item_temporal_func() { decimals= dec; }
+ bool fix_fields(THD *, Item **);
void fix_length_and_dec();
bool get_date(MYSQL_TIME *res, uint fuzzy_date);
virtual void store_now_in_TIME(MYSQL_TIME *now_time)=0;
@@ -538,8 +479,7 @@ public:
class Item_func_now_local :public Item_func_now
{
public:
- Item_func_now_local() :Item_func_now() {}
- Item_func_now_local(Item *a) :Item_func_now(a) {}
+ Item_func_now_local(uint dec) :Item_func_now(dec) {}
const char *func_name() const { return "now"; }
virtual void store_now_in_TIME(MYSQL_TIME *now_time);
virtual enum Functype functype() const { return NOW_FUNC; }
@@ -549,8 +489,7 @@ public:
class Item_func_now_utc :public Item_func_now
{
public:
- Item_func_now_utc() :Item_func_now() {}
- Item_func_now_utc(Item *a) :Item_func_now(a) {}
+ Item_func_now_utc(uint dec) :Item_func_now(dec) {}
const char *func_name() const { return "utc_timestamp"; }
virtual void store_now_in_TIME(MYSQL_TIME *now_time);
};
@@ -563,16 +502,10 @@ public:
class Item_func_sysdate_local :public Item_func_now
{
public:
- Item_func_sysdate_local() :Item_func_now() {}
- Item_func_sysdate_local(Item *a) :Item_func_now(a) {}
+ Item_func_sysdate_local(uint dec) :Item_func_now(dec) {}
bool const_item() const { return 0; }
const char *func_name() const { return "sysdate"; }
void store_now_in_TIME(MYSQL_TIME *now_time);
- double val_real();
- longlong val_int();
- int save_in_field(Field *to, bool no_conversions);
- String *val_str(String *str);
- void fix_length_and_dec();
bool get_date(MYSQL_TIME *res, uint fuzzy_date);
void update_used_tables()
{
@@ -582,10 +515,10 @@ public:
};
-class Item_func_from_days :public Item_date
+class Item_func_from_days :public Item_datefunc
{
public:
- Item_func_from_days(Item *a) :Item_date(a) {}
+ Item_func_from_days(Item *a) :Item_datefunc(a) {}
const char *func_name() const { return "from_days"; }
bool get_date(MYSQL_TIME *res, uint fuzzy_date);
bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
@@ -609,13 +542,11 @@ public:
};
-class Item_func_from_unixtime :public Item_date_func
+class Item_func_from_unixtime :public Item_temporal_func
{
THD *thd;
public:
- Item_func_from_unixtime(Item *a) :Item_date_func(a) {}
- longlong val_int();
- String *val_str(String *str);
+ Item_func_from_unixtime(Item *a) :Item_temporal_func(a) {}
const char *func_name() const { return "from_unixtime"; }
void fix_length_and_dec();
bool get_date(MYSQL_TIME *res, uint fuzzy_date);
@@ -636,7 +567,7 @@ class Time_zone;
tables can be used during this function calculation for loading time zone
descriptions.
*/
-class Item_func_convert_tz :public Item_date_func
+class Item_func_convert_tz :public Item_temporal_func
{
/*
If time zone parameters are constants we are caching objects that
@@ -648,9 +579,7 @@ class Item_func_convert_tz :public Item_date_func
Time_zone *from_tz, *to_tz;
public:
Item_func_convert_tz(Item *a, Item *b, Item *c):
- Item_date_func(a, b, c), from_tz_cached(0), to_tz_cached(0) {}
- longlong val_int();
- String *val_str(String *str);
+ Item_temporal_func(a, b, c), from_tz_cached(0), to_tz_cached(0) {}
const char *func_name() const { return "convert_tz"; }
void fix_length_and_dec();
bool get_date(MYSQL_TIME *res, uint fuzzy_date);
@@ -658,29 +587,25 @@ class Item_func_convert_tz :public Item_date_func
};
-class Item_func_sec_to_time :public Item_str_timefunc
+class Item_func_sec_to_time :public Item_timefunc
{
public:
- Item_func_sec_to_time(Item *item) :Item_str_timefunc(item) {}
- double val_real()
- {
- DBUG_ASSERT(fixed == 1);
- return (double) Item_func_sec_to_time::val_int();
- }
- longlong val_int();
- String *val_str(String *);
+ Item_func_sec_to_time(Item *item) :Item_timefunc(item) {}
+ bool get_date(MYSQL_TIME *res, uint fuzzy_date);
void fix_length_and_dec()
{
- Item_str_timefunc::fix_length_and_dec();
collation.set(&my_charset_bin);
maybe_null=1;
+ decimals= args[0]->decimals;
+ if (decimals != NOT_FIXED_DEC && decimals > MAX_SEC_PART_DIGITS)
+ decimals= MAX_SEC_PART_DIGITS;
+ Item_timefunc::fix_length_and_dec();
}
const char *func_name() const { return "sec_to_time"; }
- bool result_as_longlong() { return TRUE; }
};
-class Item_date_add_interval :public Item_date_func
+class Item_date_add_interval :public Item_temporal_func
{
String value;
enum_field_types cached_field_type;
@@ -689,12 +614,10 @@ public:
const interval_type int_type; // keep it public
const bool date_sub_interval; // keep it public
Item_date_add_interval(Item *a,Item *b,interval_type type_arg,bool neg_arg)
- :Item_date_func(a,b),int_type(type_arg), date_sub_interval(neg_arg) {}
- String *val_str(String *);
+ :Item_temporal_func(a,b),int_type(type_arg), date_sub_interval(neg_arg) {}
const char *func_name() const { return "date_add_interval"; }
void fix_length_and_dec();
enum_field_types field_type() const { return cached_field_type; }
- longlong val_int();
bool get_date(MYSQL_TIME *res, uint fuzzy_date);
bool eq(const Item *item, bool binary_cmp) const;
virtual void print(String *str, enum_query_type query_type);
@@ -718,43 +641,7 @@ class Item_extract :public Item_int_func
};
-class Item_typecast :public Item_str_func
-{
-public:
- Item_typecast(Item *a) :Item_str_func(a) {}
- String *val_str(String *a)
- {
- DBUG_ASSERT(fixed == 1);
- String *tmp=args[0]->val_str(a);
- null_value=args[0]->null_value;
- if (tmp)
- tmp->set_charset(collation.collation);
- return tmp;
- }
- void fix_length_and_dec()
- {
- collation.set(&my_charset_bin);
- max_length=args[0]->max_length;
- }
- virtual const char* cast_type() const= 0;
- virtual void print(String *str, enum_query_type query_type);
-};
-
-
-class Item_typecast_maybe_null :public Item_typecast
-{
-public:
- Item_typecast_maybe_null(Item *a) :Item_typecast(a) {}
- void fix_length_and_dec()
- {
- collation.set(&my_charset_bin);
- max_length=args[0]->max_length;
- maybe_null= 1;
- }
-};
-
-
-class Item_char_typecast :public Item_typecast
+class Item_char_typecast :public Item_str_func
{
int cast_length;
CHARSET_INFO *cast_cs, *from_cs;
@@ -762,119 +649,85 @@ class Item_char_typecast :public Item_typecast
String tmp_value;
public:
Item_char_typecast(Item *a, int length_arg, CHARSET_INFO *cs_arg)
- :Item_typecast(a), cast_length(length_arg), cast_cs(cs_arg) {}
+ :Item_str_func(a), cast_length(length_arg), cast_cs(cs_arg) {}
enum Functype functype() const { return CHAR_TYPECAST_FUNC; }
bool eq(const Item *item, bool binary_cmp) const;
const char *func_name() const { return "cast_as_char"; }
- const char* cast_type() const { return "char"; };
String *val_str(String *a);
void fix_length_and_dec();
- virtual void print(String *str, enum_query_type query_type);
+ void print(String *str, enum_query_type query_type);
};
-class Item_date_typecast :public Item_typecast_maybe_null
+class Item_temporal_typecast: public Item_temporal_func
{
public:
- Item_date_typecast(Item *a) :Item_typecast_maybe_null(a) {}
+ Item_temporal_typecast(Item *a) :Item_temporal_func(a) {}
+ virtual const char *cast_type() const = 0;
+ void print(String *str, enum_query_type query_type);
+};
+
+class Item_date_typecast :public Item_temporal_typecast
+{
+public:
+ Item_date_typecast(Item *a) :Item_temporal_typecast(a) {}
const char *func_name() const { return "cast_as_date"; }
- String *val_str(String *str);
bool get_date(MYSQL_TIME *ltime, uint fuzzy_date);
- bool get_time(MYSQL_TIME *ltime);
const char *cast_type() const { return "date"; }
enum_field_types field_type() const { return MYSQL_TYPE_DATE; }
- Field *tmp_table_field(TABLE *table)
- {
- return tmp_table_field_from_field_type(table, 0);
- }
void fix_length_and_dec()
{
collation.set(&my_charset_bin);
- max_length= 10;
+ decimals= 0;
+ max_length= MAX_DATE_WIDTH;
maybe_null= 1;
}
- bool result_as_longlong() { return TRUE; }
- longlong val_int();
- double val_real() { return (double) val_int(); }
- my_decimal *val_decimal(my_decimal *decimal_value)
- {
- DBUG_ASSERT(fixed == 1);
- return val_decimal_from_date(decimal_value);
- }
- int save_in_field(Field *field, bool no_conversions)
- {
- return save_date_in_field(field);
- }
};
-class Item_time_typecast :public Item_typecast_maybe_null
+class Item_time_typecast :public Item_temporal_typecast
{
public:
- Item_time_typecast(Item *a) :Item_typecast_maybe_null(a) {}
+ Item_time_typecast(Item *a, uint dec_arg)
+ :Item_temporal_typecast(a) { decimals= dec_arg; }
const char *func_name() const { return "cast_as_time"; }
- String *val_str(String *str);
- bool get_time(MYSQL_TIME *ltime);
+ bool get_date(MYSQL_TIME *ltime, uint fuzzy_date);
const char *cast_type() const { return "time"; }
enum_field_types field_type() const { return MYSQL_TYPE_TIME; }
- Field *tmp_table_field(TABLE *table)
- {
- return tmp_table_field_from_field_type(table, 0);
- }
- bool result_as_longlong() { return TRUE; }
- longlong val_int();
- double val_real() { return val_real_from_decimal(); }
- my_decimal *val_decimal(my_decimal *decimal_value)
- {
- DBUG_ASSERT(fixed == 1);
- return val_decimal_from_time(decimal_value);
- }
- int save_in_field(Field *field, bool no_conversions)
+ void fix_length_and_dec()
{
- return save_time_in_field(field);
+ collation.set(&my_charset_bin);
+ maybe_null= 1;
+ max_length= MAX_TIME_WIDTH;
+ if (decimals && decimals != NOT_FIXED_DEC)
+ max_length+= min(decimals, MAX_SEC_PART_DIGITS) + 1;
}
};
-class Item_datetime_typecast :public Item_typecast_maybe_null
+class Item_datetime_typecast :public Item_temporal_typecast
{
public:
- Item_datetime_typecast(Item *a) :Item_typecast_maybe_null(a) {}
+ Item_datetime_typecast(Item *a, uint dec_arg)
+ :Item_temporal_typecast(a) { decimals= dec_arg; }
const char *func_name() const { return "cast_as_datetime"; }
- String *val_str(String *str);
const char *cast_type() const { return "datetime"; }
enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; }
- Field *tmp_table_field(TABLE *table)
- {
- return tmp_table_field_from_field_type(table, 0);
- }
+ bool get_date(MYSQL_TIME *ltime, uint fuzzy_date);
void fix_length_and_dec()
{
collation.set(&my_charset_bin);
maybe_null= 1;
- max_length= MAX_DATETIME_FULL_WIDTH * MY_CHARSET_BIN_MB_MAXLEN;
- decimals= DATETIME_DEC;
- }
- bool result_as_longlong() { return TRUE; }
- longlong val_int();
- double val_real() { return val_real_from_decimal(); }
- double val() { return (double) val_int(); }
- my_decimal *val_decimal(my_decimal *decimal_value)
- {
- DBUG_ASSERT(fixed == 1);
- return val_decimal_from_date(decimal_value);
- }
- int save_in_field(Field *field, bool no_conversions)
- {
- return save_date_in_field(field);
+ max_length= MAX_DATETIME_WIDTH;
+ if (decimals && decimals != NOT_FIXED_DEC)
+ max_length+= min(decimals, MAX_SEC_PART_DIGITS) + 1;
}
};
-class Item_func_makedate :public Item_date_func
+class Item_func_makedate :public Item_temporal_func
{
public:
- Item_func_makedate(Item *a,Item *b) :Item_date_func(a,b) {}
- String *val_str(String *str);
+ Item_func_makedate(Item *a,Item *b) :Item_temporal_func(a,b) {}
const char *func_name() const { return "makedate"; }
enum_field_types field_type() const { return MYSQL_TYPE_DATE; }
void fix_length_and_dec()
@@ -884,11 +737,11 @@ public:
/* It returns NULL when the second argument is less or equal to 0 */
maybe_null= 1;
}
- longlong val_int();
+ bool get_date(MYSQL_TIME *ltime, uint fuzzy_date);
};
-class Item_func_add_time :public Item_str_func
+class Item_func_add_time :public Item_temporal_func
{
const bool is_date;
int sign;
@@ -896,61 +749,39 @@ class Item_func_add_time :public Item_str_func
public:
Item_func_add_time(Item *a, Item *b, bool type_arg, bool neg_arg)
- :Item_str_func(a, b), is_date(type_arg) { sign= neg_arg ? -1 : 1; }
- String *val_str(String *str);
+ :Item_temporal_func(a, b), is_date(type_arg) { sign= neg_arg ? -1 : 1; }
enum_field_types field_type() const { return cached_field_type; }
void fix_length_and_dec();
-
- Field *tmp_table_field(TABLE *table)
- {
- return tmp_table_field_from_field_type(table, 0);
- }
+ bool get_date(MYSQL_TIME *ltime, uint fuzzy_date);
virtual void print(String *str, enum_query_type query_type);
const char *func_name() const { return "add_time"; }
- double val_real() { return val_real_from_decimal(); }
- my_decimal *val_decimal(my_decimal *decimal_value)
- {
- DBUG_ASSERT(fixed == 1);
- if (cached_field_type == MYSQL_TYPE_TIME)
- return val_decimal_from_time(decimal_value);
- if (cached_field_type == MYSQL_TYPE_DATETIME)
- return val_decimal_from_date(decimal_value);
- return Item_str_func::val_decimal(decimal_value);
- }
- int save_in_field(Field *field, bool no_conversions)
- {
- if (cached_field_type == MYSQL_TYPE_TIME)
- return save_time_in_field(field);
- if (cached_field_type == MYSQL_TYPE_DATETIME)
- return save_date_in_field(field);
- return Item_str_func::save_in_field(field, no_conversions);
- }
};
-class Item_func_timediff :public Item_str_timefunc
+class Item_func_timediff :public Item_timefunc
{
public:
Item_func_timediff(Item *a, Item *b)
- :Item_str_timefunc(a, b) {}
- String *val_str(String *str);
+ :Item_timefunc(a, b) {}
const char *func_name() const { return "timediff"; }
void fix_length_and_dec()
{
- Item_str_timefunc::fix_length_and_dec();
+ decimals= NOT_FIXED_DEC;
+ Item_timefunc::fix_length_and_dec();
maybe_null= 1;
}
+ bool get_date(MYSQL_TIME *ltime, uint fuzzy_date);
};
-class Item_func_maketime :public Item_str_timefunc
+class Item_func_maketime :public Item_timefunc
{
public:
Item_func_maketime(Item *a, Item *b, Item *c)
- :Item_str_timefunc(a, b, c)
+ :Item_timefunc(a, b, c)
{
maybe_null= TRUE;
}
- String *val_str(String *str);
const char *func_name() const { return "maketime"; }
+ bool get_date(MYSQL_TIME *ltime, uint fuzzy_date);
};
class Item_func_microsecond :public Item_int_func
@@ -1009,32 +840,26 @@ public:
};
-class Item_func_str_to_date :public Item_str_func
+class Item_func_str_to_date :public Item_temporal_func
{
enum_field_types cached_field_type;
- date_time_format_types cached_format_type;
timestamp_type cached_timestamp_type;
bool const_item;
public:
Item_func_str_to_date(Item *a, Item *b)
- :Item_str_func(a, b), const_item(false)
+ :Item_temporal_func(a, b), const_item(false)
{}
- String *val_str(String *str);
bool get_date(MYSQL_TIME *ltime, uint fuzzy_date);
const char *func_name() const { return "str_to_date"; }
enum_field_types field_type() const { return cached_field_type; }
void fix_length_and_dec();
- Field *tmp_table_field(TABLE *table)
- {
- return tmp_table_field_from_field_type(table, 1);
- }
};
-class Item_func_last_day :public Item_date
+class Item_func_last_day :public Item_datefunc
{
public:
- Item_func_last_day(Item *a) :Item_date(a) {}
+ Item_func_last_day(Item *a) :Item_datefunc(a) {}
const char *func_name() const { return "last_day"; }
bool get_date(MYSQL_TIME *res, uint fuzzy_date);
};
diff --git a/sql/log.cc b/sql/log.cc
index 38f4677f06f..6699e42c7f6 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -436,8 +436,7 @@ bool Log_to_csv_event_handler::
DBUG_ASSERT(table->field[0]->type() == MYSQL_TYPE_TIMESTAMP);
- ((Field_timestamp*) table->field[0])->store_timestamp((my_time_t)
- event_time);
+ ((Field_timestamp*) table->field[0])->store_TIME((my_time_t) event_time, 0);
/* do a write */
if (table->field[1]->store(user_host, user_host_len, client_cs) ||
@@ -579,8 +578,7 @@ bool Log_to_csv_event_handler::
/* store the time and user values */
DBUG_ASSERT(table->field[0]->type() == MYSQL_TYPE_TIMESTAMP);
- ((Field_timestamp*) table->field[0])->store_timestamp((my_time_t)
- current_time);
+ ((Field_timestamp*) table->field[0])->store_TIME((my_time_t) current_time, 0);
if (table->field[1]->store(user_host, user_host_len, client_cs))
goto err;
@@ -992,15 +990,16 @@ bool LOGGER::slow_log_print(THD *thd, const char *query, uint query_length,
sctx->ip ? sctx->ip : "", "]", NullS) -
user_host_buff);
- current_time= my_time_possible_from_micro(current_utime);
if (thd->start_utime)
{
query_utime= (current_utime - thd->start_utime);
lock_utime= (thd->utime_after_lock - thd->start_utime);
+ current_time= thd->start_time + query_utime/1000000;
}
else
{
query_utime= lock_utime= 0;
+ current_time= my_time(0);
}
if (!query)
@@ -1011,7 +1010,8 @@ bool LOGGER::slow_log_print(THD *thd, const char *query, uint query_length,
}
for (current_handler= slow_log_handler_list; *current_handler ;)
- error= (*current_handler++)->log_slow(thd, current_time, thd->start_time,
+ error= (*current_handler++)->log_slow(thd, current_time,
+ thd->start_time,
user_host_buff, user_host_len,
query_utime, lock_utime, is_command,
query, query_length) || error;
diff --git a/sql/log_event.cc b/sql/log_event.cc
index d0635ddac1a..4abf56f70f3 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -668,7 +668,8 @@ Log_event::Log_event(THD* thd_arg, uint16 flags_arg, bool using_trans)
:log_pos(0), temp_buf(0), exec_time(0), flags(flags_arg), thd(thd_arg)
{
server_id= thd->server_id;
- when= thd->start_time;
+ when= thd->start_time;
+ when_sec_part=thd->start_time_sec_part;
cache_stmt= using_trans;
}
@@ -689,7 +690,8 @@ Log_event::Log_event()
We can't call my_time() here as this would cause a call before
my_init() is called
*/
- when= 0;
+ when= 0;
+ when_sec_part=0;
log_pos= 0;
}
#endif /* !MYSQL_CLIENT */
@@ -707,6 +709,7 @@ Log_event::Log_event(const char* buf,
thd = 0;
#endif
when = uint4korr(buf);
+ when_sec_part= 0;
server_id = uint4korr(buf + SERVER_ID_OFFSET);
data_written= uint4korr(buf + EVENT_LEN_OFFSET);
if (description_event->binlog_version==1)
@@ -795,21 +798,13 @@ int Log_event::do_update_pos(Relay_log_info *rli)
DBUG_EXECUTE_IF("let_first_flush_log_change_timestamp",
if (debug_not_change_ts_if_art_event == 1
&& is_artificial_event())
- {
- debug_not_change_ts_if_art_event= 0;
- });
-#ifndef DBUG_OFF
- rli->stmt_done(log_pos,
- is_artificial_event() &&
- debug_not_change_ts_if_art_event > 0 ? 0 : when);
-#else
- rli->stmt_done(log_pos, is_artificial_event()? 0 : when);
-#endif
+ debug_not_change_ts_if_art_event= 0; );
+ rli->stmt_done(log_pos, is_artificial_event()
+ IF_DBUG(&& debug_not_change_ts_if_art_event > 0) ?
+ 0 : when);
DBUG_EXECUTE_IF("let_first_flush_log_change_timestamp",
if (debug_not_change_ts_if_art_event == 0)
- {
- debug_not_change_ts_if_art_event= 2;
- });
+ debug_not_change_ts_if_art_event= 2; );
}
return 0; // Cannot fail currently
}
@@ -945,7 +940,7 @@ bool Log_event::write_header(IO_CACHE* file, ulong event_data_length)
log_pos= my_b_safe_tell(file)+data_written;
}
- now= (ulong) get_time(); // Query start time
+ now= get_time(); // Query start time
/*
Header will be of size LOG_EVENT_HEADER_LEN for all events, except for
@@ -2070,13 +2065,10 @@ void Log_event::print_timestamp(IO_CACHE* file, time_t* ts)
struct tm *res;
DBUG_ENTER("Log_event::print_timestamp");
if (!ts)
+ {
ts = &when;
-#ifdef MYSQL_SERVER // This is always false
- struct tm tm_tmp;
- localtime_r(ts,(res= &tm_tmp));
-#else
+ }
res=localtime(ts);
-#endif
my_b_printf(file,"%02d%02d%02d %2d:%02d:%02d",
res->tm_year % 100,
@@ -2360,6 +2352,15 @@ bool Query_log_event::write(IO_CACHE* file)
memcpy(start, host.str, host.length);
start+= host.length;
}
+
+ }
+
+ if (thd && thd->query_start_sec_part_used)
+ {
+ *start++= Q_HRNOW;
+ get_time();
+ int3store(start, when_sec_part);
+ start+= 3;
}
/*
NOTE: When adding new status vars, please don't forget to update
@@ -2452,7 +2453,7 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
error_code= errcode;
- time(&end_time);
+ end_time= my_time(0);
exec_time = (ulong) (end_time - thd_arg->start_time);
/**
@todo this means that if we have no catalog, then it is replicated
@@ -2587,6 +2588,7 @@ code_name(int code)
case Q_CHARSET_DATABASE_CODE: return "Q_CHARSET_DATABASE_CODE";
case Q_TABLE_MAP_FOR_UPDATE_CODE: return "Q_TABLE_MAP_FOR_UPDATE_CODE";
case Q_MASTER_DATA_WRITTEN_CODE: return "Q_MASTER_DATA_WRITTEN_CODE";
+ case Q_HRNOW: return "Q_HRNOW";
}
sprintf(buf, "CODE#%d", code);
return buf;
@@ -2803,6 +2805,14 @@ Query_log_event::Query_log_event(const char* buf, uint event_len,
CHECK_SPACE(pos, end, host.length);
host.str= (char *)pos;
pos+= host.length;
+ break;
+ }
+ case Q_HRNOW:
+ {
+ CHECK_SPACE(pos, end, 3);
+ when_sec_part= uint3korr(pos);
+ pos+= 3;
+ break;
}
default:
/* That's why you must write status vars in growing order of code */
@@ -2882,7 +2892,7 @@ void Query_log_event::print_query_header(IO_CACHE* file,
PRINT_EVENT_INFO* print_event_info)
{
// TODO: print the catalog ??
- char buff[40],*end; // Enough for SET TIMESTAMP
+ char buff[64], *end; // Enough for SET TIMESTAMP
bool different_db= 1;
uint32 tmp;
@@ -2904,6 +2914,11 @@ void Query_log_event::print_query_header(IO_CACHE* file,
}
end=int10_to_str((long) when, strmov(buff,"SET TIMESTAMP="),10);
+ if (when_sec_part)
+ {
+ *end++= '.';
+ end=int10_to_str(when_sec_part, end, 10);
+ }
end= strmov(end, print_event_info->delimiter);
*end++='\n';
my_b_write(file, (uchar*) buff, (uint) (end-buff));
@@ -3165,7 +3180,7 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli,
*/
if (is_trans_keyword() || rpl_filter->db_ok(thd->db))
{
- thd->set_time((time_t)when);
+ thd->set_time(when, when_sec_part);
thd->set_query((char*)query_arg, q_len_arg);
VOID(pthread_mutex_lock(&LOCK_thread_count));
thd->query_id = next_query_id();
@@ -3598,7 +3613,7 @@ bool Start_log_event_v3::write(IO_CACHE* file)
int2store(buff + ST_BINLOG_VER_OFFSET,binlog_version);
memcpy(buff + ST_SERVER_VER_OFFSET,server_version,ST_SERVER_VER_LEN);
if (!dont_set_created)
- created= when= get_time();
+ created= get_time();
int4store(buff + ST_CREATED_OFFSET,created);
return (write_header(file, sizeof(buff)) ||
my_b_safe_write(file, (uchar*) buff, sizeof(buff)));
@@ -3997,7 +4012,7 @@ bool Format_description_log_event::write(IO_CACHE* file)
int2store(buff + ST_BINLOG_VER_OFFSET,binlog_version);
memcpy((char*) buff + ST_SERVER_VER_OFFSET,server_version,ST_SERVER_VER_LEN);
if (!dont_set_created)
- created= when= get_time();
+ created= get_time();
int4store(buff + ST_CREATED_OFFSET,created);
buff[ST_COMMON_HEADER_LEN_OFFSET]= LOG_EVENT_HEADER_LEN;
memcpy((char*) buff+ST_COMMON_HEADER_LEN_OFFSET+1, (uchar*) post_header_len,
@@ -4703,7 +4718,7 @@ int Load_log_event::do_apply_event(NET* net, Relay_log_info const *rli,
*/
if (rpl_filter->db_ok(thd->db))
{
- thd->set_time((time_t)when);
+ thd->set_time(when, when_sec_part);
VOID(pthread_mutex_lock(&LOCK_thread_count));
thd->query_id = next_query_id();
VOID(pthread_mutex_unlock(&LOCK_thread_count));
@@ -7531,7 +7546,7 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
TIMESTAMP column to a table with one.
So we call set_time(), like in SBR. Presently it changes nothing.
*/
- thd->set_time((time_t)when);
+ thd->set_time(when, when_sec_part);
/*
Now we are in a statement and will stay in a statement until we
diff --git a/sql/log_event.h b/sql/log_event.h
index 75f2015a684..9331d7be4b1 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -265,6 +265,7 @@ struct sql_ex_info
1 + 2 /* type, charset_database_number */ + \
1 + 8 /* type, table_map_for_update */ + \
1 + 4 /* type, master_data_written */ + \
+ 1 + 3 /* type, sec_part of NOW() */ + \
1 + 16 + 1 + 60/* type, user_len, user, host_len, host */)
#define MAX_LOG_EVENT_HEADER ( /* in order of Query_log_event::write */ \
LOG_EVENT_HEADER_LEN + /* write_header */ \
@@ -336,6 +337,8 @@ struct sql_ex_info
#define Q_INVOKER 11
+#define Q_HRNOW 128
+
/* Intvar event post-header */
/* Intvar event data */
@@ -889,7 +892,8 @@ public:
execution time, which guarantees good replication (otherwise, we
could have a query and its event with different timestamps).
*/
- time_t when;
+ my_time_t when;
+ ulong when_sec_part;
/* The number of seconds the query took to run on the master. */
ulong exec_time;
/* Number of bytes written by write() function */
@@ -1000,16 +1004,27 @@ public:
{ return 0; }
virtual bool write_data_body(IO_CACHE* file __attribute__((unused)))
{ return 0; }
- inline time_t get_time()
+ inline my_time_t get_time()
{
THD *tmp_thd;
if (when)
return when;
if (thd)
- return thd->start_time;
+ {
+ when= thd->start_time;
+ when_sec_part= thd->start_time_sec_part;
+ return when;
+ }
if ((tmp_thd= current_thd))
- return tmp_thd->start_time;
- return my_time(0);
+ {
+ when= tmp_thd->start_time;
+ when_sec_part= tmp_thd->start_time_sec_part;
+ return when;
+ }
+ my_hrtime_t hrtime= my_hrtime();
+ when= hrtime_to_time(hrtime);
+ when_sec_part= hrtime_sec_part(hrtime);
+ return when;
}
#endif
virtual Log_event_type get_type_code() = 0;
diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc
index e901f44286c..fce8e5ab09e 100644
--- a/sql/log_event_old.cc
+++ b/sql/log_event_old.cc
@@ -159,7 +159,7 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info
TIMESTAMP column to a table with one.
So we call set_time(), like in SBR. Presently it changes nothing.
*/
- ev_thd->set_time((time_t)ev->when);
+ ev_thd->set_time(ev->when, ev->when_sec_part);
/*
There are a few flags that are replicated with each row event.
Make sure to set/clear them before executing the main body of
@@ -1655,7 +1655,7 @@ int Old_rows_log_event::do_apply_event(Relay_log_info const *rli)
TIMESTAMP column to a table with one.
So we call set_time(), like in SBR. Presently it changes nothing.
*/
- thd->set_time((time_t)when);
+ thd->set_time(when, when_sec_part);
/*
There are a few flags that are replicated with each row event.
Make sure to set/clear them before executing the main body of
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 709a49b2036..2ac2318f242 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -699,6 +699,62 @@ typedef my_bool (*qc_engine_callback)(THD *thd, char *table_key,
uint key_length,
ulonglong *engine_data);
#include "sql_string.h"
+
+/*
+ to unify the code that differs only in the argument passed to the
+ error message (string vs. number)
+
+ We pass this container around, and only convert the number
+ to a string when necessary.
+*/
+class Lazy_string
+{
+public:
+ Lazy_string() {}
+ virtual ~Lazy_string() {}
+ virtual void copy(String *str) const = 0;
+};
+
+class Lazy_string_str : public Lazy_string
+{
+ const char *str;
+ size_t len;
+public:
+ Lazy_string_str(const char *str_arg, size_t len_arg)
+ : Lazy_string(), str(str_arg), len(len_arg) {}
+ void copy(String *dst) const { dst->copy(str, len, system_charset_info); }
+};
+
+class Lazy_string_num : public Lazy_string
+{
+ longlong num;
+public:
+ Lazy_string_num(longlong num_arg) : Lazy_string(), num(num_arg) {}
+ void copy(String *dst) const { dst->set(num, &my_charset_bin); }
+};
+
+class Lazy_string_dbl: public Lazy_string
+{
+ double num;
+public:
+ Lazy_string_dbl(double num_arg) : Lazy_string(), num(num_arg) {}
+ void copy(String *dst) const
+ { dst->set_real(num, NOT_FIXED_DEC, &my_charset_bin); }
+};
+
+class Lazy_string_time : public Lazy_string
+{
+ const MYSQL_TIME *ltime;
+public:
+ Lazy_string_time(const MYSQL_TIME *ltime_arg)
+ : Lazy_string(), ltime(ltime_arg) {}
+ void copy(String *dst) const {
+ dst->alloc(MAX_DATETIME_FULL_WIDTH);
+ dst->length((uint) my_TIME_to_str(ltime, (char*) dst->ptr(), AUTO_SEC_PART_DIGITS));
+ dst->set_charset(&my_charset_bin);
+ }
+};
+
#include "sql_list.h"
#include "sql_map.h"
#include "my_decimal.h"
@@ -2157,17 +2213,25 @@ ulong convert_month_to_period(ulong month);
void get_date_from_daynr(long daynr,uint *year, uint *month,
uint *day);
my_time_t TIME_to_timestamp(THD *thd, const MYSQL_TIME *t, my_bool *not_exist);
-bool str_to_time_with_warn(const char *str,uint length,MYSQL_TIME *l_time);
timestamp_type str_to_datetime_with_warn(const char *str, uint length,
MYSQL_TIME *l_time, uint flags);
void localtime_to_TIME(MYSQL_TIME *to, struct tm *from);
void calc_time_from_sec(MYSQL_TIME *to, long seconds, long microseconds);
void make_truncated_value_warning(THD *thd, MYSQL_ERROR::enum_warning_level level,
- const char *str_val,
- uint str_length, timestamp_type time_type,
+ const Lazy_string *str_val,
+ timestamp_type time_type,
const char *field_name);
+static inline void make_truncated_value_warning(THD *thd,
+ MYSQL_ERROR::enum_warning_level level, const char *str_val,
+ uint str_length, timestamp_type time_type,
+ const char *field_name)
+{
+ const Lazy_string_str str(str_val, str_length);
+ make_truncated_value_warning(thd, level, &str, time_type, field_name);
+}
+
bool date_add_interval(MYSQL_TIME *ltime, interval_type int_type, INTERVAL interval);
bool calc_time_diff(MYSQL_TIME *l_time1, MYSQL_TIME *l_time2, int l_sign,
longlong *seconds_out, long *microseconds_out);
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index d17ccc47abb..98cf221b679 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -392,12 +392,13 @@ bool opt_large_files= sizeof(my_off_t) > 4;
*/
static my_bool opt_help= 0, opt_verbose= 0;
-arg_cmp_func Arg_comparator::comparator_matrix[5][2] =
+arg_cmp_func Arg_comparator::comparator_matrix[6][2] =
{{&Arg_comparator::compare_string, &Arg_comparator::compare_e_string},
{&Arg_comparator::compare_real, &Arg_comparator::compare_e_real},
{&Arg_comparator::compare_int_signed, &Arg_comparator::compare_e_int},
{&Arg_comparator::compare_row, &Arg_comparator::compare_e_row},
- {&Arg_comparator::compare_decimal, &Arg_comparator::compare_e_decimal}};
+ {&Arg_comparator::compare_decimal, &Arg_comparator::compare_e_decimal},
+ {&Arg_comparator::compare_datetime, &Arg_comparator::compare_e_datetime}};
const char *log_output_names[] = { "NONE", "FILE", "TABLE", NullS};
static const unsigned int log_output_names_len[]= { 4, 4, 5, 0 };
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index d4a2bc3b138..349983682ee 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -692,10 +692,7 @@ static ha_rows check_quick_keys(PARAM *param,uint index,SEL_ARG *key_tree,
QUICK_RANGE_SELECT *get_quick_select(PARAM *param,uint index,
SEL_ARG *key_tree,
MEM_ROOT *alloc = NULL);
-static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree,
- bool index_read_must_be_used,
- bool update_tbl_stats,
- double read_time);
+static TRP_RANGE *get_key_scans_params(PARAM *, SEL_TREE *, bool, bool, double);
static
TRP_ROR_INTERSECT *get_best_ror_intersect(const PARAM *param, SEL_TREE *tree,
double read_time,
@@ -713,11 +710,9 @@ static double get_index_only_read_time(const PARAM* param, ha_rows records,
int keynr);
#ifndef DBUG_OFF
-static void print_sel_tree(PARAM *param, SEL_TREE *tree, key_map *tree_map,
- const char *msg);
-static void print_ror_scans_arr(TABLE *table, const char *msg,
- struct st_ror_scan_info **start,
- struct st_ror_scan_info **end);
+static void print_sel_tree(PARAM *, SEL_TREE *, key_map *, const char *);
+static void print_ror_scans_arr(TABLE *, const char *, struct st_ror_scan_info **,
+ struct st_ror_scan_info **);
static void print_quick(QUICK_SELECT_I *quick, const key_map *needed_reg);
#endif
@@ -5656,7 +5651,6 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field,
SEL_ARG *tree= 0;
MEM_ROOT *alloc= param->mem_root;
uchar *str;
- ulong orig_sql_mode;
int err;
DBUG_ENTER("get_mm_leaf");
@@ -5824,16 +5818,8 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field,
We can't always use indexes when comparing a string index to a number
cmp_type() is checked to allow compare of dates to numbers
*/
- if (field->result_type() == STRING_RESULT &&
- value->result_type() != STRING_RESULT &&
- field->cmp_type() != value->result_type())
+ if (field->cmp_type() == STRING_RESULT && value->cmp_type() != STRING_RESULT)
goto end;
- /* For comparison purposes allow invalid dates like 2000-01-32 */
- orig_sql_mode= field->table->in_use->variables.sql_mode;
- if (value->real_item()->type() == Item::STRING_ITEM &&
- (field->type() == MYSQL_TYPE_DATE ||
- field->type() == MYSQL_TYPE_DATETIME))
- field->table->in_use->variables.sql_mode|= MODE_INVALID_DATES;
err= value->save_in_field_no_warnings(field, 1);
if (err > 0)
{
@@ -5845,7 +5831,6 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field,
{
tree= new (alloc) SEL_ARG(field, 0, 0);
tree->type= SEL_ARG::IMPOSSIBLE;
- field->table->in_use->variables.sql_mode= orig_sql_mode;
goto end;
}
else
@@ -5879,10 +5864,7 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field,
*/
}
else
- {
- field->table->in_use->variables.sql_mode= orig_sql_mode;
goto end;
- }
}
}
@@ -5905,12 +5887,10 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field,
}
else if (err < 0)
{
- field->table->in_use->variables.sql_mode= orig_sql_mode;
/* This happens when we try to insert a NULL field in a not null column */
tree= &null_element; // cmp with NULL is never TRUE
goto end;
}
- field->table->in_use->variables.sql_mode= orig_sql_mode;
/*
Any sargable predicate except "<=>" involving NULL as a constant is always
diff --git a/sql/protocol.cc b/sql/protocol.cc
index db5e15b2acd..273e3b1fd28 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -994,13 +994,7 @@ bool Protocol_text::store(Field *field)
}
-/**
- @todo
- Second_part format ("%06") needs to change when
- we support 0-6 decimals for time.
-*/
-
-bool Protocol_text::store(MYSQL_TIME *tm)
+bool Protocol_text::store(MYSQL_TIME *tm, int decimals)
{
#ifndef DBUG_OFF
DBUG_ASSERT(field_types == 0 ||
@@ -1008,14 +1002,8 @@ bool Protocol_text::store(MYSQL_TIME *tm)
field_types[field_pos] == MYSQL_TYPE_TIMESTAMP);
field_pos++;
#endif
- char buff[40];
- uint length;
- length= sprintf(buff, "%04d-%02d-%02d %02d:%02d:%02d",
- (int) tm->year, (int) tm->month,
- (int) tm->day, (int) tm->hour,
- (int) tm->minute, (int) tm->second);
- if (tm->second_part)
- length+= sprintf(buff+length, ".%06d", (int) tm->second_part);
+ char buff[MAX_DATE_STRING_REP_LENGTH];
+ uint length= my_datetime_to_str(tm, buff, decimals);
return net_store_data((uchar*) buff, length);
}
@@ -1033,27 +1021,15 @@ bool Protocol_text::store_date(MYSQL_TIME *tm)
}
-/**
- @todo
- Second_part format ("%06") needs to change when
- we support 0-6 decimals for time.
-*/
-
-bool Protocol_text::store_time(MYSQL_TIME *tm)
+bool Protocol_text::store_time(MYSQL_TIME *tm, int decimals)
{
#ifndef DBUG_OFF
DBUG_ASSERT(field_types == 0 ||
field_types[field_pos] == MYSQL_TYPE_TIME);
field_pos++;
#endif
- char buff[40];
- uint length;
- uint day= (tm->year || tm->month) ? 0 : tm->day;
- length= sprintf(buff, "%s%02ld:%02d:%02d", tm->neg ? "-" : "",
- (long) day*24L+(long) tm->hour, (int) tm->minute,
- (int) tm->second);
- if (tm->second_part)
- length+= sprintf(buff+length, ".%06d", (int) tm->second_part);
+ char buff[MAX_DATE_STRING_REP_LENGTH];
+ uint length= my_time_to_str(tm, buff, decimals);
return net_store_data((uchar*) buff, length);
}
@@ -1210,7 +1186,7 @@ bool Protocol_binary::store(Field *field)
}
-bool Protocol_binary::store(MYSQL_TIME *tm)
+bool Protocol_binary::store(MYSQL_TIME *tm, int decimals)
{
char buff[12],*pos;
uint length;
@@ -1223,6 +1199,10 @@ bool Protocol_binary::store(MYSQL_TIME *tm)
pos[4]= (uchar) tm->hour;
pos[5]= (uchar) tm->minute;
pos[6]= (uchar) tm->second;
+ DBUG_ASSERT(decimals == AUTO_SEC_PART_DIGITS ||
+ (decimals >= 0 && decimals <= MAX_SEC_PART_DIGITS));
+ if (decimals != AUTO_SEC_PART_DIGITS)
+ tm->second_part= sec_part_truncate(tm->second_part, decimals);
int4store(pos+7, tm->second_part);
if (tm->second_part)
length=11;
@@ -1240,11 +1220,11 @@ bool Protocol_binary::store_date(MYSQL_TIME *tm)
{
tm->hour= tm->minute= tm->second=0;
tm->second_part= 0;
- return Protocol_binary::store(tm);
+ return Protocol_binary::store(tm, 0);
}
-bool Protocol_binary::store_time(MYSQL_TIME *tm)
+bool Protocol_binary::store_time(MYSQL_TIME *tm, int decimals)
{
char buff[13], *pos;
uint length;
@@ -1253,7 +1233,6 @@ bool Protocol_binary::store_time(MYSQL_TIME *tm)
pos[0]= tm->neg ? 1 : 0;
if (tm->hour >= 24)
{
- /* Fix if we come from Item::send */
uint days= tm->hour/24;
tm->hour-= days*24;
tm->day+= days;
@@ -1262,6 +1241,10 @@ bool Protocol_binary::store_time(MYSQL_TIME *tm)
pos[5]= (uchar) tm->hour;
pos[6]= (uchar) tm->minute;
pos[7]= (uchar) tm->second;
+ DBUG_ASSERT(decimals == AUTO_SEC_PART_DIGITS ||
+ (decimals >= 0 && decimals <= MAX_SEC_PART_DIGITS));
+ if (decimals != AUTO_SEC_PART_DIGITS)
+ tm->second_part= sec_part_truncate(tm->second_part, decimals);
int4store(pos+8, tm->second_part);
if (tm->second_part)
length=12;
diff --git a/sql/protocol.h b/sql/protocol.h
index 251ba6fbc33..93c730c3a7e 100644
--- a/sql/protocol.h
+++ b/sql/protocol.h
@@ -89,9 +89,9 @@ public:
CHARSET_INFO *fromcs, CHARSET_INFO *tocs)=0;
virtual bool store(float from, uint32 decimals, String *buffer)=0;
virtual bool store(double from, uint32 decimals, String *buffer)=0;
- virtual bool store(MYSQL_TIME *time)=0;
+ virtual bool store(MYSQL_TIME *time, int decimals)=0;
virtual bool store_date(MYSQL_TIME *time)=0;
- virtual bool store_time(MYSQL_TIME *time)=0;
+ virtual bool store_time(MYSQL_TIME *time, int decimals)=0;
virtual bool store(Field *field)=0;
#ifdef EMBEDDED_LIBRARY
int begin_dataset();
@@ -128,9 +128,9 @@ public:
virtual bool store(const char *from, size_t length, CHARSET_INFO *cs);
virtual bool store(const char *from, size_t length,
CHARSET_INFO *fromcs, CHARSET_INFO *tocs);
- virtual bool store(MYSQL_TIME *time);
+ virtual bool store(MYSQL_TIME *time, int decimals);
virtual bool store_date(MYSQL_TIME *time);
- virtual bool store_time(MYSQL_TIME *time);
+ virtual bool store_time(MYSQL_TIME *time, int decimals);
virtual bool store(float nr, uint32 decimals, String *buffer);
virtual bool store(double from, uint32 decimals, String *buffer);
virtual bool store(Field *field);
@@ -163,9 +163,9 @@ public:
virtual bool store(const char *from, size_t length, CHARSET_INFO *cs);
virtual bool store(const char *from, size_t length,
CHARSET_INFO *fromcs, CHARSET_INFO *tocs);
- virtual bool store(MYSQL_TIME *time);
+ virtual bool store(MYSQL_TIME *time, int decimals);
virtual bool store_date(MYSQL_TIME *time);
- virtual bool store_time(MYSQL_TIME *time);
+ virtual bool store_time(MYSQL_TIME *time, int decimals);
virtual bool store(float nr, uint32 decimals, String *buffer);
virtual bool store(double from, uint32 decimals, String *buffer);
virtual bool store(Field *field);
diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc
index 99a42bbe818..1031451898d 100644
--- a/sql/rpl_rli.cc
+++ b/sql/rpl_rli.cc
@@ -1174,11 +1174,7 @@ void Relay_log_info::stmt_done(my_off_t event_master_log_pos,
is that value may take some time to display in
Seconds_Behind_Master - not critical).
*/
-#ifndef DBUG_OFF
- if (!(event_creation_time == 0 && debug_not_change_ts_if_art_event > 0))
-#else
- if (event_creation_time != 0)
-#endif
+ if (!(event_creation_time == 0 IF_DBUG(&& debug_not_change_ts_if_art_event > 0)))
last_master_timestamp= event_creation_time;
}
}
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 9fbce870dc4..4ce85452f3e 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -2715,38 +2715,38 @@ int set_var_collation_client::update(THD *thd)
bool sys_var_timestamp::check(THD *thd, set_var *var)
{
- time_t val;
- var->save_result.ulonglong_value= var->value->val_int();
- val= (time_t) var->save_result.ulonglong_value;
- if (val < (time_t) MY_TIME_T_MIN || val > (time_t) MY_TIME_T_MAX)
+ double val= var->value->val_real();
+ if (val < 0 || val > MY_TIME_T_MAX)
{
my_message(ER_UNKNOWN_ERROR,
"This version of MySQL doesn't support dates later than 2038",
MYF(0));
return TRUE;
}
+ var->save_result.ulonglong_value= hrtime_from_time(var->value->val_real());
return FALSE;
}
bool sys_var_timestamp::update(THD *thd, set_var *var)
{
- thd->set_time((time_t) var->save_result.ulonglong_value);
+ my_hrtime_t hrtime = { var->save_result.ulonglong_value };
+ thd->set_time(hrtime);
return FALSE;
}
void sys_var_timestamp::set_default(THD *thd, enum_var_type type)
{
- thd->user_time=0;
+ thd->user_time.val= 0;
}
uchar *sys_var_timestamp::value_ptr(THD *thd, enum_var_type type,
LEX_STRING *base)
{
- thd->sys_var_tmp.long_value= (long) thd->start_time;
- return (uchar*) &thd->sys_var_tmp.long_value;
+ thd->sys_var_tmp.double_value= thd->start_time + thd->start_time_sec_part/1e6;
+ return (uchar*) &thd->sys_var_tmp.double_value;
}
@@ -3045,10 +3045,10 @@ void sys_var_microseconds::set_default(THD *thd, enum_var_type type)
uchar *sys_var_microseconds::value_ptr(THD *thd, enum_var_type type,
LEX_STRING *base)
{
- thd->tmp_double_value= (double) ((type == OPT_GLOBAL) ?
+ thd->sys_var_tmp.double_value= (double) ((type == OPT_GLOBAL) ?
global_system_variables.*offset :
thd->variables.*offset) / 1000000.0;
- return (uchar*) &thd->tmp_double_value;
+ return (uchar*) &thd->sys_var_tmp.double_value;
}
diff --git a/sql/set_var.h b/sql/set_var.h
index 68cd94a5670..4f982890a63 100644
--- a/sql/set_var.h
+++ b/sql/set_var.h
@@ -667,8 +667,12 @@ public:
void set_default(THD *thd, enum_var_type type);
bool check_type(enum_var_type type) { return type == OPT_GLOBAL; }
bool check_default(enum_var_type type) { return 0; }
- SHOW_TYPE show_type() { return SHOW_LONG; }
+ SHOW_TYPE show_type() { return SHOW_DOUBLE; }
uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
+ virtual bool check_update_type(Item_result type)
+ {
+ return type != INT_RESULT && type != REAL_RESULT && type != DECIMAL_RESULT;
+ }
};
diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt
index bbae17c4327..c2fa3d12829 100644
--- a/sql/share/errmsg.txt
+++ b/sql/share/errmsg.txt
@@ -5513,11 +5513,11 @@ ER_SP_NO_RECURSION
eng "Recursive stored functions and triggers are not allowed."
ger "Rekursive gespeicherte Routinen und Triggers sind nicht erlaubt"
ER_TOO_BIG_SCALE 42000 S1009
- eng "Too big scale %d specified for column '%-.192s'. Maximum is %lu."
- ger "Zu großer Skalierungsfaktor %d für Feld '%-.192s' angegeben. Maximum ist %lu"
+ eng "Too big scale %u specified for column '%-.192s'. Maximum is %lu."
+ ger "Zu großer Skalierungsfaktor %u für Feld '%-.192s' angegeben. Maximum ist %lu"
ER_TOO_BIG_PRECISION 42000 S1009
- eng "Too big precision %d specified for column '%-.192s'. Maximum is %lu."
- ger "Zu große Genauigkeit %d für Feld '%-.192s' angegeben. Maximum ist %lu"
+ eng "Too big precision %u specified for column '%-.192s'. Maximum is %lu."
+ ger "Zu große Genauigkeit %u für Feld '%-.192s' angegeben. Maximum ist %lu"
ER_M_BIGGER_THAN_D 42000 S1009
eng "For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column '%-.192s')."
ger "Für FLOAT(M,D), DOUBLE(M,D) oder DECIMAL(M,D) muss M >= D sein (Feld '%-.192s')"
diff --git a/sql/slave.cc b/sql/slave.cc
index 644aade517c..ebf0ba22f85 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -2152,7 +2152,11 @@ int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli)
thd->set_time(); // time the query
thd->lex->current_select= 0;
if (!ev->when)
- ev->when= my_time(0);
+ {
+ my_hrtime_t hrtime= my_hrtime();
+ ev->when= hrtime_to_time(hrtime);
+ ev->when_sec_part= hrtime_sec_part(hrtime);
+ }
ev->thd = thd; // because up to this point, ev->thd == 0
int reason= ev->shall_skip(rli);
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 2473abea3c7..d68ec1a0968 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -49,19 +49,7 @@ static void reset_start_time_for_sp(THD *thd)
constant during the execution of those.
*/
if (!thd->in_sub_stmt)
- {
- /*
- First investigate if there is a cached time stamp
- */
- if (thd->user_time)
- {
- thd->start_time= thd->user_time;
- }
- else
- {
- my_micro_time_and_time(&thd->start_time);
- }
- }
+ thd->set_time();
}
Item_result
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index a61ce7bfd14..7c7751f922f 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -602,7 +602,7 @@ THD::THD()
/* statement id */ 0),
Open_tables_state(refresh_version), rli_fake(0),
lock_id(&main_lock_id),
- user_time(0), in_sub_stmt(0),
+ in_sub_stmt(0),
sql_log_bin_toplevel(false),
binlog_table_maps(0), binlog_flags(0UL),
table_map_for_update(0),
@@ -641,7 +641,7 @@ THD::THD()
main_security_ctx.init();
security_ctx= &main_security_ctx;
locked=some_tables_deleted=no_errors=password= 0;
- query_start_used= 0;
+ query_start_used= query_start_sec_part_used= 0;
count_cuted_fields= CHECK_FIELD_IGNORE;
killed= NOT_KILLED;
col_access=0;
@@ -658,7 +658,7 @@ THD::THD()
#endif
// Must be reset to handle error with THD's created for init of mysqld
lex->current_select= 0;
- start_time=(time_t) 0;
+ user_time.val= start_time= start_time_sec_part= 0;
start_utime= prior_thr_create_utime= 0L;
utime_after_lock= 0L;
current_linfo = 0;
@@ -2338,7 +2338,7 @@ bool select_max_min_finder_subselect::send_data(List<Item> &items)
case DECIMAL_RESULT:
op= &select_max_min_finder_subselect::cmp_decimal;
break;
- case ROW_RESULT:
+ default:
// This case should never be choosen
DBUG_ASSERT(0);
op= 0;
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 774ae4abac4..1298dd734c9 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1393,7 +1393,6 @@ public:
*/
const char *where;
- double tmp_double_value; /* Used in set_var.cc */
ulong client_capabilities; /* What the client supports */
ulong max_client_packet_length;
@@ -1417,7 +1416,9 @@ public:
uint32 file_id; // for LOAD DATA INFILE
/* remote (peer) port */
uint16 peer_port;
- time_t start_time, user_time;
+ my_time_t start_time; // start_time and its sec_part
+ ulong start_time_sec_part; // are almost always used separately
+ my_hrtime_t user_time;
// track down slow pthread_create
ulonglong prior_thr_create_utime, thr_create_utime;
ulonglong start_utime, utime_after_lock;
@@ -1836,6 +1837,7 @@ public:
*/
bool is_fatal_sub_stmt_error;
bool query_start_used, rand_used, time_zone_used;
+ bool query_start_sec_part_used;
/* for IS NULL => = last_insert_id() fix in remove_eq_conds() */
bool substitute_null_with_insert_id;
bool in_lock_tables;
@@ -1881,6 +1883,7 @@ public:
long long_value;
ulong ulong_value;
ulonglong ulonglong_value;
+ double double_value;
} sys_var_tmp;
struct {
@@ -2016,27 +2019,44 @@ public:
proc_info = old_msg;
pthread_mutex_unlock(&mysys_var->mutex);
}
- inline time_t query_start() { query_start_used=1; return start_time; }
+ inline my_time_t query_start() { query_start_used=1; return start_time; }
+ inline ulong query_start_sec_part()
+ { query_start_sec_part_used=1; return start_time_sec_part; }
inline void set_time()
{
- if (user_time)
+ if (user_time.val)
{
- start_time= user_time;
+ start_time= hrtime_to_time(user_time);
+ start_time_sec_part= hrtime_sec_part(user_time);
start_utime= utime_after_lock= my_micro_time();
}
else
- start_utime= utime_after_lock= my_micro_time_and_time(&start_time);
+ {
+ my_hrtime_t hrtime;
+ my_timediff_t timediff;
+ my_micro_and_hrtime(&timediff, &hrtime);
+ start_time= hrtime_to_time(hrtime);
+ start_time_sec_part= hrtime_sec_part(hrtime);
+ utime_after_lock= start_utime= timediff.val;
+ }
}
- inline void set_current_time() { start_time= my_time(MY_WME); }
- inline void set_time(time_t t)
+ inline void set_current_time()
{
- start_time= user_time= t;
+ my_hrtime_t hrtime= my_hrtime();
+ start_time= hrtime_to_time(hrtime);
+ start_time_sec_part= hrtime_sec_part(hrtime);
+ }
+ inline void set_time(my_hrtime_t t)
+ {
+ user_time= t;
+ start_time= hrtime_to_time(user_time);
+ start_time_sec_part= hrtime_sec_part(user_time);
start_utime= utime_after_lock= my_micro_time();
}
- /*TODO: this will be obsolete when we have support for 64 bit my_time_t */
- inline bool is_valid_time()
- {
- return (start_time < (time_t) MY_TIME_T_MAX);
+ inline void set_time(my_time_t t, ulong sec_part)
+ {
+ my_hrtime_t hrtime= { hrtime_from_time(t) + sec_part };
+ set_time(hrtime);
}
void set_time_after_lock() { utime_after_lock= my_micro_time(); }
ulonglong current_utime() { return my_micro_time(); }
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index f0735a9e093..12c5478b0ae 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -1694,10 +1694,11 @@ class delayed_row :public ilink {
public:
char *record;
enum_duplicates dup;
- time_t start_time;
+ my_time_t start_time;
+ ulong start_time_sec_part;
ulong sql_mode;
bool auto_increment_field_not_null;
- bool query_start_used, ignore, log_query;
+ bool query_start_used, ignore, log_query, query_start_sec_part_used;
bool stmt_depends_on_first_successful_insert_id_in_prev_stmt;
ulonglong first_successful_insert_id_in_prev_stmt;
ulonglong forced_insert_id;
@@ -2185,8 +2186,10 @@ int write_delayed(THD *thd, TABLE *table, enum_duplicates duplic,
if (!(row->record= (char*) my_malloc(table->s->reclength, MYF(MY_WME))))
goto err;
memcpy(row->record, table->record[0], table->s->reclength);
- row->start_time= thd->start_time;
- row->query_start_used= thd->query_start_used;
+ row->start_time= thd->start_time;
+ row->query_start_used= thd->query_start_used;
+ row->start_time_sec_part= thd->start_time_sec_part;
+ row->query_start_sec_part_used= thd->query_start_sec_part_used;
/*
those are for the binlog: LAST_INSERT_ID() has been evaluated at this
time, so record does not need it, but statement-based binlogging of the
@@ -2640,6 +2643,8 @@ bool Delayed_insert::handle_inserts(void)
thd.start_time=row->start_time;
thd.query_start_used=row->query_start_used;
+ thd.start_time_sec_part=row->start_time_sec_part;
+ thd.query_start_sec_part_used=row->query_start_sec_part_used;
/*
To get the exact auto_inc interval to store in the binlog we must not
use values from the previous interval (of the previous rows).
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 7cf64134d70..c45c4b7dd83 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1001,18 +1001,6 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
thd->enable_slow_log= TRUE;
thd->lex->sql_command= SQLCOM_END; /* to avoid confusing VIEW detectors */
thd->set_time();
- if (!thd->is_valid_time())
- {
- /*
- If the time has got past 2038 we need to shut this server down
- We do this by making sure every command is a shutdown and we
- have enough privileges to shut the server down
-
- TODO: remove this when we have full 64 bit my_time_t support
- */
- thd->security_ctx->master_access|= SHUTDOWN_ACL;
- command= COM_SHUTDOWN;
- }
VOID(pthread_mutex_lock(&LOCK_thread_count));
thd->query_id= global_query_id;
@@ -1518,10 +1506,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
packet[0].
*/
enum mysql_enum_shutdown_level level;
- if (!thd->is_valid_time())
- level= SHUTDOWN_DEFAULT;
- else
- level= (enum mysql_enum_shutdown_level) (uchar) packet[0];
+ level= (enum mysql_enum_shutdown_level) (uchar) packet[0];
if (level == SHUTDOWN_DEFAULT)
level= SHUTDOWN_WAIT_ALL_BUFFERS; // soon default will be configurable
else if (level != SHUTDOWN_WAIT_ALL_BUFFERS)
@@ -5767,6 +5752,7 @@ void mysql_reset_thd_for_next_command(THD *thd)
thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt= 0;
thd->query_start_used= 0;
+ thd->query_start_sec_part_used= 0;
thd->is_fatal_error= thd->time_zone_used= 0;
/*
Clear the status flag that are expected to be cleared at the
@@ -6219,17 +6205,6 @@ bool add_field_to_list(THD *thd, LEX_STRING *field_name, enum_field_types type,
DBUG_RETURN(1);
}
- if (type == MYSQL_TYPE_TIMESTAMP && length)
- {
- /* Display widths are no longer supported for TIMSTAMP as of MySQL 4.1.
- In other words, for declarations such as TIMESTAMP(2), TIMESTAMP(4),
- and so on, the display width is ignored.
- */
- char buf[32];
- my_snprintf(buf, sizeof(buf), "TIMESTAMP(%s)", length);
- WARN_DEPRECATED(thd, "6.0", buf, "'TIMESTAMP'");
- }
-
if (!(new_field= new Create_field()) ||
new_field->init(thd, field_name->str, type, length, decimals, type_modifier,
default_value, on_update_value, comment, change,
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 5ba375f9710..32e7a9dfcc6 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -487,8 +487,7 @@ static void set_param_time(Item_param *param, uchar **pos, ulong len)
}
else
set_zero_time(&tm, MYSQL_TIMESTAMP_TIME);
- param->set_time(&tm, MYSQL_TIMESTAMP_TIME,
- MAX_TIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
+ param->set_time(&tm, MYSQL_TIMESTAMP_TIME, MAX_TIME_FULL_WIDTH);
*pos+= length;
}
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index c17cb946fa3..e02c22c3250 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -3342,12 +3342,8 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, Item_func *cond,
(*sargables)->arg_value= value;
(*sargables)->num_values= num_values;
}
- /*
- We can't always use indexes when comparing a string index to a
- number. cmp_type() is checked to allow compare of dates to numbers.
- eq_func is NEVER true when num_values > 1
- */
- if (!eq_func)
+
+ if (!eq_func) // eq_func is NEVER true when num_values > 1
{
/*
Additional optimization: if we're processing
@@ -3368,23 +3364,17 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, Item_func *cond,
eq_func= TRUE;
}
- if (field->result_type() == STRING_RESULT)
+ /*
+ We can't use indexes when comparing a string index to a
+ number or two strings if the effective collation
+ of the operation differ from the field collation.
+ */
+ if (field->cmp_type() == STRING_RESULT)
{
- if ((*value)->result_type() != STRING_RESULT)
- {
- if (field->cmp_type() != (*value)->result_type())
- return;
- }
- else
- {
- /*
- We can't use indexes if the effective collation
- of the operation differ from the field collation.
- */
- if (field->cmp_type() == STRING_RESULT &&
- ((Field_str*)field)->charset() != cond->compare_collation())
+ if ((*value)->cmp_type() != STRING_RESULT)
return;
- }
+ if (((Field_str*)field)->charset() != cond->compare_collation())
+ return;
}
}
}
@@ -9455,7 +9445,7 @@ test_if_equality_guarantees_uniqueness(Item *l, Item *r)
{
return r->const_item() &&
/* elements must be compared as dates */
- (Arg_comparator::can_compare_as_dates(l, r, 0) ||
+ (l->cmp_type() == TIME_RESULT ||
/* or of the same result type */
(r->result_type() == l->result_type() &&
/* and must have the same collation if compared as strings */
@@ -9640,15 +9630,12 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table,
case STRING_RESULT:
DBUG_ASSERT(item->collation.collation);
- enum enum_field_types type;
/*
DATE/TIME and GEOMETRY fields have STRING_RESULT result type.
To preserve type they needed to be handled separately.
*/
- if ((type= item->field_type()) == MYSQL_TYPE_DATETIME ||
- type == MYSQL_TYPE_TIME || type == MYSQL_TYPE_DATE ||
- type == MYSQL_TYPE_NEWDATE ||
- type == MYSQL_TYPE_TIMESTAMP || type == MYSQL_TYPE_GEOMETRY)
+ if (item->cmp_type() == TIME_RESULT ||
+ item->field_type() == MYSQL_TYPE_GEOMETRY)
new_field= item->tmp_table_field_from_field_type(table, 1);
/*
Make sure that the blob fits into a Field_varstring which has
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 9b344204d64..c5df62c09cf 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -1930,6 +1930,7 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond)
Security_context *tmp_sctx= tmp->security_ctx;
struct st_my_thread_var *mysys_var;
const char *val;
+ time_t start_time;
if ((!tmp->vio_ok() && !tmp->system_thread) ||
(user && (!tmp_sctx->user || strcmp(tmp_sctx->user, user))))
@@ -1970,8 +1971,9 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond)
table->field[4]->store(command_name[tmp->command].str,
command_name[tmp->command].length, cs);
/* MYSQL_TIME */
- table->field[5]->store((longlong)(tmp->start_time ?
- now - tmp->start_time : 0), FALSE);
+
+ start_time= tmp->start_time;
+ table->field[5]->store((longlong)(start_time ? now-start_time : 0), 0);
/* STATE */
#ifndef EMBEDDED_LIBRARY
val= (char*) (tmp->locked ? "Locked" :
@@ -3902,7 +3904,7 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables,
end=strmov(end,grant_types.type_names[bitnr]);
}
}
- table->field[17]->store(tmp+1,end == tmp ? 0 : (uint) (end-tmp-1), cs);
+ table->field[18]->store(tmp+1,end == tmp ? 0 : (uint) (end-tmp-1), cs);
#endif
table->field[1]->store(db_name->str, db_name->length, cs);
@@ -3911,7 +3913,7 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables,
cs);
table->field[4]->store((longlong) count, TRUE);
field->sql_type(type);
- table->field[14]->store(type.ptr(), type.length(), cs);
+ table->field[15]->store(type.ptr(), type.length(), cs);
/*
MySQL column type has the following format:
base_type [(dimension)] [unsigned] [zerofill].
@@ -3958,6 +3960,7 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables,
They are set to -1 if they should not be set (we should return NULL)
*/
+ field_length= -1;
decimals= field->decimals();
switch (field->type()) {
case MYSQL_TYPE_NEWDECIMAL:
@@ -3986,8 +3989,13 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables,
if (decimals == NOT_FIXED_DEC)
decimals= -1; // return NULL
break;
+ case MYSQL_TYPE_TIME:
+ case MYSQL_TYPE_TIMESTAMP:
+ case MYSQL_TYPE_DATETIME:
+ table->field[12]->store((longlong) field->decimals(), TRUE);
+ table->field[12]->set_notnull();
+ break;
default:
- field_length= decimals= -1;
break;
}
@@ -3995,38 +4003,38 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables,
{
table->field[10]->store((longlong) field_length, TRUE);
table->field[10]->set_notnull();
- }
- if (decimals >= 0)
- {
- table->field[11]->store((longlong) decimals, TRUE);
- table->field[11]->set_notnull();
+ if (decimals >= 0)
+ {
+ table->field[11]->store((longlong) decimals, TRUE);
+ table->field[11]->set_notnull();
+ }
}
if (field->has_charset())
{
pos=(uchar*) field->charset()->csname;
- table->field[12]->store((const char*) pos,
- strlen((const char*) pos), cs);
- table->field[12]->set_notnull();
- pos=(uchar*) field->charset()->name;
table->field[13]->store((const char*) pos,
strlen((const char*) pos), cs);
table->field[13]->set_notnull();
+ pos=(uchar*) field->charset()->name;
+ table->field[14]->store((const char*) pos,
+ strlen((const char*) pos), cs);
+ table->field[14]->set_notnull();
}
pos=(uchar*) ((field->flags & PRI_KEY_FLAG) ? "PRI" :
(field->flags & UNIQUE_KEY_FLAG) ? "UNI" :
(field->flags & MULTIPLE_KEY_FLAG) ? "MUL":"");
- table->field[15]->store((const char*) pos,
+ table->field[16]->store((const char*) pos,
strlen((const char*) pos), cs);
if (field->unireg_check == Field::NEXT_NUMBER)
- table->field[16]->store(STRING_WITH_LEN("auto_increment"), cs);
+ table->field[17]->store(STRING_WITH_LEN("auto_increment"), cs);
if (show_table->timestamp_field == field &&
field->unireg_check != Field::TIMESTAMP_DN_FIELD)
- table->field[16]->store(STRING_WITH_LEN("on update CURRENT_TIMESTAMP"),
+ table->field[17]->store(STRING_WITH_LEN("on update CURRENT_TIMESTAMP"),
cs);
- table->field[18]->store(field->comment.str, field->comment.length, cs);
+ table->field[19]->store(field->comment.str, field->comment.length, cs);
if (schema_table_store_record(thd, table))
DBUG_RETURN(1);
}
@@ -5706,14 +5714,23 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list)
item->unsigned_flag= (fields_info->field_flags & MY_I_S_UNSIGNED);
break;
case MYSQL_TYPE_DATE:
+ if (!(item=new Item_return_date_time(fields_info->field_name,
+ MAX_DATE_WIDTH,
+ fields_info->field_type)))
+ DBUG_RETURN(0);
+ break;
case MYSQL_TYPE_TIME:
+ if (!(item=new Item_return_date_time(fields_info->field_name,
+ MAX_TIME_FULL_WIDTH,
+ fields_info->field_type)))
+ DBUG_RETURN(0);
+ break;
case MYSQL_TYPE_TIMESTAMP:
case MYSQL_TYPE_DATETIME:
if (!(item=new Item_return_date_time(fields_info->field_name,
+ MAX_DATETIME_WIDTH,
fields_info->field_type)))
- {
DBUG_RETURN(0);
- }
break;
case MYSQL_TYPE_FLOAT:
case MYSQL_TYPE_DOUBLE:
@@ -5893,7 +5910,7 @@ int make_table_names_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
int make_columns_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
{
- int fields_arr[]= {3, 14, 13, 6, 15, 5, 16, 17, 18, -1};
+ int fields_arr[]= {3, 15, 14, 6, 16, 5, 17, 18, 19, -1};
int *field_num= fields_arr;
ST_FIELD_INFO *field_info;
Name_resolution_context *context= &thd->lex->select_lex.context;
@@ -5901,9 +5918,9 @@ int make_columns_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
for (; *field_num >= 0; field_num++)
{
field_info= &schema_table->fields_info[*field_num];
- if (!thd->lex->verbose && (*field_num == 13 ||
- *field_num == 17 ||
- *field_num == 18))
+ if (!thd->lex->verbose && (*field_num == 14 ||
+ *field_num == 18 ||
+ *field_num == 19))
continue;
Item_field *field= new Item_field(context,
NullS, NullS, field_info->field_name);
@@ -6288,6 +6305,8 @@ ST_FIELD_INFO columns_fields_info[]=
0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FRM_ONLY},
{"NUMERIC_SCALE", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONGLONG,
0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FRM_ONLY},
+ {"DATETIME_PRECISION", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
+ 0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FRM_ONLY},
{"CHARACTER_SET_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 1, 0,
OPEN_FRM_ONLY},
{"COLLATION_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 1, "Collation",
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index b919ea9eae7..f11a4e683f1 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -34,26 +34,16 @@ const char *primary_key_name="PRIMARY";
static bool check_if_keyname_exists(const char *name,KEY *start, KEY *end);
static char *make_unique_key_name(const char *field_name,KEY *start,KEY *end);
-static int copy_data_between_tables(TABLE *from,TABLE *to,
- List<Create_field> &create, bool ignore,
- uint order_num, ORDER *order,
- ha_rows *copied,ha_rows *deleted,
- enum enum_enable_or_disable keys_onoff,
- bool error_if_not_empty);
+static int copy_data_between_tables(TABLE *,TABLE *, List<Create_field> &, bool,
+ uint, ORDER *, ha_rows *,ha_rows *,
+ enum enum_enable_or_disable, bool);
static bool prepare_blob_field(THD *thd, Create_field *sql_field);
static bool check_engine(THD *, const char *, HA_CREATE_INFO *);
-static int
-mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
- Alter_info *alter_info,
- bool tmp_table,
- uint *db_options,
- handler *file, KEY **key_info_buffer,
- uint *key_count, int select_field_count);
-static bool
-mysql_prepare_alter_table(THD *thd, TABLE *table,
- HA_CREATE_INFO *create_info,
- Alter_info *alter_info);
+static int mysql_prepare_create_table(THD *, HA_CREATE_INFO *, Alter_info *,
+ bool, uint *, handler *, KEY **, uint *, int);
+static bool mysql_prepare_alter_table(THD *, TABLE *, HA_CREATE_INFO *,
+ Alter_info *);
#ifndef DBUG_OFF
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 4e24e69af42..46ba53e7e3e 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -675,10 +675,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%pure_parser /* We have threads */
/*
- Currently there are 169 shift/reduce conflicts.
+ Currently there are 171 shift/reduce conflicts.
We should not introduce new conflicts any more.
*/
-%expect 169
+%expect 171
/*
Comments for TOKENS.
@@ -1317,6 +1317,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
opt_natural_language_mode opt_query_expansion
opt_ev_status opt_ev_on_completion ev_on_completion opt_ev_comment
ev_alter_on_schedule_completion opt_ev_rename_to opt_ev_sql_stmt
+ opt_time_precision
%type <ulong_num>
ulong_num real_ulong_num merge_insert_types
@@ -2041,7 +2042,7 @@ opt_ev_status:
ev_starts:
/* empty */
{
- Item *item= new (YYTHD->mem_root) Item_func_now_local();
+ Item *item= new (YYTHD->mem_root) Item_func_now_local(0);
if (item == NULL)
MYSQL_YYABORT;
Lex->event_parse_data->item_starts= item;
@@ -5026,7 +5027,7 @@ type:
{ $$=MYSQL_TYPE_YEAR; }
| DATE_SYM
{ $$=MYSQL_TYPE_DATE; }
- | TIME_SYM
+ | TIME_SYM opt_field_length
{ $$=MYSQL_TYPE_TIME; }
| TIMESTAMP opt_field_length
{
@@ -5041,7 +5042,7 @@ type:
$$=MYSQL_TYPE_TIMESTAMP;
}
}
- | DATETIME
+ | DATETIME opt_field_length
{ $$=MYSQL_TYPE_DATETIME; }
| TINYBLOB
{
@@ -5234,9 +5235,9 @@ attribute:
NULL_SYM { Lex->type&= ~ NOT_NULL_FLAG; }
| not NULL_SYM { Lex->type|= NOT_NULL_FLAG; }
| DEFAULT now_or_signed_literal { Lex->default_value=$2; }
- | ON UPDATE_SYM NOW_SYM optional_braces
+ | ON UPDATE_SYM NOW_SYM opt_time_precision
{
- Item *item= new (YYTHD->mem_root) Item_func_now_local();
+ Item *item= new (YYTHD->mem_root) Item_func_now_local($4);
if (item == NULL)
MYSQL_YYABORT;
Lex->on_update_value= item;
@@ -5283,9 +5284,9 @@ attribute:
;
now_or_signed_literal:
- NOW_SYM optional_braces
+ NOW_SYM opt_time_precision
{
- $$= new (YYTHD->mem_root) Item_func_now_local();
+ $$= new (YYTHD->mem_root) Item_func_now_local($2);
if ($$ == NULL)
MYSQL_YYABORT;
}
@@ -6849,6 +6850,12 @@ select_alias:
| TEXT_STRING_sys { $$=$1; }
;
+opt_time_precision:
+ /* empty */ { $$= 0; }
+ | '(' ')' { $$= 0; }
+ | '(' real_ulong_num ')' { $$= $2; };
+ ;
+
optional_braces:
/* empty */ {}
| '(' ')' {}
@@ -7527,13 +7534,13 @@ function_call_keyword:
}
| TIME_SYM '(' expr ')'
{
- $$= new (YYTHD->mem_root) Item_time_typecast($3);
+ $$= new (YYTHD->mem_root) Item_time_typecast($3, AUTO_SEC_PART_DIGITS);
if ($$ == NULL)
MYSQL_YYABORT;
}
| TIMESTAMP '(' expr ')'
{
- $$= new (YYTHD->mem_root) Item_datetime_typecast($3);
+ $$= new (YYTHD->mem_root) Item_datetime_typecast($3, AUTO_SEC_PART_DIGITS);
if ($$ == NULL)
MYSQL_YYABORT;
}
@@ -7640,16 +7647,9 @@ function_call_nonkeyword:
MYSQL_YYABORT;
Lex->safe_to_cache_query=0;
}
- | CURTIME optional_braces
- {
- $$= new (YYTHD->mem_root) Item_func_curtime_local();
- if ($$ == NULL)
- MYSQL_YYABORT;
- Lex->safe_to_cache_query=0;
- }
- | CURTIME '(' expr ')'
+ | CURTIME opt_time_precision
{
- $$= new (YYTHD->mem_root) Item_func_curtime_local($3);
+ $$= new (YYTHD->mem_root) Item_func_curtime_local($2);
if ($$ == NULL)
MYSQL_YYABORT;
Lex->safe_to_cache_query=0;
@@ -7680,16 +7680,9 @@ function_call_nonkeyword:
if ($$ == NULL)
MYSQL_YYABORT;
}
- | NOW_SYM optional_braces
+ | NOW_SYM opt_time_precision
{
- $$= new (YYTHD->mem_root) Item_func_now_local();
- if ($$ == NULL)
- MYSQL_YYABORT;
- Lex->safe_to_cache_query=0;
- }
- | NOW_SYM '(' expr ')'
- {
- $$= new (YYTHD->mem_root) Item_func_now_local($3);
+ $$= new (YYTHD->mem_root) Item_func_now_local($2);
if ($$ == NULL)
MYSQL_YYABORT;
Lex->safe_to_cache_query=0;
@@ -7737,7 +7730,7 @@ function_call_nonkeyword:
if ($$ == NULL)
MYSQL_YYABORT;
}
- | SYSDATE optional_braces
+ | SYSDATE opt_time_precision
{
/*
Unlike other time-related functions, SYSDATE() is
@@ -7748,19 +7741,9 @@ function_call_nonkeyword:
*/
Lex->set_stmt_unsafe();
if (global_system_variables.sysdate_is_now == 0)
- $$= new (YYTHD->mem_root) Item_func_sysdate_local();
- else
- $$= new (YYTHD->mem_root) Item_func_now_local();
- if ($$ == NULL)
- MYSQL_YYABORT;
- Lex->safe_to_cache_query=0;
- }
- | SYSDATE '(' expr ')'
- {
- if (global_system_variables.sysdate_is_now == 0)
- $$= new (YYTHD->mem_root) Item_func_sysdate_local($3);
+ $$= new (YYTHD->mem_root) Item_func_sysdate_local($2);
else
- $$= new (YYTHD->mem_root) Item_func_now_local($3);
+ $$= new (YYTHD->mem_root) Item_func_now_local($2);
if ($$ == NULL)
MYSQL_YYABORT;
Lex->safe_to_cache_query=0;
@@ -7784,16 +7767,16 @@ function_call_nonkeyword:
MYSQL_YYABORT;
Lex->safe_to_cache_query=0;
}
- | UTC_TIME_SYM optional_braces
+ | UTC_TIME_SYM opt_time_precision
{
- $$= new (YYTHD->mem_root) Item_func_curtime_utc();
+ $$= new (YYTHD->mem_root) Item_func_curtime_utc($2);
if ($$ == NULL)
MYSQL_YYABORT;
Lex->safe_to_cache_query=0;
}
- | UTC_TIMESTAMP_SYM optional_braces
+ | UTC_TIMESTAMP_SYM opt_time_precision
{
- $$= new (YYTHD->mem_root) Item_func_now_utc();
+ $$= new (YYTHD->mem_root) Item_func_now_utc($2);
if ($$ == NULL)
MYSQL_YYABORT;
Lex->safe_to_cache_query=0;
@@ -8409,10 +8392,10 @@ cast_type:
{ $$=ITEM_CAST_UNSIGNED_INT; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; }
| DATE_SYM
{ $$=ITEM_CAST_DATE; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; }
- | TIME_SYM
- { $$=ITEM_CAST_TIME; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; }
- | DATETIME
- { $$=ITEM_CAST_DATETIME; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; }
+ | TIME_SYM opt_field_length
+ { $$=ITEM_CAST_TIME; Lex->charset= NULL; Lex->dec= (char*)0; }
+ | DATETIME opt_field_length
+ { $$=ITEM_CAST_DATETIME; Lex->charset= NULL; Lex->dec= (char*)0; }
| DECIMAL_SYM float_options
{ $$=ITEM_CAST_DECIMAL; Lex->charset= NULL; }
;
diff --git a/sql/time.cc b/sql/time.cc
index 8b554beb94b..7d23a795413 100644
--- a/sql/time.cc
+++ b/sql/time.cc
@@ -236,7 +236,8 @@ str_to_datetime_with_warn(const char *str, uint length, MYSQL_TIME *l_time,
&was_cut);
if (was_cut || ts_type <= MYSQL_TIMESTAMP_ERROR)
make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- str, length, ts_type, NullS);
+ str, length, flags & TIME_TIME_ONLY ?
+ MYSQL_TIMESTAMP_TIME : ts_type, NullS);
return ts_type;
}
@@ -277,25 +278,6 @@ my_time_t TIME_to_timestamp(THD *thd, const MYSQL_TIME *t, my_bool *in_dst_time_
/*
- Convert a time string to a MYSQL_TIME struct and produce a warning
- if string was cut during conversion.
-
- NOTE
- See str_to_time() for more info.
-*/
-bool
-str_to_time_with_warn(const char *str, uint length, MYSQL_TIME *l_time)
-{
- int warning;
- bool ret_val= str_to_time(str, length, l_time, &warning);
- if (ret_val || warning)
- make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- str, length, MYSQL_TIMESTAMP_TIME, NullS);
- return ret_val;
-}
-
-
-/*
Convert a system time structure to TIME
*/
@@ -687,15 +669,13 @@ const char *get_date_time_format_str(KNOWN_DATE_TIME_FORMAT *format,
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. Additionally, make_time doesn't take into
- account time->day member: it's assumed that days have been converted
- to hours already.
+ valid date either.
****************************************************************************/
void make_time(const DATE_TIME_FORMAT *format __attribute__((unused)),
const MYSQL_TIME *l_time, String *str)
{
- uint length= (uint) my_time_to_str(l_time, (char*) str->ptr());
+ uint length= (uint) my_time_to_str(l_time, (char*) str->ptr(), 0);
str->length(length);
str->set_charset(&my_charset_bin);
}
@@ -713,15 +693,15 @@ void make_date(const DATE_TIME_FORMAT *format __attribute__((unused)),
void make_datetime(const DATE_TIME_FORMAT *format __attribute__((unused)),
const MYSQL_TIME *l_time, String *str)
{
- uint length= (uint) my_datetime_to_str(l_time, (char*) str->ptr());
+ 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 char *str_val,
- uint str_length, timestamp_type time_type,
+ const Lazy_string *sval,
+ timestamp_type time_type,
const char *field_name)
{
char warn_buff[MYSQL_ERRMSG_SIZE];
@@ -729,8 +709,7 @@ void make_truncated_value_warning(THD *thd, MYSQL_ERROR::enum_warning_level leve
CHARSET_INFO *cs= &my_charset_latin1;
char buff[128];
String str(buff,(uint32) sizeof(buff), system_charset_info);
- str.copy(str_val, str_length, system_charset_info);
- str[str_length]= 0; // Ensure we have end 0 for snprintf
+ sval->copy(&str);
switch (time_type) {
case MYSQL_TIMESTAMP_DATE:
@@ -765,14 +744,16 @@ void make_truncated_value_warning(THD *thd, MYSQL_ERROR::enum_warning_level leve
/* Daynumber from year 0 to 9999-12-31 */
#define MAX_DAY_NUMBER 3652424L
+#define COMBINE(X) \
+ (((((X)->day * 24LL + (X)->hour) * 60LL + \
+ (X)->minute) * 60LL + (X)->second)*1000000LL + \
+ (X)->second_part)
bool date_add_interval(MYSQL_TIME *ltime, interval_type int_type, INTERVAL interval)
{
long period, sign;
- ltime->neg= 0;
-
- sign= (interval.neg ? -1 : 1);
+ sign= (interval.neg == ltime->neg ? 1 : -1);
switch (int_type) {
case INTERVAL_SECOND:
@@ -789,35 +770,29 @@ bool date_add_interval(MYSQL_TIME *ltime, interval_type int_type, INTERVAL inter
case INTERVAL_DAY_SECOND:
case INTERVAL_DAY_MINUTE:
case INTERVAL_DAY_HOUR:
+ case INTERVAL_DAY:
{
- longlong sec, days, daynr, microseconds, extra_sec;
- ltime->time_type= MYSQL_TIMESTAMP_DATETIME; // Return full date
- microseconds= ltime->second_part + sign*interval.second_part;
- extra_sec= microseconds/1000000L;
- microseconds= microseconds%1000000L;
-
- sec=((ltime->day-1)*3600*24L+ltime->hour*3600+ltime->minute*60+
- ltime->second +
- sign* (longlong) (interval.day*3600*24L +
- interval.hour*LL(3600)+interval.minute*LL(60)+
- interval.second))+ extra_sec;
- if (microseconds < 0)
- {
- microseconds+= LL(1000000);
- sec--;
- }
- days= sec/(3600*LL(24));
- sec-= days*3600*LL(24);
- if (sec < 0)
- {
- days--;
- sec+= 3600*LL(24);
- }
- ltime->second_part= (uint) microseconds;
- ltime->second= (uint) (sec % 60);
- ltime->minute= (uint) (sec/60 % 60);
- ltime->hour= (uint) (sec/3600);
- daynr= calc_daynr(ltime->year,ltime->month,1) + days;
+ longlong usec, daynr;
+ my_bool neg= ltime->neg;
+ enum enum_mysql_timestamp_type time_type= ltime->time_type;
+
+ if (ltime->time_type != MYSQL_TIMESTAMP_TIME)
+ ltime->day+= calc_daynr(ltime->year, ltime->month, 1) - 1;
+
+ usec= COMBINE(ltime) + sign*COMBINE(&interval);
+
+ unpack_time(usec, ltime);
+ ltime->time_type= time_type;
+ ltime->neg^= neg;
+
+ if (time_type == MYSQL_TIMESTAMP_TIME)
+ break;
+
+ if (int_type != INTERVAL_DAY)
+ ltime->time_type= MYSQL_TIMESTAMP_DATETIME; // Return full date
+
+ daynr= ltime->day + 32*(ltime->month + 13*ltime->year);
+
/* Day number from year 0 to 9999-12-31 */
if ((ulonglong) daynr > MAX_DAY_NUMBER)
goto invalid_date;
@@ -825,7 +800,6 @@ bool date_add_interval(MYSQL_TIME *ltime, interval_type int_type, INTERVAL inter
&ltime->day);
break;
}
- case INTERVAL_DAY:
case INTERVAL_WEEK:
period= (calc_daynr(ltime->year,ltime->month,ltime->day) +
sign * (long) interval.day);
@@ -969,19 +943,14 @@ calc_time_diff(MYSQL_TIME *l_time1, MYSQL_TIME *l_time2, int l_sign, longlong *s
int my_time_compare(MYSQL_TIME *a, MYSQL_TIME *b)
{
- ulonglong a_t= TIME_to_ulonglong_datetime(a);
- ulonglong b_t= TIME_to_ulonglong_datetime(b);
+ ulonglong a_t= pack_time(a);
+ ulonglong b_t= pack_time(b);
if (a_t < b_t)
return -1;
if (a_t > b_t)
return 1;
- if (a->second_part < b->second_part)
- return -1;
- if (a->second_part > b->second_part)
- return 1;
-
return 0;
}
diff --git a/sql/unireg.h b/sql/unireg.h
index 4f6b647964d..50facf51d02 100644
--- a/sql/unireg.h
+++ b/sql/unireg.h
@@ -72,10 +72,13 @@
#define MAX_BIT_FIELD_LENGTH 64 /* Max length in bits for bit fields */
#define MAX_DATE_WIDTH 10 /* YYYY-MM-DD */
-#define MAX_TIME_WIDTH 23 /* -DDDDDD HH:MM:SS.###### */
+#define MIN_TIME_WIDTH 9 /* HHH:MM:SS */
+#define MAX_TIME_WIDTH 16 /* -DDDDDD HH:MM:SS */
+#define MAX_TIME_FULL_WIDTH 23 /* -DDDDDD HH:MM:SS.###### */
#define MAX_DATETIME_FULL_WIDTH 29 /* YYYY-MM-DD HH:MM:SS.###### AM */
#define MAX_DATETIME_WIDTH 19 /* YYYY-MM-DD HH:MM:SS */
#define MAX_DATETIME_COMPRESSED_WIDTH 14 /* YYYYMMDDHHMMSS */
+#define MAX_DATETIME_PRECISION 6
#define MAX_TABLES (sizeof(table_map)*8-3) /* Max tables in join */
#define PARAM_TABLE_BIT (((table_map) 1) << (sizeof(table_map)*8-3))