From 6eceb7f5df95fefc03f01422e13d3505a9722671 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 1 Mar 2011 13:24:36 +0100 Subject: 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 --- sql/event_data_objects.cc | 6 +- sql/event_db_repository.cc | 7 +- sql/event_parse_data.cc | 2 +- sql/event_queue.cc | 8 +- sql/event_queue.h | 2 +- sql/field.cc | 1880 ++++++++++++++++++-------------------------- sql/field.h | 356 +++++---- sql/filesort.cc | 45 +- sql/item.cc | 235 +++--- sql/item.h | 60 +- sql/item_cmpfunc.cc | 741 ++++++----------- sql/item_cmpfunc.h | 44 +- sql/item_create.cc | 50 +- sql/item_func.cc | 108 ++- sql/item_func.h | 10 +- sql/item_row.h | 1 + sql/item_sum.cc | 9 +- sql/item_timefunc.cc | 881 ++++++--------------- sql/item_timefunc.h | 407 +++------- sql/log.cc | 12 +- sql/log_event.cc | 71 +- sql/log_event.h | 25 +- sql/log_event_old.cc | 4 +- sql/mysql_priv.h | 70 +- sql/mysqld.cc | 5 +- sql/opt_range.cc | 30 +- sql/protocol.cc | 51 +- sql/protocol.h | 12 +- sql/rpl_rli.cc | 6 +- sql/set_var.cc | 20 +- sql/set_var.h | 6 +- sql/share/errmsg.txt | 8 +- sql/slave.cc | 6 +- sql/sp_head.cc | 14 +- sql/sql_class.cc | 8 +- sql/sql_class.h | 46 +- sql/sql_insert.cc | 13 +- sql/sql_parse.cc | 29 +- sql/sql_prepare.cc | 3 +- sql/sql_select.cc | 41 +- sql/sql_show.cc | 67 +- sql/sql_table.cc | 24 +- sql/sql_yacc.yy | 83 +- sql/time.cc | 105 +-- sql/unireg.h | 5 +- 45 files changed, 2296 insertions(+), 3320 deletions(-) (limited to 'sql') 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(<ime, 0); + return protocol->store(<ime, 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, <ime, &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(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(<ime, 0); + return protocol->store(<ime, 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, <ime, + (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(<ime, &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), <ime, (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(<ime, &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, <ime, (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(<ime, &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, <ime, TIME_TIME_ONLY, + &was_cut) > MYSQL_TIMESTAMP_ERROR; + + if (ltime.month) + ltime.day=0; + ltime.month= ltime.year= 0; + + return store_TIME_with_warning(<ime, &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, <ime, &was_cut); + + return store_TIME_with_warning(<ime, &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, <ime, &was_cut); + + return store_TIME_with_warning(<ime, &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(<ime, TIME_TIME_ONLY); + return protocol->store_time(<ime, 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(<ime, TIME_TIME_ONLY); + return TIME_to_double(<ime); +} + +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(<ime, TIME_TIME_ONLY); + str->alloc(field_length+1); + str->length(my_time_to_str(<ime, (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(<ime, TIME_TIME_ONLY); + return protocol->store_time(<ime, 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, ¬_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) +void Field_newdate::store_TIME(MYSQL_TIME *ltime) { - 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) -{ - 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; @@ -5967,149 +5903,22 @@ void Field_newdate::sql_type(String &res) const ** In string context: YYYY-MM-DD HH:MM:DD ** In number context: YYYYMMDDHHMMDD ** 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) -{ - 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) - { - 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, ¬_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) +void Field_datetime::store_TIME(MYSQL_TIME *ltime) { - 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) - { + 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; } 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(<ime, TIME_FUZZY_DATE); + return protocol->store(<ime, dec); +} + + +double Field_datetime_hires::val_real(void) +{ + MYSQL_TIME ltime; + Field_datetime_hires::get_date(<ime, TIME_FUZZY_DATE); + return TIME_to_double(<ime); +} + +longlong Field_datetime_hires::val_int(void) +{ + MYSQL_TIME ltime; + Field_datetime_hires::get_date(<ime, TIME_FUZZY_DATE); + return TIME_to_ulonglong_datetime(<ime); +} + + +String *Field_datetime_hires::val_str(String *str, + String *unused __attribute__((unused))) +{ + MYSQL_TIME ltime; + Field_datetime_hires::get_date(<ime, TIME_FUZZY_DATE); + str->alloc(field_length+1); + str->length(field_length); + my_datetime_to_str(<ime, (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, <ime); +} + +int Item_datetime::save_in_field(Field *field, bool no_conversions) +{ + field->set_notnull(); + return field->store_time(<ime, ltime.time_type); +} + +longlong Item_datetime::val_int() +{ + return TIME_to_ulonglong(<ime); +} + 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("(")); 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 &fields) {} @@ -808,7 +810,7 @@ public: void split_sum_func2(THD *thd, Item **ref_pointer_array, List &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(<ime); - value= !*is_null ? (longlong) TIME_to_ulonglong_datetime(<ime) : 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; @@ -1154,64 +921,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. @@ -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(base)+pos; + Item_datetime *dt= reinterpret_cast(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(<ime)) 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(<ime, 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(<ime)) + return 0; + + return TIME_to_double(<ime); } 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(<ime)) + return 0; + + return TIME_to_ulonglong(<ime); } 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(<ime)) + return 0; + + return date2my_decimal(<ime, 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 &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(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(<ime, 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(<ime); - 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(<ime, TIME_FUZZY_DATE)) return (String *) 0; - if (str->alloc(MAX_DATE_STRING_REP_LENGTH)) + if (make_datetime(<ime, str, decimals)) { null_value= 1; return (String *) 0; } - make_date((DATE_TIME_FORMAT *) 0, <ime, str); return str; } -longlong Item_date::val_int() +longlong Item_temporal_func::val_int() +{ + DBUG_ASSERT(fixed == 1); + MYSQL_TIME ltime; + if (get_date(<ime, TIME_FUZZY_DATE)) + return 0; + return (longlong)TIME_to_ulonglong(<ime); +} + + +double Item_temporal_func::val_real() { DBUG_ASSERT(fixed == 1); MYSQL_TIME ltime; if (get_date(<ime, TIME_FUZZY_DATE)) return 0; - return (longlong) (ltime.year*10000L+ltime.month*100+ltime.day); + return TIME_to_double(<ime); } @@ -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(<ime); -} - -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, <ime, 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(<ime); - value= TIME_to_ulonglong_time(<ime); - buff_length= (uint) my_time_to_str(<ime, 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(<ime); - value= (longlong) TIME_to_ulonglong_datetime(<ime); - - buff_length= (uint) my_datetime_to_str(<ime, 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(<ime, 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(<ime); - buff_length= (uint) my_datetime_to_str(<ime, 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(<ime); - return (longlong) TIME_to_ulonglong_datetime(<ime); -} - - -double Item_func_sysdate_local::val_real() -{ - DBUG_ASSERT(fixed == 1); - store_now_in_TIME(<ime); - return ulonglong2double(TIME_to_ulonglong_datetime(<ime)); -} - - -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(<ime); *res= ltime; return 0; } -int Item_func_sysdate_local::save_in_field(Field *to, bool no_conversions) -{ - store_now_in_TIME(<ime); - to->set_notnull(); - to->store_time(<ime, 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, <ime); + double arg_val= args[0]->val_real(); - make_time((DATE_TIME_FORMAT *) 0, <ime, 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, <ime); - - 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, ¬_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(<ime, 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, <ime, 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(<ime, 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(<ime, 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(), <ime)) - { - 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(<ime, 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(<ime, TIME_FUZZY_DATE) && - !make_datetime(ltime.second_part ? DATE_TIME_MICROSECOND : DATE_TIME, - <ime, 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(<ime,1)) - { - null_value= 1; - return 0; - } - - return TIME_to_ulonglong_datetime(<ime); -} - - -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(<ime)) - { - 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(<ime) && - !make_datetime(ltime.second_part ? TIME_MICROSECOND : TIME_ONLY, - <ime, 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(<ime, 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, <ime, 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(<ime, 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, <ime->year, <ime->month, <ime->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, µseconds); /* @@ -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,<ime->year,<ime->month,<ime->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(©); + + 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 *)<ime, 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, <ime, 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(<ime, TIME_FUZZY_DATE)) - return 0; - - if (!make_datetime((const_item ? cached_format_type : - (ltime.second_part ? DATE_TIME_MICROSECOND : DATE_TIME)), - <ime, 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 &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, 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 &, 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 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; } @@ -276,25 +277,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 <ime->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)) -- cgit v1.2.1 From 507afb0070b66f0de9d0cc4b198202e6a017c2e1 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 7 Mar 2011 16:27:49 +0100 Subject: lp:730627 TIME_to_ulonglong: Assertion `0' failed in 5.1-micro on wrong argument to MAKETIME correct the return value of Item_func_maketime::get_date() --- sql/item_timefunc.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index aa42d869df5..feae39e1509 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -2582,7 +2582,7 @@ bool Item_func_maketime::get_date(MYSQL_TIME *ltime, uint fuzzy_date) args[2]->null_value || minute < 0 || minute > 59 || second < 0 || second > 59))) - return 0; + return 1; bzero(ltime, sizeof(*ltime)); ltime->time_type= MYSQL_TIMESTAMP_TIME; -- cgit v1.2.1 From 5c8cbba300c7591467ec9ee6fef5a1148d871807 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 7 Mar 2011 21:57:17 +0100 Subject: lp:730637 - Valgrind warnings in 5.1-micro sql/field.cc: initialize ltime completely sql/filesort.cc: don't pack MYSQL_TIME if it's not initialized (safe here, but valgrind complains) sql/item_cmpfunc.cc: don't pack MYSQL_TIME if it's not initialized (safe here, but valgrind complains) sql/item_timefunc.cc: don't check MYSQL_TIME members if it's uninitialized (safe here, but valgrind complains) sql/time.cc: use c_ptr_safe() instead of c_ptr() (make valgrind happy) --- sql/field.cc | 1 + sql/filesort.cc | 6 ++++-- sql/item_cmpfunc.cc | 6 ++++-- sql/item_timefunc.cc | 10 ++++++---- sql/time.cc | 6 +++--- 5 files changed, 18 insertions(+), 11 deletions(-) (limited to 'sql') diff --git a/sql/field.cc b/sql/field.cc index 43e210d1bc9..32ac51a1e39 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -5410,6 +5410,7 @@ String *Field_time::val_str(String *val_buffer, tmp= -tmp; ltime.neg= 1; } + ltime.year= ltime.month= 0; ltime.day= (uint) 0; ltime.hour= (uint) (tmp/10000); ltime.minute= (uint) (tmp/100 % 100); diff --git a/sql/filesort.cc b/sql/filesort.cc index 236a628cce6..4c096dad4d9 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -850,8 +850,10 @@ static void make_sortkey(register SORTPARAM *param, else { MYSQL_TIME buf; - item->get_date_result(&buf, TIME_FUZZY_DATE | TIME_INVALID_DATES); - value= pack_time(&buf); + if (item->get_date_result(&buf, TIME_FUZZY_DATE | TIME_INVALID_DATES)) + DBUG_ASSERT(maybe_null && item->null_value); + else + value= pack_time(&buf); } if (maybe_null) { diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index f2935137de7..dd47e4ab89f 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -842,8 +842,10 @@ get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg, else { MYSQL_TIME buf; - item->get_date_result(&buf, TIME_FUZZY_DATE | TIME_INVALID_DATES); - value= pack_time(&buf); + if (item->get_date_result(&buf, TIME_FUZZY_DATE | TIME_INVALID_DATES)) + DBUG_ASSERT(item->null_value); + else + value= pack_time(&buf); f_type= item->field_type(); // for Item_cache_int below. } break; diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index feae39e1509..7ec41299ed7 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -2293,7 +2293,8 @@ void Item_char_typecast::fix_length_and_dec() bool Item_time_typecast::get_date(MYSQL_TIME *ltime, uint fuzzy_date) { - bool res= get_arg0_time(ltime); + if (get_arg0_time(ltime)) + return 1; /* MYSQL_TIMESTAMP_TIME value can have non-zero day part, which we should not lose. @@ -2301,16 +2302,17 @@ bool Item_time_typecast::get_date(MYSQL_TIME *ltime, uint fuzzy_date) if (ltime->time_type != MYSQL_TIMESTAMP_TIME) ltime->year= ltime->month= ltime->day= 0; ltime->time_type= MYSQL_TIMESTAMP_TIME; - return res; + return 0; } bool Item_date_typecast::get_date(MYSQL_TIME *ltime, uint fuzzy_date) { - bool res= get_arg0_date(ltime, TIME_FUZZY_DATE); + if (get_arg0_date(ltime, TIME_FUZZY_DATE)) + return 1; ltime->hour= ltime->minute= ltime->second= ltime->second_part= 0; ltime->time_type= MYSQL_TIMESTAMP_DATE; - return res; + return 0; } bool Item_datetime_typecast::get_date(MYSQL_TIME *ltime, uint fuzzy_date) diff --git a/sql/time.cc b/sql/time.cc index 7d23a795413..2badb77d14b 100644 --- a/sql/time.cc +++ b/sql/time.cc @@ -726,17 +726,17 @@ void make_truncated_value_warning(THD *thd, MYSQL_ERROR::enum_warning_level leve if (field_name) cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff), ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD), - type_str, str.c_ptr(), field_name, + type_str, str.c_ptr_safe(), field_name, (ulong) thd->row_count); else { if (time_type > MYSQL_TIMESTAMP_ERROR) cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff), ER(ER_TRUNCATED_WRONG_VALUE), - type_str, str.c_ptr()); + type_str, str.c_ptr_safe()); else cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff), - ER(ER_WRONG_VALUE), type_str, str.c_ptr()); + ER(ER_WRONG_VALUE), type_str, str.c_ptr_safe()); } push_warning(thd, level, ER_TRUNCATED_WRONG_VALUE, warn_buff); -- cgit v1.2.1 From 3c110d4963c051c5239cbe0d7cebdab943b7a5b6 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 8 Mar 2011 10:14:43 +0100 Subject: lp:731103 Assertion `maybe_null && item->null_value' failed with ORDER BY LAST_DAY() Item_func_last_day did not set mayby_null=1 --- sql/item_timefunc.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sql') diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index e2e65142902..36be86cd89c 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -862,4 +862,9 @@ public: 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); + void fix_length_and_dec() + { + maybe_null=1; + Item_datefunc::fix_length_and_dec(); + } }; -- cgit v1.2.1 From edad8ed9e8904fa528e6d19809ebcc05c17c47cd Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 8 Mar 2011 19:41:58 +0100 Subject: lp:731124 Loss of precision on DISTINCT many changes: * NOT_FIXED_DEC now create hires fields, not old ones. As a result, temp tables preserve microseconds (on DISTINCT, GROUP BY) * I_S tables force decimals=0 on temporal types (backward compatibility) * Item_func_coalesce calculates decimals for temporal types * no precision for TIME/DATETIME in CAST means 0, not NOT_FIXED_DEC * addtime/timediff calculate decimals from arguments (not NOT_FIXED_DEC) sql/field.h: NOT_FIXED_DEC now create hires fields, not old ones sql/item.h: force decimals=0 for I_S tables sql/item_cmpfunc.cc: Item_func_coalesce calculates decimals for temporal types sql/item_create.cc: no precision for TIME/DATETIME in CAST means 0, not NOT_FIXED_DEC sql/item_timefunc.cc: addtime calculates decimals from arguments (not NOT_FIXED_DEC) sql/item_timefunc.h: timediff calculates decimals from arguments (not NOT_FIXED_DEC) --- sql/field.h | 27 +++++++++++++++------------ sql/item.h | 2 +- sql/item_cmpfunc.cc | 7 +++++++ sql/item_create.cc | 2 +- sql/item_timefunc.cc | 2 +- sql/item_timefunc.h | 2 +- 6 files changed, 26 insertions(+), 16 deletions(-) (limited to 'sql') diff --git a/sql/field.h b/sql/field.h index 9475e28bc0f..c955981531a 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1501,12 +1501,13 @@ 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) + if (dec==0) 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); + if (dec == NOT_FIXED_DEC) + dec= MAX_DATETIME_PRECISION; + return new Field_timestamp_hires(ptr, null_ptr, null_bit, unireg_check, + field_name, share, dec, cs); } static inline Field_time * @@ -1514,12 +1515,13 @@ 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) + if (dec == 0) 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); + if (dec == NOT_FIXED_DEC) + dec= MAX_DATETIME_PRECISION; + return new Field_time_hires(ptr, null_ptr, null_bit, + unireg_check, field_name, dec, cs); } static inline Field_datetime * @@ -1527,12 +1529,13 @@ 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) + if (dec == 0) 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); + if (dec == NOT_FIXED_DEC) + dec= MAX_DATETIME_PRECISION; + return new Field_datetime_hires(ptr, null_ptr, null_bit, + unireg_check, field_name, dec, cs); } class Field_string :public Field_longstr { diff --git a/sql/item.h b/sql/item.h index 0be8312750d..af0f3d1c024 100644 --- a/sql/item.h +++ b/sql/item.h @@ -2075,7 +2075,7 @@ public: 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) - { } + { decimals= 0; } enum_field_types field_type() const { return date_time_field_type; } }; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index dd47e4ab89f..2749270112d 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -2920,6 +2920,13 @@ void Item_func_coalesce::fix_length_and_dec() { cached_field_type= agg_field_type(args, arg_count); agg_result_type(&hybrid_type, args, arg_count); + Item_result cmp_type; + agg_cmp_type(&cmp_type, args, arg_count); + if (cmp_type == TIME_RESULT) + { + count_real_length(); + return; + } switch (hybrid_type) { case STRING_RESULT: count_only_length(); diff --git a/sql/item_create.cc b/sql/item_create.cc index ac1102fabbb..abf32543494 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -5091,7 +5091,7 @@ create_func_cast(THD *thd, Item *a, Cast_target cast_type, } } else - len= NOT_FIXED_DEC; + len= 0; if (cast_type == ITEM_CAST_TIME) res= new (thd->mem_root) Item_time_typecast(a, len); diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 7ec41299ed7..813f4d61f2f 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -2379,7 +2379,7 @@ void Item_func_add_time::fix_length_and_dec() { enum_field_types arg0_field_type; max_length= MAX_DATETIME_WIDTH; - decimals= NOT_FIXED_DEC; + decimals= max(args[0]->decimals, args[1]->decimals); maybe_null= 1; /* diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index 36be86cd89c..b28daed202b 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -765,7 +765,7 @@ public: const char *func_name() const { return "timediff"; } void fix_length_and_dec() { - decimals= NOT_FIXED_DEC; + decimals= max(args[0]->decimals, args[1]->decimals); Item_timefunc::fix_length_and_dec(); maybe_null= 1; } -- cgit v1.2.1 From 862c42dda52e14f2c47c414d83bcc22cc31cf6d8 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 8 Mar 2011 22:01:40 +0100 Subject: lp:731229 Different results depending on table access method with TIME column and CURDATE() issue a warning when a datetime is truncated for storing in a TIME column. this automatically prevents optimizer from using indexes when comparing time column to a datetime --- sql/field.cc | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'sql') diff --git a/sql/field.cc b/sql/field.cc index 32ac51a1e39..f32f7d3c214 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -5197,6 +5197,14 @@ int Field_temporal::store_TIME_with_warning(MYSQL_TIME *ltime, was_cut|= MYSQL_TIME_WARN_TRUNCATED; ret= 3; } + else if (temporal_type() == MYSQL_TIMESTAMP_TIME && + (ltime->year || ltime->month)) + { + ltime->year= ltime->month= ltime->day= 0; + trunc_level= MYSQL_ERROR::WARN_LEVEL_NOTE; + was_cut|= MYSQL_TIME_WARN_TRUNCATED; + ret= 3; + } /* error code logic: @@ -5207,7 +5215,6 @@ int Field_temporal::store_TIME_with_warning(MYSQL_TIME *ltime, 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, @@ -5330,10 +5337,6 @@ int Field_time::store(const char *from,uint len,CHARSET_INFO *cs) int was_cut; int have_smth_to_conv= str_to_datetime(from, len, <ime, TIME_TIME_ONLY, &was_cut) > MYSQL_TIMESTAMP_ERROR; - - if (ltime.month) - ltime.day=0; - ltime.month= ltime.year= 0; return store_TIME_with_warning(<ime, &str, was_cut, have_smth_to_conv); } @@ -5345,11 +5348,6 @@ int Field_time::store_time(MYSQL_TIME *ltime, timestamp_type time_type) 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); } -- cgit v1.2.1 From 3a0774b1b697f156aafd7debf697aea7715c8fa3 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 9 Mar 2011 09:20:23 +0100 Subject: lp:731089 Crash in Field_time_hires::pack_length on CREATE TABLE TIME(3) add missing size_of() methods to new Field* classes --- sql/field.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sql') diff --git a/sql/field.h b/sql/field.h index c955981531a..dc24bc3be3d 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1255,6 +1255,7 @@ public: 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); } + uint size_of() const { return sizeof(*this); } }; @@ -1419,6 +1420,7 @@ public: uint32 pack_length() const; void sql_type(String &str) const; void make_field(Send_field *); + uint size_of() const { return sizeof(*this); } }; class Field_datetime :public Field_temporal { @@ -1494,6 +1496,7 @@ public: 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); } + uint size_of() const { return sizeof(*this); } }; static inline Field_timestamp * -- cgit v1.2.1 From 4f1dbac62706afb40be110b54daaa0bc4905eca9 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 9 Mar 2011 11:59:47 +0100 Subject: lp:731815 Crash/valgrind warning Item::send with 5.1-micro Two problems: * Item_func_convert_tz() did not tell args[0] that it needs TIME_NO_ZERO_IN_DATE result * Item_func_timediff did not respect fuzzy_date limitations, truncated seconds when casting to signed long, resulting in invalid time value (hours, seconds = (uint)-1). --- sql/item_timefunc.cc | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 813f4d61f2f..1575c1345af 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -1872,7 +1872,8 @@ bool Item_func_convert_tz::get_date(MYSQL_TIME *ltime, to_tz_cached= args[2]->const_item(); } - if (from_tz==0 || to_tz==0 || get_arg0_date(ltime, TIME_NO_ZERO_DATE)) + if (from_tz==0 || to_tz==0 || + get_arg0_date(ltime, TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE)) { null_value= 1; return 1; @@ -2534,6 +2535,9 @@ bool Item_func_timediff::get_date(MYSQL_TIME *ltime, uint fuzzy_date) l_time1.time_type != l_time2.time_type) goto null_date; + if (fuzzy_date & TIME_NO_ZERO_IN_DATE) + goto null_date; + if (l_time1.neg != l_time2.neg) l_sign= -l_sign; @@ -2550,8 +2554,12 @@ bool Item_func_timediff::get_date(MYSQL_TIME *ltime, uint fuzzy_date) if (l_time1.neg && (seconds || microseconds)) l_time3.neg= 1-l_time3.neg; // Swap sign of result + set_if_smaller(seconds, INT_MAX32); calc_time_from_sec(&l_time3, (long) seconds, microseconds); + if ((fuzzy_date & TIME_NO_ZERO_DATE) && (seconds == 0) && (microseconds == 0)) + goto null_date; + *ltime= l_time3; check_time_range(ltime, &was_cut); -- cgit v1.2.1 From 8f6cb92581e6640cba8cd7b47cf94e4270e73650 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 17 Mar 2011 11:54:36 +0100 Subject: lp:736358 Unexpected increased timestamp resolution with UNION partial fix --- sql/item_timefunc.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sql') diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index b28daed202b..df4491e61e6 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -699,6 +699,8 @@ public: collation.set(&my_charset_bin); maybe_null= 1; max_length= MAX_TIME_WIDTH; + if (decimals == NOT_FIXED_DEC) + decimals= args[0]->decimals; if (decimals && decimals != NOT_FIXED_DEC) max_length+= min(decimals, MAX_SEC_PART_DIGITS) + 1; } -- cgit v1.2.1 From 1ac6371a48a71835d532fda6d986855312bf0dc2 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 17 Mar 2011 14:13:03 +0100 Subject: * fix for ALTER TABLE ... MODIFY timestamp->timestamp. Use dedicated do_field_temporal() for Copy_field. * check_time_range() needs to know TIME's precision to use the correct max value. --- sql/field.cc | 2 +- sql/field_conv.cc | 12 +++++++++++- sql/item_timefunc.cc | 4 ++-- 3 files changed, 14 insertions(+), 4 deletions(-) (limited to 'sql') diff --git a/sql/field.cc b/sql/field.cc index f32f7d3c214..16b250ed63c 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -5348,7 +5348,7 @@ int Field_time::store_time(MYSQL_TIME *ltime, timestamp_type time_type) Lazy_string_time str(ltime); int was_cut= 0; - int have_smth_to_conv= !check_time_range(&l_time, &was_cut); + int have_smth_to_conv= !check_time_range(&l_time, decimals(), &was_cut); return store_TIME_with_warning(&l_time, &str, was_cut, have_smth_to_conv); } diff --git a/sql/field_conv.cc b/sql/field_conv.cc index a4fca6f8ad7..e4da3f114ef 100644 --- a/sql/field_conv.cc +++ b/sql/field_conv.cc @@ -365,6 +365,14 @@ static void do_field_decimal(Copy_field *copy) } +static void do_field_temporal(Copy_field *copy) +{ + MYSQL_TIME ltime; + copy->from_field->get_date(<ime, TIME_FUZZY_DATE); + copy->to_field->store_time(<ime, ltime.time_type); +} + + /** string copy for single byte characters set when to string is shorter than from string. @@ -559,7 +567,7 @@ void Copy_field::set(uchar *to,Field *from) /* To do: - If 'save\ is set to true and the 'from' is a blob field, do_copy is set to + If 'save' is set to true and the 'from' is a blob field, do_copy is set to do_save_blob rather than do_conv_blob. The only differences between them appears to be: @@ -657,6 +665,8 @@ Copy_field::get_copy_func(Field *to,Field *from) return do_field_int; if (to->result_type() == DECIMAL_RESULT) return do_field_decimal; + if (to->cmp_type() == TIME_RESULT) + return do_field_temporal; // Check if identical fields if (from->result_type() == STRING_RESULT) { diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 1575c1345af..b27e9d72cfc 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -2482,7 +2482,7 @@ bool Item_func_add_time::get_date(MYSQL_TIME *ltime, uint fuzzy_date) MYSQL_TIME copy= *ltime; Lazy_string_time str(©); - check_time_range(ltime, &was_cut); + check_time_range(ltime, decimals, &was_cut); if (was_cut) make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, &str, MYSQL_TIMESTAMP_TIME, NullS); @@ -2561,7 +2561,7 @@ bool Item_func_timediff::get_date(MYSQL_TIME *ltime, uint fuzzy_date) goto null_date; *ltime= l_time3; - check_time_range(ltime, &was_cut); + check_time_range(ltime, decimals, &was_cut); if (was_cut) make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, -- cgit v1.2.1 From b37d333e389d64e236f29b85f7d5c8ef4c3a9e54 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 17 Mar 2011 15:57:04 +0100 Subject: lp:736791 Crash in make_truncated_value_warningwith LEAST()/GREATEST/COALESCE and a test case for lp:736370 Datetime functions in subquery context cause wrong result --- sql/item_func.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/item_func.cc b/sql/item_func.cc index b37156efa02..821341aa82d 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -2221,6 +2221,7 @@ void Item_func_min_max::fix_length_and_dec() decimals=0; max_length=0; maybe_null=0; + thd= current_thd; cmp_type=args[0]->result_type(); for (uint i=0 ; i < arg_count ; i++) @@ -2240,8 +2241,6 @@ void Item_func_min_max::fix_length_and_dec() if (cmp_type == STRING_RESULT) { agg_arg_charsets(collation, args, arg_count, MY_COLL_CMP_CONV, 1); - if (compare_as_dates) - thd= current_thd; } else if ((cmp_type == DECIMAL_RESULT) || (cmp_type == INT_RESULT)) max_length= my_decimal_precision_to_length_no_truncation(max_int_part + -- cgit v1.2.1 From ddb7d04d6e6352d3a4871cdf25aeefc89cb511a5 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 17 Mar 2011 18:19:47 +0100 Subject: lp:736370 Datetime functions in subquery context cause wrong result and bogus warnings in mysql-5.1-micro Don't cache temporal value in an Item_string, it is compared differently. --- sql/item.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index 7f7e39c9dac..92df6bb0953 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -6880,11 +6880,12 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item) Item *new_item= NULL; if (item->basic_const_item()) return; // Can't be better - Item_result res_type=item_cmp_type(comp_item->result_type(), - item->result_type()); + Item_result res_type=item_cmp_type(comp_item->cmp_type(), item->cmp_type()); char *name=item->name; // Alloced by sql_alloc switch (res_type) { + case TIME_RESULT: // will be handled by get_datetime_value() + break; case STRING_RESULT: { char buff[MAX_FIELD_WIDTH]; -- cgit v1.2.1 From cc392275f4a15198d805f3e482bb0ec7751a22ee Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 17 Mar 2011 22:04:45 +0100 Subject: lp:737092 Assertion `item->null_value' failed in get_datetime_value in 5.1-micro Implement Item_func_coalesce::get_date() --- sql/item_cmpfunc.cc | 15 +++++++++++++++ sql/item_cmpfunc.h | 1 + 2 files changed, 16 insertions(+) (limited to 'sql') diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 2749270112d..24a117ef8ca 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -2901,6 +2901,21 @@ double Item_func_coalesce::real_op() } +bool Item_func_coalesce::get_date(MYSQL_TIME *ltime,uint fuzzydate) +{ + DBUG_ASSERT(fixed == 1); + null_value= 0; + for (uint i= 0; i < arg_count; i++) + { + bool res= args[i]->get_date(ltime, fuzzydate); + if (!args[i]->null_value) + return res; + } + null_value=1; + return 0; +} + + my_decimal *Item_func_coalesce::decimal_op(my_decimal *decimal_value) { DBUG_ASSERT(fixed == 1); diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index ec5ba8bb616..d86ae7422c6 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -675,6 +675,7 @@ public: const char *func_name() const { return "coalesce"; } table_map not_null_tables() const { return 0; } enum_field_types field_type() const { return cached_field_type; } + bool get_date(MYSQL_TIME *ltime,uint fuzzydate); }; -- cgit v1.2.1 From e77d03339183bd81ab5a5bc36c92b8d46ea6f561 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 17 Mar 2011 22:38:34 +0100 Subject: lp:737104 Crash in DTCollation::set in 5.1-micro and a different fix for lp:736370 cache temporal expression in Item_cache_int, not in Item_string. invoke get_datetime_value() to create a correct Item_cache_int. Implement Item_cache_int::clone, as it's a proper constant --- sql/item.cc | 9 ++++++++- sql/item.h | 6 ++++++ 2 files changed, 14 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index 92df6bb0953..40e23f524db 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -6884,8 +6884,15 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item) char *name=item->name; // Alloced by sql_alloc switch (res_type) { - case TIME_RESULT: // will be handled by get_datetime_value() + case TIME_RESULT: + { + bool is_null; + Item **ref_copy= ref; + get_datetime_value(thd, &ref_copy, &new_item, comp_item, &is_null); + if (is_null) + new_item= new Item_null(name); break; + } case STRING_RESULT: { char buff[MAX_FIELD_WIDTH]; diff --git a/sql/item.h b/sql/item.h index af0f3d1c024..d45df4ebe53 100644 --- a/sql/item.h +++ b/sql/item.h @@ -3035,6 +3035,12 @@ public: my_decimal *val_decimal(my_decimal *); enum Item_result result_type() const { return INT_RESULT; } bool cache_value(); + Item *clone_item() + { + Item_cache_int *item= new Item_cache_int(cached_field_type); + item->store(this, value); + return item; + } }; -- cgit v1.2.1 From eea264b283fd0f2383e93d463ba88ca325261b21 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 18 Mar 2011 13:43:33 +0100 Subject: lp:737111 Different behavior for TIMESTAMPADD with 0000-00-00 argument in 5.1-micro respect fuzzydate flags in Item_*::get_date() methods --- sql/field.cc | 7 +++++-- sql/item_timefunc.cc | 6 +++--- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'sql') diff --git a/sql/field.cc b/sql/field.cc index 16b250ed63c..4ff9f83f5cc 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -5869,8 +5869,11 @@ bool Field_newdate::get_date(MYSQL_TIME *ltime,uint fuzzydate) ltime->year= (tmp >> 9); ltime->time_type= MYSQL_TIMESTAMP_DATE; ltime->hour= ltime->minute= ltime->second= ltime->second_part= ltime->neg= 0; - return ((!(fuzzydate & TIME_FUZZY_DATE) && (!ltime->month || !ltime->day)) ? - 1 : 0); + if ((fuzzydate & TIME_NO_ZERO_DATE) && !tmp) + return 1; + if (!(fuzzydate & TIME_FUZZY_DATE) && (!ltime->month || !ltime->day)) + return 1; + return 0; } diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index b27e9d72cfc..6ca15873199 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -2309,7 +2309,7 @@ bool Item_time_typecast::get_date(MYSQL_TIME *ltime, uint fuzzy_date) bool Item_date_typecast::get_date(MYSQL_TIME *ltime, uint fuzzy_date) { - if (get_arg0_date(ltime, TIME_FUZZY_DATE)) + if (get_arg0_date(ltime, fuzzy_date & ~TIME_TIME_ONLY)) return 1; ltime->hour= ltime->minute= ltime->second= ltime->second_part= 0; ltime->time_type= MYSQL_TIMESTAMP_DATE; @@ -2318,11 +2318,11 @@ bool Item_date_typecast::get_date(MYSQL_TIME *ltime, uint fuzzy_date) bool Item_datetime_typecast::get_date(MYSQL_TIME *ltime, uint fuzzy_date) { - if (get_arg0_date(ltime, TIME_FUZZY_DATE)) + if (get_arg0_date(ltime, fuzzy_date & ~TIME_TIME_ONLY)) return 1; /* - ltime is valid MYSQL_TYPE_TIME ( according to fuzzy_date). + 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) -- cgit v1.2.1 From ffdf98f2b8b51d033b379ee2b32eea624bc93a18 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 18 Mar 2011 13:50:39 +0100 Subject: number to time comparison --- sql/item_cmpfunc.cc | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 24a117ef8ca..2cbcbbdb55f 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -870,9 +870,14 @@ get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg, { MYSQL_TIME buf; int was_cut; + longlong res; - if (number_to_datetime(value, &buf, TIME_INVALID_DATES|TIME_FUZZY_DATE, - &was_cut) == -1) + if (t_type == MYSQL_TIMESTAMP_TIME) + res= number_to_time(value, &buf, &was_cut); + else + res= number_to_datetime(value, &buf, TIME_INVALID_DATES|TIME_FUZZY_DATE, + &was_cut); + if (res == -1) { const Lazy_string_num str(value); make_truncated_value_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, -- cgit v1.2.1 From 79f6e6f681378357b680bba74b767408070fef7e Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 18 Mar 2011 14:52:20 +0100 Subject: lp:737458 Casting dates and times into integers works differently in 5.1-micro better default for Field::cast_to_int_type() --- sql/field.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/field.h b/sql/field.h index dc24bc3be3d..f40a4e2fb3c 100644 --- a/sql/field.h +++ b/sql/field.h @@ -149,7 +149,7 @@ public: virtual bool str_needs_quotes() { return FALSE; } virtual Item_result result_type () const=0; virtual Item_result cmp_type () const { return result_type(); } - virtual Item_result cast_to_int_type () const { return result_type(); } + virtual Item_result cast_to_int_type () const { return cmp_type(); } static bool type_can_have_key_part(enum_field_types); static enum_field_types field_type_merge(enum_field_types, enum_field_types); static Item_result result_merge_type(enum_field_types); -- cgit v1.2.1 From 340a29ecd9b96d28b1e79ca97246fdc135b6d2a9 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 18 Mar 2011 19:23:32 +0100 Subject: lp:737450 Second Assertion `item->null_value' failed in 5.1-micro implement Item_func_min_max::get_date() --- sql/item_func.cc | 14 ++++++-------- sql/item_func.h | 2 +- 2 files changed, 7 insertions(+), 9 deletions(-) (limited to 'sql') diff --git a/sql/item_func.cc b/sql/item_func.cc index 821341aa82d..3e539585dde 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -2259,9 +2259,6 @@ void Item_func_min_max::fix_length_and_dec() /* Compare item arguments in the DATETIME context. - SYNOPSIS - cmp_datetimes() - DESCRIPTION Compare item arguments as DATETIME values and return the index of the least/greatest argument in the arguments array. @@ -2273,9 +2270,10 @@ void Item_func_min_max::fix_length_and_dec() 0 Otherwise */ -bool Item_func_min_max::cmp_datetimes(MYSQL_TIME *ltime) +bool Item_func_min_max::get_date(MYSQL_TIME *ltime, uint fuzzy_date) { longlong UNINIT_VAR(min_max); + DBUG_ASSERT(fixed == 1); for (uint i=0; i < arg_count ; i++) { @@ -2309,7 +2307,7 @@ String *Item_func_min_max::val_str(String *str) if (compare_as_dates) { MYSQL_TIME ltime; - if (cmp_datetimes(<ime)) + if (get_date(<ime, TIME_FUZZY_DATE)) return 0; char buf[MAX_DATE_STRING_REP_LENGTH]; @@ -2383,7 +2381,7 @@ double Item_func_min_max::val_real() if (compare_as_dates) { MYSQL_TIME ltime; - if (cmp_datetimes(<ime)) + if (get_date(<ime, TIME_FUZZY_DATE)) return 0; return TIME_to_double(<ime); @@ -2412,7 +2410,7 @@ longlong Item_func_min_max::val_int() if (compare_as_dates) { MYSQL_TIME ltime; - if (cmp_datetimes(<ime)) + if (get_date(<ime, TIME_FUZZY_DATE)) return 0; return TIME_to_ulonglong(<ime); @@ -2442,7 +2440,7 @@ my_decimal *Item_func_min_max::val_decimal(my_decimal *dec) if (compare_as_dates) { MYSQL_TIME ltime; - if (cmp_datetimes(<ime)) + if (get_date(<ime, TIME_FUZZY_DATE)) return 0; return date2my_decimal(<ime, dec); diff --git a/sql/item_func.h b/sql/item_func.h index d0f5d8d8d8f..cd2829fb5a7 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -769,9 +769,9 @@ public: longlong val_int(); String *val_str(String *); my_decimal *val_decimal(my_decimal *); + bool get_date(MYSQL_TIME *res, uint fuzzy_date); void fix_length_and_dec(); enum Item_result result_type () const { return cmp_type; } - bool cmp_datetimes(MYSQL_TIME *ltime); enum_field_types field_type() const { return cached_field_type; } }; -- cgit v1.2.1 From 47b201ab45055b7886fc4bf40e9cafc620406cf0 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 18 Mar 2011 19:29:52 +0100 Subject: lp:737474 Wrong result with DAY(COALESCE(NULL)) in 5.1-micro fix the return value of Item_func_coalesce::get_date() --- sql/item_cmpfunc.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 2cbcbbdb55f..925582be542 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -2917,7 +2917,7 @@ bool Item_func_coalesce::get_date(MYSQL_TIME *ltime,uint fuzzydate) return res; } null_value=1; - return 0; + return 1; } -- cgit v1.2.1 From 14e4f8032b1a378280c5be74dd087bfa5ebef27b Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 18 Mar 2011 19:45:00 +0100 Subject: lp:737496 Assertion `(was_cut & 1) == 0' failed in Field_temporal::store_TIME_with_warning() in 5.1-micro fix incorrect assert --- sql/field.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/field.cc b/sql/field.cc index 4ff9f83f5cc..f7675b82a99 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -5189,15 +5189,16 @@ int Field_temporal::store_TIME_with_warning(MYSQL_TIME *ltime, was_cut= MYSQL_TIME_WARN_TRUNCATED; ret= 1; } - else if (temporal_type() == MYSQL_TIMESTAMP_DATE && + else if (!(was_cut & MYSQL_TIME_WARN_TRUNCATED) && + temporal_type() == MYSQL_TIMESTAMP_DATE && (ltime->hour || ltime->minute || ltime->second || ltime->second_part)) { - DBUG_ASSERT((was_cut & MYSQL_TIME_WARN_TRUNCATED) == 0); trunc_level= MYSQL_ERROR::WARN_LEVEL_NOTE; was_cut|= MYSQL_TIME_WARN_TRUNCATED; ret= 3; } - else if (temporal_type() == MYSQL_TIMESTAMP_TIME && + else if (!(was_cut & MYSQL_TIME_WARN_TRUNCATED) && + temporal_type() == MYSQL_TIMESTAMP_TIME && (ltime->year || ltime->month)) { ltime->year= ltime->month= ltime->day= 0; -- cgit v1.2.1 From 8cda55a7dd779a2eaa19ddaa25f10d1c84faa6ba Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 19 Mar 2011 14:54:46 +0100 Subject: lp:738067 Crash in get_datetime_value() in 5.1-micro --- sql/item_func.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sql') diff --git a/sql/item_func.cc b/sql/item_func.cc index 3e539585dde..9ee239b702b 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -2274,6 +2274,8 @@ bool Item_func_min_max::get_date(MYSQL_TIME *ltime, uint fuzzy_date) { longlong UNINIT_VAR(min_max); DBUG_ASSERT(fixed == 1); + if (!compare_as_dates) + return Item_func::get_date(ltime, fuzzy_date); for (uint i=0; i < arg_count ; i++) { -- cgit v1.2.1 From 9daa6c6e722233f6af51a6590d25f730fa17ac06 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 19 Mar 2011 15:19:05 +0100 Subject: lp:738091 cast(timestamp() AS time returns NULL for 0000-00-00 00:00:00 in 5.1-micro --- sql/field.cc | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) (limited to 'sql') diff --git a/sql/field.cc b/sql/field.cc index f7675b82a99..352dd187bb9 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -5870,10 +5870,10 @@ bool Field_newdate::get_date(MYSQL_TIME *ltime,uint fuzzydate) ltime->year= (tmp >> 9); ltime->time_type= MYSQL_TIMESTAMP_DATE; ltime->hour= ltime->minute= ltime->second= ltime->second_part= ltime->neg= 0; - if ((fuzzydate & TIME_NO_ZERO_DATE) && !tmp) - return 1; - if (!(fuzzydate & TIME_FUZZY_DATE) && (!ltime->month || !ltime->day)) - return 1; + if (!tmp) + return fuzzydate & TIME_NO_ZERO_DATE; + if (!ltime->month || !ltime->day) + return !(fuzzydate & TIME_FUZZY_DATE); return 0; } @@ -6003,7 +6003,11 @@ bool Field_datetime::get_date(MYSQL_TIME *ltime, uint fuzzydate) ltime->day= (int) (part1%100); ltime->month= (int) (part1/100%100); ltime->year= (int) (part1/10000); - return (!(fuzzydate & TIME_FUZZY_DATE) && (!ltime->month || !ltime->day)) ? 1 : 0; + if (!tmp) + return fuzzydate & TIME_NO_ZERO_DATE; + if (!ltime->month || !ltime->day) + return !(fuzzydate & TIME_FUZZY_DATE); + return 0; } int Field_datetime::cmp(const uchar *a_ptr, const uchar *b_ptr) @@ -6110,7 +6114,11 @@ 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; + if (!packed) + return fuzzydate & TIME_NO_ZERO_DATE; + if (!ltime->month || !ltime->day) + return !(fuzzydate & TIME_FUZZY_DATE); + return 0; } uint32 Field_datetime_hires::pack_length() const -- cgit v1.2.1 From c5547dcff230941434ddac1369c4ddf19d0b482b Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 23 Mar 2011 13:31:06 +0100 Subject: lp:740173 5.1-micro reports incorrect Length metadata for TIME expressions --- sql/item_timefunc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index df4491e61e6..68fd34aa29e 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -698,7 +698,7 @@ public: { collation.set(&my_charset_bin); maybe_null= 1; - max_length= MAX_TIME_WIDTH; + max_length= MIN_TIME_WIDTH; if (decimals == NOT_FIXED_DEC) decimals= args[0]->decimals; if (decimals && decimals != NOT_FIXED_DEC) -- cgit v1.2.1 From 9b38137a964fe96f8f6ec63572d0556498b1347a Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 23 Mar 2011 14:10:11 +0100 Subject: lp:740958 5.1-micro can not handle prepared statements with timestamps involving nanoseconds fix a typo in the boundary test. simplify make_truncated_value_warning call. --- sql/item.cc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index 40e23f524db..6105aaa0ed1 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -2756,12 +2756,11 @@ void Item_param::set_time(MYSQL_TIME *tm, timestamp_type time_type, value.time.day > 31 || (time_type != MYSQL_TIMESTAMP_TIME && value.time.hour > 23) || value.time.minute > 59 || value.time.second > 59 || - value.time.second_part >= MAX_SEC_PART_VALUE) + value.time.second_part > MAX_SEC_PART_VALUE) { - char buff[MAX_DATE_STRING_REP_LENGTH]; - uint length= my_TIME_to_str(&value.time, buff, decimals); + Lazy_string_time str(tm); make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, - buff, length, time_type, 0); + &str, time_type, 0); set_zero_time(&value.time, MYSQL_TIMESTAMP_ERROR); } -- cgit v1.2.1 From 259def9f2f7865b6a5d051700fd6b40df237aeab Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 23 Mar 2011 16:14:34 +0100 Subject: lp:740958 5.1-micro can not handle prepared statements with timestamps involving nanoseconds fix a typo in the boundary test. simplify make_truncated_value_warning call. --- sql/item.cc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index 40e23f524db..ea69f60bc9c 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -2756,12 +2756,11 @@ void Item_param::set_time(MYSQL_TIME *tm, timestamp_type time_type, value.time.day > 31 || (time_type != MYSQL_TIMESTAMP_TIME && value.time.hour > 23) || value.time.minute > 59 || value.time.second > 59 || - value.time.second_part >= MAX_SEC_PART_VALUE) + value.time.second_part > MAX_SEC_PART_VALUE) { - char buff[MAX_DATE_STRING_REP_LENGTH]; - uint length= my_TIME_to_str(&value.time, buff, decimals); + Lazy_string_time str(&value.time); make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, - buff, length, time_type, 0); + &str, time_type, 0); set_zero_time(&value.time, MYSQL_TIMESTAMP_ERROR); } -- cgit v1.2.1 From e5591e3e1bacbb38ae0c039c46873e3164f79964 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Thu, 24 Mar 2011 12:30:03 +0100 Subject: Fix compilation on Windows: - Fixes for type-conversion (time_t is not interchangeable with my_time_t on Windows as time_t s 64 bit while my_time_t is long) - BIGENDIAN-> ARCH_BIGENDIAN . BIGENDIAN constant is defined in winsock2.h (as 0) - added explicit cast for longlong->double conversion in sql/item.h (fixed many warnings) Also, HAVE_SNPRINTF is now defined and snprintf is defined to _snprintf in config-win.h --- sql/field.h | 24 ++++++++++++------------ sql/item.h | 2 +- sql/item_timefunc.cc | 2 +- sql/log_event.cc | 3 ++- 4 files changed, 16 insertions(+), 15 deletions(-) (limited to 'sql') diff --git a/sql/field.h b/sql/field.h index f40a4e2fb3c..8eacfcd404f 100644 --- a/sql/field.h +++ b/sql/field.h @@ -22,10 +22,10 @@ #pragma interface /* gcc class implementation */ #endif -#ifdef WORDS_BIGENDIAN -#define BIGENDIAN 1 +#ifdef WORDS_ARCH_BIGENDIAN +#define ARCH_BIGENDIAN 1 #else -#define BIGENDIAN 0 +#define ARCH_BIGENDIAN 0 #endif #define NOT_FIXED_DEC 31 @@ -548,12 +548,12 @@ protected: bool low_byte_first_from, bool low_byte_first_to) { int32 val; - if (BIGENDIAN && low_byte_first_from) + if (ARCH_BIGENDIAN && low_byte_first_from) val = sint4korr(from); else longget(val, from); - if (BIGENDIAN && low_byte_first_to) + if (ARCH_BIGENDIAN && low_byte_first_to) int4store(to, val); else longstore(to, val); @@ -566,12 +566,12 @@ protected: bool low_byte_first_from, bool low_byte_first_to) { int64 val; - if (BIGENDIAN && low_byte_first_from) + if (ARCH_BIGENDIAN && low_byte_first_from) val = sint8korr(from); else longlongget(val, from); - if (BIGENDIAN && low_byte_first_to) + if (ARCH_BIGENDIAN && low_byte_first_to) int8store(to, val); else longlongstore(to, val); @@ -883,12 +883,12 @@ public: uint max_length, bool low_byte_first) { int16 val; - if (BIGENDIAN && table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && table->s->db_low_byte_first) val = sint2korr(from); else shortget(val, from); - if (BIGENDIAN && low_byte_first) + if (ARCH_BIGENDIAN && low_byte_first) int2store(to, val); else shortstore(to, val); @@ -899,12 +899,12 @@ public: uint param_data, bool low_byte_first) { int16 val; - if (BIGENDIAN && low_byte_first) + if (ARCH_BIGENDIAN && low_byte_first) val = sint2korr(from); else shortget(val, from); - if (BIGENDIAN && table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && table->s->db_low_byte_first) int2store(to, val); else shortstore(to, val); @@ -1200,7 +1200,7 @@ public: virtual long get_timestamp(ulong *sec_part) const; virtual void store_TIME(my_time_t timestamp, ulong sec_part) { - if (BIGENDIAN && table && table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && table && table->s->db_low_byte_first) int4store(ptr,timestamp); else longstore(ptr,(uint32) timestamp); diff --git a/sql/item.h b/sql/item.h index d45df4ebe53..866b3fcb4fc 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1786,7 +1786,7 @@ 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(); } + double val_real() { return (double)val_int(); } void set(longlong packed); }; diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 6ca15873199..4f9022cb579 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -86,7 +86,7 @@ static bool sec_to_time(double seconds, MYSQL_TIME *ltime) ltime->hour= (uint) (seconds/3600); ltime->minute= sec/60; ltime->second= sec % 60; - ltime->second_part= (ulong)((seconds - trunc(seconds))*1e6); + ltime->second_part= (ulong)((seconds - floor(seconds))*1e6); return 0; diff --git a/sql/log_event.cc b/sql/log_event.cc index 4abf56f70f3..8a0c8f93af3 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -2063,10 +2063,11 @@ void Log_event::print_base64(IO_CACHE* file, void Log_event::print_timestamp(IO_CACHE* file, time_t* ts) { struct tm *res; + time_t my_when= when; DBUG_ENTER("Log_event::print_timestamp"); if (!ts) { - ts = &when; + ts = &my_when; } res=localtime(ts); -- cgit v1.2.1 From fb5850c07f3025078a85126523a6a7c1b653857c Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 24 Mar 2011 15:55:52 +0100 Subject: fixes for funcs_1 suite --- sql/item.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index ea69f60bc9c..f28b14725c3 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -544,8 +544,6 @@ Item_result Item::cmp_type() const 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: @@ -558,6 +556,8 @@ Item_result Item::cmp_type() const case MYSQL_TYPE_BLOB: case MYSQL_TYPE_VAR_STRING: case MYSQL_TYPE_STRING: + case MYSQL_TYPE_ENUM: + case MYSQL_TYPE_SET: case MYSQL_TYPE_GEOMETRY: return STRING_RESULT; case MYSQL_TYPE_TIMESTAMP: -- cgit v1.2.1 From 1351170ef6b98e72d85405ed3adaac49b0606568 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 26 Mar 2011 11:59:34 +0100 Subject: lp:705210 Compiling with BUILD/compile-pentium64-debug fails --- sql/field.cc | 126 +++++++++++++++++++++++++-------------------------- sql/item_cmpfunc.cc | 2 +- sql/item_timefunc.cc | 2 +- sql/log_event.cc | 8 ++-- sql/log_event.h | 2 +- sql/slave.cc | 2 +- sql/sql_class.h | 8 ++-- 7 files changed, 75 insertions(+), 75 deletions(-) (limited to 'sql') diff --git a/sql/field.cc b/sql/field.cc index 352dd187bb9..fcb4e618fa6 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -3141,7 +3141,7 @@ 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; - if (BIGENDIAN && table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && table->s->db_low_byte_first) int2store(ptr, store_tmp); else shortstore(ptr, (short) store_tmp); @@ -3189,7 +3189,7 @@ int Field_short::store(double nr) else res=(int16) (int) nr; } - if (BIGENDIAN && table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && table->s->db_low_byte_first) int2store(ptr,res); else shortstore(ptr,res); @@ -3240,7 +3240,7 @@ int Field_short::store(longlong nr, bool unsigned_val) else res=(int16) nr; } - if (BIGENDIAN && table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && table->s->db_low_byte_first) int2store(ptr,res); else shortstore(ptr,res); @@ -3252,7 +3252,7 @@ double Field_short::val_real(void) { ASSERT_COLUMN_MARKED_FOR_READ; short j; - if (BIGENDIAN && table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && table->s->db_low_byte_first) j=sint2korr(ptr); else shortget(j,ptr); @@ -3263,7 +3263,7 @@ longlong Field_short::val_int(void) { ASSERT_COLUMN_MARKED_FOR_READ; short j; - if (BIGENDIAN && table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && table->s->db_low_byte_first) j=sint2korr(ptr); else shortget(j,ptr); @@ -3281,7 +3281,7 @@ String *Field_short::val_str(String *val_buffer, val_buffer->alloc(mlength); char *to=(char*) val_buffer->ptr(); short j; - if (BIGENDIAN && table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && table->s->db_low_byte_first) j=sint2korr(ptr); else shortget(j,ptr); @@ -3307,7 +3307,7 @@ bool Field_short::send_binary(Protocol *protocol) int Field_short::cmp(const uchar *a_ptr, const uchar *b_ptr) { short a,b; - if (BIGENDIAN && table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && table->s->db_low_byte_first) { a=sint2korr(a_ptr); b=sint2korr(b_ptr); @@ -3326,7 +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))) { - if (BIGENDIAN && !table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && !table->s->db_low_byte_first) { if (unsigned_flag) to[0] = ptr[0]; @@ -3556,7 +3556,7 @@ 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; - if (BIGENDIAN && table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && table->s->db_low_byte_first) int4store(ptr, store_tmp); else longstore(ptr, store_tmp); @@ -3604,7 +3604,7 @@ int Field_long::store(double nr) if (error) set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); - if (BIGENDIAN && table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && table->s->db_low_byte_first) int4store(ptr,res); else longstore(ptr,res); @@ -3653,7 +3653,7 @@ 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); - if (BIGENDIAN && table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && table->s->db_low_byte_first) int4store(ptr,res); else longstore(ptr,res); @@ -3665,7 +3665,7 @@ double Field_long::val_real(void) { ASSERT_COLUMN_MARKED_FOR_READ; int32 j; - if (BIGENDIAN && table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && table->s->db_low_byte_first) j=sint4korr(ptr); else longget(j,ptr); @@ -3678,7 +3678,7 @@ longlong Field_long::val_int(void) int32 j; /* See the comment in Field_long::store(long long) */ DBUG_ASSERT(table->in_use == current_thd); - if (BIGENDIAN && table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && table->s->db_low_byte_first) j=sint4korr(ptr); else longget(j,ptr); @@ -3695,7 +3695,7 @@ String *Field_long::val_str(String *val_buffer, val_buffer->alloc(mlength); char *to=(char*) val_buffer->ptr(); int32 j; - if (BIGENDIAN && table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && table->s->db_low_byte_first) j=sint4korr(ptr); else longget(j,ptr); @@ -3720,7 +3720,7 @@ bool Field_long::send_binary(Protocol *protocol) int Field_long::cmp(const uchar *a_ptr, const uchar *b_ptr) { int32 a,b; - if (BIGENDIAN && table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && table->s->db_low_byte_first) { a=sint4korr(a_ptr); b=sint4korr(b_ptr); @@ -3737,7 +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))) { - if (BIGENDIAN && !table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && !table->s->db_low_byte_first) { if (unsigned_flag) to[0] = ptr[0]; @@ -3790,7 +3790,7 @@ int Field_longlong::store(const char *from,uint len,CHARSET_INFO *cs) error= 1; else error= 0; - if (BIGENDIAN && table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && table->s->db_low_byte_first) int8store(ptr,tmp); else longlongstore(ptr,tmp); @@ -3838,7 +3838,7 @@ int Field_longlong::store(double nr) if (error) set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); - if (BIGENDIAN && table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && table->s->db_low_byte_first) int8store(ptr,res); else longlongstore(ptr,res); @@ -3865,7 +3865,7 @@ int Field_longlong::store(longlong nr, bool unsigned_val) } } - if (BIGENDIAN && table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && table->s->db_low_byte_first) int8store(ptr,nr); else longlongstore(ptr,nr); @@ -3877,7 +3877,7 @@ double Field_longlong::val_real(void) { ASSERT_COLUMN_MARKED_FOR_READ; longlong j; - if (BIGENDIAN && table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && table->s->db_low_byte_first) j=sint8korr(ptr); else longlongget(j,ptr); @@ -3895,7 +3895,7 @@ longlong Field_longlong::val_int(void) { ASSERT_COLUMN_MARKED_FOR_READ; longlong j; - if (BIGENDIAN && table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && table->s->db_low_byte_first) j=sint8korr(ptr); else longlongget(j,ptr); @@ -3912,7 +3912,7 @@ String *Field_longlong::val_str(String *val_buffer, val_buffer->alloc(mlength); char *to=(char*) val_buffer->ptr(); longlong j; - if (BIGENDIAN && table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && table->s->db_low_byte_first) j=sint8korr(ptr); else longlongget(j,ptr); @@ -3936,7 +3936,7 @@ bool Field_longlong::send_binary(Protocol *protocol) int Field_longlong::cmp(const uchar *a_ptr, const uchar *b_ptr) { longlong a,b; - if (BIGENDIAN && table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && table->s->db_low_byte_first) { a=sint8korr(a_ptr); b=sint8korr(b_ptr); @@ -3954,7 +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))) { - if (BIGENDIAN && !table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && !table->s->db_low_byte_first) { if (unsigned_flag) to[0] = ptr[0]; @@ -4004,7 +4004,7 @@ Field_real::pack(uchar *to, const uchar *from, { DBUG_ENTER("Field_real::pack"); DBUG_ASSERT(max_length >= pack_length()); - if (BIGENDIAN && low_byte_first != table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && low_byte_first != table->s->db_low_byte_first) { const uchar *dptr= from + pack_length(); while (dptr-- > from) @@ -4020,7 +4020,7 @@ Field_real::unpack(uchar *to, const uchar *from, uint param_data, bool low_byte_first) { DBUG_ENTER("Field_real::unpack"); - if (BIGENDIAN && low_byte_first != table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && low_byte_first != table->s->db_low_byte_first) { const uchar *dptr= from + pack_length(); while (dptr-- > from) @@ -4058,7 +4058,7 @@ int Field_float::store(double nr) int error= truncate(&nr, FLT_MAX); float j= (float)nr; - if (BIGENDIAN && table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && table->s->db_low_byte_first) float4store(ptr,j); else memcpy_fixed(ptr,(uchar*) &j,sizeof(j)); @@ -4077,7 +4077,7 @@ double Field_float::val_real(void) { ASSERT_COLUMN_MARKED_FOR_READ; float j; - if (BIGENDIAN && table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && table->s->db_low_byte_first) float4get(j,ptr); else memcpy_fixed((uchar*) &j,ptr,sizeof(j)); @@ -4087,7 +4087,7 @@ double Field_float::val_real(void) longlong Field_float::val_int(void) { float j; - if (BIGENDIAN && table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && table->s->db_low_byte_first) float4get(j,ptr); else memcpy_fixed((uchar*) &j,ptr,sizeof(j)); @@ -4100,7 +4100,7 @@ String *Field_float::val_str(String *val_buffer, { ASSERT_COLUMN_MARKED_FOR_READ; float nr; - if (BIGENDIAN && table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && table->s->db_low_byte_first) float4get(nr,ptr); else memcpy_fixed((uchar*) &nr,ptr,sizeof(nr)); @@ -4178,7 +4178,7 @@ String *Field_float::val_str(String *val_buffer, int Field_float::cmp(const uchar *a_ptr, const uchar *b_ptr) { float a,b; - if (BIGENDIAN && table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && table->s->db_low_byte_first) { float4get(a,a_ptr); float4get(b,b_ptr); @@ -4196,7 +4196,7 @@ 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; - if (BIGENDIAN && table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && table->s->db_low_byte_first) float4get(nr,ptr); else memcpy_fixed(&nr,ptr,sizeof(float)); @@ -4297,7 +4297,7 @@ int Field_double::store(double nr) ASSERT_COLUMN_MARKED_FOR_WRITE; int error= truncate(&nr, DBL_MAX); - if (BIGENDIAN && table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && table->s->db_low_byte_first) float8store(ptr,nr); else doublestore(ptr,nr); @@ -4380,7 +4380,7 @@ double Field_double::val_real(void) { ASSERT_COLUMN_MARKED_FOR_READ; double j; - if (BIGENDIAN && table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && table->s->db_low_byte_first) float8get(j,ptr); else doubleget(j,ptr); @@ -4392,7 +4392,7 @@ longlong Field_double::val_int(void) ASSERT_COLUMN_MARKED_FOR_READ; double j; longlong res; - if (BIGENDIAN && table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && table->s->db_low_byte_first) float8get(j,ptr); else doubleget(j,ptr); @@ -4436,7 +4436,7 @@ String *Field_double::val_str(String *val_buffer, { ASSERT_COLUMN_MARKED_FOR_READ; double nr; - if (BIGENDIAN && table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && table->s->db_low_byte_first) float8get(nr,ptr); else doubleget(nr,ptr); @@ -4520,7 +4520,7 @@ bool Field_double::send_binary(Protocol *protocol) int Field_double::cmp(const uchar *a_ptr, const uchar *b_ptr) { double a,b; - if (BIGENDIAN && table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && table->s->db_low_byte_first) { float8get(a,a_ptr); float8get(b,b_ptr); @@ -4541,7 +4541,7 @@ 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; - if (BIGENDIAN && table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && table->s->db_low_byte_first) float8get(nr,ptr); else doubleget(nr,ptr); @@ -4686,7 +4686,7 @@ 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) + if (ARCH_BIGENDIAN && table && table->s->db_low_byte_first) return sint4korr(ptr); long tmp; longget(tmp,ptr); @@ -4920,7 +4920,7 @@ bool Field_timestamp::send_binary(Protocol *protocol) int Field_timestamp::cmp(const uchar *a_ptr, const uchar *b_ptr) { int32 a,b; - if (BIGENDIAN && table && table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && table && table->s->db_low_byte_first) { a=sint4korr(a_ptr); b=sint4korr(b_ptr); @@ -4936,7 +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))) { - if (BIGENDIAN && !(table && table->s->db_low_byte_first)) + if (ARCH_BIGENDIAN && !(table && table->s->db_low_byte_first)) { to[0] = ptr[0]; to[1] = ptr[1]; @@ -5063,7 +5063,7 @@ void Field_timestamp_hires::store_TIME(my_time_t timestamp, ulong sec_part) 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); + *sec_part= (long)sec_part_unshift(read_bigendian(ptr+4, sec_part_bytes[dec]), dec); return mi_uint4korr(ptr); } @@ -5089,14 +5089,14 @@ double Field_timestamp_hires::val_real(void) 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]); + ulong sec_part= (ulong)read_bigendian(ptr+4, sec_part_bytes[dec]); if (tmp->ptr() == zero_timestamp) return tmp; char *buf= const_cast(tmp->ptr() + MAX_DATETIME_WIDTH); for (int i=dec; i>0; i--, sec_part/=10) - buf[i]= (sec_part % 10) + '0'; + buf[i]= (char)(sec_part % 10) + '0'; buf[0]= '.'; buf[dec+1]= 0; return tmp; @@ -5134,9 +5134,9 @@ 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]); + a_sec_part= (ulong)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]); + b_sec_part= (ulong)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; } @@ -5370,7 +5370,7 @@ 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, <ime, &was_cut); + int have_smth_to_conv= !number_to_time((double)nr, <ime, &was_cut); return store_TIME_with_warning(<ime, &str, was_cut, have_smth_to_conv); } @@ -5694,7 +5694,7 @@ void Field_year::sql_type(String &res) const void Field_date::store_TIME(MYSQL_TIME *ltime) { uint tmp= ltime->year*10000L + ltime->month*100+ltime->day; - if (BIGENDIAN && table && table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && table && table->s->db_low_byte_first) int4store(ptr,tmp); else longstore(ptr,tmp); @@ -5715,7 +5715,7 @@ double Field_date::val_real(void) { ASSERT_COLUMN_MARKED_FOR_READ; int32 j; - if (BIGENDIAN && table && table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && table && table->s->db_low_byte_first) j=sint4korr(ptr); else longget(j,ptr); @@ -5727,7 +5727,7 @@ longlong Field_date::val_int(void) { ASSERT_COLUMN_MARKED_FOR_READ; int32 j; - if (BIGENDIAN && table && table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && table && table->s->db_low_byte_first) j=sint4korr(ptr); else longget(j,ptr); @@ -5742,7 +5742,7 @@ String *Field_date::val_str(String *val_buffer, MYSQL_TIME ltime; val_buffer->alloc(field_length); int32 tmp; - if (BIGENDIAN && table && table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && table && table->s->db_low_byte_first) tmp=sint4korr(ptr); else longget(tmp,ptr); @@ -5758,7 +5758,7 @@ String *Field_date::val_str(String *val_buffer, int Field_date::cmp(const uchar *a_ptr, const uchar *b_ptr) { int32 a,b; - if (BIGENDIAN && table && table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && table && table->s->db_low_byte_first) { a=sint4korr(a_ptr); b=sint4korr(b_ptr); @@ -5774,7 +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))) { - if (BIGENDIAN && !(table && table->s->db_low_byte_first)) + if (ARCH_BIGENDIAN && !(table && table->s->db_low_byte_first)) { to[0] = ptr[0]; to[1] = ptr[1]; @@ -5911,7 +5911,7 @@ void Field_newdate::sql_type(String &res) const void Field_datetime::store_TIME(MYSQL_TIME *ltime) { ulonglong tmp= TIME_to_ulonglong_datetime(ltime); - if (BIGENDIAN && table && table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && table && table->s->db_low_byte_first) int8store(ptr,tmp); else longlongstore(ptr,tmp); @@ -5934,7 +5934,7 @@ longlong Field_datetime::val_int(void) { ASSERT_COLUMN_MARKED_FOR_READ; longlong j; - if (BIGENDIAN && table && table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && table && table->s->db_low_byte_first) j=sint8korr(ptr); else longlongget(j,ptr); @@ -6013,7 +6013,7 @@ bool Field_datetime::get_date(MYSQL_TIME *ltime, uint fuzzydate) int Field_datetime::cmp(const uchar *a_ptr, const uchar *b_ptr) { longlong a,b; - if (BIGENDIAN && table && table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && table && table->s->db_low_byte_first) { a=sint8korr(a_ptr); b=sint8korr(b_ptr); @@ -6029,7 +6029,7 @@ int Field_datetime::cmp(const uchar *a_ptr, const uchar *b_ptr) void Field_datetime::sort_string(uchar *to,uint length __attribute__((unused))) { - if (BIGENDIAN && !(table && table->s->db_low_byte_first)) + if (ARCH_BIGENDIAN && !(table && table->s->db_low_byte_first)) { to[0] = ptr[0]; to[1] = ptr[1]; @@ -7466,7 +7466,7 @@ void Field_blob::store_length(uchar *i_ptr, uint32 i_number, bool low_byte_first) { - if (BIGENDIAN && low_byte_first) + if (ARCH_BIGENDIAN && low_byte_first) store_lowendian(i_number, i_ptr, i_packlength); else store_native(i_number, i_ptr, i_packlength); @@ -7475,10 +7475,10 @@ void Field_blob::store_length(uchar *i_ptr, uint32 Field_blob::get_length(const uchar *pos, uint packlength_arg, bool low_byte_first) { - if (BIGENDIAN && table->s->db_low_byte_first) - return read_lowendian(pos, packlength_arg); + if (ARCH_BIGENDIAN && table->s->db_low_byte_first) + return (uint32)read_lowendian(pos, packlength_arg); else - return read_native(pos, packlength_arg); + return (uint32)read_native(pos, packlength_arg); } @@ -8188,7 +8188,7 @@ enum ha_base_keytype Field_enum::key_type() const void Field_enum::store_type(ulonglong value) { - if (BIGENDIAN && table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && table->s->db_low_byte_first) store_lowendian(value, ptr, packlength); else store_native(value, ptr, packlength); @@ -8277,7 +8277,7 @@ double Field_enum::val_real(void) longlong Field_enum::val_int(void) { ASSERT_COLUMN_MARKED_FOR_READ; - if (BIGENDIAN && table->s->db_low_byte_first) + if (ARCH_BIGENDIAN && table->s->db_low_byte_first) return read_lowendian(ptr, packlength); else return read_native(ptr, packlength); diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 925582be542..1573dfddf98 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -873,7 +873,7 @@ get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg, longlong res; if (t_type == MYSQL_TIMESTAMP_TIME) - res= number_to_time(value, &buf, &was_cut); + res= number_to_time((double)value, &buf, &was_cut); else res= number_to_datetime(value, &buf, TIME_INVALID_DATES|TIME_FUZZY_DATE, &was_cut); diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 4f9022cb579..51da306af48 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -1610,7 +1610,7 @@ void Item_func_sysdate_local::store_now_in_TIME(MYSQL_TIME *now_time) { THD *thd= current_thd; my_hrtime_t now= my_hrtime(); - thd->variables.time_zone->gmt_sec_to_TIME(now_time, hrtime_to_time(now)); + thd->variables.time_zone->gmt_sec_to_TIME(now_time, hrtime_to_my_time(now)); set_sec_part(hrtime_sec_part(now), now_time, this); thd->time_zone_used= 1; } diff --git a/sql/log_event.cc b/sql/log_event.cc index 8a0c8f93af3..49f18b919d3 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1719,11 +1719,11 @@ beg: case MYSQL_TYPE_DATETIME: { - size_t d, t; + uint d, t; uint64 i64= uint8korr(ptr); /* YYYYMMDDhhmmss */ - d= i64 / 1000000; - t= i64 % 1000000; - my_b_printf(file, "%04d-%02d-%02d %02d:%02d:%02d", + d= (uint)(i64 / 1000000); + t= (uint)(i64 % 1000000); + my_b_printf(file, "%04u-%02u-%02u %02u:%02u:%02u", d / 10000, (d % 10000) / 100, d % 100, t / 10000, (t % 10000) / 100, t % 100); my_snprintf(typestr, typestr_length, "DATETIME"); diff --git a/sql/log_event.h b/sql/log_event.h index 9331d7be4b1..6327a53844d 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -1022,7 +1022,7 @@ public: return when; } my_hrtime_t hrtime= my_hrtime(); - when= hrtime_to_time(hrtime); + when= hrtime_to_my_time(hrtime); when_sec_part= hrtime_sec_part(hrtime); return when; } diff --git a/sql/slave.cc b/sql/slave.cc index ebf0ba22f85..3448009cd20 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -2154,7 +2154,7 @@ int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli) if (!ev->when) { my_hrtime_t hrtime= my_hrtime(); - ev->when= hrtime_to_time(hrtime); + ev->when= hrtime_to_my_time(hrtime); ev->when_sec_part= hrtime_sec_part(hrtime); } ev->thd = thd; // because up to this point, ev->thd == 0 diff --git a/sql/sql_class.h b/sql/sql_class.h index 1298dd734c9..507b2902eda 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2026,7 +2026,7 @@ public: { if (user_time.val) { - start_time= hrtime_to_time(user_time); + start_time= hrtime_to_my_time(user_time); start_time_sec_part= hrtime_sec_part(user_time); start_utime= utime_after_lock= my_micro_time(); } @@ -2035,7 +2035,7 @@ public: my_hrtime_t hrtime; my_timediff_t timediff; my_micro_and_hrtime(&timediff, &hrtime); - start_time= hrtime_to_time(hrtime); + start_time= hrtime_to_my_time(hrtime); start_time_sec_part= hrtime_sec_part(hrtime); utime_after_lock= start_utime= timediff.val; } @@ -2043,13 +2043,13 @@ public: inline void set_current_time() { my_hrtime_t hrtime= my_hrtime(); - start_time= hrtime_to_time(hrtime); + start_time= hrtime_to_my_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= hrtime_to_my_time(user_time); start_time_sec_part= hrtime_sec_part(user_time); start_utime= utime_after_lock= my_micro_time(); } -- cgit v1.2.1 From c4229519990c277ac56f938474fa2546e7266542 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 28 Mar 2011 19:01:56 +0200 Subject: bugfix: datetime(X) and time(X) were taking one byte more than necessary for certain values of X. --- sql/field.cc | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'sql') diff --git a/sql/field.cc b/sql/field.cc index fcb4e618fa6..914376b91e0 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -5053,6 +5053,10 @@ static longlong read_bigendian(const uchar *from, uint bytes) } static uint sec_part_bytes[MAX_DATETIME_PRECISION+1]= { 0, 1, 1, 2, 2, 3, 3 }; +static uint datetime_hires_bytes[MAX_DATETIME_PRECISION+1]= +{ 5, 6, 6, 7, 7, 7, 8 }; +static uint time_hires_bytes[MAX_DATETIME_PRECISION+1]= +{ 3, 4, 4, 4, 5, 5, 6 }; void Field_timestamp_hires::store_TIME(my_time_t timestamp, ulong sec_part) { @@ -5491,7 +5495,7 @@ void Field_time_hires::store_TIME(MYSQL_TIME *ltime) uint32 Field_time_hires::pack_length() const { - return 3 + sec_part_bytes[dec]; + return time_hires_bytes[dec]; } double Field_time_hires::val_real(void) @@ -6123,7 +6127,7 @@ bool Field_datetime_hires::get_date(MYSQL_TIME *ltime, uint fuzzydate) uint32 Field_datetime_hires::pack_length() const { - return 5 + sec_part_bytes[dec]; + return datetime_hires_bytes[dec]; } int Field_datetime_hires::cmp(const uchar *a_ptr, const uchar *b_ptr) @@ -9696,7 +9700,7 @@ uint32 calc_pack_length(enum_field_types type,uint32 length) case MYSQL_TYPE_INT24: case MYSQL_TYPE_NEWDATE: return 3; case MYSQL_TYPE_TIME: return length > MIN_TIME_WIDTH - ? 3 + sec_part_bytes[length - 1 - MIN_TIME_WIDTH] + ? time_hires_bytes[length - 1 - MIN_TIME_WIDTH] : 3; case MYSQL_TYPE_TIMESTAMP: return length > MAX_DATETIME_WIDTH @@ -9708,7 +9712,7 @@ uint32 calc_pack_length(enum_field_types type,uint32 length) 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] + ? datetime_hires_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; -- cgit v1.2.1 From 01aab9ed6d0a4be87ba55aca19aa6e72af60a997 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 29 Mar 2011 14:48:48 +0200 Subject: lp:743017 Diverging results with TIME(3) and ranges depending on the execution plan in 5.1-micro rewrite get_innobase_type_from_mysql_type() to use types as reported by the Field objects, instead of relying on ad-hoc assumptions. --- sql/field.h | 1 + 1 file changed, 1 insertion(+) (limited to 'sql') diff --git a/sql/field.h b/sql/field.h index 8eacfcd404f..d5d5ad32744 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1157,6 +1157,7 @@ public: void sql_type(String &str) const; uint size_of() const { return sizeof(*this); } uint32 max_display_length() { return 4; } + void move_field_offset(my_ptrdiff_t ptr_diff) {} }; -- cgit v1.2.1 From 40b6eb9f1d088f210a954cd616294f1a8db81d22 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 18 Apr 2011 21:01:49 +0200 Subject: lp:750117 Bogus warning with aggregate and datetime column implement Item_cache_int::getdate() and Item_cache_int::save_in_field() that handle the case of the cached packed datetime value. --- sql/item.cc | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++---- sql/item.h | 2 ++ sql/mysql_priv.h | 13 +++++++++++++ 3 files changed, 65 insertions(+), 4 deletions(-) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index f28b14725c3..cce985fe80d 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -999,11 +999,9 @@ bool Item::get_date(MYSQL_TIME *ltime,uint fuzzydate) int was_cut; if (number_to_datetime(value, ltime, fuzzydate, &was_cut) == LL(-1)) { - char buff[22], *end; - end= longlong10_to_str(value, buff, -10); + Lazy_string_num str(value); make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, - buff, (int) (end-buff), MYSQL_TIMESTAMP_NONE, - NullS); + &str, MYSQL_TIMESTAMP_NONE, NullS); goto err; } } @@ -7190,6 +7188,54 @@ longlong Item_cache_int::val_int() return value; } +bool Item_cache_int::get_date(MYSQL_TIME *ltime, uint fuzzydate) +{ + if (!value_cached && !cache_value()) + goto err; + + if (cmp_type() == TIME_RESULT) + { + unpack_time(value, ltime); + ltime->time_type= mysql_type_to_time_type(field_type()); + } + else + { + int was_cut; + if (number_to_datetime(value, ltime, fuzzydate, &was_cut) == -1LL) + { + Lazy_string_num str(value); + make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, + &str, MYSQL_TIMESTAMP_NONE, NullS); + goto err; + } + } + return 0; + +err: + bzero((char*) ltime,sizeof(*ltime)); + return 1; +} + +int Item_cache_int::save_in_field(Field *field, bool no_conversions) +{ + int error; + if (!value_cached && !cache_value()) + return set_field_to_null_with_conversions(field, no_conversions); + + field->set_notnull(); + if (cmp_type() == TIME_RESULT) + { + MYSQL_TIME ltime; + unpack_time(value, <ime); + ltime.time_type= mysql_type_to_time_type(field_type()); + error= field->store_time(<ime, ltime.time_type); + } + else + error= field->store(value, unsigned_flag); + + return error ? error : field->table->in_use->is_error() ? 1 : 0; +} + bool Item_cache_real::cache_value() { if (!example) diff --git a/sql/item.h b/sql/item.h index 866b3fcb4fc..275b876f521 100644 --- a/sql/item.h +++ b/sql/item.h @@ -3035,6 +3035,8 @@ public: my_decimal *val_decimal(my_decimal *); enum Item_result result_type() const { return INT_RESULT; } bool cache_value(); + bool get_date(MYSQL_TIME *ltime, uint fuzzydate); + int save_in_field(Field *field, bool no_conversions); Item *clone_item() { Item_cache_int *item= new Item_cache_int(cached_field_type); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 2ac2318f242..acdbac4ff68 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -2257,6 +2257,19 @@ int my_time_compare(MYSQL_TIME *a, MYSQL_TIME *b); longlong get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg, Item *warn_item, bool *is_null); +static inline enum enum_mysql_timestamp_type +mysql_type_to_time_type(enum enum_field_types mysql_type) +{ + switch(mysql_type) { + case MYSQL_TYPE_TIME: return MYSQL_TIMESTAMP_TIME; + case MYSQL_TYPE_TIMESTAMP: + case MYSQL_TYPE_DATETIME: return MYSQL_TIMESTAMP_DATETIME; + case MYSQL_TYPE_NEWDATE: + case MYSQL_TYPE_DATE: return MYSQL_TIMESTAMP_DATE; + default: return MYSQL_TIMESTAMP_ERROR; + } +} + int test_if_number(char *str,int *res,bool allow_wildcards); void change_byte(uchar *,uint,char,char); void init_read_record(READ_RECORD *info, THD *thd, TABLE *reg_form, -- cgit v1.2.1 From 404928b9f4348c1a476c4a1fa030cc89c33f08d2 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 19 May 2011 19:01:46 +0200 Subject: post-review changes 1 include/my_time.h: remove duplicate defines. cast to ulonglong to avoid overflow sql/field.cc: perform sign extension when reading packed TIME values sql/item_cmpfunc.cc: when converting a string to a date for the purpose of comparing it with another date, we should ignore strict sql mode. sql/item_timefunc.cc: better error message sql/item_timefunc.h: limit decimals appropriately sql/share/errmsg.txt: don't refer to an object as a "column" in error messages that are used not only for columns. --- sql/field.cc | 11 +++++++++-- sql/field.h | 6 +++--- sql/item.cc | 4 ++-- sql/item_cmpfunc.cc | 16 ++++++++-------- sql/item_timefunc.cc | 28 +++++++++++++++------------- sql/item_timefunc.h | 18 ++++++++++++------ sql/protocol.cc | 4 ++-- sql/share/errmsg.txt | 8 ++++---- 8 files changed, 55 insertions(+), 40 deletions(-) (limited to 'sql') diff --git a/sql/field.cc b/sql/field.cc index 914376b91e0..731aaea4659 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -5056,7 +5056,7 @@ static uint sec_part_bytes[MAX_DATETIME_PRECISION+1]= { 0, 1, 1, 2, 2, 3, 3 }; static uint datetime_hires_bytes[MAX_DATETIME_PRECISION+1]= { 5, 6, 6, 7, 7, 7, 8 }; static uint time_hires_bytes[MAX_DATETIME_PRECISION+1]= -{ 3, 4, 4, 4, 5, 5, 6 }; +{ 3, 4, 4, 5, 5, 5, 6 }; void Field_timestamp_hires::store_TIME(my_time_t timestamp, ulong sec_part) { @@ -5520,7 +5520,14 @@ String *Field_time_hires::val_str(String *str, bool Field_time_hires::get_date(MYSQL_TIME *ltime, uint fuzzydate) { - ulonglong packed= read_bigendian(ptr, Field_time_hires::pack_length()); + uint32 len= pack_length(); + longlong packed= read_bigendian(ptr, len); + + /* sign extension */ + longlong mask= 1LL << (len*8 - 1); + if (packed & mask) + packed|= ~(mask-1); + unpack_time(sec_part_unshift(packed, dec), ltime); /* unpack_time() returns MYSQL_TIMESTAMP_DATETIME. diff --git a/sql/field.h b/sql/field.h index d5d5ad32744..75cf3858e6f 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1234,7 +1234,7 @@ public: dec(dec_arg) { DBUG_ASSERT(dec); - DBUG_ASSERT(dec <= MAX_SEC_PART_DIGITS); + DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS); } void sql_type(String &str) const; long get_timestamp(ulong *sec_part) const; @@ -1407,7 +1407,7 @@ public: dec(dec_arg) { DBUG_ASSERT(dec); - DBUG_ASSERT(dec <= MAX_SEC_PART_DIGITS); + DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS); } enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; } uint decimals() const { return dec; } @@ -1476,7 +1476,7 @@ public: field_name_arg, cs), dec(dec_arg) { DBUG_ASSERT(dec); - DBUG_ASSERT(dec <= MAX_SEC_PART_DIGITS); + DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS); } enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; } int store_decimal(const my_decimal *d); diff --git a/sql/item.cc b/sql/item.cc index cce985fe80d..997ce821f9a 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -2748,13 +2748,13 @@ 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; + decimals= value.time.second_part > 0 ? TIME_SECOND_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.second_part > MAX_SEC_PART_VALUE) + value.time.second_part > TIME_MAX_SECOND_PART) { Lazy_string_time str(&value.time); make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 1573dfddf98..e7418c2a53a 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -629,12 +629,14 @@ int Arg_comparator::set_compare_func(Item_result_field *item, Item_result type) @param[in] warn_name Field name for issuing the warning @param[out] l_time The MYSQL_TIME objects is initialized. - Parses a date provided in the string str into a MYSQL_TIME object. If the - string contains an incorrect date or doesn't correspond to a date at all - then a warning is issued. The warn_type and the warn_name arguments are used - as the name and the type of the field when issuing the warning. If any input - was discarded (trailing or non-timestamp-y characters), return value will be - TRUE. + Parses a date provided in the string str into a MYSQL_TIME object. + The date is used for comparison, that is fuzzy dates are allowed + independently of sql_mode. + If the string contains an incorrect date or doesn't correspond to a date at + all then a warning is issued. The warn_type and the warn_name arguments are + used as the name and the type of the field when issuing the warning. If any + input was discarded (trailing or non-timestamp-y characters), return value + will be TRUE. @return Status flag @retval FALSE Success. @@ -649,8 +651,6 @@ bool get_mysql_time_from_str(THD *thd, String *str, timestamp_type warn_type, 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; diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 51da306af48..a173f50e605 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -1479,9 +1479,10 @@ bool Item_func_curdate::get_date(MYSQL_TIME *res, bool Item_func_curtime::fix_fields(THD *thd, Item **items) { - if (decimals > MAX_SEC_PART_DIGITS) + if (decimals > TIME_SECOND_PART_DIGITS) { - my_error(ER_WRONG_ARGUMENTS, MYF(0), func_name()); + my_error(ER_TOO_BIG_PRECISION, MYF(0), decimals, func_name(), + TIME_SECOND_PART_DIGITS); return 1; } return Item_timefunc::fix_fields(thd, items); @@ -1492,7 +1493,7 @@ void Item_func_curtime::fix_length_and_dec() collation.set(&my_charset_bin); store_now_in_TIME(<ime); max_length= MAX_TIME_WIDTH + - (decimals ? min(decimals, MAX_SEC_PART_DIGITS)+1 : 0); + (decimals ? min(decimals, TIME_SECOND_PART_DIGITS)+1 : 0); } bool Item_func_curtime::get_date(MYSQL_TIME *res, @@ -1505,11 +1506,11 @@ bool Item_func_curtime::get_date(MYSQL_TIME *res, 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); + item->decimals <= TIME_SECOND_PART_DIGITS); if (item->decimals) { ltime->second_part= sec_part; - if (item->decimals < MAX_SEC_PART_DIGITS) + if (item->decimals < TIME_SECOND_PART_DIGITS) ltime->second_part= sec_part_truncate(ltime->second_part, item->decimals); } } @@ -1548,9 +1549,10 @@ void Item_func_curtime_utc::store_now_in_TIME(MYSQL_TIME *now_time) bool Item_func_now::fix_fields(THD *thd, Item **items) { - if (decimals > MAX_SEC_PART_DIGITS) + if (decimals > TIME_SECOND_PART_DIGITS) { - my_error(ER_WRONG_ARGUMENTS, MYF(0), func_name()); + my_error(ER_TOO_BIG_PRECISION, MYF(0), decimals, func_name(), + TIME_SECOND_PART_DIGITS); return 1; } return Item_temporal_func::fix_fields(thd, items); @@ -1561,7 +1563,7 @@ void Item_func_now::fix_length_and_dec() collation.set(&my_charset_bin); store_now_in_TIME(<ime); max_length= MAX_DATETIME_WIDTH + - (decimals ? min(decimals, MAX_SEC_PART_DIGITS)+1 : 0); + (decimals ? min(decimals, TIME_SECOND_PART_DIGITS)+1 : 0); } @@ -1848,7 +1850,7 @@ void Item_func_convert_tz::fix_length_and_dec() max_length= MAX_DATETIME_WIDTH; decimals= args[0]->decimals; if (decimals && decimals != NOT_FIXED_DEC) - max_length+= min(decimals, MAX_SEC_PART_DIGITS) + 1; + max_length+= min(decimals, TIME_SECOND_PART_DIGITS) + 1; maybe_null= 1; } @@ -1949,7 +1951,7 @@ void Item_date_add_interval::fix_length_and_dec() else decimals= args[0]->decimals; if (decimals) - max_length+= min(decimals, MAX_SEC_PART_DIGITS) + 1; + max_length+= min(decimals, TIME_SECOND_PART_DIGITS) + 1; value.alloc(max_length); } @@ -2402,7 +2404,7 @@ void Item_func_add_time::fix_length_and_dec() 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; + max_length+= min(decimals, TIME_SECOND_PART_DIGITS) + 1; } /** @@ -2467,7 +2469,7 @@ bool Item_func_add_time::get_date(MYSQL_TIME *ltime, uint fuzzy_date) if (cached_field_type == MYSQL_TYPE_STRING && (l_time1.second_part || l_time2.second_part)) - dec= MAX_SEC_PART_DIGITS; + dec= TIME_SECOND_PART_DIGITS; if (!is_time) { @@ -2931,7 +2933,7 @@ void Item_func_str_to_date::fix_length_and_dec() { maybe_null= 1; cached_field_type= MYSQL_TYPE_DATETIME; - max_length= MAX_DATETIME_WIDTH+MAX_SEC_PART_DIGITS; + max_length= MAX_DATETIME_WIDTH + TIME_SECOND_PART_DIGITS; cached_timestamp_type= MYSQL_TIMESTAMP_DATETIME; decimals= AUTO_SEC_PART_DIGITS; if ((const_item= args[1]->const_item())) diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index 68fd34aa29e..9f45655add6 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -332,7 +332,9 @@ public: void fix_length_and_dec() { maybe_null= TRUE; - decimals=args[0]->decimals; + decimals= args[0]->decimals; + if (decimals != NOT_FIXED_DEC) + set_if_smaller(decimals, TIME_SECOND_PART_DIGITS); max_length=17; } bool check_partition_func_processor(uchar *int_arg) {return FALSE;} @@ -389,7 +391,7 @@ public: void fix_length_and_dec() { max_length= MAX_TIME_WIDTH + - (decimals ? min(decimals, MAX_SEC_PART_DIGITS)+1 : 0); + (decimals ? min(decimals, TIME_SECOND_PART_DIGITS)+1 : 0); } }; @@ -597,8 +599,8 @@ public: 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; + if (decimals != NOT_FIXED_DEC) + set_if_smaller(decimals, TIME_SECOND_PART_DIGITS); Item_timefunc::fix_length_and_dec(); } const char *func_name() const { return "sec_to_time"; } @@ -700,9 +702,13 @@ public: maybe_null= 1; max_length= MIN_TIME_WIDTH; if (decimals == NOT_FIXED_DEC) + { decimals= args[0]->decimals; + if (decimals != NOT_FIXED_DEC) + set_if_smaller(decimals, TIME_SECOND_PART_DIGITS); + } if (decimals && decimals != NOT_FIXED_DEC) - max_length+= min(decimals, MAX_SEC_PART_DIGITS) + 1; + max_length+= min(decimals, TIME_SECOND_PART_DIGITS) + 1; } }; @@ -722,7 +728,7 @@ public: maybe_null= 1; max_length= MAX_DATETIME_WIDTH; if (decimals && decimals != NOT_FIXED_DEC) - max_length+= min(decimals, MAX_SEC_PART_DIGITS) + 1; + max_length+= min(decimals, TIME_SECOND_PART_DIGITS) + 1; } }; diff --git a/sql/protocol.cc b/sql/protocol.cc index 273e3b1fd28..9242b348f0b 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -1200,7 +1200,7 @@ bool Protocol_binary::store(MYSQL_TIME *tm, int decimals) pos[5]= (uchar) tm->minute; pos[6]= (uchar) tm->second; DBUG_ASSERT(decimals == AUTO_SEC_PART_DIGITS || - (decimals >= 0 && decimals <= MAX_SEC_PART_DIGITS)); + (decimals >= 0 && decimals <= TIME_SECOND_PART_DIGITS)); if (decimals != AUTO_SEC_PART_DIGITS) tm->second_part= sec_part_truncate(tm->second_part, decimals); int4store(pos+7, tm->second_part); @@ -1242,7 +1242,7 @@ bool Protocol_binary::store_time(MYSQL_TIME *tm, int decimals) pos[6]= (uchar) tm->minute; pos[7]= (uchar) tm->second; DBUG_ASSERT(decimals == AUTO_SEC_PART_DIGITS || - (decimals >= 0 && decimals <= MAX_SEC_PART_DIGITS)); + (decimals >= 0 && decimals <= TIME_SECOND_PART_DIGITS)); if (decimals != AUTO_SEC_PART_DIGITS) tm->second_part= sec_part_truncate(tm->second_part, decimals); int4store(pos+8, tm->second_part); diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index c2fa3d12829..a9880913c5e 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 %u specified for column '%-.192s'. Maximum is %lu." - ger "Zu großer Skalierungsfaktor %u für Feld '%-.192s' angegeben. Maximum ist %lu" + eng "Too big scale %u specified for '%-.192s'. Maximum is %lu." + ger "Zu großer Skalierungsfaktor %u für '%-.192s' angegeben. Maximum ist %lu" ER_TOO_BIG_PRECISION 42000 S1009 - 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" + eng "Too big precision %u specified for '%-.192s'. Maximum is %lu." + ger "Zu große Genauigkeit %u für '%-.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')" -- cgit v1.2.1 From 90b1a385daaa6bbcdc7dea518c7c527a165f1425 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 19 May 2011 19:05:35 +0200 Subject: many changes to my_getsystime.c: * my_getsystime() is only an interval timer. Its value can beused for calculating time intervals. * renamed my_getsystime() to my_interval_timer(), to make the semantics clearer and let the compiler catch wrong usages of my_getsystime() (also future ones, that may come in merges). * increased its granularity from 100ns to 1ns, old value was for UUID, but as UUID can no longer use it directly there is no need to downgrade the OS provided value * fixed the UUID code to anchor the my_interval_timer() on the epoch, as required by the UUID standard. That is, this was only needed by UUID, and now I've moved it to UUID code from my_getsystime(). * fixed other wrong usages of my_getsystime() - e.g. in calculating times for pthread_cond_timedwait. It was buggy and could've caused long waits if OS clock would be changed. --- sql/item_strfunc.cc | 7 +++++-- sql/mysqld.cc | 6 +++--- sql/sql_class.h | 13 +++++-------- sql/sql_connect.cc | 2 +- sql/sql_profile.cc | 2 +- 5 files changed, 15 insertions(+), 15 deletions(-) (limited to 'sql') diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index fd5c47d25cb..ef6bf611637 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -3446,6 +3446,8 @@ err: static struct rand_struct uuid_rand; static uint nanoseq; static ulonglong uuid_time=0; +static longlong interval_timer_offset; + static char clock_seq_and_node_str[]="-0000-000000000000"; /** @@ -3473,6 +3475,7 @@ static void set_clock_seq_str() uint16 clock_seq= ((uint)(my_rnd(&uuid_rand)*16383)) | UUID_VARIANT; tohex(clock_seq_and_node_str+1, clock_seq, 4); nanoseq= 0; + interval_timer_offset= my_hrtime().val * 10 - my_interval_timer()/100 + UUID_TIME_OFFSET; } String *Item_func_uuid::val_str(String *str) @@ -3512,7 +3515,7 @@ String *Item_func_uuid::val_str(String *str) set_clock_seq_str(); } - ulonglong tv= my_getsystime() + UUID_TIME_OFFSET + nanoseq; + ulonglong tv= my_interval_timer()/100 + interval_timer_offset + nanoseq; if (likely(tv > uuid_time)) { @@ -3564,7 +3567,7 @@ String *Item_func_uuid::val_str(String *str) irrelevant in the new numberspace. */ set_clock_seq_str(); - tv= my_getsystime() + UUID_TIME_OFFSET; + tv= my_interval_timer()/100 + interval_timer_offset; nanoseq= 0; DBUG_PRINT("uuid",("making new numberspace")); } diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 98cf221b679..07d76edcbbf 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1947,7 +1947,7 @@ static bool cache_thread() this thread for handling of new THD object/connection. */ thd->mysys_var->abort= 0; - thd->thr_create_utime= my_micro_time(); + thd->thr_create_utime= microsecond_interval_timer(); threads.append(thd); return(1); } @@ -4907,7 +4907,7 @@ void handle_connection_in_main_thread(THD *thd) thread_cache_size=0; // Safety threads.append(thd); pthread_mutex_unlock(&LOCK_thread_count); - thd->start_utime= my_micro_time(); + thd->start_utime= microsecond_interval_timer(); handle_one_connection(thd); } @@ -4933,7 +4933,7 @@ void create_thread_to_handle_connection(THD *thd) thread_created++; threads.append(thd); DBUG_PRINT("info",(("creating thread %lu"), thd->thread_id)); - thd->prior_thr_create_utime= thd->start_utime= my_micro_time(); + thd->prior_thr_create_utime= thd->start_utime= microsecond_interval_timer(); if ((error=pthread_create(&thd->real_id,&connection_attrib, handle_one_connection, (void*) thd))) diff --git a/sql/sql_class.h b/sql/sql_class.h index 507b2902eda..9a0a9bc5b38 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2028,17 +2028,14 @@ public: { start_time= hrtime_to_my_time(user_time); start_time_sec_part= hrtime_sec_part(user_time); - start_utime= utime_after_lock= my_micro_time(); } else { - my_hrtime_t hrtime; - my_timediff_t timediff; - my_micro_and_hrtime(&timediff, &hrtime); + my_hrtime_t hrtime= my_hrtime(); start_time= hrtime_to_my_time(hrtime); start_time_sec_part= hrtime_sec_part(hrtime); - utime_after_lock= start_utime= timediff.val; } + start_utime= utime_after_lock= microsecond_interval_timer(); } inline void set_current_time() { @@ -2051,15 +2048,15 @@ public: user_time= t; start_time= hrtime_to_my_time(user_time); start_time_sec_part= hrtime_sec_part(user_time); - start_utime= utime_after_lock= my_micro_time(); + start_utime= utime_after_lock= microsecond_interval_timer(); } 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(); } + void set_time_after_lock() { utime_after_lock= microsecond_interval_timer(); } + ulonglong current_utime() { return microsecond_interval_timer(); } inline ulonglong found_rows(void) { return limit_found_rows; diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 28c1acc4716..a6e91b0f910 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -1084,7 +1084,7 @@ pthread_handler_t handle_one_connection(void *arg) { THD *thd= (THD*) arg; - thd->thr_create_utime= my_micro_time(); + thd->thr_create_utime= microsecond_interval_timer(); if (thread_scheduler.init_new_connection_thread()) { diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc index c661f3744aa..732e7431efc 100644 --- a/sql/sql_profile.cc +++ b/sql/sql_profile.cc @@ -221,7 +221,7 @@ void PROF_MEASUREMENT::set_label(const char *status_arg, */ void PROF_MEASUREMENT::collect() { - time_usecs= (double) my_getsystime() / 10.0; /* 1 sec was 1e7, now is 1e6 */ + time_usecs= my_interval_timer() / 1e3; /* ns to us */ #ifdef HAVE_GETRUSAGE getrusage(RUSAGE_SELF, &rusage); #endif -- cgit v1.2.1 From d0fae7542fce4dc11099056e602f47c4e5707811 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 19 May 2011 19:16:17 +0200 Subject: post review changes 2 sql/event_parse_data.cc: don't use "not_used" variable sql/item_timefunc.cc: Item_temporal_func::fix_length_and_dec() and other changes sql/item_timefunc.h: introducing Item_timefunc::fix_length_and_dec() sql/share/errmsg.txt: don't say "column X" in the error message that used not only for columns --- sql/event_parse_data.cc | 12 ++--- sql/field.cc | 112 +++++++++++++++++++++---------------------- sql/field.h | 3 -- sql/item.cc | 71 ++++++++++++++------------- sql/item.h | 6 ++- sql/item_cmpfunc.cc | 93 ++++++++++++++++++++++-------------- sql/item_create.cc | 117 ++++++++++++++++++--------------------------- sql/item_func.cc | 71 ++++++++++++++++----------- sql/item_timefunc.cc | 124 +++++++++++++++++------------------------------- sql/item_timefunc.h | 94 ++++++++++++++++-------------------- sql/log_event.cc | 4 +- sql/mysql_priv.h | 32 ++++++------- sql/set_var.cc | 2 +- sql/share/errmsg.txt | 4 +- sql/sql_class.cc | 3 +- sql/sql_string.cc | 2 +- sql/sql_string.h | 2 +- sql/time.cc | 29 +++++++---- 18 files changed, 379 insertions(+), 402 deletions(-) (limited to 'sql') diff --git a/sql/event_parse_data.cc b/sql/event_parse_data.cc index 04416232eb4..4555da44f18 100644 --- a/sql/event_parse_data.cc +++ b/sql/event_parse_data.cc @@ -198,7 +198,7 @@ Event_parse_data::check_dates(THD *thd, int previous_on_completion) int Event_parse_data::init_execute_at(THD *thd) { - my_bool not_used; + uint not_used; MYSQL_TIME ltime; my_time_t ltime_utc; @@ -215,7 +215,7 @@ Event_parse_data::init_execute_at(THD *thd) (starts_null && ends_null))); DBUG_ASSERT(starts_null && ends_null); - if ((not_used= item_execute_at->get_date(<ime, TIME_NO_ZERO_DATE))) + if (item_execute_at->get_date(<ime, TIME_NO_ZERO_DATE)) goto wrong_value; ltime_utc= TIME_to_timestamp(thd,<ime,¬_used); @@ -368,7 +368,7 @@ wrong_value: int Event_parse_data::init_starts(THD *thd) { - my_bool not_used; + uint not_used; MYSQL_TIME ltime; my_time_t ltime_utc; @@ -379,7 +379,7 @@ Event_parse_data::init_starts(THD *thd) if (item_starts->fix_fields(thd, &item_starts)) goto wrong_value; - if ((not_used= item_starts->get_date(<ime, TIME_NO_ZERO_DATE))) + if (item_starts->get_date(<ime, TIME_NO_ZERO_DATE)) goto wrong_value; ltime_utc= TIME_to_timestamp(thd, <ime, ¬_used); @@ -422,7 +422,7 @@ wrong_value: int Event_parse_data::init_ends(THD *thd) { - my_bool not_used; + uint not_used; MYSQL_TIME ltime; my_time_t ltime_utc; @@ -434,7 +434,7 @@ Event_parse_data::init_ends(THD *thd) goto error_bad_params; DBUG_PRINT("info", ("convert to TIME")); - if ((not_used= item_ends->get_date(<ime, TIME_NO_ZERO_DATE))) + if (item_ends->get_date(<ime, TIME_NO_ZERO_DATE)) goto error_bad_params; ltime_utc= TIME_to_timestamp(thd, <ime, ¬_used); diff --git a/sql/field.cc b/sql/field.cc index 731aaea4659..7e0d99bc9f5 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -47,6 +47,17 @@ template class List; template class List_iterator; #endif +static const char *zero_timestamp="0000-00-00 00:00:00.000000"; + +/* number of bytes to store second_part part of the TIMESTAMP(N) */ +static uint sec_part_bytes[MAX_DATETIME_PRECISION+1]= { 0, 1, 1, 2, 2, 3, 3 }; + +/* number of bytes to store DATETIME(N) */ +static uint datetime_hires_bytes[MAX_DATETIME_PRECISION+1]= { 5, 6, 6, 7, 7, 7, 8 }; + +/* number of bytes to store TIME(N) */ +static uint time_hires_bytes[MAX_DATETIME_PRECISION+1]= { 3, 4, 4, 5, 5, 5, 6 }; + uchar Field_null::null[1]={1}; const char field_separator=','; @@ -4693,6 +4704,7 @@ long Field_timestamp::get_timestamp(ulong *sec_part) const return tmp; } + 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) @@ -4700,7 +4712,6 @@ int Field_timestamp::store_TIME_with_warning(THD *thd, MYSQL_TIME *l_time, ASSERT_COLUMN_MARKED_FOR_WRITE; uint error = 0; my_time_t timestamp; - my_bool in_dst_time_gap; if (was_cut || !have_smth_to_conv) { @@ -4708,19 +4719,14 @@ int Field_timestamp::store_TIME_with_warning(THD *thd, MYSQL_TIME *l_time, set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, str, MYSQL_TIMESTAMP_DATETIME, 1); } + /* Only convert a correct date (not a zero date) */ if (have_smth_to_conv && l_time->month) { - 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, - str, MYSQL_TIMESTAMP_DATETIME, !error); - error= 1; - } - else if (in_dst_time_gap) + uint conversion_error; + timestamp= TIME_to_timestamp(thd, l_time, &conversion_error); + if (conversion_error) { - set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, - ER_WARN_INVALID_TIMESTAMP, + set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, conversion_error, str, MYSQL_TIMESTAMP_DATETIME, !error); error= 1; } @@ -4736,7 +4742,7 @@ int Field_timestamp::store_TIME_with_warning(THD *thd, MYSQL_TIME *l_time, int Field_timestamp::store_time(MYSQL_TIME *ltime,timestamp_type time_type) { - THD *thd= table ? table->in_use : current_thd; + THD *thd= table->in_use; int unused; MYSQL_TIME l_time= *ltime; Lazy_string_time str(ltime); @@ -4753,7 +4759,7 @@ int Field_timestamp::store(const char *from,uint len,CHARSET_INFO *cs) int error; int have_smth_to_conv; Lazy_string_str str(from, len); - THD *thd= table ? table->in_use : current_thd; + THD *thd= table->in_use; /* We don't want to store invalid or fuzzy datetime values in TIMESTAMP */ have_smth_to_conv= (str_to_datetime(from, len, &l_time, @@ -4769,16 +4775,18 @@ int Field_timestamp::store(double nr) { MYSQL_TIME l_time; int error; - Lazy_string_dbl str(nr); - THD *thd= table ? table->in_use : current_thd; + Lazy_string_double str(nr); + THD *thd= table->in_use; /* We don't want to store invalid or fuzzy datetime values in TIMESTAMP */ + if (nr < 0 || nr > LONGLONG_MAX) + nr= LONGLONG_MAX; 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)); + l_time.second_part= (ulong)((nr-floor(nr))*TIME_SECOND_PART_FACTOR); + return store_TIME_with_warning(thd, &l_time, &str, error, tmp != -1); } @@ -4787,7 +4795,7 @@ int Field_timestamp::store(longlong nr, bool unsigned_val) MYSQL_TIME l_time; int error; Lazy_string_num str(nr); - THD *thd= table ? table->in_use : current_thd; + THD *thd= table->in_use; /* 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 & @@ -4804,12 +4812,17 @@ double Field_timestamp::val_real(void) longlong Field_timestamp::val_int(void) { MYSQL_TIME time_tmp; - THD *thd= table ? table->in_use : current_thd; + THD *thd= table->in_use; thd->time_zone_used= 1; ulong sec_part; uint32 temp= get_timestamp(&sec_part); + /* + Field_timestamp() and Field_timestamp_hres() shares this code. + This is why are also testing sec_part below. + */ + if (temp == 0 && sec_part == 0) return(0); @@ -4820,11 +4833,10 @@ 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) { uint32 temp2; - THD *thd= table ? table->in_use : current_thd; + THD *thd= table->in_use; MYSQL_TIME time_tmp; char *to; @@ -4891,7 +4903,7 @@ String *Field_timestamp::val_str(String *val_buffer, String *val_ptr) bool Field_timestamp::get_date(MYSQL_TIME *ltime, uint fuzzydate) { - THD *thd= table ? table->in_use : current_thd; + THD *thd= table->in_use; thd->time_zone_used= 1; ulong sec_part; uint32 temp= get_timestamp(&sec_part); @@ -4961,7 +4973,7 @@ void Field_timestamp::sql_type(String &res) const int Field_timestamp::set_time() { - THD *thd= table ? table->in_use : current_thd; + THD *thd= table->in_use; set_notnull(); store_TIME(thd->query_start(), 0); return 0; @@ -5052,12 +5064,6 @@ static longlong read_bigendian(const uchar *from, uint bytes) } } -static uint sec_part_bytes[MAX_DATETIME_PRECISION+1]= { 0, 1, 1, 2, 2, 3, 3 }; -static uint datetime_hires_bytes[MAX_DATETIME_PRECISION+1]= -{ 5, 6, 6, 7, 7, 7, 8 }; -static uint time_hires_bytes[MAX_DATETIME_PRECISION+1]= -{ 3, 4, 4, 5, 5, 5, 6 }; - void Field_timestamp_hires::store_TIME(my_time_t timestamp, ulong sec_part) { mi_int4store(ptr, timestamp); @@ -5074,7 +5080,7 @@ long Field_timestamp_hires::get_timestamp(ulong *sec_part) const double Field_timestamp_hires::val_real(void) { MYSQL_TIME time_tmp; - THD *thd= table ? table->in_use : current_thd; + THD *thd= table->in_use; thd->time_zone_used= 1; ulong sec_part; @@ -5119,7 +5125,7 @@ int Field_timestamp_hires::store_decimal(const my_decimal *d) int Field_timestamp_hires::set_time() { - THD *thd= table ? table->in_use : current_thd; + THD *thd= table->in_use; set_notnull(); store_TIME(thd->query_start(), thd->query_start_sec_part()); return 0; @@ -5238,7 +5244,7 @@ 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; + THD *thd= table->in_use; Lazy_string_str str(from, len); func_res= str_to_datetime(from, len, <ime, @@ -5255,22 +5261,18 @@ int Field_temporal::store(double nr) { int error= 0; MYSQL_TIME ltime; - longlong tmp; - THD *thd= table ? table->in_use : current_thd; - Lazy_string_dbl str(nr); + THD *thd= table->in_use; + Lazy_string_double str(nr); - if (nr < 0.0 || nr > 99991231235959.0) - { - tmp= -1; - error= 1; - } - else - tmp= number_to_datetime((longlong) floor(nr), <ime, (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); + if (nr < 0 || nr > LONGLONG_MAX) + nr= LONGLONG_MAX; + longlong tmp= number_to_datetime((longlong) floor(nr), <ime, + (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))*TIME_SECOND_PART_FACTOR); return store_TIME_with_warning(<ime, &str, error, tmp != -1); } @@ -5280,7 +5282,7 @@ int Field_temporal::store(longlong nr, bool unsigned_val) int error; MYSQL_TIME ltime; longlong tmp; - THD *thd= table ? table->in_use : current_thd; + THD *thd= table->in_use; Lazy_string_num str(nr); tmp= number_to_datetime(nr, <ime, (TIME_FUZZY_DATE | @@ -5340,8 +5342,8 @@ 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, <ime, TIME_TIME_ONLY, - &was_cut) > MYSQL_TIMESTAMP_ERROR; + int have_smth_to_conv= + str_to_time(from, len, <ime, &was_cut) > MYSQL_TIMESTAMP_ERROR; return store_TIME_with_warning(<ime, &str, was_cut, have_smth_to_conv); } @@ -5361,7 +5363,7 @@ int Field_time::store_time(MYSQL_TIME *ltime, timestamp_type time_type) int Field_time::store(double nr) { MYSQL_TIME ltime; - Lazy_string_dbl str(nr); + Lazy_string_double str(nr); int was_cut; int have_smth_to_conv= !number_to_time(nr, <ime, &was_cut); @@ -5405,7 +5407,6 @@ String *Field_time::val_str(String *val_buffer, { ASSERT_COLUMN_MARKED_FOR_READ; MYSQL_TIME ltime; - val_buffer->alloc(MAX_DATE_STRING_REP_LENGTH); long tmp=(long) sint3korr(ptr); ltime.neg= 0; if (tmp < 0) @@ -5432,7 +5433,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; + THD *thd= table->in_use; if (!(fuzzydate & (TIME_FUZZY_DATE|TIME_TIME_ONLY))) { push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, @@ -5751,7 +5752,6 @@ String *Field_date::val_str(String *val_buffer, { ASSERT_COLUMN_MARKED_FOR_READ; MYSQL_TIME ltime; - val_buffer->alloc(field_length); int32 tmp; if (ARCH_BIGENDIAN && table && table->s->db_low_byte_first) tmp=sint4korr(ptr); @@ -10085,7 +10085,7 @@ Field::set_warning(MYSQL_ERROR::enum_warning_level level, uint code, If this field was created only for type conversion purposes it will have table == NULL. */ - THD *thd= table ? table->in_use : current_thd; + THD *thd= table->in_use; if (thd->count_cuted_fields) { thd->cuted_fields+= cuted_increment; @@ -10119,7 +10119,7 @@ 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; + THD *thd= table->in_use; if ((thd->really_abort_on_warning() && level >= MYSQL_ERROR::WARN_LEVEL_WARN) || set_warning(level, code, cuted_increment)) diff --git a/sql/field.h b/sql/field.h index 75cf3858e6f..6361636771e 100644 --- a/sql/field.h +++ b/sql/field.h @@ -149,7 +149,6 @@ public: virtual bool str_needs_quotes() { return FALSE; } virtual Item_result result_type () const=0; virtual Item_result cmp_type () const { return result_type(); } - virtual Item_result cast_to_int_type () const { return cmp_type(); } static bool type_can_have_key_part(enum_field_types); static enum_field_types field_type_merge(enum_field_types, enum_field_types); static Item_result result_merge_type(enum_field_types); @@ -1437,7 +1436,6 @@ public: {} enum_field_types type() const { return MYSQL_TYPE_DATETIME;} enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONGLONG; } - enum Item_result cmp_type () const { return TIME_RESULT; } uint decimals() const { return 0; } double val_real(void); longlong val_int(void); @@ -1934,7 +1932,6 @@ public: Field *new_field(MEM_ROOT *root, struct st_table *new_table, bool keep_type); enum_field_types type() const { return MYSQL_TYPE_STRING; } enum Item_result cmp_type () const { return INT_RESULT; } - enum Item_result cast_to_int_type () const { return INT_RESULT; } enum ha_base_keytype key_type() const; int store(const char *to,uint length,CHARSET_INFO *charset); int store(double nr); diff --git a/sql/item.cc b/sql/item.cc index 997ce821f9a..fd0be90c216 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -194,10 +194,11 @@ bool Item::val_bool() case STRING_RESULT: return val_real() != 0.0; case ROW_RESULT: - default: + case TIME_RESULT: DBUG_ASSERT(0); return 0; // Wrong (but safe) } + return 0; // Wrong (but safe) } @@ -472,18 +473,17 @@ void Item::print_value(String *str) { switch (result_type()) { - default: - DBUG_ASSERT(0); case STRING_RESULT: - str->append('\''); - str->append(*ptr); - str->append('\''); + append_unescaped(str, ptr->ptr(), ptr->length()); break; case DECIMAL_RESULT: case REAL_RESULT: case INT_RESULT: str->append(*ptr); break; + case ROW_RESULT: + case TIME_RESULT: + DBUG_ASSERT(0); } } } @@ -533,7 +533,7 @@ void Item::rename(char *new_name) Item_result Item::cmp_type() const { - switch(field_type()) { + switch (field_type()) { case MYSQL_TYPE_DECIMAL: case MYSQL_TYPE_NEWDECIMAL: return DECIMAL_RESULT; @@ -1020,7 +1020,7 @@ err: bool Item::get_time(MYSQL_TIME *ltime) { - return get_date(ltime, TIME_TIME_ONLY); + return get_date(ltime, TIME_TIME_ONLY | TIME_FUZZY_DATE); } CHARSET_INFO *Item::default_charset() @@ -2187,10 +2187,11 @@ bool Item_field::val_bool_result() case STRING_RESULT: return result_field->val_real() != 0.0; case ROW_RESULT: - default: + case TIME_RESULT: DBUG_ASSERT(0); return 0; // Shut up compiler } + return 0; } @@ -2748,8 +2749,6 @@ 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 ? TIME_SECOND_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) || @@ -2765,6 +2764,7 @@ void Item_param::set_time(MYSQL_TIME *tm, timestamp_type time_type, state= TIME_VALUE; maybe_null= 0; max_length= max_length_arg; + decimals= tm->second_part > 0 ? TIME_SECOND_PART_DIGITS : 0; DBUG_VOID_RETURN; } @@ -2888,7 +2888,8 @@ bool Item_param::set_from_user_var(THD *thd, const user_var_entry *entry) param_type= MYSQL_TYPE_NEWDECIMAL; break; } - default: + case ROW_RESULT: + case TIME_RESULT: DBUG_ASSERT(0); set_null(); } @@ -3355,7 +3356,8 @@ Item_copy *Item_copy::create (Item *item) new Item_copy_uint (item) : new Item_copy_int (item); case DECIMAL_RESULT: return new Item_copy_decimal (item); - default: + case TIME_RESULT: + case ROW_RESULT: DBUG_ASSERT (0); } /* should not happen */ @@ -4810,10 +4812,11 @@ enum_field_types Item::field_type() const case DECIMAL_RESULT: return MYSQL_TYPE_NEWDECIMAL; case REAL_RESULT: return MYSQL_TYPE_DOUBLE; case ROW_RESULT: - default: + case TIME_RESULT: DBUG_ASSERT(0); return MYSQL_TYPE_VARCHAR; } + return MYSQL_TYPE_VARCHAR; } @@ -6232,7 +6235,7 @@ bool Item_ref::val_bool_result() case STRING_RESULT: return result_field->val_real() != 0.0; case ROW_RESULT: - default: + case TIME_RESULT: DBUG_ASSERT(0); } } @@ -6885,6 +6888,7 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item) { bool is_null; Item **ref_copy= ref; + /* the following call creates a constant and puts it in new_item */ get_datetime_value(thd, &ref_copy, &new_item, comp_item, &is_null); if (is_null) new_item= new Item_null(name); @@ -6964,8 +6968,6 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item) (Item*) new Item_decimal(name, result, length, decimals)); break; } - default: - DBUG_ASSERT(0); } if (new_item) thd->change_item_tree(ref, new_item); @@ -7045,20 +7047,24 @@ 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); } + /* + We have to check field->cmp_type() instead of res_type, + as result_type() - and thus res_type - can never be TIME_RESULT (yet). + */ 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); + 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) @@ -7101,11 +7107,8 @@ Item_cache* Item_cache::get_cache(const Item *item, const Item_result type) 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); - return 0; } + return 0; } void Item_cache::store(Item *item) @@ -7614,7 +7617,7 @@ enum_field_types Item_type_holder::get_real_type(Item *item) case DECIMAL_RESULT: return MYSQL_TYPE_NEWDECIMAL; case ROW_RESULT: - default: + case TIME_RESULT: DBUG_ASSERT(0); return MYSQL_TYPE_VAR_STRING; } diff --git a/sql/item.h b/sql/item.h index 275b876f521..3be654abdd8 100644 --- a/sql/item.h +++ b/sql/item.h @@ -568,7 +568,9 @@ public: { return save_in_field(field, 1); } virtual bool send(Protocol *protocol, String *str); virtual bool eq(const Item *, bool binary_cmp) const; + /* result_type() of an item specifies how the value should be returned */ virtual Item_result result_type() const { return REAL_RESULT; } + /* ... while cmp_type() specifies how it should be compared */ 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; @@ -731,6 +733,8 @@ public: /* This is also used to create fields in CREATE ... SELECT: */ virtual Field *tmp_table_field(TABLE *t_arg) { return 0; } virtual const char *full_name() const { return name ? name : "???"; } + const char *field_name_or_null() + { return real_item()->type() == Item::FIELD_ITEM ? name : NULL; } /* *result* family of methods is analog of *val* family (see above) but @@ -1492,7 +1496,7 @@ public: } Item_result cast_to_int_type() const { - return field->cast_to_int_type(); + return field->cmp_type(); } enum_field_types field_type() const { diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index e7418c2a53a..e99835083a6 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -614,8 +614,6 @@ int Arg_comparator::set_compare_func(Item_result_field *item, Item_result type) } break; } - default: - DBUG_ASSERT(0); } return 0; } @@ -708,6 +706,18 @@ static ulonglong get_date_from_str(THD *thd, String *str, return pack_time(&l_time); } +/** + Prepare the comparator (set the comparison function) for comparing + items *a1 and *a2 in the context of 'type'. + + @param[in] owner_arg Item, peforming the comparison (e.g. Item_func_eq) + @param[in,out] a1 first argument to compare + @param[in,out] a2 second argument to compare + @param[in] type type context to compare in + + Both *a1 and *a2 can be replaced by this method - typically by constant + items, holding the cached converted value of the original (constant) item. +*/ int Arg_comparator::set_cmp_func(Item_result_field *owner_arg, Item **a1, Item **a2, @@ -791,19 +801,16 @@ void Arg_comparator::set_datetime_cmp_func(Item_result_field *owner_arg, func= comparator_matrix[TIME_RESULT][is_owner_equal_func()]; } - -/* +/** Retrieves correct DATETIME value from given item. - SYNOPSIS - get_datetime_value() - thd thread handle - item_arg [in/out] item to retrieve DATETIME 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 + @param[in] thd thread handle + @param[in,out] item_arg item to retrieve DATETIME value from + @param[in,out] cache_arg pointer to place to store the caching item to + @param[in] warn_item item for issuing the conversion warning + @param[out] is_null TRUE <=> the item_arg is null - DESCRIPTION + @details Retrieves the correct DATETIME value from given item for comparison by the compare_datetime() function. @@ -818,7 +825,10 @@ void Arg_comparator::set_datetime_cmp_func(Item_result_field *owner_arg, 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 + If the item is a constant it is replaced by the Item_cache_int, that + holds the packed datetime value. + + @return MYSQL_TIME value, packed in a longlong, suitable for comparison. */ @@ -829,16 +839,15 @@ get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg, longlong UNINIT_VAR(value); Item *item= **item_arg; 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(); + cache_arg= 0; + } else { MYSQL_TIME buf; @@ -872,7 +881,7 @@ get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg, int was_cut; longlong res; - if (t_type == MYSQL_TIMESTAMP_TIME) + if (f_type == MYSQL_TYPE_TIME) res= number_to_time((double)value, &buf, &was_cut); else res= number_to_datetime(value, &buf, TIME_INVALID_DATES|TIME_FUZZY_DATE, @@ -880,8 +889,9 @@ get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg, if (res == -1) { const Lazy_string_num str(value); - make_truncated_value_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - &str, t_type, warn_item->name); + make_truncated_value_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, &str, + mysql_type_to_time_type(f_type), + warn_item->field_name_or_null()); value= 0; } else @@ -903,7 +913,10 @@ get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg, some insignificant zeros. */ bool error; - value= (longlong) get_date_from_str(thd, str, t_type, warn_item->name, &error); + value= (longlong) get_date_from_str(thd, str, + mysql_type_to_time_type(f_type), + warn_item->field_name_or_null(), + &error); /* If str did not contain a valid date according to the current SQL_MODE, get_date_from_str() has already thrown a warning, @@ -913,12 +926,23 @@ get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg, } break; } - default: DBUG_ASSERT(0); + case ROW_RESULT: + DBUG_ASSERT(0); } if ((*is_null= item->null_value)) return ~(ulonglong) 0; - if (cache_arg && item->const_item() && item->type() != Item::CACHE_ITEM) + if (cache_arg && item->const_item()) { + /* + cache the packed datetime value in the Item_cache object. + Because the packed datetime value is longlong, we use Item_cache_int, + and it has result_type() == INT_RESULT. + But we create it to have field_type() == MYSQL_TYPE_TIME (or + MYSQL_TIMESTAMP_DATE or MYSQL_TYPE_DATETIME), and thus it will have + cmp_type() == TIME_RESULT. + As no other item can have this combination of cmp_type() and result_type(), + it allows us to identify our cache items, see 'case TIME_RESULT:' above. + */ Item_cache_int *cache= new Item_cache_int(f_type); cache->store(item, value); *cache_arg= cache; @@ -976,9 +1000,6 @@ 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); @@ -1961,10 +1982,9 @@ bool Item_func_between::fix_fields(THD *thd, Item **ref) void Item_func_between::fix_length_and_dec() { + THD *thd= current_thd; max_length= 1; - int i; compare_as_dates= 0; - THD *thd= current_thd; /* As some compare functions are generated after sql_yacc, @@ -1980,7 +2000,7 @@ void Item_func_between::fix_length_and_dec() /* When comparing as date/time, we need to convert non-temporal values - (e.g. strings) to MYSQL_TIME. get_datetime_value() doees it + (e.g. strings) to MYSQL_TIME. get_datetime_value() does 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 @@ -1988,7 +2008,7 @@ void Item_func_between::fix_length_and_dec() */ if (cmp_type == TIME_RESULT) { - for (i= 0; i < 3; i++) + for (int i= 0; i < 3; i++) { if (args[i]->cmp_type() == TIME_RESULT) { @@ -2149,7 +2169,7 @@ longlong Item_func_between::val_int() } break; } - default: + case ROW_RESULT: DBUG_ASSERT(0); null_value= 1; return 0; @@ -2203,7 +2223,7 @@ Item_func_ifnull::fix_length_and_dec() decimals= 0; break; case ROW_RESULT: - default: + case TIME_RESULT: DBUG_ASSERT(0); } cached_field_type= agg_field_type(args, 2); @@ -2942,6 +2962,7 @@ void Item_func_coalesce::fix_length_and_dec() agg_result_type(&hybrid_type, args, arg_count); Item_result cmp_type; agg_cmp_type(&cmp_type, args, arg_count); + ///< @todo let result_type() return TIME_RESULT and remove this special case if (cmp_type == TIME_RESULT) { count_real_length(); @@ -2964,7 +2985,7 @@ void Item_func_coalesce::fix_length_and_dec() decimals= 0; break; case ROW_RESULT: - default: + case TIME_RESULT: DBUG_ASSERT(0); } } @@ -3293,7 +3314,7 @@ cmp_item* cmp_item::get_comparator(Item_result type, return new cmp_item_row; case DECIMAL_RESULT: return new cmp_item_decimal; - default: + case TIME_RESULT: DBUG_ASSERT(0); break; } @@ -3741,9 +3762,9 @@ void Item_func_in::fix_length_and_dec() case DECIMAL_RESULT: array= new in_decimal(arg_count - 1); break; - default: + case TIME_RESULT: DBUG_ASSERT(0); - return; + break; } } if (array && !(thd->is_fatal_error)) // If not EOM diff --git a/sql/item_create.cc b/sql/item_create.cc index abf32543494..3cc875509a0 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -5044,7 +5044,7 @@ find_qualified_function_builder(THD *thd) return & Create_sp_func::s_singleton; } -static inline const char* item_name(Item *a, String *str) +static const char* item_name(Item *a, String *str) { if (a->name) return a->name; @@ -5053,15 +5053,33 @@ static inline const char* item_name(Item *a, String *str) return str->c_ptr_safe(); } -Item * -create_func_cast(THD *thd, Item *a, Cast_target cast_type, - const char *c_len, const char *c_dec, - CHARSET_INFO *cs) +static uint get_number(Item *a, const char *c_len, bool *err, + uint maximum, uint errcode) { - Item *UNINIT_VAR(res); + if (!c_len) + return 0; + + int unused; char buff[1024]; String buf(buff, sizeof(buff), system_charset_info); + ulonglong decoded_size= my_strtoll10(c_len, NULL, &unused); + uint len= min(decoded_size, UINT_MAX32); + + if (decoded_size > maximum) + { + my_error(errcode, MYF(0), len, item_name(a, &buf), maximum); + *err= true; + } + return len; +} + +Item *create_func_cast(THD *thd, Item *a, Cast_target cast_type, + const char *c_len, const char *c_dec, + CHARSET_INFO *cs) +{ + Item *UNINIT_VAR(res); + switch (cast_type) { case ITEM_CAST_BINARY: res= new (thd->mem_root) Item_func_binary(a); @@ -5078,20 +5096,11 @@ create_func_cast(THD *thd, Item *a, Cast_target cast_type, case ITEM_CAST_TIME: case ITEM_CAST_DATETIME: { - 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= 0; + bool err= false; + uint len= get_number(a, c_len, &err, MAX_DATETIME_PRECISION, + ER_TOO_BIG_PRECISION); + if (err) + return NULL; if (cast_type == ITEM_CAST_TIME) res= new (thd->mem_root) Item_time_typecast(a, len); @@ -5101,72 +5110,40 @@ create_func_cast(THD *thd, Item *a, Cast_target cast_type, } case ITEM_CAST_DECIMAL: { - ulong len= 0; - uint dec= 0; + bool err= false; + ulong len= get_number(a, c_len, &err, DECIMAL_MAX_PRECISION, + ER_TOO_BIG_PRECISION); + uint dec= get_number(a, c_dec, &err, DECIMAL_MAX_SCALE, + ER_TOO_BIG_SCALE); + if (err) + return NULL; - if (c_len) - { - ulong decoded_size; - errno= 0; - decoded_size= strtoul(c_len, NULL, 10); - if (errno != 0) - { - my_error(ER_TOO_BIG_PRECISION, MYF(0), decoded_size, - item_name(a, &buf), DECIMAL_MAX_PRECISION); - return NULL; - } - len= decoded_size; - } - - if (c_dec) - { - ulong decoded_size; - errno= 0; - decoded_size= strtoul(c_dec, NULL, 10); - if ((errno != 0) || (decoded_size > UINT_MAX)) - { - my_error(ER_TOO_BIG_SCALE, MYF(0), decoded_size, - item_name(a, &buf), DECIMAL_MAX_SCALE); - return NULL; - } - dec= decoded_size; - } - my_decimal_trim(&len, &dec); if (len < dec) { my_error(ER_M_BIGGER_THAN_D, MYF(0), ""); - return 0; - } - if (len > 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, item_name(a, &buf), - DECIMAL_MAX_SCALE); - return 0; + return NULL; } + my_decimal_trim(&len, &dec); res= new (thd->mem_root) Item_decimal_typecast(a, len, dec); break; } case ITEM_CAST_CHAR: { - int len= -1; + uint len= ~0U; CHARSET_INFO *real_cs= (cs ? cs : thd->variables.collation_connection); if (c_len) { - ulong decoded_size; - errno= 0; - decoded_size= strtoul(c_len, NULL, 10); - if ((errno != 0) || (decoded_size > MAX_FIELD_BLOBLENGTH)) + int err; + ulonglong decoded_size= my_strtoll10(c_len, NULL, &err); + if (decoded_size> MAX_FIELD_BLOBLENGTH) { - my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), "cast as char", MAX_FIELD_BLOBLENGTH); + char buff[1024]; + String buf(buff, sizeof(buff), system_charset_info); + my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), + item_name(a, &buf), MAX_FIELD_BLOBLENGTH); return NULL; } - len= (int) decoded_size; + len= decoded_size; } res= new (thd->mem_root) Item_char_typecast(a, len, real_cs); break; diff --git a/sql/item_func.cc b/sql/item_func.cc index 9ee239b702b..870a481ce85 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -461,7 +461,7 @@ Field *Item_func::tmp_table_field(TABLE *table) field= Field_new_decimal::create_from_item(this); break; case ROW_RESULT: - default: + case TIME_RESULT: // This case should never be chosen DBUG_ASSERT(0); field= 0; @@ -716,7 +716,8 @@ void Item_func_num1::find_num_type() break; case DECIMAL_RESULT: break; - default: + case TIME_RESULT: + case ROW_RESULT: DBUG_ASSERT(0); } DBUG_PRINT("info", ("Type: %s", @@ -773,7 +774,8 @@ String *Item_func_numhybrid::val_str(String *str) } case STRING_RESULT: return str_op(&str_value); - default: + case TIME_RESULT: + case ROW_RESULT: DBUG_ASSERT(0); } return str; @@ -808,7 +810,8 @@ double Item_func_numhybrid::val_real() return (res ? my_strntod(res->charset(), (char*) res->ptr(), res->length(), &end_not_used, &err_not_used) : 0.0); } - default: + case TIME_RESULT: + case ROW_RESULT: DBUG_ASSERT(0); } return 0.0; @@ -843,7 +846,8 @@ longlong Item_func_numhybrid::val_int() CHARSET_INFO *cs= str_value.charset(); return (*(cs->cset->strtoll10))(cs, res->ptr(), &end, &err_not_used); } - default: + case TIME_RESULT: + case ROW_RESULT: DBUG_ASSERT(0); } return 0; @@ -881,7 +885,7 @@ my_decimal *Item_func_numhybrid::val_decimal(my_decimal *decimal_value) break; } case ROW_RESULT: - default: + case TIME_RESULT: DBUG_ASSERT(0); } return val; @@ -1340,7 +1344,9 @@ void Item_func_div::fix_length_and_dec() case DECIMAL_RESULT: result_precision(); break; - default: + case STRING_RESULT: + case ROW_RESULT: + case TIME_RESULT: DBUG_ASSERT(0); } maybe_null= 1; // devision by zero @@ -1833,7 +1839,8 @@ void Item_func_int_val::find_num_type() hybrid_type= INT_RESULT; } break; - default: + case ROW_RESULT: + case TIME_RESULT: DBUG_ASSERT(0); } DBUG_PRINT("info", ("Type: %s", @@ -2009,7 +2016,8 @@ void Item_func_round::fix_length_and_dec() unsigned_flag); break; } - default: + case ROW_RESULT: + case TIME_RESULT: DBUG_ASSERT(0); /* This result type isn't handled */ } } @@ -2230,8 +2238,8 @@ void Item_func_min_max::fix_length_and_dec() set_if_bigger(decimals, args[i]->decimals); set_if_bigger(max_int_part, args[i]->decimal_int_part()); if (args[i]->maybe_null) - maybe_null=1; - cmp_type=item_cmp_type(cmp_type,args[i]->result_type()); + maybe_null= 1; + cmp_type= item_cmp_type(cmp_type,args[i]->result_type()); if (args[i]->cmp_type() == TIME_RESULT) { if (!compare_as_dates || args[i]->field_type() == MYSQL_TYPE_DATETIME) @@ -2284,20 +2292,21 @@ bool Item_func_min_max::get_date(MYSQL_TIME *ltime, uint fuzzy_date) 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()) + if (thd->is_error() || args[i]->null_value) { null_value= 1; return 1; } - if ((null_value= args[i]->null_value)) - return 1; if (i == 0 || (res < min_max ? cmp_sign : -cmp_sign) > 0) min_max= res; } unpack_time(min_max, ltime); if (compare_as_dates->field_type() == MYSQL_TYPE_DATE) + { ltime->time_type= MYSQL_TIMESTAMP_DATE; + ltime->hour= ltime->minute= ltime->second= ltime->second_part= 0; + } return 0; } @@ -2312,9 +2321,9 @@ String *Item_func_min_max::val_str(String *str) if (get_date(<ime, TIME_FUZZY_DATE)) return 0; - char buf[MAX_DATE_STRING_REP_LENGTH]; - int len= my_TIME_to_str(<ime, buf, decimals); - str->copy(buf, len, collation.collation); + str->alloc(MAX_DATE_STRING_REP_LENGTH); + str->set_charset(collation.collation); + str->length(my_TIME_to_str(<ime, const_cast(str->ptr()), decimals)); return str; } switch (cmp_type) { @@ -2367,7 +2376,7 @@ String *Item_func_min_max::val_str(String *str) return res; } case ROW_RESULT: - default: + case TIME_RESULT: // This case should never be chosen DBUG_ASSERT(0); return 0; @@ -2955,7 +2964,7 @@ udf_handler::fix_fields(THD *thd, Item_result_field *func, to+= ALIGN_SIZE(sizeof(double)); break; case ROW_RESULT: - default: + case TIME_RESULT: // This case should never be chosen DBUG_ASSERT(0); break; @@ -3030,7 +3039,7 @@ bool udf_handler::get_arguments() } break; case ROW_RESULT: - default: + case TIME_RESULT: // This case should never be chosen DBUG_ASSERT(0); break; @@ -3634,7 +3643,7 @@ longlong Item_func_benchmark::val_int() (void) args[1]->val_decimal(&tmp_decimal); break; case ROW_RESULT: - default: + case TIME_RESULT: // This case should never be chosen DBUG_ASSERT(0); return 0; @@ -3968,7 +3977,8 @@ double user_var_entry::val_real(my_bool *null_value) } case STRING_RESULT: return my_atof(value); // This is null terminated - default: + case ROW_RESULT: + case TIME_RESULT: DBUG_ASSERT(1); // Impossible break; } @@ -3999,7 +4009,8 @@ longlong user_var_entry::val_int(my_bool *null_value) const int error; return my_strtoll10(value, (char**) 0, &error);// String is null terminated } - default: + case ROW_RESULT: + case TIME_RESULT: DBUG_ASSERT(1); // Impossible break; } @@ -4031,7 +4042,8 @@ 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 - default: + case ROW_RESULT: + case TIME_RESULT: DBUG_ASSERT(1); // Impossible break; } @@ -4058,7 +4070,8 @@ 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; - default: + case ROW_RESULT: + case TIME_RESULT: DBUG_ASSERT(1); // Impossible break; } @@ -4115,7 +4128,7 @@ Item_func_set_user_var::check(bool use_result_field) break; } case ROW_RESULT: - default: + case TIME_RESULT: // This case should never be chosen DBUG_ASSERT(0); break; @@ -4150,7 +4163,7 @@ void Item_func_set_user_var::save_item_result(Item *item) save_result.vdec= item->val_decimal_result(&decimal_buff); break; case ROW_RESULT: - default: + case TIME_RESULT: // Should never happen DBUG_ASSERT(0); break; @@ -4218,7 +4231,7 @@ Item_func_set_user_var::update() break; } case ROW_RESULT: - default: + case TIME_RESULT: // This case should never be chosen DBUG_ASSERT(0); break; @@ -4669,7 +4682,7 @@ void Item_func_get_user_var::fix_length_and_dec() decimals= DECIMAL_MAX_SCALE; break; case ROW_RESULT: // Keep compiler happy - default: + case TIME_RESULT: DBUG_ASSERT(0); break; } diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index a173f50e605..a32cfabcaa1 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -64,9 +64,12 @@ static bool make_datetime(MYSQL_TIME *ltime, String *str, uint decimals) 0 otherwise */ -static bool sec_to_time(double seconds, MYSQL_TIME *ltime) +bool Item_func_sec_to_time::sec_to_time(double seconds, MYSQL_TIME *ltime) { + Lazy_string_double str(seconds); uint sec; + const double max_sec_val= TIME_MAX_VALUE_SECONDS + + TIME_MAX_SECOND_PART/(double)TIME_SECOND_PART_FACTOR; bzero((char *)ltime, sizeof(*ltime)); @@ -75,32 +78,28 @@ static bool sec_to_time(double seconds, MYSQL_TIME *ltime) if (seconds < 0) { ltime->neg= 1; - if (seconds < -3020399) + if (seconds < -max_sec_val) goto overflow; seconds= -seconds; } - else if (seconds > 3020399) + else if (seconds > max_sec_val) goto overflow; sec= (uint) ((ulonglong) seconds % 3600); ltime->hour= (uint) (seconds/3600); ltime->minute= sec/60; ltime->second= sec % 60; - ltime->second_part= (ulong)((seconds - floor(seconds))*1e6); + ltime->second_part= (ulong)((seconds - floor(seconds))*TIME_SECOND_PART_FACTOR); return 0; overflow: - ltime->hour= TIME_MAX_HOUR; - ltime->minute= TIME_MAX_MINUTE; - ltime->second= TIME_MAX_SECOND; - - char buf[100]; - uint len= snprintf(buf, sizeof(buf), "%.80g", ltime->neg ? -seconds: seconds); + /* use check_time_range() to set ltime to the max value depending on dec */ + int unused; + ltime->hour= TIME_MAX_HOUR+1; + check_time_range(ltime, decimals, &unused); make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, - buf, len, MYSQL_TIMESTAMP_TIME, - NullS); - + &str, MYSQL_TIMESTAMP_TIME, NullS); return 1; } @@ -908,7 +907,7 @@ longlong Item_func_dayofyear::val_int() { DBUG_ASSERT(fixed == 1); MYSQL_TIME ltime; - if (get_arg0_date(<ime,TIME_NO_ZERO_DATE)) + if (get_arg0_date(<ime, TIME_NO_ZERO_IN_DATE | TIME_NO_ZERO_DATE)) return 0; return (longlong) calc_daynr(ltime.year,ltime.month,ltime.day) - calc_daynr(ltime.year,1,1) + 1; @@ -1180,7 +1179,7 @@ longlong Item_func_year::val_int_endpoint(bool left_endp, bool *incl_endp) longlong Item_func_unix_timestamp::val_int() { MYSQL_TIME ltime; - my_bool not_used; + uint not_used; DBUG_ASSERT(fixed == 1); if (arg_count == 0) @@ -1430,15 +1429,12 @@ bool Item_func_from_days::get_date(MYSQL_TIME *ltime, uint fuzzy_date) void Item_func_curdate::fix_length_and_dec() { - collation.set(&my_charset_bin); - decimals=0; - max_length=MAX_DATE_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; - store_now_in_TIME(<ime); /* 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; + Item_datefunc::fix_length_and_dec(); } /** @@ -1461,7 +1457,6 @@ void Item_func_curdate_utc::store_now_in_TIME(MYSQL_TIME *now_time) { 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. @@ -1488,14 +1483,6 @@ bool Item_func_curtime::fix_fields(THD *thd, Item **items) return Item_timefunc::fix_fields(thd, items); } -void Item_func_curtime::fix_length_and_dec() -{ - collation.set(&my_charset_bin); - store_now_in_TIME(<ime); - max_length= MAX_TIME_WIDTH + - (decimals ? min(decimals, TIME_SECOND_PART_DIGITS)+1 : 0); -} - bool Item_func_curtime::get_date(MYSQL_TIME *res, uint fuzzy_date __attribute__((unused))) { @@ -1558,15 +1545,6 @@ bool Item_func_now::fix_fields(THD *thd, Item **items) return Item_temporal_func::fix_fields(thd, items); } -void Item_func_now::fix_length_and_dec() -{ - collation.set(&my_charset_bin); - store_now_in_TIME(<ime); - max_length= MAX_DATETIME_WIDTH + - (decimals ? min(decimals, TIME_SECOND_PART_DIGITS)+1 : 0); -} - - /** Converts current time in my_time_t to MYSQL_TIME represenatation for local time zone. Defines time zone (local) used for whole NOW function. @@ -1621,9 +1599,7 @@ void Item_func_sysdate_local::store_now_in_TIME(MYSQL_TIME *now_time) bool Item_func_sysdate_local::get_date(MYSQL_TIME *res, uint fuzzy_date __attribute__((unused))) { - MYSQL_TIME ltime; - store_now_in_TIME(<ime); - *res= ltime; + store_now_in_TIME(res); return 0; } @@ -1819,11 +1795,9 @@ null_date: void Item_func_from_unixtime::fix_length_and_dec() { thd= current_thd; - collation.set(&my_charset_bin); - decimals= 0; - max_length=MAX_DATETIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; maybe_null= 1; thd->time_zone_used= 1; + Item_temporal_func::fix_length_and_dec(); } @@ -1846,12 +1820,9 @@ bool Item_func_from_unixtime::get_date(MYSQL_TIME *ltime, void Item_func_convert_tz::fix_length_and_dec() { - collation.set(&my_charset_bin); - max_length= MAX_DATETIME_WIDTH; - decimals= args[0]->decimals; - if (decimals && decimals != NOT_FIXED_DEC) - max_length+= min(decimals, TIME_SECOND_PART_DIGITS) + 1; maybe_null= 1; + decimals= args[0]->decimals; + Item_temporal_func::fix_length_and_dec(); } @@ -1907,10 +1878,7 @@ void Item_func_convert_tz::cleanup() void Item_date_add_interval::fix_length_and_dec() { enum_field_types arg0_field_type; - - collation.set(&my_charset_bin); maybe_null=1; - max_length=MAX_DATETIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; /* The field type for the result of an Item_date function is defined as @@ -1950,8 +1918,8 @@ void Item_date_add_interval::fix_length_and_dec() decimals= 6; else decimals= args[0]->decimals; - if (decimals) - max_length+= min(decimals, TIME_SECOND_PART_DIGITS) + 1; + + Item_temporal_func::fix_length_and_dec(); value.alloc(max_length); } @@ -1962,7 +1930,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|TIME_FUZZY_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); @@ -2159,13 +2127,13 @@ void Item_char_typecast::print(String *str, enum_query_type query_type) str->append(STRING_WITH_LEN("cast(")); args[0]->print(str, query_type); str->append(STRING_WITH_LEN(" as char")); - if (cast_length >= 0) + if (cast_length != ~0U) { str->append('('); char buffer[20]; // my_charset_bin is good enough for numbers String st(buffer, sizeof(buffer), &my_charset_bin); - st.set((ulonglong)cast_length, &my_charset_bin); + st.set(static_cast(cast_length), &my_charset_bin); str->append(st); str->append(')'); } @@ -2212,7 +2180,7 @@ String *Item_char_typecast::val_str(String *str) and the result is longer than cast length, e.g. CAST('string' AS CHAR(1)) */ - if (cast_length >= 0) + if (cast_length != ~0U) { if (res->length() > (length= (uint32) res->charpos(cast_length))) { // Safe even if const arg @@ -2232,16 +2200,15 @@ String *Item_char_typecast::val_str(String *str) res->c_ptr_safe()); res->length((uint) length); } - else if (cast_cs == &my_charset_bin && res->length() < (uint) cast_length) + else if (cast_cs == &my_charset_bin && res->length() < cast_length) { - if (res->alloced_length() < (uint) cast_length) + if (res->alloced_length() < cast_length) { str_value.alloc(cast_length); str_value.copy(*res); res= &str_value; } - bzero((char*) res->ptr() + res->length(), - (uint) cast_length - res->length()); + bzero((char*) res->ptr() + res->length(), cast_length - res->length()); res->length(cast_length); } } @@ -2287,7 +2254,7 @@ void Item_char_typecast::fix_length_and_dec() from_cs != &my_charset_bin && cast_cs != &my_charset_bin); collation.set(cast_cs, DERIVATION_IMPLICIT); - char_length= (cast_length >= 0) ? cast_length : + char_length= (cast_length != ~0U) ? cast_length : args[0]->max_length / (cast_cs == &my_charset_bin ? 1 : args[0]->collation.collation->mbmaxlen); max_length= char_length * cast_cs->mbmaxlen; @@ -2381,7 +2348,6 @@ err: void Item_func_add_time::fix_length_and_dec() { enum_field_types arg0_field_type; - max_length= MAX_DATETIME_WIDTH; decimals= max(args[0]->decimals, args[1]->decimals); maybe_null= 1; @@ -2403,8 +2369,7 @@ 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, TIME_SECOND_PART_DIGITS) + 1; + Item_temporal_func::fix_length_and_dec(); } /** @@ -2531,15 +2496,15 @@ bool Item_func_timediff::get_date(MYSQL_TIME *ltime, uint fuzzy_date) MYSQL_TIME l_time1,l_time2,l_time3; Lazy_string_time str(&l_time3); - null_value= 0; + /* the following may be true in, for example, date_add(timediff(...), ... */ + if (fuzzy_date & TIME_NO_ZERO_IN_DATE) + goto null_date; + if (args[0]->get_time(&l_time1) || args[1]->get_time(&l_time2) || l_time1.time_type != l_time2.time_type) goto null_date; - if (fuzzy_date & TIME_NO_ZERO_IN_DATE) - goto null_date; - if (l_time1.neg != l_time2.neg) l_sign= -l_sign; @@ -2556,7 +2521,14 @@ bool Item_func_timediff::get_date(MYSQL_TIME *ltime, uint fuzzy_date) if (l_time1.neg && (seconds || microseconds)) l_time3.neg= 1-l_time3.neg; // Swap sign of result + /* + seconds is longlong, when casted to long it may become a small number + even if the original seconds value was too large and invalid. + as a workaround we limit seconds by a large invalid long number + ("invalid" means > TIME_MAX_SECOND) + */ set_if_smaller(seconds, INT_MAX32); + calc_time_from_sec(&l_time3, (long) seconds, microseconds); if ((fuzzy_date & TIME_NO_ZERO_DATE) && (seconds == 0) && (microseconds == 0)) @@ -2933,9 +2905,7 @@ void Item_func_str_to_date::fix_length_and_dec() { maybe_null= 1; cached_field_type= MYSQL_TYPE_DATETIME; - max_length= MAX_DATETIME_WIDTH + TIME_SECOND_PART_DIGITS; - cached_timestamp_type= MYSQL_TIMESTAMP_DATETIME; - decimals= AUTO_SEC_PART_DIGITS; + decimals= NOT_FIXED_DEC; if ((const_item= args[1]->const_item())) { char format_buff[64]; @@ -2948,31 +2918,25 @@ void Item_func_str_to_date::fix_length_and_dec() 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_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; 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; } } + cached_timestamp_type= mysql_type_to_time_type(cached_field_type); + Item_temporal_func::fix_length_and_dec(); } diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index 9f45655add6..14275680d15 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -360,23 +360,35 @@ public: { return tmp_table_field_from_field_type(table, 0); } int save_in_field(Field *field, bool no_conversions) { return save_date_in_field(field); } + void fix_length_and_dec() + { + static const uint max_time_type_width[5]= + { MAX_DATETIME_WIDTH, MAX_DATETIME_WIDTH, MAX_DATE_WIDTH, + MAX_DATETIME_WIDTH, MIN_TIME_WIDTH }; + + max_length= max_time_type_width[mysql_type_to_time_type(field_type())+2]; + if (decimals) + { + if (decimals == NOT_FIXED_DEC) + max_length+= TIME_SECOND_PART_DIGITS + 1; + else + { + set_if_smaller(decimals, TIME_SECOND_PART_DIGITS); + max_length+= decimals + 1; + } + } + } }; class Item_datefunc :public Item_temporal_func { public: - Item_datefunc() :Item_temporal_func() {} - Item_datefunc(Item *a) :Item_temporal_func(a) {} + 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; - } }; @@ -388,11 +400,6 @@ public: 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() - { - max_length= MAX_TIME_WIDTH + - (decimals ? min(decimals, TIME_SECOND_PART_DIGITS)+1 : 0); - } }; @@ -404,7 +411,11 @@ class Item_func_curtime :public Item_timefunc public: Item_func_curtime(uint dec) :Item_timefunc() { decimals= dec; } bool fix_fields(THD *, Item **); - void fix_length_and_dec(); + void fix_length_and_dec() + { + store_now_in_TIME(<ime); + Item_timefunc::fix_length_and_dec(); + } bool get_date(MYSQL_TIME *res, uint fuzzy_date); /* Abstract method that defines which time zone is used for conversion. @@ -472,7 +483,11 @@ class Item_func_now :public Item_temporal_func public: Item_func_now(uint dec) :Item_temporal_func() { decimals= dec; } bool fix_fields(THD *, Item **); - void fix_length_and_dec(); + void fix_length_and_dec() + { + store_now_in_TIME(<ime); + Item_temporal_func::fix_length_and_dec(); + } bool get_date(MYSQL_TIME *res, uint fuzzy_date); virtual void store_now_in_TIME(MYSQL_TIME *now_time)=0; }; @@ -591,16 +606,14 @@ class Item_func_convert_tz :public Item_temporal_func class Item_func_sec_to_time :public Item_timefunc { + bool sec_to_time(double seconds, MYSQL_TIME *ltime); public: Item_func_sec_to_time(Item *item) :Item_timefunc(item) {} bool get_date(MYSQL_TIME *res, uint fuzzy_date); void fix_length_and_dec() - { - collation.set(&my_charset_bin); + { maybe_null=1; decimals= args[0]->decimals; - if (decimals != NOT_FIXED_DEC) - set_if_smaller(decimals, TIME_SECOND_PART_DIGITS); Item_timefunc::fix_length_and_dec(); } const char *func_name() const { return "sec_to_time"; } @@ -645,12 +658,12 @@ class Item_extract :public Item_int_func class Item_char_typecast :public Item_str_func { - int cast_length; + uint cast_length; CHARSET_INFO *cast_cs, *from_cs; bool charset_conversion; String tmp_value; public: - Item_char_typecast(Item *a, int length_arg, CHARSET_INFO *cs_arg) + Item_char_typecast(Item *a, uint length_arg, CHARSET_INFO *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; @@ -667,6 +680,13 @@ public: 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); + void fix_length_and_dec() + { + maybe_null= 1; + if (decimals == NOT_FIXED_DEC) + decimals= args[0]->decimals; + Item_temporal_func::fix_length_and_dec(); + } }; class Item_date_typecast :public Item_temporal_typecast @@ -677,13 +697,6 @@ public: bool get_date(MYSQL_TIME *ltime, uint fuzzy_date); const char *cast_type() const { return "date"; } enum_field_types field_type() const { return MYSQL_TYPE_DATE; } - void fix_length_and_dec() - { - collation.set(&my_charset_bin); - decimals= 0; - max_length= MAX_DATE_WIDTH; - maybe_null= 1; - } }; @@ -696,20 +709,6 @@ public: 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; } - void fix_length_and_dec() - { - collation.set(&my_charset_bin); - maybe_null= 1; - max_length= MIN_TIME_WIDTH; - if (decimals == NOT_FIXED_DEC) - { - decimals= args[0]->decimals; - if (decimals != NOT_FIXED_DEC) - set_if_smaller(decimals, TIME_SECOND_PART_DIGITS); - } - if (decimals && decimals != NOT_FIXED_DEC) - max_length+= min(decimals, TIME_SECOND_PART_DIGITS) + 1; - } }; @@ -722,14 +721,6 @@ public: const char *cast_type() const { return "datetime"; } enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; } 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_WIDTH; - if (decimals && decimals != NOT_FIXED_DEC) - max_length+= min(decimals, TIME_SECOND_PART_DIGITS) + 1; - } }; class Item_func_makedate :public Item_temporal_func @@ -740,10 +731,9 @@ public: enum_field_types field_type() const { return MYSQL_TYPE_DATE; } void fix_length_and_dec() { - decimals=0; - max_length=MAX_DATE_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; /* It returns NULL when the second argument is less or equal to 0 */ maybe_null= 1; + Item_temporal_func::fix_length_and_dec(); } bool get_date(MYSQL_TIME *ltime, uint fuzzy_date); }; diff --git a/sql/log_event.cc b/sql/log_event.cc index 49f18b919d3..3aef379ad3a 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1978,12 +1978,10 @@ end: delete td; } -#ifdef MYSQL_CLIENT void free_table_map_log_event(Table_map_log_event *event) { delete event; } -#endif void Log_event::print_base64(IO_CACHE* file, PRINT_EVENT_INFO* print_event_info, @@ -3614,7 +3612,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= get_time(); + created= get_time(); // this sets when and when_sec_part as a side effect int4store(buff + ST_CREATED_OFFSET,created); return (write_header(file, sizeof(buff)) || my_b_safe_write(file, (uchar*) buff, sizeof(buff))); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index acdbac4ff68..035f546f37a 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -733,11 +733,11 @@ public: void copy(String *dst) const { dst->set(num, &my_charset_bin); } }; -class Lazy_string_dbl: public Lazy_string +class Lazy_string_double: public Lazy_string { double num; public: - Lazy_string_dbl(double num_arg) : Lazy_string(), num(num_arg) {} + Lazy_string_double(double num_arg) : Lazy_string(), num(num_arg) {} void copy(String *dst) const { dst->set_real(num, NOT_FIXED_DEC, &my_charset_bin); } }; @@ -755,6 +755,19 @@ public: } }; +static inline enum enum_mysql_timestamp_type +mysql_type_to_time_type(enum enum_field_types mysql_type) +{ + switch(mysql_type) { + case MYSQL_TYPE_TIME: return MYSQL_TIMESTAMP_TIME; + case MYSQL_TYPE_TIMESTAMP: + case MYSQL_TYPE_DATETIME: return MYSQL_TIMESTAMP_DATETIME; + case MYSQL_TYPE_NEWDATE: + case MYSQL_TYPE_DATE: return MYSQL_TIMESTAMP_DATE; + default: return MYSQL_TIMESTAMP_ERROR; + } +} + #include "sql_list.h" #include "sql_map.h" #include "my_decimal.h" @@ -2212,7 +2225,7 @@ ulong convert_period_to_month(ulong period); 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); +my_time_t TIME_to_timestamp(THD *thd, const MYSQL_TIME *t, uint *error_code); 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); @@ -2257,19 +2270,6 @@ int my_time_compare(MYSQL_TIME *a, MYSQL_TIME *b); longlong get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg, Item *warn_item, bool *is_null); -static inline enum enum_mysql_timestamp_type -mysql_type_to_time_type(enum enum_field_types mysql_type) -{ - switch(mysql_type) { - case MYSQL_TYPE_TIME: return MYSQL_TIMESTAMP_TIME; - case MYSQL_TYPE_TIMESTAMP: - case MYSQL_TYPE_DATETIME: return MYSQL_TIMESTAMP_DATETIME; - case MYSQL_TYPE_NEWDATE: - case MYSQL_TYPE_DATE: return MYSQL_TIMESTAMP_DATE; - default: return MYSQL_TIMESTAMP_ERROR; - } -} - int test_if_number(char *str,int *res,bool allow_wildcards); void change_byte(uchar *,uint,char,char); void init_read_record(READ_RECORD *info, THD *thd, TABLE *reg_form, diff --git a/sql/set_var.cc b/sql/set_var.cc index 4ce85452f3e..376364bab60 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -2999,7 +2999,7 @@ void sys_var_thd_lc_time_names::set_default(THD *thd, enum_var_type type) } /* - Handling of microseoncds given as seconds.part_seconds + Handling of microseconds given as seconds.part_seconds NOTES The argument to long query time is in seconds in decimal diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index a9880913c5e..0e014a1a00a 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5555,8 +5555,8 @@ ER_WARN_CANT_DROP_DEFAULT_KEYCACHE eng "Cannot drop default keycache" ger "Der vorgabemäßige Schlüssel-Cache kann nicht gelöscht werden" ER_TOO_BIG_DISPLAYWIDTH 42000 S1009 - eng "Display width out of range for column '%-.192s' (max = %lu)" - ger "Anzeigebreite außerhalb des zulässigen Bereichs für Spalte '%-.192s' (Maximum: %lu)" + eng "Display width out of range for '%-.192s' (max = %lu)" + ger "Anzeigebreite außerhalb des zulässigen Bereichs für '%-.192s' (Maximum: %lu)" ER_XAER_DUPID XAE08 eng "XAER_DUPID: The XID already exists" ger "XAER_DUPID: Die XID existiert bereits" diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 7c7751f922f..94ab9f2dc41 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -2338,7 +2338,8 @@ bool select_max_min_finder_subselect::send_data(List &items) case DECIMAL_RESULT: op= &select_max_min_finder_subselect::cmp_decimal; break; - default: + case ROW_RESULT: + case TIME_RESULT: // This case should never be choosen DBUG_ASSERT(0); op= 0; diff --git a/sql/sql_string.cc b/sql/sql_string.cc index a41f4d52101..8d30055be5b 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -551,7 +551,7 @@ uint32 String::numchars() return str_charset->cset->numchars(str_charset, Ptr, Ptr+str_length); } -int String::charpos(int i,uint32 offset) +int String::charpos(longlong i,uint32 offset) { if (i <= 0) return i; diff --git a/sql/sql_string.h b/sql/sql_string.h index b15179bcbe5..e5d91c6ff6e 100644 --- a/sql/sql_string.h +++ b/sql/sql_string.h @@ -286,7 +286,7 @@ public: friend int stringcmp(const String *a,const String *b); friend String *copy_if_not_alloced(String *a,String *b,uint32 arg_length); uint32 numchars(); - int charpos(int i,uint32 offset=0); + int charpos(longlong i,uint32 offset=0); int reserve(uint32 space_needed) { diff --git a/sql/time.cc b/sql/time.cc index 2badb77d14b..ba81fcc86c2 100644 --- a/sql/time.cc +++ b/sql/time.cc @@ -250,30 +250,36 @@ str_to_datetime_with_warn(const char *str, uint length, MYSQL_TIME *l_time, TIME_to_timestamp() thd - current thread t - datetime in broken-down representation, - in_dst_time_gap - pointer to bool which is set to true if t represents - value which doesn't exists (falls into the spring - time-gap) or to false otherwise. + error_code - 0, if the conversion was successful; + ER_WARN_DATA_OUT_OF_RANGE, if t contains datetime value + which is out of TIMESTAMP range; + ER_WARN_INVALID_TIMESTAMP, if t represents value which + doesn't exists (falls into the spring time-gap). RETURN Number seconds in UTC since start of Unix Epoch corresponding to t. - 0 - t contains datetime value which is out of TIMESTAMP range. + 0 - in case of ER_WARN_DATA_OUT_OF_RANGE */ -my_time_t TIME_to_timestamp(THD *thd, const MYSQL_TIME *t, my_bool *in_dst_time_gap) +my_time_t TIME_to_timestamp(THD *thd, const MYSQL_TIME *t, uint *error_code) { my_time_t timestamp; + my_bool in_dst_time_gap= 0; - *in_dst_time_gap= 0; + *error_code= 0; thd->time_zone_used= 1; - timestamp= thd->variables.time_zone->TIME_to_gmt_sec(t, in_dst_time_gap); + timestamp= thd->variables.time_zone->TIME_to_gmt_sec(t, &in_dst_time_gap); if (timestamp) { + if (in_dst_time_gap) + *error_code= ER_WARN_INVALID_TIMESTAMP; return timestamp; } /* If we are here we have range error. */ - return(0); + *error_code= ER_WARN_DATA_OUT_OF_RANGE; + return 0; } @@ -675,6 +681,7 @@ const char *get_date_time_format_str(KNOWN_DATE_TIME_FORMAT *format, void make_time(const DATE_TIME_FORMAT *format __attribute__((unused)), const MYSQL_TIME *l_time, String *str) { + str->alloc(MAX_DATE_STRING_REP_LENGTH); uint length= (uint) my_time_to_str(l_time, (char*) str->ptr(), 0); str->length(length); str->set_charset(&my_charset_bin); @@ -684,6 +691,7 @@ void make_time(const DATE_TIME_FORMAT *format __attribute__((unused)), void make_date(const DATE_TIME_FORMAT *format __attribute__((unused)), const MYSQL_TIME *l_time, String *str) { + str->alloc(MAX_DATE_STRING_REP_LENGTH); uint length= (uint) my_date_to_str(l_time, (char*) str->ptr()); str->length(length); str->set_charset(&my_charset_bin); @@ -693,6 +701,7 @@ 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) { + str->alloc(MAX_DATE_STRING_REP_LENGTH); uint length= (uint) my_datetime_to_str(l_time, (char*) str->ptr(), 0); str->length(length); str->set_charset(&my_charset_bin); @@ -776,7 +785,7 @@ bool date_add_interval(MYSQL_TIME *ltime, interval_type int_type, INTERVAL inter my_bool neg= ltime->neg; enum enum_mysql_timestamp_type time_type= ltime->time_type; - if (ltime->time_type != MYSQL_TIMESTAMP_TIME) + if (time_type != MYSQL_TIMESTAMP_TIME) ltime->day+= calc_daynr(ltime->year, ltime->month, 1) - 1; usec= COMBINE(ltime) + sign*COMBINE(&interval); @@ -791,7 +800,7 @@ bool date_add_interval(MYSQL_TIME *ltime, interval_type int_type, INTERVAL inter if (int_type != INTERVAL_DAY) ltime->time_type= MYSQL_TIMESTAMP_DATETIME; // Return full date - daynr= ltime->day + 32*(ltime->month + 13*ltime->year); + daynr= usec/1000000/24/60/60; /* Day number from year 0 to 9999-12-31 */ if ((ulonglong) daynr > MAX_DAY_NUMBER) -- cgit v1.2.1 From 7ffb52499cf87ef9f6dd7179779b05a5d6a6128b Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 19 May 2011 19:19:44 +0200 Subject: microseconds in log tables: TIMESTAMP -> TIMESTAMP(6) TIME -> TIME(6) in general_log and slow_log tables. include/my_sys.h: use constants --- sql/log.cc | 107 +++++++++++++++++++++++++++---------------------------------- sql/log.h | 20 ++++++------ 2 files changed, 57 insertions(+), 70 deletions(-) (limited to 'sql') diff --git a/sql/log.cc b/sql/log.cc index 6699e42c7f6..dea93fa1f46 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -355,7 +355,7 @@ void Log_to_csv_event_handler::cleanup() */ bool Log_to_csv_event_handler:: - log_general(THD *thd, time_t event_time, const char *user_host, + log_general(THD *thd, my_hrtime_t event_time, const char *user_host, uint user_host_len, int thread_id, const char *command_type, uint command_type_len, const char *sql_text, uint sql_text_len, @@ -436,7 +436,8 @@ bool Log_to_csv_event_handler:: DBUG_ASSERT(table->field[0]->type() == MYSQL_TYPE_TIMESTAMP); - ((Field_timestamp*) table->field[0])->store_TIME((my_time_t) event_time, 0); + ((Field_timestamp*) table->field[0])->store_TIME( + hrtime_to_my_time(event_time), hrtime_sec_part(event_time)); /* do a write */ if (table->field[1]->store(user_host, user_host_len, client_cs) || @@ -500,7 +501,6 @@ err: log_slow() thd THD of the query current_time current timestamp - query_start_arg command start timestamp user_host the pointer to the string with user@host info user_host_len length of the user_host string. this is computed once and passed to all general log event handlers @@ -523,7 +523,7 @@ err: */ bool Log_to_csv_event_handler:: - log_slow(THD *thd, time_t current_time, time_t query_start_arg, + log_slow(THD *thd, my_hrtime_t current_time, const char *user_host, uint user_host_len, ulonglong query_utime, ulonglong lock_utime, bool is_command, const char *sql_text, uint sql_text_len) @@ -537,6 +537,11 @@ bool Log_to_csv_event_handler:: Open_tables_state open_tables_backup; CHARSET_INFO *client_cs= thd->variables.character_set_client; bool save_time_zone_used; + long query_time= (long) min(query_utime/1000000, TIME_MAX_VALUE_SECONDS); + long lock_time= (long) min(lock_utime/1000000, TIME_MAX_VALUE_SECONDS); + long query_time_micro= (long) (query_utime % 1000000); + long lock_time_micro= (long) (lock_utime % 1000000); + DBUG_ENTER("Log_to_csv_event_handler::log_slow"); thd->push_internal_handler(& error_handler); @@ -578,44 +583,34 @@ 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_TIME((my_time_t) current_time, 0); + ((Field_timestamp*) table->field[0])->store_TIME( + hrtime_to_my_time(current_time), hrtime_sec_part(current_time)); if (table->field[1]->store(user_host, user_host_len, client_cs)) goto err; - if (query_start_arg) - { - longlong query_time= (longlong) (query_utime/1000000); - longlong lock_time= (longlong) (lock_utime/1000000); - /* - A TIME field can not hold the full longlong range; query_time or - lock_time may be truncated without warning here, if greater than - 839 hours (~35 days) - */ - MYSQL_TIME t; - t.neg= 0; + /* + A TIME field can not hold the full longlong range; query_time or + lock_time may be truncated without warning here, if greater than + 839 hours (~35 days) + */ + MYSQL_TIME t; + t.neg= 0; + + /* fill in query_time field */ + calc_time_from_sec(&t, query_time, query_time_micro); + if (table->field[2]->store_time(&t, MYSQL_TIMESTAMP_TIME)) + goto err; + /* lock_time */ + calc_time_from_sec(&t, lock_time, lock_time_micro); + if (table->field[3]->store_time(&t, MYSQL_TIMESTAMP_TIME)) + goto err; + /* rows_sent */ + if (table->field[4]->store((longlong) thd->sent_row_count, TRUE)) + goto err; + /* rows_examined */ + if (table->field[5]->store((longlong) thd->examined_row_count, TRUE)) + goto err; - /* fill in query_time field */ - calc_time_from_sec(&t, (long) min(query_time, (longlong) TIME_MAX_VALUE_SECONDS), 0); - if (table->field[2]->store_time(&t, MYSQL_TIMESTAMP_TIME)) - goto err; - /* lock_time */ - calc_time_from_sec(&t, (long) min(lock_time, (longlong) TIME_MAX_VALUE_SECONDS), 0); - if (table->field[3]->store_time(&t, MYSQL_TIMESTAMP_TIME)) - goto err; - /* rows_sent */ - if (table->field[4]->store((longlong) thd->sent_row_count, TRUE)) - goto err; - /* rows_examined */ - if (table->field[5]->store((longlong) thd->examined_row_count, TRUE)) - goto err; - } - else - { - table->field[2]->set_null(); - table->field[3]->set_null(); - table->field[4]->set_null(); - table->field[5]->set_null(); - } /* fill database field */ if (thd->db) { @@ -752,14 +747,14 @@ void Log_to_file_event_handler::init_pthread_objects() /** Wrapper around MYSQL_LOG::write() for slow log. */ bool Log_to_file_event_handler:: - log_slow(THD *thd, time_t current_time, time_t query_start_arg, + log_slow(THD *thd, my_hrtime_t current_time, const char *user_host, uint user_host_len, ulonglong query_utime, ulonglong lock_utime, bool is_command, const char *sql_text, uint sql_text_len) { Silence_log_table_errors error_handler; thd->push_internal_handler(&error_handler); - bool retval= mysql_slow_log.write(thd, current_time, query_start_arg, + bool retval= mysql_slow_log.write(thd, hrtime_to_my_time(current_time), user_host, user_host_len, query_utime, lock_utime, is_command, sql_text, sql_text_len); @@ -774,7 +769,7 @@ bool Log_to_file_event_handler:: */ bool Log_to_file_event_handler:: - log_general(THD *thd, time_t event_time, const char *user_host, + log_general(THD *thd, my_hrtime_t event_time, const char *user_host, uint user_host_len, int thread_id, const char *command_type, uint command_type_len, const char *sql_text, uint sql_text_len, @@ -782,7 +777,8 @@ bool Log_to_file_event_handler:: { Silence_log_table_errors error_handler; thd->push_internal_handler(&error_handler); - bool retval= mysql_log.write(event_time, user_host, user_host_len, + bool retval= mysql_log.write(hrtime_to_time(event_time), user_host, + user_host_len, thread_id, command_type, command_type_len, sql_text, sql_text_len); thd->pop_internal_handler(); @@ -969,8 +965,6 @@ bool LOGGER::slow_log_print(THD *thd, const char *query, uint query_length, if (*slow_log_handler_list) { - time_t current_time; - /* do not log slow queries from replication threads */ if (thd->slave_thread && !opt_log_slow_slave_statements) return 0; @@ -990,17 +984,12 @@ bool LOGGER::slow_log_print(THD *thd, const char *query, uint query_length, sctx->ip ? sctx->ip : "", "]", NullS) - user_host_buff); - 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); - } + DBUG_ASSERT(thd->start_utime); + DBUG_ASSERT(thd->start_time); + query_utime= (current_utime - thd->start_utime); + lock_utime= (thd->utime_after_lock - thd->start_utime); + my_hrtime_t current_time= { hrtime_from_time(thd->start_time) + + thd->start_time_sec_part + query_utime }; if (!query) { @@ -1011,7 +1000,6 @@ 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, user_host_buff, user_host_len, query_utime, lock_utime, is_command, query, query_length) || error; @@ -1029,7 +1017,7 @@ bool LOGGER::general_log_write(THD *thd, enum enum_server_command command, char user_host_buff[MAX_USER_HOST_SIZE + 1]; Security_context *sctx= thd->security_ctx; uint user_host_len= 0; - time_t current_time; + my_hrtime_t current_time; DBUG_ASSERT(thd); @@ -1046,7 +1034,7 @@ bool LOGGER::general_log_write(THD *thd, enum enum_server_command command, sctx->ip ? sctx->ip : "", "]", NullS) - user_host_buff; - current_time= my_time(0); + current_time= my_hrtime(); while (*current_handler) error|= (*current_handler++)-> log_general(thd, current_time, user_host_buff, @@ -2259,7 +2247,6 @@ err: thd THD of the query current_time current timestamp - query_start_arg command start timestamp user_host the pointer to the string with user@host info user_host_len length of the user_host string. this is computed once and passed to all general log event handlers @@ -2281,7 +2268,7 @@ err: */ bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time, - time_t query_start_arg, const char *user_host, + const char *user_host, uint user_host_len, ulonglong query_utime, ulonglong lock_utime, bool is_command, const char *sql_text, uint sql_text_len) diff --git a/sql/log.h b/sql/log.h index 8f1ed7ee90c..77c6d8b1465 100644 --- a/sql/log.h +++ b/sql/log.h @@ -211,7 +211,7 @@ public: uint user_host_len, int thread_id, const char *command_type, uint command_type_len, const char *sql_text, uint sql_text_len); - bool write(THD *thd, time_t current_time, time_t query_start_arg, + bool write(THD *thd, time_t current_time, const char *user_host, uint user_host_len, ulonglong query_utime, ulonglong lock_utime, bool is_command, const char *sql_text, uint sql_text_len); @@ -425,14 +425,14 @@ public: virtual bool init()= 0; virtual void cleanup()= 0; - virtual bool log_slow(THD *thd, time_t current_time, - time_t query_start_arg, const char *user_host, + virtual bool log_slow(THD *thd, my_hrtime_t current_time, + const char *user_host, uint user_host_len, ulonglong query_utime, ulonglong lock_utime, bool is_command, const char *sql_text, uint sql_text_len)= 0; virtual bool log_error(enum loglevel level, const char *format, va_list args)= 0; - virtual bool log_general(THD *thd, time_t event_time, const char *user_host, + virtual bool log_general(THD *thd, my_hrtime_t event_time, const char *user_host, uint user_host_len, int thread_id, const char *command_type, uint command_type_len, const char *sql_text, uint sql_text_len, @@ -454,14 +454,14 @@ public: virtual bool init(); virtual void cleanup(); - virtual bool log_slow(THD *thd, time_t current_time, - time_t query_start_arg, const char *user_host, + virtual bool log_slow(THD *thd, my_hrtime_t current_time, + const char *user_host, uint user_host_len, ulonglong query_utime, ulonglong lock_utime, bool is_command, const char *sql_text, uint sql_text_len); virtual bool log_error(enum loglevel level, const char *format, va_list args); - virtual bool log_general(THD *thd, time_t event_time, const char *user_host, + virtual bool log_general(THD *thd, my_hrtime_t event_time, const char *user_host, uint user_host_len, int thread_id, const char *command_type, uint command_type_len, const char *sql_text, uint sql_text_len, @@ -486,14 +486,14 @@ public: virtual bool init(); virtual void cleanup(); - virtual bool log_slow(THD *thd, time_t current_time, - time_t query_start_arg, const char *user_host, + virtual bool log_slow(THD *thd, my_hrtime_t current_time, + const char *user_host, uint user_host_len, ulonglong query_utime, ulonglong lock_utime, bool is_command, const char *sql_text, uint sql_text_len); virtual bool log_error(enum loglevel level, const char *format, va_list args); - virtual bool log_general(THD *thd, time_t event_time, const char *user_host, + virtual bool log_general(THD *thd, my_hrtime_t event_time, const char *user_host, uint user_host_len, int thread_id, const char *command_type, uint command_type_len, const char *sql_text, uint sql_text_len, -- cgit v1.2.1 From 5ce4dab7bf1bdcfdfaa59e5290d0668bc4bd1a61 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 20 May 2011 23:56:13 +0200 Subject: db_low_byte_first is gone --- sql/field.cc | 581 +++++++++++----------------------------------------- sql/field.h | 302 ++++++++++----------------- sql/field_conv.cc | 15 +- sql/ha_partition.cc | 8 - sql/ha_partition.h | 7 - sql/handler.h | 1 - sql/rpl_record.cc | 4 +- sql/rpl_utility.cc | 2 +- sql/sql_insert.cc | 3 - sql/sql_select.cc | 1 - sql/table.cc | 3 - sql/table.h | 1 - sql/unireg.cc | 1 - 13 files changed, 238 insertions(+), 691 deletions(-) (limited to 'sql') diff --git a/sql/field.cc b/sql/field.cc index 7e0d99bc9f5..0f1a8a2cdb6 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1418,13 +1418,6 @@ int Field::store(const char *to, uint length, CHARSET_INFO *cs, should be overridden. The other functions are just convenience functions and hence should not be overridden. - The value of low_byte_first is dependent on how the - packed data is going to be used: for local use, e.g., temporary - store on disk or in memory, use the native format since that is - faster. For data that is going to be transfered to other machines - (e.g., when writing data to the binary log), data should always be - stored in little-endian format. - @note The default method for packing fields just copy the raw bytes of the record into the destination, but never more than max_length characters. @@ -1442,15 +1435,9 @@ int Field::store(const char *to, uint length, CHARSET_INFO *cs, is 1000. This information is sometimes needed to decide how to pack the data. - @param low_byte_first - @c TRUE if integers should be stored little-endian, @c FALSE if - native format should be used. Note that for little-endian machines, - the value of this flag is a moot point since the native format is - little-endian. */ uchar * -Field::pack(uchar *to, const uchar *from, uint max_length, - bool low_byte_first __attribute__((unused))) +Field::pack(uchar *to, const uchar *from, uint max_length) { uint32 length= pack_length(); set_if_smaller(length, max_length); @@ -1481,16 +1468,10 @@ Field::pack(uchar *to, const uchar *from, uint max_length, @param param_data Real type and original pack length of the field data - @param low_byte_first - If this flag is @c true, all composite entities (e.g., lengths) - should be unpacked in little-endian format; otherwise, the entities - are unpacked in native order. - @return New pointer into memory based on from + length of the data */ const uchar * -Field::unpack(uchar* to, const uchar *from, uint param_data, - bool low_byte_first __attribute__((unused))) +Field::unpack(uchar* to, const uchar *from, uint param_data) { uint length=pack_length(); int from_type= 0; @@ -2924,13 +2905,10 @@ uint Field_new_decimal::is_equal(Create_field *new_field) @return New pointer into memory based on from + length of the data */ const uchar * -Field_new_decimal::unpack(uchar* to, - const uchar *from, - uint param_data, - bool low_byte_first) +Field_new_decimal::unpack(uchar* to, const uchar *from, uint param_data) { if (param_data == 0) - return Field::unpack(to, from, param_data, low_byte_first); + return Field::unpack(to, from, param_data); uint from_precision= (param_data & 0xff00) >> 8U; uint from_decimal= param_data & 0x00ff; @@ -3152,10 +3130,7 @@ 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; - if (ARCH_BIGENDIAN && table->s->db_low_byte_first) - int2store(ptr, store_tmp); - else - shortstore(ptr, (short) store_tmp); + int2store(ptr, store_tmp); return error; } @@ -3200,10 +3175,7 @@ int Field_short::store(double nr) else res=(int16) (int) nr; } - if (ARCH_BIGENDIAN && table->s->db_low_byte_first) - int2store(ptr,res); - else - shortstore(ptr,res); + int2store(ptr,res); return error; } @@ -3251,10 +3223,7 @@ int Field_short::store(longlong nr, bool unsigned_val) else res=(int16) nr; } - if (ARCH_BIGENDIAN && table->s->db_low_byte_first) - int2store(ptr,res); - else - shortstore(ptr,res); + int2store(ptr,res); return error; } @@ -3263,10 +3232,7 @@ double Field_short::val_real(void) { ASSERT_COLUMN_MARKED_FOR_READ; short j; - if (ARCH_BIGENDIAN && table->s->db_low_byte_first) - j=sint2korr(ptr); - else - shortget(j,ptr); + j=sint2korr(ptr); return unsigned_flag ? (double) (unsigned short) j : (double) j; } @@ -3274,10 +3240,7 @@ longlong Field_short::val_int(void) { ASSERT_COLUMN_MARKED_FOR_READ; short j; - if (ARCH_BIGENDIAN && table->s->db_low_byte_first) - j=sint2korr(ptr); - else - shortget(j,ptr); + j=sint2korr(ptr); return unsigned_flag ? (longlong) (unsigned short) j : (longlong) j; } @@ -3292,10 +3255,7 @@ String *Field_short::val_str(String *val_buffer, val_buffer->alloc(mlength); char *to=(char*) val_buffer->ptr(); short j; - if (ARCH_BIGENDIAN && table->s->db_low_byte_first) - j=sint2korr(ptr); - else - shortget(j,ptr); + j=sint2korr(ptr); if (unsigned_flag) length=(uint) cs->cset->long10_to_str(cs, to, mlength, 10, @@ -3318,16 +3278,8 @@ bool Field_short::send_binary(Protocol *protocol) int Field_short::cmp(const uchar *a_ptr, const uchar *b_ptr) { short a,b; - if (ARCH_BIGENDIAN && table->s->db_low_byte_first) - { - a=sint2korr(a_ptr); - b=sint2korr(b_ptr); - } - else - { - shortget(a,a_ptr); - shortget(b,b_ptr); - } + a=sint2korr(a_ptr); + b=sint2korr(b_ptr); if (unsigned_flag) return ((unsigned short) a < (unsigned short) b) ? -1 : @@ -3337,22 +3289,11 @@ int Field_short::cmp(const uchar *a_ptr, const uchar *b_ptr) void Field_short::sort_string(uchar *to,uint length __attribute__((unused))) { - if (ARCH_BIGENDIAN && !table->s->db_low_byte_first) - { - if (unsigned_flag) - to[0] = ptr[0]; - else - to[0] = (char) (ptr[0] ^ 128); /* Revers signbit */ - to[1] = ptr[1]; - } + if (unsigned_flag) + to[0] = ptr[1]; else - { - if (unsigned_flag) - to[0] = ptr[1]; - else - to[0] = (char) (ptr[1] ^ 128); /* Revers signbit */ - to[1] = ptr[0]; - } + to[0] = (char) (ptr[1] ^ 128); /* Revers signbit */ + to[1] = ptr[0]; } void Field_short::sql_type(String &res) const @@ -3567,10 +3508,7 @@ 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; - if (ARCH_BIGENDIAN && table->s->db_low_byte_first) - int4store(ptr, store_tmp); - else - longstore(ptr, store_tmp); + int4store(ptr, store_tmp); return error; } @@ -3615,10 +3553,7 @@ int Field_long::store(double nr) if (error) set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); - if (ARCH_BIGENDIAN && table->s->db_low_byte_first) - int4store(ptr,res); - else - longstore(ptr,res); + int4store(ptr,res); return error; } @@ -3664,10 +3599,7 @@ 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); - if (ARCH_BIGENDIAN && table->s->db_low_byte_first) - int4store(ptr,res); - else - longstore(ptr,res); + int4store(ptr,res); return error; } @@ -3676,10 +3608,7 @@ double Field_long::val_real(void) { ASSERT_COLUMN_MARKED_FOR_READ; int32 j; - if (ARCH_BIGENDIAN && table->s->db_low_byte_first) - j=sint4korr(ptr); - else - longget(j,ptr); + j=sint4korr(ptr); return unsigned_flag ? (double) (uint32) j : (double) j; } @@ -3689,10 +3618,7 @@ longlong Field_long::val_int(void) int32 j; /* See the comment in Field_long::store(long long) */ DBUG_ASSERT(table->in_use == current_thd); - if (ARCH_BIGENDIAN && table->s->db_low_byte_first) - j=sint4korr(ptr); - else - longget(j,ptr); + j=sint4korr(ptr); return unsigned_flag ? (longlong) (uint32) j : (longlong) j; } @@ -3706,10 +3632,7 @@ String *Field_long::val_str(String *val_buffer, val_buffer->alloc(mlength); char *to=(char*) val_buffer->ptr(); int32 j; - if (ARCH_BIGENDIAN && table->s->db_low_byte_first) - j=sint4korr(ptr); - else - longget(j,ptr); + j=sint4korr(ptr); if (unsigned_flag) length=cs->cset->long10_to_str(cs,to,mlength, 10,(long) (uint32)j); @@ -3731,16 +3654,8 @@ bool Field_long::send_binary(Protocol *protocol) int Field_long::cmp(const uchar *a_ptr, const uchar *b_ptr) { int32 a,b; - if (ARCH_BIGENDIAN && table->s->db_low_byte_first) - { - a=sint4korr(a_ptr); - b=sint4korr(b_ptr); - } - else - { - longget(a,a_ptr); - longget(b,b_ptr); - } + a=sint4korr(a_ptr); + b=sint4korr(b_ptr); if (unsigned_flag) return ((uint32) a < (uint32) b) ? -1 : ((uint32) a > (uint32) b) ? 1 : 0; return (a < b) ? -1 : (a > b) ? 1 : 0; @@ -3748,26 +3663,13 @@ int Field_long::cmp(const uchar *a_ptr, const uchar *b_ptr) void Field_long::sort_string(uchar *to,uint length __attribute__((unused))) { - if (ARCH_BIGENDIAN && !table->s->db_low_byte_first) - { - if (unsigned_flag) - to[0] = ptr[0]; - else - to[0] = (char) (ptr[0] ^ 128); /* Revers signbit */ - to[1] = ptr[1]; - to[2] = ptr[2]; - to[3] = ptr[3]; - } + if (unsigned_flag) + to[0] = ptr[3]; else - { - if (unsigned_flag) - to[0] = ptr[3]; - else - to[0] = (char) (ptr[3] ^ 128); /* Revers signbit */ - to[1] = ptr[2]; - to[2] = ptr[1]; - to[3] = ptr[0]; - } + to[0] = (char) (ptr[3] ^ 128); /* Revers signbit */ + to[1] = ptr[2]; + to[2] = ptr[1]; + to[3] = ptr[0]; } @@ -3801,10 +3703,7 @@ int Field_longlong::store(const char *from,uint len,CHARSET_INFO *cs) error= 1; else error= 0; - if (ARCH_BIGENDIAN && table->s->db_low_byte_first) - int8store(ptr,tmp); - else - longlongstore(ptr,tmp); + int8store(ptr,tmp); return error; } @@ -3849,10 +3748,7 @@ int Field_longlong::store(double nr) if (error) set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); - if (ARCH_BIGENDIAN && table->s->db_low_byte_first) - int8store(ptr,res); - else - longlongstore(ptr,res); + int8store(ptr,res); return error; } @@ -3876,10 +3772,7 @@ int Field_longlong::store(longlong nr, bool unsigned_val) } } - if (ARCH_BIGENDIAN && table->s->db_low_byte_first) - int8store(ptr,nr); - else - longlongstore(ptr,nr); + int8store(ptr,nr); return error; } @@ -3888,10 +3781,7 @@ double Field_longlong::val_real(void) { ASSERT_COLUMN_MARKED_FOR_READ; longlong j; - if (ARCH_BIGENDIAN && table->s->db_low_byte_first) - j=sint8korr(ptr); - else - longlongget(j,ptr); + j=sint8korr(ptr); /* The following is open coded to avoid a bug in gcc 3.3 */ if (unsigned_flag) { @@ -3906,10 +3796,7 @@ longlong Field_longlong::val_int(void) { ASSERT_COLUMN_MARKED_FOR_READ; longlong j; - if (ARCH_BIGENDIAN && table->s->db_low_byte_first) - j=sint8korr(ptr); - else - longlongget(j,ptr); + j=sint8korr(ptr); return j; } @@ -3923,10 +3810,7 @@ String *Field_longlong::val_str(String *val_buffer, val_buffer->alloc(mlength); char *to=(char*) val_buffer->ptr(); longlong j; - if (ARCH_BIGENDIAN && table->s->db_low_byte_first) - j=sint8korr(ptr); - else - longlongget(j,ptr); + j=sint8korr(ptr); length=(uint) (cs->cset->longlong10_to_str)(cs,to,mlength, unsigned_flag ? 10 : -10, j); @@ -3947,16 +3831,8 @@ bool Field_longlong::send_binary(Protocol *protocol) int Field_longlong::cmp(const uchar *a_ptr, const uchar *b_ptr) { longlong a,b; - if (ARCH_BIGENDIAN && table->s->db_low_byte_first) - { - a=sint8korr(a_ptr); - b=sint8korr(b_ptr); - } - else - { - longlongget(a,a_ptr); - longlongget(b,b_ptr); - } + a=sint8korr(a_ptr); + b=sint8korr(b_ptr); if (unsigned_flag) return ((ulonglong) a < (ulonglong) b) ? -1 : ((ulonglong) a > (ulonglong) b) ? 1 : 0; @@ -3965,34 +3841,17 @@ int Field_longlong::cmp(const uchar *a_ptr, const uchar *b_ptr) void Field_longlong::sort_string(uchar *to,uint length __attribute__((unused))) { - if (ARCH_BIGENDIAN && !table->s->db_low_byte_first) - { - if (unsigned_flag) - to[0] = ptr[0]; - else - to[0] = (char) (ptr[0] ^ 128); /* Revers signbit */ - to[1] = ptr[1]; - to[2] = ptr[2]; - to[3] = ptr[3]; - to[4] = ptr[4]; - to[5] = ptr[5]; - to[6] = ptr[6]; - to[7] = ptr[7]; - } + if (unsigned_flag) + to[0] = ptr[7]; else - { - if (unsigned_flag) - to[0] = ptr[7]; - else - to[0] = (char) (ptr[7] ^ 128); /* Revers signbit */ - to[1] = ptr[6]; - to[2] = ptr[5]; - to[3] = ptr[4]; - to[4] = ptr[3]; - to[5] = ptr[2]; - to[6] = ptr[1]; - to[7] = ptr[0]; - } + to[0] = (char) (ptr[7] ^ 128); /* Revers signbit */ + to[1] = ptr[6]; + to[2] = ptr[5]; + to[3] = ptr[4]; + to[4] = ptr[3]; + to[5] = ptr[2]; + to[6] = ptr[1]; + to[7] = ptr[0]; } @@ -4009,39 +3868,6 @@ void Field_longlong::sql_type(String &res) const Floating-point numbers */ -uchar * -Field_real::pack(uchar *to, const uchar *from, - uint max_length, bool low_byte_first) -{ - DBUG_ENTER("Field_real::pack"); - DBUG_ASSERT(max_length >= pack_length()); - if (ARCH_BIGENDIAN && low_byte_first != table->s->db_low_byte_first) - { - const uchar *dptr= from + pack_length(); - while (dptr-- > from) - *to++ = *dptr; - DBUG_RETURN(to); - } - else - DBUG_RETURN(Field::pack(to, from, max_length, low_byte_first)); -} - -const uchar * -Field_real::unpack(uchar *to, const uchar *from, - uint param_data, bool low_byte_first) -{ - DBUG_ENTER("Field_real::unpack"); - if (ARCH_BIGENDIAN && low_byte_first != table->s->db_low_byte_first) - { - const uchar *dptr= from + pack_length(); - while (dptr-- > from) - *to++ = *dptr; - DBUG_RETURN(from + pack_length()); - } - else - DBUG_RETURN(Field::unpack(to, from, param_data, low_byte_first)); -} - /**************************************************************************** single precision float ****************************************************************************/ @@ -4069,10 +3895,7 @@ int Field_float::store(double nr) int error= truncate(&nr, FLT_MAX); float j= (float)nr; - if (ARCH_BIGENDIAN && table->s->db_low_byte_first) - float4store(ptr,j); - else - memcpy_fixed(ptr,(uchar*) &j,sizeof(j)); + float4store(ptr,j); return error; } @@ -4088,20 +3911,14 @@ double Field_float::val_real(void) { ASSERT_COLUMN_MARKED_FOR_READ; float j; - if (ARCH_BIGENDIAN && table->s->db_low_byte_first) - float4get(j,ptr); - else - memcpy_fixed((uchar*) &j,ptr,sizeof(j)); + float4get(j,ptr); return ((double) j); } longlong Field_float::val_int(void) { float j; - if (ARCH_BIGENDIAN && table->s->db_low_byte_first) - float4get(j,ptr); - else - memcpy_fixed((uchar*) &j,ptr,sizeof(j)); + float4get(j,ptr); return (longlong) rint(j); } @@ -4111,10 +3928,7 @@ String *Field_float::val_str(String *val_buffer, { ASSERT_COLUMN_MARKED_FOR_READ; float nr; - if (ARCH_BIGENDIAN && table->s->db_low_byte_first) - float4get(nr,ptr); - else - memcpy_fixed((uchar*) &nr,ptr,sizeof(nr)); + float4get(nr,ptr); uint to_length=max(field_length,70); val_buffer->alloc(to_length); @@ -4189,16 +4003,8 @@ String *Field_float::val_str(String *val_buffer, int Field_float::cmp(const uchar *a_ptr, const uchar *b_ptr) { float a,b; - if (ARCH_BIGENDIAN && table->s->db_low_byte_first) - { - float4get(a,a_ptr); - float4get(b,b_ptr); - } - else - { - memcpy_fixed(&a,a_ptr,sizeof(float)); - memcpy_fixed(&b,b_ptr,sizeof(float)); - } + float4get(a,a_ptr); + float4get(b,b_ptr); return (a < b) ? -1 : (a > b) ? 1 : 0; } @@ -4207,10 +4013,7 @@ 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; - if (ARCH_BIGENDIAN && table->s->db_low_byte_first) - float4get(nr,ptr); - else - memcpy_fixed(&nr,ptr,sizeof(float)); + float4get(nr,ptr); uchar *tmp= to; if (nr == (float) 0.0) @@ -4308,10 +4111,7 @@ int Field_double::store(double nr) ASSERT_COLUMN_MARKED_FOR_WRITE; int error= truncate(&nr, DBL_MAX); - if (ARCH_BIGENDIAN && table->s->db_low_byte_first) - float8store(ptr,nr); - else - doublestore(ptr,nr); + float8store(ptr,nr); return error; } @@ -4391,10 +4191,7 @@ double Field_double::val_real(void) { ASSERT_COLUMN_MARKED_FOR_READ; double j; - if (ARCH_BIGENDIAN && table->s->db_low_byte_first) - float8get(j,ptr); - else - doubleget(j,ptr); + float8get(j,ptr); return j; } @@ -4403,10 +4200,7 @@ longlong Field_double::val_int(void) ASSERT_COLUMN_MARKED_FOR_READ; double j; longlong res; - if (ARCH_BIGENDIAN && table->s->db_low_byte_first) - float8get(j,ptr); - else - doubleget(j,ptr); + float8get(j,ptr); /* Check whether we fit into longlong range */ if (j <= (double) LONGLONG_MIN) { @@ -4447,10 +4241,7 @@ String *Field_double::val_str(String *val_buffer, { ASSERT_COLUMN_MARKED_FOR_READ; double nr; - if (ARCH_BIGENDIAN && table->s->db_low_byte_first) - float8get(nr,ptr); - else - doubleget(nr,ptr); + float8get(nr,ptr); uint to_length= DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE; val_buffer->alloc(to_length); @@ -4531,16 +4322,8 @@ bool Field_double::send_binary(Protocol *protocol) int Field_double::cmp(const uchar *a_ptr, const uchar *b_ptr) { double a,b; - if (ARCH_BIGENDIAN && table->s->db_low_byte_first) - { - float8get(a,a_ptr); - float8get(b,b_ptr); - } - else - { - doubleget(a, a_ptr); - doubleget(b, b_ptr); - } + float8get(a,a_ptr); + float8get(b,b_ptr); return (a < b) ? -1 : (a > b) ? 1 : 0; } @@ -4552,10 +4335,7 @@ 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; - if (ARCH_BIGENDIAN && table->s->db_low_byte_first) - float8get(nr,ptr); - else - doubleget(nr,ptr); + float8get(nr,ptr); change_double_for_sort(nr, to); } @@ -4697,11 +4477,7 @@ long Field_timestamp::get_timestamp(ulong *sec_part) const { ASSERT_COLUMN_MARKED_FOR_READ; *sec_part= 0; - if (ARCH_BIGENDIAN && table && table->s->db_low_byte_first) - return sint4korr(ptr); - long tmp; - longget(tmp,ptr); - return tmp; + return sint4korr(ptr); } @@ -4932,36 +4708,18 @@ bool Field_timestamp::send_binary(Protocol *protocol) int Field_timestamp::cmp(const uchar *a_ptr, const uchar *b_ptr) { int32 a,b; - if (ARCH_BIGENDIAN && table && table->s->db_low_byte_first) - { - a=sint4korr(a_ptr); - b=sint4korr(b_ptr); - } - else - { - longget(a,a_ptr); - longget(b,b_ptr); - } + a=sint4korr(a_ptr); + b=sint4korr(b_ptr); return ((uint32) a < (uint32) b) ? -1 : ((uint32) a > (uint32) b) ? 1 : 0; } void Field_timestamp::sort_string(uchar *to,uint length __attribute__((unused))) { - if (ARCH_BIGENDIAN && !(table && table->s->db_low_byte_first)) - { - to[0] = ptr[0]; - to[1] = ptr[1]; - to[2] = ptr[2]; - to[3] = ptr[3]; - } - else - { - to[0] = ptr[3]; - to[1] = ptr[2]; - to[2] = ptr[1]; - to[3] = ptr[0]; - } + to[0] = ptr[3]; + to[1] = ptr[2]; + to[2] = ptr[1]; + to[3] = ptr[0]; } @@ -4986,6 +4744,7 @@ void Field_timestamp_hires::sql_type(String &res) const "timestamp(%u)", dec)); } +#ifdef NOT_USED static void store_native(ulonglong num, uchar *to, uint bytes) { switch(bytes) { @@ -5009,6 +4768,7 @@ static longlong read_native(const uchar *from, uint bytes) default: DBUG_ASSERT(0); return 0; } } +#endif static void store_lowendian(ulonglong num, uchar *to, uint bytes) { @@ -5706,10 +5466,7 @@ void Field_year::sql_type(String &res) const void Field_date::store_TIME(MYSQL_TIME *ltime) { uint tmp= ltime->year*10000L + ltime->month*100+ltime->day; - if (ARCH_BIGENDIAN && table && table->s->db_low_byte_first) - int4store(ptr,tmp); - else - longstore(ptr,tmp); + int4store(ptr,tmp); } bool Field_date::send_binary(Protocol *protocol) @@ -5727,10 +5484,7 @@ double Field_date::val_real(void) { ASSERT_COLUMN_MARKED_FOR_READ; int32 j; - if (ARCH_BIGENDIAN && table && table->s->db_low_byte_first) - j=sint4korr(ptr); - else - longget(j,ptr); + j=sint4korr(ptr); return (double) (uint32) j; } @@ -5739,10 +5493,7 @@ longlong Field_date::val_int(void) { ASSERT_COLUMN_MARKED_FOR_READ; int32 j; - if (ARCH_BIGENDIAN && table && table->s->db_low_byte_first) - j=sint4korr(ptr); - else - longget(j,ptr); + j=sint4korr(ptr); return (longlong) (uint32) j; } @@ -5753,10 +5504,7 @@ String *Field_date::val_str(String *val_buffer, ASSERT_COLUMN_MARKED_FOR_READ; MYSQL_TIME ltime; int32 tmp; - if (ARCH_BIGENDIAN && table && table->s->db_low_byte_first) - tmp=sint4korr(ptr); - else - longget(tmp,ptr); + tmp=sint4korr(ptr); ltime.neg= 0; ltime.year= (int) ((uint32) tmp/10000L % 10000); ltime.month= (int) ((uint32) tmp/100 % 100); @@ -5769,36 +5517,18 @@ String *Field_date::val_str(String *val_buffer, int Field_date::cmp(const uchar *a_ptr, const uchar *b_ptr) { int32 a,b; - if (ARCH_BIGENDIAN && table && table->s->db_low_byte_first) - { - a=sint4korr(a_ptr); - b=sint4korr(b_ptr); - } - else - { - longget(a,a_ptr); - longget(b,b_ptr); - } + a=sint4korr(a_ptr); + b=sint4korr(b_ptr); return ((uint32) a < (uint32) b) ? -1 : ((uint32) a > (uint32) b) ? 1 : 0; } void Field_date::sort_string(uchar *to,uint length __attribute__((unused))) { - if (ARCH_BIGENDIAN && !(table && table->s->db_low_byte_first)) - { - to[0] = ptr[0]; - to[1] = ptr[1]; - to[2] = ptr[2]; - to[3] = ptr[3]; - } - else - { - to[0] = ptr[3]; - to[1] = ptr[2]; - to[2] = ptr[1]; - to[3] = ptr[0]; - } + to[0] = ptr[3]; + to[1] = ptr[2]; + to[2] = ptr[1]; + to[3] = ptr[0]; } void Field_date::sql_type(String &res) const @@ -5922,10 +5652,7 @@ void Field_newdate::sql_type(String &res) const void Field_datetime::store_TIME(MYSQL_TIME *ltime) { ulonglong tmp= TIME_to_ulonglong_datetime(ltime); - if (ARCH_BIGENDIAN && table && table->s->db_low_byte_first) - int8store(ptr,tmp); - else - longlongstore(ptr,tmp); + int8store(ptr,tmp); } bool Field_datetime::send_binary(Protocol *protocol) @@ -5945,10 +5672,7 @@ longlong Field_datetime::val_int(void) { ASSERT_COLUMN_MARKED_FOR_READ; longlong j; - if (ARCH_BIGENDIAN && table && table->s->db_low_byte_first) - j=sint8korr(ptr); - else - longlongget(j,ptr); + j=sint8korr(ptr); return j; } @@ -6024,44 +5748,22 @@ bool Field_datetime::get_date(MYSQL_TIME *ltime, uint fuzzydate) int Field_datetime::cmp(const uchar *a_ptr, const uchar *b_ptr) { longlong a,b; - if (ARCH_BIGENDIAN && table && table->s->db_low_byte_first) - { - a=sint8korr(a_ptr); - b=sint8korr(b_ptr); - } - else - { - longlongget(a,a_ptr); - longlongget(b,b_ptr); - } + a=sint8korr(a_ptr); + b=sint8korr(b_ptr); return ((ulonglong) a < (ulonglong) b) ? -1 : ((ulonglong) a > (ulonglong) b) ? 1 : 0; } void Field_datetime::sort_string(uchar *to,uint length __attribute__((unused))) { - if (ARCH_BIGENDIAN && !(table && table->s->db_low_byte_first)) - { - to[0] = ptr[0]; - to[1] = ptr[1]; - to[2] = ptr[2]; - to[3] = ptr[3]; - to[4] = ptr[4]; - to[5] = ptr[5]; - to[6] = ptr[6]; - to[7] = ptr[7]; - } - else - { - to[0] = ptr[7]; - to[1] = ptr[6]; - to[2] = ptr[5]; - to[3] = ptr[4]; - to[4] = ptr[3]; - to[5] = ptr[2]; - to[6] = ptr[1]; - to[7] = ptr[0]; - } + to[0] = ptr[7]; + to[1] = ptr[6]; + to[2] = ptr[5]; + to[3] = ptr[4]; + to[4] = ptr[3]; + to[5] = ptr[2]; + to[6] = ptr[1]; + to[7] = ptr[0]; } @@ -6614,9 +6316,7 @@ void Field_string::sql_type(String &res) const } -uchar *Field_string::pack(uchar *to, const uchar *from, - uint max_length, - bool low_byte_first __attribute__((unused))) +uchar *Field_string::pack(uchar *to, const uchar *from, uint max_length) { uint length= min(field_length,max_length); uint local_char_length= max_length/field_charset->mbmaxlen; @@ -6658,10 +6358,7 @@ uchar *Field_string::pack(uchar *to, const uchar *from, @return New pointer into memory based on from + length of the data */ const uchar * -Field_string::unpack(uchar *to, - const uchar *from, - uint param_data, - bool low_byte_first __attribute__((unused))) +Field_string::unpack(uchar *to, const uchar *from, uint param_data) { uint from_length, length; @@ -7123,9 +6820,7 @@ uint32 Field_varstring::data_length() Here the number of length bytes are depending on the given max_length */ -uchar *Field_varstring::pack(uchar *to, const uchar *from, - uint max_length, - bool low_byte_first __attribute__((unused))) +uchar *Field_varstring::pack(uchar *to, const uchar *from, uint max_length) { uint length= length_bytes == 1 ? (uint) *from : uint2korr(from); set_if_smaller(max_length, field_length); @@ -7145,8 +6840,7 @@ uchar *Field_varstring::pack(uchar *to, const uchar *from, uchar * -Field_varstring::pack_key(uchar *to, const uchar *key, uint max_length, - bool low_byte_first __attribute__((unused))) +Field_varstring::pack_key(uchar *to, const uchar *key, uint max_length) { uint length= length_bytes == 1 ? (uint) *key : uint2korr(key); uint local_char_length= ((field_charset->mbmaxlen > 1) ? @@ -7183,8 +6877,7 @@ Field_varstring::pack_key(uchar *to, const uchar *key, uint max_length, */ const uchar * -Field_varstring::unpack_key(uchar *to, const uchar *key, uint max_length, - bool low_byte_first __attribute__((unused))) +Field_varstring::unpack_key(uchar *to, const uchar *key, uint max_length) { /* get length of the blob key */ uint32 length= *key++; @@ -7211,9 +6904,8 @@ Field_varstring::unpack_key(uchar *to, const uchar *key, uint max_length, end of key storage */ -uchar * -Field_varstring::pack_key_from_key_image(uchar *to, const uchar *from, uint max_length, - bool low_byte_first __attribute__((unused))) +uchar * Field_varstring::pack_key_from_key_image(uchar *to, const uchar *from, + uint max_length) { /* Key length is always stored as 2 bytes */ uint length= uint2korr(from); @@ -7244,9 +6936,7 @@ Field_varstring::pack_key_from_key_image(uchar *to, const uchar *from, uint max_ @return New pointer into memory based on from + length of the data */ const uchar * -Field_varstring::unpack(uchar *to, const uchar *from, - uint param_data, - bool low_byte_first __attribute__((unused))) +Field_varstring::unpack(uchar *to, const uchar *from, uint param_data) { uint length; uint l_bytes= (param_data && (param_data < field_length)) ? @@ -7472,24 +7162,15 @@ Field_blob::Field_blob(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, } -void Field_blob::store_length(uchar *i_ptr, - uint i_packlength, - uint32 i_number, - bool low_byte_first) +void Field_blob::store_length(uchar *i_ptr, uint i_packlength, uint32 i_number) { - if (ARCH_BIGENDIAN && low_byte_first) - store_lowendian(i_number, i_ptr, i_packlength); - else - store_native(i_number, i_ptr, i_packlength); + store_lowendian(i_number, i_ptr, i_packlength); } -uint32 Field_blob::get_length(const uchar *pos, uint packlength_arg, bool low_byte_first) +uint32 Field_blob::get_length(const uchar *pos, uint packlength_arg) { - if (ARCH_BIGENDIAN && table->s->db_low_byte_first) - return (uint32)read_lowendian(pos, packlength_arg); - else - return (uint32)read_native(pos, packlength_arg); + return (uint32)read_lowendian(pos, packlength_arg); } @@ -7858,14 +7539,11 @@ void Field_blob::sql_type(String &res) const } } -uchar *Field_blob::pack(uchar *to, const uchar *from, - uint max_length, bool low_byte_first) +uchar *Field_blob::pack(uchar *to, const uchar *from, uint max_length) { DBUG_ENTER("Field_blob::pack"); - DBUG_PRINT("enter", ("to: 0x%lx; from: 0x%lx;" - " max_length: %u; low_byte_first: %d", - (ulong) to, (ulong) from, - max_length, low_byte_first)); + DBUG_PRINT("enter", ("to: 0x%lx; from: 0x%lx; max_length: %u", + (ulong) to, (ulong) from, max_length)); DBUG_DUMP("record", from, table->s->reclength); uchar *save= ptr; ptr= (uchar*) from; @@ -7876,7 +7554,7 @@ uchar *Field_blob::pack(uchar *to, const uchar *from, length given is smaller than the actual length of the blob, we just store the initial bytes of the blob. */ - store_length(to, packlength, min(length, max_length), low_byte_first); + store_length(to, packlength, min(length, max_length)); /* Store the actual blob data, which will occupy 'length' bytes. @@ -7909,18 +7587,14 @@ uchar *Field_blob::pack(uchar *to, const uchar *from, @return New pointer into memory based on from + length of the data */ -const uchar *Field_blob::unpack(uchar *to, - const uchar *from, - uint param_data, - bool low_byte_first) +const uchar *Field_blob::unpack(uchar *to, const uchar *from, uint param_data) { DBUG_ENTER("Field_blob::unpack"); - DBUG_PRINT("enter", ("to: 0x%lx; from: 0x%lx;" - " param_data: %u; low_byte_first: %d", - (ulong) to, (ulong) from, param_data, low_byte_first)); + DBUG_PRINT("enter", ("to: 0x%lx; from: 0x%lx; param_data: %u", + (ulong) to, (ulong) from, param_data)); uint const master_packlength= param_data > 0 ? param_data & 0xFF : packlength; - uint32 const length= get_length(from, master_packlength, low_byte_first); + uint32 const length= get_length(from, master_packlength); DBUG_DUMP("packed", from, length + master_packlength); bitmap_set_bit(table->write_set, field_index); store(reinterpret_cast(from) + master_packlength, @@ -7977,8 +7651,7 @@ int Field_blob::pack_cmp(const uchar *b, uint key_length_arg, /** Create a packed key that will be used for storage from a MySQL row. */ uchar * -Field_blob::pack_key(uchar *to, const uchar *from, uint max_length, - bool low_byte_first __attribute__((unused))) +Field_blob::pack_key(uchar *to, const uchar *from, uint max_length) { uchar *save= ptr; ptr= (uchar*) from; @@ -8022,8 +7695,7 @@ Field_blob::pack_key(uchar *to, const uchar *from, uint max_length, */ const uchar * -Field_blob::unpack_key(uchar *to, const uchar *from, uint max_length, - bool low_byte_first __attribute__((unused))) +Field_blob::unpack_key(uchar *to, const uchar *from, uint max_length) { /* get length of the blob key */ uint32 length= *from++; @@ -8031,7 +7703,7 @@ Field_blob::unpack_key(uchar *to, const uchar *from, uint max_length, length+= *from++ << 8; /* put the length into the record buffer */ - store_length(to, packlength, length, table->s->db_low_byte_first); + store_length(to, packlength, length); /* put the address of the blob buffer or NULL */ if (length) @@ -8046,9 +7718,8 @@ Field_blob::unpack_key(uchar *to, const uchar *from, uint max_length, /** Create a packed key that will be used for storage from a MySQL key. */ -uchar * -Field_blob::pack_key_from_key_image(uchar *to, const uchar *from, uint max_length, - bool low_byte_first __attribute__((unused))) +uchar *Field_blob::pack_key_from_key_image(uchar *to, const uchar *from, + uint max_length) { uint length=uint2korr(from); if (length > max_length) @@ -8199,10 +7870,7 @@ enum ha_base_keytype Field_enum::key_type() const void Field_enum::store_type(ulonglong value) { - if (ARCH_BIGENDIAN && table->s->db_low_byte_first) - store_lowendian(value, ptr, packlength); - else - store_native(value, ptr, packlength); + store_lowendian(value, ptr, packlength); } @@ -8288,10 +7956,7 @@ double Field_enum::val_real(void) longlong Field_enum::val_int(void) { ASSERT_COLUMN_MARKED_FOR_READ; - if (ARCH_BIGENDIAN && table->s->db_low_byte_first) - return read_lowendian(ptr, packlength); - else - return read_native(ptr, packlength); + return read_lowendian(ptr, packlength); } @@ -9043,8 +8708,7 @@ void Field_bit::sql_type(String &res) const uchar * -Field_bit::pack(uchar *to, const uchar *from, uint max_length, - bool low_byte_first __attribute__((unused))) +Field_bit::pack(uchar *to, const uchar *from, uint max_length) { DBUG_ASSERT(max_length > 0); uint length; @@ -9091,8 +8755,7 @@ Field_bit::pack(uchar *to, const uchar *from, uint max_length, @return New pointer into memory based on from + length of the data */ const uchar * -Field_bit::unpack(uchar *to, const uchar *from, uint param_data, - bool low_byte_first __attribute__((unused))) +Field_bit::unpack(uchar *to, const uchar *from, uint param_data) { uint const from_len= (param_data >> 8U) & 0x00ff; uint const from_bit_len= param_data & 0x00ff; diff --git a/sql/field.h b/sql/field.h index 6361636771e..95c2fd30559 100644 --- a/sql/field.h +++ b/sql/field.h @@ -22,12 +22,6 @@ #pragma interface /* gcc class implementation */ #endif -#ifdef WORDS_ARCH_BIGENDIAN -#define ARCH_BIGENDIAN 1 -#else -#define ARCH_BIGENDIAN 0 -#endif - #define NOT_FIXED_DEC 31 const uint32 max_field_size= (uint32) 4294967295U; @@ -386,44 +380,39 @@ public: } virtual bool send_binary(Protocol *protocol); - virtual uchar *pack(uchar *to, const uchar *from, - uint max_length, bool low_byte_first); + virtual uchar *pack(uchar *to, const uchar *from, uint max_length); /** @overload Field::pack(uchar*, const uchar*, uint, bool) */ uchar *pack(uchar *to, const uchar *from) { DBUG_ENTER("Field::pack"); - uchar *result= this->pack(to, from, UINT_MAX, table->s->db_low_byte_first); + uchar *result= this->pack(to, from, UINT_MAX); DBUG_RETURN(result); } - virtual const uchar *unpack(uchar* to, const uchar *from, - uint param_data, bool low_byte_first); + virtual const uchar *unpack(uchar* to, const uchar *from, uint param_data); /** @overload Field::unpack(uchar*, const uchar*, uint, bool) */ const uchar *unpack(uchar* to, const uchar *from) { DBUG_ENTER("Field::unpack"); - const uchar *result= unpack(to, from, 0U, table->s->db_low_byte_first); + const uchar *result= unpack(to, from, 0); DBUG_RETURN(result); } - virtual uchar *pack_key(uchar* to, const uchar *from, - uint max_length, bool low_byte_first) + virtual uchar *pack_key(uchar* to, const uchar *from, uint max_length) { - return pack(to, from, max_length, low_byte_first); + return pack(to, from, max_length); } - virtual uchar *pack_key_from_key_image(uchar* to, const uchar *from, - uint max_length, bool low_byte_first) + virtual uchar *pack_key_from_key_image(uchar* to, const uchar *from, uint max_length) { - return pack(to, from, max_length, low_byte_first); + return pack(to, from, max_length); } - virtual const uchar *unpack_key(uchar* to, const uchar *from, - uint max_length, bool low_byte_first) + virtual const uchar *unpack_key(uchar* to, const uchar *from, uint max_length) { - return unpack(to, from, max_length, low_byte_first); + return unpack(to, from, max_length); } virtual uint packed_col_length(const uchar *to, uint length) { return length;} @@ -543,62 +532,44 @@ protected: /* Helper function to pack()/unpack() int32 values */ - static void handle_int32(uchar *to, const uchar *from, - bool low_byte_first_from, bool low_byte_first_to) + static void handle_int32(uchar *to, const uchar *from) { int32 val; - if (ARCH_BIGENDIAN && low_byte_first_from) - val = sint4korr(from); - else - longget(val, from); - - if (ARCH_BIGENDIAN && low_byte_first_to) - int4store(to, val); - else - longstore(to, val); + val = sint4korr(from); + int4store(to, val); } /* Helper function to pack()/unpack() int64 values */ - static void handle_int64(uchar* to, const uchar *from, - bool low_byte_first_from, bool low_byte_first_to) + static void handle_int64(uchar* to, const uchar *from) { int64 val; - if (ARCH_BIGENDIAN && low_byte_first_from) - val = sint8korr(from); - else - longlongget(val, from); - - if (ARCH_BIGENDIAN && low_byte_first_to) - int8store(to, val); - else - longlongstore(to, val); + val = sint8korr(from); + int8store(to, val); } - uchar *pack_int32(uchar *to, const uchar *from, bool low_byte_first_to) + uchar *pack_int32(uchar *to, const uchar *from) { - handle_int32(to, from, table->s->db_low_byte_first, low_byte_first_to); + handle_int32(to, from); return to + sizeof(int32); } - const uchar *unpack_int32(uchar* to, const uchar *from, - bool low_byte_first_from) + const uchar *unpack_int32(uchar* to, const uchar *from) { - handle_int32(to, from, low_byte_first_from, table->s->db_low_byte_first); + handle_int32(to, from); return from + sizeof(int32); } - uchar *pack_int64(uchar* to, const uchar *from, bool low_byte_first_to) + uchar *pack_int64(uchar* to, const uchar *from) { - handle_int64(to, from, table->s->db_low_byte_first, low_byte_first_to); + handle_int64(to, from); return to + sizeof(int64); } - const uchar *unpack_int64(uchar* to, const uchar *from, - bool low_byte_first_from) + const uchar *unpack_int64(uchar* to, const uchar *from) { - handle_int64(to, from, low_byte_first_from, table->s->db_low_byte_first); + handle_int64(to, from); return from + sizeof(int64); } @@ -702,10 +673,6 @@ public: int truncate(double *nr, double max_length); uint32 max_display_length() { return field_length; } uint size_of() const { return sizeof(*this); } - virtual const uchar *unpack(uchar* to, const uchar *from, - uint param_data, bool low_byte_first); - virtual uchar *pack(uchar* to, const uchar *from, - uint max_length, bool low_byte_first); }; @@ -734,15 +701,13 @@ public: void overflow(bool negative); bool zero_pack() const { return 0; } void sql_type(String &str) const; - virtual const uchar *unpack(uchar* to, const uchar *from, - uint param_data, bool low_byte_first) + virtual const uchar *unpack(uchar* to, const uchar *from, uint param_data) { - return Field::unpack(to, from, param_data, low_byte_first); + return Field::unpack(to, from, param_data); } - virtual uchar *pack(uchar* to, const uchar *from, - uint max_length, bool low_byte_first) + virtual uchar *pack(uchar* to, const uchar *from, uint max_length) { - return Field::pack(to, from, max_length, low_byte_first); + return Field::pack(to, from, max_length); } }; @@ -795,8 +760,7 @@ public: int compatible_field_size(uint field_metadata, const Relay_log_info *rli, uint16 mflags); uint is_equal(Create_field *new_field); - virtual const uchar *unpack(uchar* to, const uchar *from, - uint param_data, bool low_byte_first); + virtual const uchar *unpack(uchar* to, const uchar *from, uint param_data); static Field *create_from_item (Item *); }; @@ -829,15 +793,13 @@ public: void sql_type(String &str) const; uint32 max_display_length() { return 4; } - virtual uchar *pack(uchar* to, const uchar *from, - uint max_length, bool low_byte_first) + virtual uchar *pack(uchar* to, const uchar *from, uint max_length) { *to= *from; return to + 1; } - virtual const uchar *unpack(uchar* to, const uchar *from, - uint param_data, bool low_byte_first) + virtual const uchar *unpack(uchar* to, const uchar *from, uint param_data) { *to= *from; return from + 1; @@ -878,35 +840,19 @@ public: void sql_type(String &str) const; uint32 max_display_length() { return 6; } - virtual uchar *pack(uchar* to, const uchar *from, - uint max_length, bool low_byte_first) + virtual uchar *pack(uchar* to, const uchar *from, uint max_length) { int16 val; - if (ARCH_BIGENDIAN && table->s->db_low_byte_first) - val = sint2korr(from); - else - shortget(val, from); - - if (ARCH_BIGENDIAN && low_byte_first) - int2store(to, val); - else - shortstore(to, val); + val = sint2korr(from); + int2store(to, val); return to + sizeof(val); } - virtual const uchar *unpack(uchar* to, const uchar *from, - uint param_data, bool low_byte_first) + virtual const uchar *unpack(uchar* to, const uchar *from, uint param_data) { int16 val; - if (ARCH_BIGENDIAN && low_byte_first) - val = sint2korr(from); - else - shortget(val, from); - - if (ARCH_BIGENDIAN && table->s->db_low_byte_first) - int2store(to, val); - else - shortstore(to, val); + val = sint2korr(from); + int2store(to, val); return from + sizeof(val); } }; @@ -939,16 +885,14 @@ public: void sql_type(String &str) const; uint32 max_display_length() { return 8; } - virtual uchar *pack(uchar* to, const uchar *from, - uint max_length, bool low_byte_first) + virtual uchar *pack(uchar* to, const uchar *from, uint max_length) { - return Field::pack(to, from, max_length, low_byte_first); + return Field::pack(to, from, max_length); } - virtual const uchar *unpack(uchar* to, const uchar *from, - uint param_data, bool low_byte_first) + virtual const uchar *unpack(uchar* to, const uchar *from, uint param_data) { - return Field::unpack(to, from, param_data, low_byte_first); + return Field::unpack(to, from, param_data); } }; @@ -986,16 +930,14 @@ public: void sql_type(String &str) const; uint32 max_display_length() { return MY_INT32_NUM_DECIMAL_DIGITS; } virtual uchar *pack(uchar* to, const uchar *from, - uint max_length __attribute__((unused)), - bool low_byte_first) + uint max_length __attribute__((unused))) { - return pack_int32(to, from, low_byte_first); + return pack_int32(to, from); } virtual const uchar *unpack(uchar* to, const uchar *from, - uint param_data __attribute__((unused)), - bool low_byte_first) + uint param_data __attribute__((unused))) { - return unpack_int32(to, from, low_byte_first); + return unpack_int32(to, from); } }; @@ -1038,16 +980,14 @@ public: void sql_type(String &str) const; uint32 max_display_length() { return 20; } virtual uchar *pack(uchar* to, const uchar *from, - uint max_length __attribute__((unused)), - bool low_byte_first) + uint max_length __attribute__((unused))) { - return pack_int64(to, from, low_byte_first); + return pack_int64(to, from); } virtual const uchar *unpack(uchar* to, const uchar *from, - uint param_data __attribute__((unused)), - bool low_byte_first) + uint param_data __attribute__((unused))) { - return unpack_int64(to, from, low_byte_first); + return unpack_int64(to, from); } }; @@ -1200,23 +1140,19 @@ public: virtual long get_timestamp(ulong *sec_part) const; virtual void store_TIME(my_time_t timestamp, ulong sec_part) { - if (ARCH_BIGENDIAN && table && table->s->db_low_byte_first) - int4store(ptr,timestamp); - else - longstore(ptr,(uint32) timestamp); + int4store(ptr,timestamp); } bool get_date(MYSQL_TIME *ltime,uint fuzzydate); 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) + uint max_length __attribute__((unused))) { - return pack_int32(to, from, low_byte_first); + return pack_int32(to, from); } const uchar *unpack(uchar* to, const uchar *from, - uint param_data __attribute__((unused)), - bool low_byte_first) + uint param_data __attribute__((unused))) { - return unpack_int32(to, from, low_byte_first); + return unpack_int32(to, from); } }; @@ -1249,12 +1185,10 @@ public: 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); } + uchar *pack(uchar *to, const uchar *from, uint max_length) + { return Field::pack(to, from, max_length); } + const uchar *unpack(uchar* to, const uchar *from, uint param_data) + { return Field::unpack(to, from, param_data); } uint size_of() const { return sizeof(*this); } }; @@ -1323,15 +1257,14 @@ public: void sql_type(String &str) const; bool zero_pack() const { return 1; } uchar *pack(uchar* to, const uchar *from, - uint max_length __attribute__((unused)), bool low_byte_first) + uint max_length __attribute__((unused))) { - return pack_int32(to, from, low_byte_first); + return pack_int32(to, from); } const uchar *unpack(uchar* to, const uchar *from, - uint param_data __attribute__((unused)), - bool low_byte_first) + uint param_data __attribute__((unused))) { - return unpack_int32(to, from, low_byte_first); + return unpack_int32(to, from); } }; @@ -1448,15 +1381,14 @@ public: bool zero_pack() const { return 1; } bool get_date(MYSQL_TIME *ltime,uint fuzzydate); uchar *pack(uchar* to, const uchar *from, - uint max_length __attribute__((unused)), bool low_byte_first) + uint max_length __attribute__((unused))) { - return pack_int64(to, from, low_byte_first); + return pack_int64(to, from); } const uchar *unpack(uchar* to, const uchar *from, - uint param_data __attribute__((unused)), - bool low_byte_first) + uint param_data __attribute__((unused))) { - return unpack_int64(to, from, low_byte_first); + return unpack_int64(to, from); } }; @@ -1489,12 +1421,10 @@ public: 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); } + uchar *pack(uchar *to, const uchar *from, uint max_length) + { return Field::pack(to, from, max_length); } + const uchar *unpack(uchar* to, const uchar *from, uint param_data) + { return Field::unpack(to, from, param_data); } uint size_of() const { return sizeof(*this); } }; @@ -1584,9 +1514,8 @@ public: void sort_string(uchar *buff,uint length); void sql_type(String &str) const; virtual uchar *pack(uchar *to, const uchar *from, - uint max_length, bool low_byte_first); - virtual const uchar *unpack(uchar* to, const uchar *from, - uint param_data, bool low_byte_first); + uint max_length); + virtual const uchar *unpack(uchar* to, const uchar *from, uint param_data); uint pack_length_from_metadata(uint field_metadata) { DBUG_PRINT("debug", ("field_metadata: 0x%04x", field_metadata)); @@ -1671,15 +1600,11 @@ public: uint get_key_image(uchar *buff,uint length, imagetype type); void set_key_image(const uchar *buff,uint length); void sql_type(String &str) const; - virtual uchar *pack(uchar *to, const uchar *from, - uint max_length, bool low_byte_first); - uchar *pack_key(uchar *to, const uchar *from, uint max_length, bool low_byte_first); - uchar *pack_key_from_key_image(uchar* to, const uchar *from, - uint max_length, bool low_byte_first); - virtual const uchar *unpack(uchar* to, const uchar *from, - uint param_data, bool low_byte_first); - const uchar *unpack_key(uchar* to, const uchar *from, - uint max_length, bool low_byte_first); + virtual uchar *pack(uchar *to, const uchar *from, uint max_length); + uchar *pack_key(uchar *to, const uchar *from, uint max_length); + uchar *pack_key_from_key_image(uchar* to, const uchar *from, uint max_length); + virtual const uchar *unpack(uchar* to, const uchar *from, uint param_data); + const uchar *unpack_key(uchar* to, const uchar *from, uint max_length); int pack_cmp(const uchar *a, const uchar *b, uint key_length, my_bool insert_or_update); int pack_cmp(const uchar *b, uint key_length,my_bool insert_or_update); @@ -1787,11 +1712,7 @@ 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(); } - 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) - { - store_length(i_ptr, i_packlength, i_number, table->s->db_low_byte_first); - } + void store_length(uchar *i_ptr, uint i_packlength, uint32 i_number); inline void store_length(uint32 number) { store_length(ptr, packlength, number); @@ -1805,37 +1726,37 @@ public: @returns The length in the row plus the size of the data. */ - uint32 get_packed_size(const uchar *ptr_arg, bool low_byte_first) - {return packlength + get_length(ptr_arg, packlength, low_byte_first);} + uint32 get_packed_size(const uchar *ptr_arg) + {return packlength + get_length(ptr_arg, packlength);} inline uint32 get_length(uint row_offset= 0) - { return get_length(ptr+row_offset, this->packlength, table->s->db_low_byte_first); } - uint32 get_length(const uchar *ptr, uint packlength, bool low_byte_first); + { return get_length(ptr+row_offset, this->packlength); } + uint32 get_length(const uchar *ptr, uint packlength); uint32 get_length(const uchar *ptr_arg) - { return get_length(ptr_arg, this->packlength, table->s->db_low_byte_first); } + { return get_length(ptr_arg, this->packlength); } inline void get_ptr(uchar **str) - { - memcpy_fixed((uchar*) str,ptr+packlength,sizeof(uchar*)); - } + { + memcpy_fixed((uchar*) str,ptr+packlength,sizeof(uchar*)); + } inline void get_ptr(uchar **str, uint row_offset) - { - memcpy_fixed((uchar*) str,ptr+packlength+row_offset,sizeof(char*)); - } + { + memcpy_fixed((uchar*) str,ptr+packlength+row_offset,sizeof(char*)); + } inline void set_ptr(uchar *length, uchar *data) - { - memcpy(ptr,length,packlength); - memcpy_fixed(ptr+packlength,&data,sizeof(char*)); - } + { + memcpy(ptr,length,packlength); + memcpy_fixed(ptr+packlength,&data,sizeof(char*)); + } void set_ptr_offset(my_ptrdiff_t ptr_diff, uint32 length, uchar *data) - { - uchar *ptr_ofs= ADD_TO_PTR(ptr,ptr_diff,uchar*); - store_length(ptr_ofs, packlength, length); - memcpy_fixed(ptr_ofs+packlength,&data,sizeof(char*)); - } + { + uchar *ptr_ofs= ADD_TO_PTR(ptr,ptr_diff,uchar*); + store_length(ptr_ofs, packlength, length); + memcpy_fixed(ptr_ofs+packlength,&data,sizeof(char*)); + } inline void set_ptr(uint32 length, uchar *data) - { - set_ptr_offset(0, length, data); - } + { + set_ptr_offset(0, length, data); + } uint get_key_image(uchar *buff,uint length, imagetype type); void set_key_image(const uchar *buff,uint length); void sql_type(String &str) const; @@ -1852,16 +1773,11 @@ public: memcpy_fixed(ptr+packlength,&tmp,sizeof(char*)); return 0; } - virtual uchar *pack(uchar *to, const uchar *from, - uint max_length, bool low_byte_first); - uchar *pack_key(uchar *to, const uchar *from, - uint max_length, bool low_byte_first); - uchar *pack_key_from_key_image(uchar* to, const uchar *from, - uint max_length, bool low_byte_first); - virtual const uchar *unpack(uchar *to, const uchar *from, - uint param_data, bool low_byte_first); - const uchar *unpack_key(uchar* to, const uchar *from, - uint max_length, bool low_byte_first); + virtual uchar *pack(uchar *to, const uchar *from, uint max_length); + uchar *pack_key(uchar *to, const uchar *from, uint max_length); + uchar *pack_key_from_key_image(uchar* to, const uchar *from, uint max_length); + virtual const uchar *unpack(uchar *to, const uchar *from, uint param_data); + const uchar *unpack_key(uchar* to, const uchar *from, uint max_length); int pack_cmp(const uchar *a, const uchar *b, uint key_length, my_bool insert_or_update); int pack_cmp(const uchar *b, uint key_length,my_bool insert_or_update); @@ -2061,10 +1977,8 @@ public: int compatible_field_size(uint field_metadata, const Relay_log_info *rli, uint16 mflags); void sql_type(String &str) const; - virtual uchar *pack(uchar *to, const uchar *from, - uint max_length, bool low_byte_first); - virtual const uchar *unpack(uchar *to, const uchar *from, - uint param_data, bool low_byte_first); + virtual uchar *pack(uchar *to, const uchar *from, uint max_length); + virtual const uchar *unpack(uchar *to, const uchar *from, uint param_data); virtual void set_default(); Field *new_key_field(MEM_ROOT *root, struct st_table *new_table, diff --git a/sql/field_conv.cc b/sql/field_conv.cc index e4da3f114ef..2d08cd0694b 100644 --- a/sql/field_conv.cc +++ b/sql/field_conv.cc @@ -644,13 +644,11 @@ void Copy_field::set(Field *to,Field *from,bool save) Copy_field::Copy_func * Copy_field::get_copy_func(Field *to,Field *from) { - bool compatible_db_low_byte_first= (to->table->s->db_low_byte_first == - from->table->s->db_low_byte_first); if (to->flags & BLOB_FLAG) { if (!(from->flags & BLOB_FLAG) || from->charset() != to->charset()) return do_conv_blob; - if (from_length != to_length || !compatible_db_low_byte_first) + if (from_length != to_length) { // Correct pointer to point at char pointer to_ptr+= to_length - to->table->s->blob_ptr_size; @@ -684,7 +682,6 @@ Copy_field::get_copy_func(Field *to,Field *from) if we don't allow 'all' dates. */ if (to->real_type() != from->real_type() || - !compatible_db_low_byte_first || (((to->table->in_use->variables.sql_mode & (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE | MODE_INVALID_DATES)) && to->type() == MYSQL_TYPE_DATE) || @@ -735,8 +732,7 @@ Copy_field::get_copy_func(Field *to,Field *from) } else if (to->real_type() != from->real_type() || - to_length != from_length || - !compatible_db_low_byte_first) + to_length != from_length) { if (to->real_type() == MYSQL_TYPE_DECIMAL || to->result_type() == STRING_RESULT) @@ -747,7 +743,7 @@ Copy_field::get_copy_func(Field *to,Field *from) } else { - if (!to->eq_def(from) || !compatible_db_low_byte_first) + if (!to->eq_def(from)) { if (to->real_type() == MYSQL_TYPE_DECIMAL) return do_field_string; @@ -780,14 +776,13 @@ int field_conv(Field *to,Field *from) { if (to->pack_length() == from->pack_length() && !(to->flags & UNSIGNED_FLAG && !(from->flags & UNSIGNED_FLAG)) && + to->decimals() == from->decimals() && to->real_type() != MYSQL_TYPE_ENUM && to->real_type() != MYSQL_TYPE_SET && to->real_type() != MYSQL_TYPE_BIT && (to->real_type() != MYSQL_TYPE_NEWDECIMAL || - (to->field_length == from->field_length && - (((Field_num*)to)->dec == ((Field_num*)from)->dec))) && + to->field_length == from->field_length) && from->charset() == to->charset() && - to->table->s->db_low_byte_first == from->table->s->db_low_byte_first && (!(to->table->in_use->variables.sql_mode & (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE | MODE_INVALID_DATES)) || (to->type() != MYSQL_TYPE_DATE && diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 7bcbd241541..e3ed9289f11 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -235,7 +235,6 @@ void ha_partition::init_handler_variables() m_extra_prepare_for_update= FALSE; m_extra_cache_part_id= NO_CURRENT_PART_ID; m_handler_status= handler_not_initialized; - m_low_byte_first= 1; m_part_field_array= NULL; m_ordered_rec_buffer= NULL; m_top_entry= NO_CURRENT_PART_ID; @@ -374,18 +373,11 @@ bool ha_partition::initialize_partition(MEM_ROOT *mem_root) Verify that all partitions have the same table_flags. */ check_table_flags= m_file[0]->ha_table_flags(); - m_low_byte_first= m_file[0]->low_byte_first(); m_pkey_is_clustered= TRUE; file_array= m_file; do { file= *file_array; - if (m_low_byte_first != file->low_byte_first()) - { - // Cannot have handlers with different endian - my_error(ER_MIX_HANDLER_ERROR, MYF(0)); - DBUG_RETURN(1); - } if (!file->primary_key_is_clustered()) m_pkey_is_clustered= FALSE; if (check_table_flags != file->ha_table_flags()) diff --git a/sql/ha_partition.h b/sql/ha_partition.h index 76b91e160ca..cbc97c60818 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -99,7 +99,6 @@ private: for this since the MySQL Server sometimes allocating the handler object without freeing them. */ - ulong m_low_byte_first; enum enum_handler_status { handler_not_initialized= 0, @@ -884,12 +883,6 @@ public: virtual uint max_supported_key_length() const; virtual uint max_supported_key_part_length() const; - /* - All handlers in a partitioned table must have the same low_byte_first - */ - virtual bool low_byte_first() const - { return m_low_byte_first; } - /* The extra record buffer length is the maximum needed by all handlers. The minimum record length is the maximum of all involved handlers. diff --git a/sql/handler.h b/sql/handler.h index dabc179079a..64aa0c56ce3 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1623,7 +1623,6 @@ public: virtual uint max_supported_key_part_length() const { return 255; } virtual uint min_record_length(uint options) const { return 1; } - virtual bool low_byte_first() const { return 1; } virtual uint checksum() const { return 0; } virtual bool is_crashed() const { return 0; } virtual bool auto_repair() const { return 0; } diff --git a/sql/rpl_record.cc b/sql/rpl_record.cc index 3a46bbcd6ee..551870ede44 100644 --- a/sql/rpl_record.cc +++ b/sql/rpl_record.cc @@ -103,7 +103,7 @@ pack_row(TABLE *table, MY_BITMAP const* cols, const uchar *old_pack_ptr= pack_ptr; #endif pack_ptr= field->pack(pack_ptr, field->ptr + offset, - field->max_data_length(), TRUE); + field->max_data_length()); DBUG_PRINT("debug", ("field: %s; pack_ptr: 0x%lx;" " pack_ptr':0x%lx; bytes: %d", field->field_name, (ulong) old_pack_ptr, @@ -283,7 +283,7 @@ unpack_row(Relay_log_info const *rli, #ifndef DBUG_OFF uchar const *const old_pack_ptr= pack_ptr; #endif - pack_ptr= f->unpack(f->ptr, pack_ptr, metadata, TRUE); + pack_ptr= f->unpack(f->ptr, pack_ptr, metadata); DBUG_PRINT("debug", ("field: %s; metadata: 0x%x;" " pack_ptr: 0x%lx; pack_ptr': 0x%lx; bytes: %d", f->field_name, metadata, diff --git a/sql/rpl_utility.cc b/sql/rpl_utility.cc index 6058c473e9f..56b0b293d88 100644 --- a/sql/rpl_utility.cc +++ b/sql/rpl_utility.cc @@ -133,7 +133,7 @@ uint32 table_def::calc_field_size(uint col, uchar *master_data) const always read the length in little-endian order. */ Field_blob fb(m_field_metadata[col]); - length= fb.get_packed_size(master_data, TRUE); + length= fb.get_packed_size(master_data); #else /* Compute the length of the data. We cannot use get_length() here diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 12c5478b0ae..1aa1d50fc49 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -3542,9 +3542,6 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, tmp_table.s->db_create_options=0; tmp_table.s->blob_ptr_size= portable_sizeof_char_ptr; - tmp_table.s->db_low_byte_first= - test(create_info->db_type == myisam_hton || - create_info->db_type == heap_hton); tmp_table.null_row=tmp_table.maybe_null=0; while ((item=it++)) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index e02c22c3250..cda934cd549 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -10081,7 +10081,6 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, init_tmp_table_share(thd, share, "", 0, tmpname, tmpname); share->blob_field= blob_field; share->blob_ptr_size= portable_sizeof_char_ptr; - share->db_low_byte_first=1; // True for HEAP and MyISAM share->table_charset= param->table_charset; share->primary_key= MAX_KEY; // Indicate no primary key share->keys_for_keyread.init(); diff --git a/sql/table.cc b/sql/table.cc index 18523f08551..76df042eb40 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -757,8 +757,6 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, share->db_record_offset= 1; if (db_create_options & HA_OPTION_LONG_BLOB_PTR) share->blob_ptr_size= portable_sizeof_char_ptr; - /* Set temporarily a good value for db_low_byte_first */ - share->db_low_byte_first= test(legacy_db_type != DB_TYPE_ISAM); error=4; share->max_rows= uint4korr(head+18); share->min_rows= uint4korr(head+22); @@ -1597,7 +1595,6 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, (null_bit_pos + 7) / 8); share->last_null_bit_pos= null_bit_pos; - share->db_low_byte_first= handler_file->low_byte_first(); share->column_bitmap_size= bitmap_buffer_size(share->fields); if (!(bitmaps= (my_bitmap_map*) alloc_root(&share->mem_root, diff --git a/sql/table.h b/sql/table.h index 132279169cb..858201891f5 100644 --- a/sql/table.h +++ b/sql/table.h @@ -423,7 +423,6 @@ typedef struct st_table_share bool null_field_first; bool system; /* Set if system table (one record) */ bool crypted; /* If .frm file is crypted */ - bool db_low_byte_first; /* Portable row format */ bool crashed; bool is_view; bool name_lock, replace_with_name_lock; diff --git a/sql/unireg.cc b/sql/unireg.cc index 84160da9d77..6463ed2d950 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -944,7 +944,6 @@ static bool make_empty_rec(THD *thd, File file,enum legacy_db_type table_type, } table.in_use= thd; - table.s->db_low_byte_first= handler->low_byte_first(); table.s->blob_ptr_size= portable_sizeof_char_ptr; null_count=0; -- cgit v1.2.1 From fd0c94aba9f3d61f0329bf9b391b767778b7ff7c Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 21 May 2011 18:41:56 +0200 Subject: comments --- sql/field.cc | 12 ++++++------ sql/field.h | 4 ++-- sql/item.cc | 1 + sql/item.h | 5 +++++ sql/item_func.cc | 8 ++++++++ sql/log_event.h | 1 + sql/sql_select.cc | 40 ++++++++++++++++++++-------------------- 7 files changed, 43 insertions(+), 28 deletions(-) (limited to 'sql') diff --git a/sql/field.cc b/sql/field.cc index 0f1a8a2cdb6..87fd7317e9b 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -4473,7 +4473,7 @@ timestamp_auto_set_type Field_timestamp::get_auto_set_type() const } } -long Field_timestamp::get_timestamp(ulong *sec_part) const +my_time_t Field_timestamp::get_timestamp(ulong *sec_part) const { ASSERT_COLUMN_MARKED_FOR_READ; *sec_part= 0; @@ -4592,7 +4592,7 @@ longlong Field_timestamp::val_int(void) thd->time_zone_used= 1; ulong sec_part; - uint32 temp= get_timestamp(&sec_part); + my_time_t temp= get_timestamp(&sec_part); /* Field_timestamp() and Field_timestamp_hres() shares this code. @@ -4622,7 +4622,7 @@ String *Field_timestamp::val_str(String *val_buffer, String *val_ptr) thd->time_zone_used= 1; ulong sec_part; - uint32 temp= get_timestamp(&sec_part); + my_time_t temp= get_timestamp(&sec_part); if (temp == 0 && sec_part == 0) { /* Zero time is "000000" */ @@ -4682,7 +4682,7 @@ bool Field_timestamp::get_date(MYSQL_TIME *ltime, uint fuzzydate) THD *thd= table->in_use; thd->time_zone_used= 1; ulong sec_part; - uint32 temp= get_timestamp(&sec_part); + my_time_t temp= get_timestamp(&sec_part); if (temp == 0 && sec_part == 0) { /* Zero time is "000000" */ if (fuzzydate & TIME_NO_ZERO_DATE) @@ -4830,7 +4830,7 @@ void Field_timestamp_hires::store_TIME(my_time_t timestamp, ulong sec_part) store_bigendian(sec_part_shift(sec_part, dec), ptr+4, sec_part_bytes[dec]); } -long Field_timestamp_hires::get_timestamp(ulong *sec_part) const +my_time_t Field_timestamp_hires::get_timestamp(ulong *sec_part) const { ASSERT_COLUMN_MARKED_FOR_READ; *sec_part= (long)sec_part_unshift(read_bigendian(ptr+4, sec_part_bytes[dec]), dec); @@ -4844,7 +4844,7 @@ double Field_timestamp_hires::val_real(void) thd->time_zone_used= 1; ulong sec_part; - uint32 temp= get_timestamp(&sec_part); + my_time_t temp= get_timestamp(&sec_part); if (temp == 0 && sec_part == 0) return(0); diff --git a/sql/field.h b/sql/field.h index 95c2fd30559..a976d8b5ce5 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1137,7 +1137,7 @@ public: Field::set_default(); } /* Get TIMESTAMP field value as seconds since begging of Unix Epoch */ - virtual long get_timestamp(ulong *sec_part) const; + virtual my_time_t get_timestamp(ulong *sec_part) const; virtual void store_TIME(my_time_t timestamp, ulong sec_part) { int4store(ptr,timestamp); @@ -1172,7 +1172,7 @@ public: DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS); } void sql_type(String &str) const; - long get_timestamp(ulong *sec_part) const; + my_time_t 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); diff --git a/sql/item.cc b/sql/item.cc index fd0be90c216..520386b90fa 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -7106,6 +7106,7 @@ Item_cache* Item_cache::get_cache(const Item *item, const Item_result type) case ROW_RESULT: return new Item_cache_row(); case TIME_RESULT: + /* this item will store a packed datetime value as an integer */ return new Item_cache_int(MYSQL_TYPE_DATETIME); } return 0; diff --git a/sql/item.h b/sql/item.h index 3be654abdd8..16f0857958d 100644 --- a/sql/item.h +++ b/sql/item.h @@ -3041,6 +3041,11 @@ public: bool cache_value(); bool get_date(MYSQL_TIME *ltime, uint fuzzydate); int save_in_field(Field *field, bool no_conversions); + /* + Having a clone_item method tells optimizer that this object + is a constant and need not be optimized further. + Important when storing packed datetime values. + */ Item *clone_item() { Item_cache_int *item= new Item_cache_int(cached_field_type); diff --git a/sql/item_func.cc b/sql/item_func.cc index 870a481ce85..5a8e8a4defd 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -2282,6 +2282,14 @@ bool Item_func_min_max::get_date(MYSQL_TIME *ltime, uint fuzzy_date) { longlong UNINIT_VAR(min_max); DBUG_ASSERT(fixed == 1); + + /* + just like ::val_int() method of an string item can be called, + for example, SELECT CONCAT("10", "12") + 1, + ::get_date() can be called for non-temporal values, + for example, SELECT MONTH(GREATEST("2011-11-21", "2010-10-09")) + + */ if (!compare_as_dates) return Item_func::get_date(ltime, fuzzy_date); diff --git a/sql/log_event.h b/sql/log_event.h index 6327a53844d..79e3c1e2f15 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -1015,6 +1015,7 @@ public: when_sec_part= thd->start_time_sec_part; return when; } + /* thd will only be 0 here at time of log creation */ if ((tmp_thd= current_thd)) { when= tmp_thd->start_time; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index cda934cd549..aa5c1f7668d 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -9417,36 +9417,36 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value) return cond; // Point at next and level } -/* +/** Check if equality can be used in removing components of GROUP BY/DISTINCT - SYNOPSIS - test_if_equality_guarantees_uniqueness() - l the left comparison argument (a field if any) - r the right comparison argument (a const of any) + @param l the left comparison argument (a field if any) + @param r the right comparison argument (a const of any) - DESCRIPTION - Checks if an equality predicate can be used to take away - DISTINCT/GROUP BY because it is known to be true for exactly one - distinct value (e.g. == ). - Arguments must be of the same type because e.g. - = may match more than 1 distinct value from - the column. - We must take into consideration and the optimization done for various - string constants when compared to dates etc (see Item_int_with_ref) as - well as the collation of the arguments. + @details + Checks if an equality predicate can be used to take away + DISTINCT/GROUP BY because it is known to be true for exactly one + distinct value (e.g. == ). + Arguments must be of the same type because e.g. + = may match more than 1 distinct value from + the column. + Additionally, strings must have the same collation. + Or the *field* must be a datetime - if the constant is a datetime + and a field is not - this is not enough, consider: + create table t1 (a varchar(100)); + insert t1 values ('2010-01-02'), ('2010-1-2'), ('20100102'); + select distinct t1 from t1 where a=date('2010-01-02'); - RETURN VALUE - TRUE can be used - FALSE cannot be used + @retval true can be used + @retval false cannot be used */ static bool test_if_equality_guarantees_uniqueness(Item *l, Item *r) { return r->const_item() && - /* elements must be compared as dates */ + /* the field is a date (the const will be converted to a date) */ (l->cmp_type() == TIME_RESULT || - /* or of the same result type */ + /* or arguments are of the same result type */ (r->result_type() == l->result_type() && /* and must have the same collation if compared as strings */ (l->result_type() != STRING_RESULT || -- cgit v1.2.1 From a0869fa02c5ad6b5d4ba9ad793dcf88e576a441c Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sun, 22 May 2011 11:58:48 +0200 Subject: unix_timestamp() and from_unixtime() supports microseconds. unix_timestamp() and time_to_sec() are hybrid items, returning integer or double depending on the argument. --- sql/item_func.h | 2 ++ sql/item_timefunc.cc | 77 ++++++++++++++++++++++++++++++++++++++-------------- sql/item_timefunc.h | 55 ++++++++++++++++++++++++------------- 3 files changed, 94 insertions(+), 40 deletions(-) (limited to 'sql') diff --git a/sql/item_func.h b/sql/item_func.h index cd2829fb5a7..7a4fd742cf5 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -242,6 +242,8 @@ class Item_func_numhybrid: public Item_func protected: Item_result hybrid_type; public: + Item_func_numhybrid() :Item_func(), hybrid_type(REAL_RESULT) + {} Item_func_numhybrid(Item *a) :Item_func(a), hybrid_type(REAL_RESULT) {} Item_func_numhybrid(Item *a,Item *b) diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index a32cfabcaa1..18fde7abce3 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -1176,26 +1176,23 @@ longlong Item_func_year::val_int_endpoint(bool left_endp, bool *incl_endp) } -longlong Item_func_unix_timestamp::val_int() +bool Item_func_unix_timestamp::get_timestamp_value(my_time_t *seconds, + ulong *second_part) { - MYSQL_TIME ltime; - uint not_used; - DBUG_ASSERT(fixed == 1); - if (arg_count == 0) - return (longlong) current_thd->query_start(); if (args[0]->type() == FIELD_ITEM) { // Optimize timestamp field Field *field=((Item_field*) args[0])->field; if (field->type() == MYSQL_TYPE_TIMESTAMP) { if ((null_value= field->is_null())) - return 0; - ulong unused; - return ((Field_timestamp*) field)->get_timestamp(&unused); + return 1; + *seconds= ((Field_timestamp*)field)->get_timestamp(second_part); + return 0; } } - + + MYSQL_TIME ltime; if (get_arg0_date(<ime, 0)) { /* @@ -1204,14 +1201,53 @@ longlong Item_func_unix_timestamp::val_int() this case). */ null_value= args[0]->null_value; - return 0; + return 1; } + + uint not_used; + *seconds= TIME_to_timestamp(current_thd, <ime, ¬_used); + *second_part= ltime.second_part; + return 0; +} + + +longlong Item_func_unix_timestamp::int_op() +{ + if (arg_count == 0) + return (longlong) current_thd->query_start(); - return (longlong) TIME_to_timestamp(current_thd, <ime, ¬_used); + ulong second_part; + my_time_t seconds; + if (get_timestamp_value(&seconds, &second_part)) + return 0; + + return seconds; } -double Item_func_time_to_sec::val_real() +double Item_func_unix_timestamp::real_op() +{ + ulong second_part; + my_time_t seconds; + if (get_timestamp_value(&seconds, &second_part)) + return 0; + + return seconds + second_part/(double)TIME_SECOND_PART_FACTOR; +} + + +longlong Item_func_time_to_sec::int_op() +{ + DBUG_ASSERT(fixed == 1); + MYSQL_TIME ltime; + longlong seconds; + (void) get_arg0_time(<ime); + seconds=ltime.hour*3600L+ltime.minute*60+ltime.second; + return ltime.neg ? -seconds : seconds; +} + + +double Item_func_time_to_sec::real_op() { DBUG_ASSERT(fixed == 1); MYSQL_TIME ltime; @@ -1797,6 +1833,7 @@ void Item_func_from_unixtime::fix_length_and_dec() thd= current_thd; maybe_null= 1; thd->time_zone_used= 1; + decimals= args[0]->decimals; Item_temporal_func::fix_length_and_dec(); } @@ -1804,17 +1841,15 @@ void Item_func_from_unixtime::fix_length_and_dec() bool Item_func_from_unixtime::get_date(MYSQL_TIME *ltime, uint fuzzy_date __attribute__((unused))) { - ulonglong tmp= (ulonglong)(args[0]->val_int()); - /* - "tmp > TIMESTAMP_MAX_VALUE" check also covers case of negative - from_unixtime() argument since tmp is unsigned. - */ - if ((null_value= (args[0]->null_value || tmp > TIMESTAMP_MAX_VALUE))) - return 1; + double tmp= args[0]->val_real(); + if (args[0]->null_value || tmp < 0 || tmp > TIMESTAMP_MAX_VALUE) + return (null_value= 1); thd->variables.time_zone->gmt_sec_to_TIME(ltime, (my_time_t)tmp); - return 0; + ltime->second_part= (ulong)((tmp - floor(tmp))*TIME_SECOND_PART_FACTOR); + + return (null_value= 0); } diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index 14275680d15..d50b0c20716 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -297,15 +297,37 @@ class Item_func_dayname :public Item_func_weekday }; -class Item_func_unix_timestamp :public Item_int_func +class Item_func_seconds_hybrid: public Item_func_numhybrid { - String value; public: - Item_func_unix_timestamp() :Item_int_func() {} - Item_func_unix_timestamp(Item *a) :Item_int_func(a) {} - longlong val_int(); + Item_func_seconds_hybrid() :Item_func_numhybrid() {} + Item_func_seconds_hybrid(Item *a) :Item_func_numhybrid(a) {} + void fix_num_length_and_dec() + { + if (arg_count) + decimals= args[0]->decimals; + if (decimals != NOT_FIXED_DEC) + set_if_smaller(decimals, TIME_SECOND_PART_DIGITS); + max_length=17 + (decimals ? decimals + 1 : 0); + } + void find_num_type() { hybrid_type= decimals ? REAL_RESULT : INT_RESULT; } + my_decimal *decimal_op(my_decimal* buf) { DBUG_ASSERT(0); return 0; } + String *str_op(String *str) { DBUG_ASSERT(0); return 0; } +}; + +class Item_func_unix_timestamp :public Item_func_seconds_hybrid +{ + bool get_timestamp_value(my_time_t *seconds, ulong *second_part); +public: + Item_func_unix_timestamp() :Item_func_seconds_hybrid() {} + Item_func_unix_timestamp(Item *a) :Item_func_seconds_hybrid(a) {} const char *func_name() const { return "unix_timestamp"; } bool check_partition_func_processor(uchar *int_arg) {return FALSE;} + void fix_num_length_and_dec() + { + maybe_null= false; + Item_func_seconds_hybrid::fix_num_length_and_dec(); + } /* UNIX_TIMESTAMP() depends on the current timezone (and thus may not be used as a partitioning function) @@ -315,29 +337,24 @@ public: { return !has_timestamp_args(); } - void fix_length_and_dec() - { - decimals=0; - max_length=10*MY_CHARSET_BIN_MB_MAXLEN; - } + longlong int_op(); + double real_op(); }; -class Item_func_time_to_sec :public Item_real_func +class Item_func_time_to_sec :public Item_func_seconds_hybrid { public: - Item_func_time_to_sec(Item *item) :Item_real_func(item) {} + Item_func_time_to_sec(Item *item) :Item_func_seconds_hybrid(item) {} const char *func_name() const { return "time_to_sec"; } - double val_real(); - void fix_length_and_dec() + void fix_num_length_and_dec() { - maybe_null= TRUE; - decimals= args[0]->decimals; - if (decimals != NOT_FIXED_DEC) - set_if_smaller(decimals, TIME_SECOND_PART_DIGITS); - max_length=17; + maybe_null= true; + Item_func_seconds_hybrid::fix_num_length_and_dec(); } bool check_partition_func_processor(uchar *int_arg) {return FALSE;} + longlong int_op(); + double real_op(); }; -- cgit v1.2.1