summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorMichael Widenius <monty@askmonty.org>2011-05-28 05:11:32 +0300
committerMichael Widenius <monty@askmonty.org>2011-05-28 05:11:32 +0300
commitf197991f4102ed8ac66b7b57071f24f1d3b86aea (patch)
treeb4590b80e7d50b664d8e6ff6a62978cb2402f0a6 /sql
parentde44b51e151a00a00d0e396dc57ced3682d24d78 (diff)
parent306ed65302e14f303fdc33cfa9d19016fb319440 (diff)
downloadmariadb-git-f197991f4102ed8ac66b7b57071f24f1d3b86aea.tar.gz
Merge with 5.1-microseconds
A lot of small fixes and new test cases. client/mysqlbinlog.cc: Cast removed client/mysqltest.cc: Added missing DBUG_RETURN include/my_pthread.h: set_timespec_time_nsec() now only takes one argument mysql-test/t/date_formats.test: Remove --disable_ps_protocl as now also ps supports microseconds mysys/my_uuid.c: Changed to use my_interval_timer() instead of my_getsystime() mysys/waiting_threads.c: Changed to use my_hrtime() sql/field.h: Added bool special_const_compare() for fields that may convert values before compare (like year) sql/field_conv.cc: Added test to get optimal copying of identical temporal values. sql/item.cc: Return that item_int is equal if it's positive, even if unsigned flag is different. Fixed Item_cache_str::save_in_field() to have identical null check as other similar functions Added proper NULL check to Item_cache_int::save_in_field() sql/item_cmpfunc.cc: Don't call convert_constant_item() if there is nothing that is worth converting. Simplified test when years should be converted sql/item_sum.cc: Mark cache values in Item_sum_hybrid as not constants to ensure they are not replaced by other cache values in compare_datetime() sql/item_timefunc.cc: Changed sec_to_time() to take a my_decimal argument to ensure we don't loose any sub seconds. Added Item_temporal_func::get_time() (This simplifies some things) sql/mysql_priv.h: Added Lazy_string_decimal() sql/mysqld.cc: Added my_decimal constants max_seconds_for_time_type, time_second_part_factor sql/table.cc: Changed expr_arena to be of type CONVENTIONAL_EXECUTION to ensure that we don't loose any items that are created by fix_fields() sql/tztime.cc: TIME_to_gmt_sec() now sets *in_dst_time_gap in case of errors This is needed to be able to detect if timestamp is 0 storage/maria/lockman.c: Changed from my_getsystime() to set_timespec_time_nsec() storage/maria/ma_loghandler.c: Changed from my_getsystime() to my_hrtime() storage/maria/ma_recovery.c: Changed from my_getsystime() to mmicrosecond_interval_timer() storage/maria/unittest/trnman-t.c: Changed from my_getsystime() to mmicrosecond_interval_timer() storage/xtradb/handler/ha_innodb.cc: Added support for new time,datetime and timestamp unittest/mysys/thr_template.c: my_getsystime() -> my_interval_timer() unittest/mysys/waiting_threads-t.c: my_getsystime() -> my_interval_timer()
Diffstat (limited to 'sql')
-rw-r--r--sql/event_data_objects.cc6
-rw-r--r--sql/event_db_repository.cc7
-rw-r--r--sql/event_parse_data.cc14
-rw-r--r--sql/event_queue.cc7
-rw-r--r--sql/event_queue.h2
-rw-r--r--sql/field.cc2398
-rw-r--r--sql/field.h634
-rw-r--r--sql/field_conv.cc44
-rw-r--r--sql/filesort.cc47
-rw-r--r--sql/ha_partition.cc8
-rw-r--r--sql/ha_partition.h7
-rw-r--r--sql/handler.h1
-rw-r--r--sql/item.cc373
-rw-r--r--sql/item.h83
-rw-r--r--sql/item_cmpfunc.cc882
-rw-r--r--sql/item_cmpfunc.h45
-rw-r--r--sql/item_create.cc55
-rw-r--r--sql/item_func.cc225
-rw-r--r--sql/item_func.h12
-rw-r--r--sql/item_row.h1
-rw-r--r--sql/item_strfunc.cc20
-rw-r--r--sql/item_sum.cc30
-rw-r--r--sql/item_timefunc.cc1107
-rw-r--r--sql/item_timefunc.h518
-rw-r--r--sql/log.cc109
-rw-r--r--sql/log.h20
-rw-r--r--sql/log_event.cc77
-rw-r--r--sql/log_event.h26
-rw-r--r--sql/log_event_old.cc4
-rw-r--r--sql/mysql_priv.h104
-rw-r--r--sql/mysqld.cc31
-rw-r--r--sql/opt_range.cc17
-rw-r--r--sql/opt_subselect.cc31
-rw-r--r--sql/protocol.cc57
-rw-r--r--sql/protocol.h12
-rw-r--r--sql/rpl_record.cc4
-rw-r--r--sql/rpl_rli.cc6
-rw-r--r--sql/rpl_utility.cc2
-rw-r--r--sql/set_var.cc23
-rw-r--r--sql/set_var.h6
-rw-r--r--sql/share/errmsg.txt12
-rw-r--r--sql/slave.cc6
-rw-r--r--sql/sp_head.cc14
-rw-r--r--sql/sql_class.cc15
-rw-r--r--sql/sql_class.h69
-rw-r--r--sql/sql_connect.cc2
-rw-r--r--sql/sql_insert.cc16
-rw-r--r--sql/sql_parse.cc29
-rw-r--r--sql/sql_prepare.cc3
-rw-r--r--sql/sql_profile.cc2
-rw-r--r--sql/sql_select.cc78
-rw-r--r--sql/sql_show.cc73
-rw-r--r--sql/sql_string.cc2
-rw-r--r--sql/sql_string.h2
-rw-r--r--sql/sql_table.cc12
-rw-r--r--sql/sql_yacc.yy101
-rw-r--r--sql/table.cc10
-rw-r--r--sql/table.h1
-rw-r--r--sql/time.cc144
-rw-r--r--sql/tztime.cc34
-rw-r--r--sql/unireg.cc1
-rw-r--r--sql/unireg.h5
62 files changed, 3342 insertions, 4344 deletions
diff --git a/sql/event_data_objects.cc b/sql/event_data_objects.cc
index 959f6ec06c0..6e2aa013d88 100644
--- a/sql/event_data_objects.cc
+++ b/sql/event_data_objects.cc
@@ -927,7 +927,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));
@@ -1130,7 +1130,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++;
@@ -1190,7 +1190,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 2a2fc6bdd3d..7d82126cbe5 100644
--- a/sql/event_db_repository.cc
+++ b/sql/event_db_repository.cc
@@ -232,6 +232,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.
@@ -318,7 +321,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)
{
@@ -674,8 +677,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..4555da44f18 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;
/*
@@ -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(&ltime, TIME_NO_ZERO_DATE)))
+ if (item_execute_at->get_date(&ltime, TIME_NO_ZERO_DATE))
goto wrong_value;
ltime_utc= TIME_to_timestamp(thd,&ltime,&not_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(&ltime, TIME_NO_ZERO_DATE)))
+ if (item_starts->get_date(&ltime, TIME_NO_ZERO_DATE))
goto wrong_value;
ltime_utc= TIME_to_timestamp(thd, &ltime, &not_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(&ltime, TIME_NO_ZERO_DATE)))
+ if (item_ends->get_date(&ltime, TIME_NO_ZERO_DATE))
goto error_bad_params;
ltime_utc= TIME_to_timestamp(thd, &ltime, &not_used);
diff --git a/sql/event_queue.cc b/sql/event_queue.cc
index c551cf74095..6016048aa9c 100644
--- a/sql/event_queue.cc
+++ b/sql/event_queue.cc
@@ -530,9 +530,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");
@@ -618,9 +619,9 @@ Event_queue::get_top_for_execution_if_time(THD *thd,
time or until signaled. Release LOCK_queue while waiting.
*/
struct timespec top_time;
- set_timespec(top_time, next_activation_at - thd->query_start());
- cond_wait(thd, &top_time, queue_wait_msg, SCHED_FUNC, __LINE__);
+ set_timespec_time_nsec(top_time, next_activation_at*1000000000ULL);
+ 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 c9851b8af50..7976c8b0e3c 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2010, Oracle and/or its affiliates.
-
+ Copyright (c) 2009-2011 Monty Program Ab
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
@@ -47,6 +47,17 @@ template class List<Create_field>;
template class List_iterator<Create_field>;
#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=',';
@@ -1408,13 +1419,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 <code>low_byte_first</code> 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
<code>max_length</code> characters.
@@ -1432,15 +1436,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);
@@ -1471,16 +1469,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;
@@ -1750,19 +1742,6 @@ bool Field::get_date(MYSQL_TIME *ltime,uint fuzzydate)
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,
- table->in_use->variables.sql_mode &
- (MODE_NO_ZERO_DATE | MODE_NO_ZERO_IN_DATE |
- MODE_INVALID_DATES)))
- return 1;
- return 0;
-}
-
/**
This is called when storing a date in a string.
@@ -1774,7 +1753,7 @@ int Field::store_time(MYSQL_TIME *ltime, timestamp_type type_arg)
{
ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
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);
}
@@ -2935,13 +2914,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;
@@ -3163,14 +3139,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;
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- {
- int2store(ptr, store_tmp);
- }
- else
-#endif
- shortstore(ptr, (short) store_tmp);
+ int2store(ptr, store_tmp);
return error;
}
@@ -3215,14 +3184,7 @@ int Field_short::store(double nr)
else
res=(int16) (int) nr;
}
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- {
- int2store(ptr,res);
- }
- else
-#endif
- shortstore(ptr,res);
+ int2store(ptr,res);
return error;
}
@@ -3270,14 +3232,7 @@ int Field_short::store(longlong nr, bool unsigned_val)
else
res=(int16) nr;
}
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- {
- int2store(ptr,res);
- }
- else
-#endif
- shortstore(ptr,res);
+ int2store(ptr,res);
return error;
}
@@ -3286,12 +3241,7 @@ double Field_short::val_real(void)
{
ASSERT_COLUMN_MARKED_FOR_READ;
short j;
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- j=sint2korr(ptr);
- else
-#endif
- shortget(j,ptr);
+ j=sint2korr(ptr);
return unsigned_flag ? (double) (unsigned short) j : (double) j;
}
@@ -3299,12 +3249,7 @@ longlong Field_short::val_int(void)
{
ASSERT_COLUMN_MARKED_FOR_READ;
short j;
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- j=sint2korr(ptr);
- else
-#endif
- shortget(j,ptr);
+ j=sint2korr(ptr);
return unsigned_flag ? (longlong) (unsigned short) j : (longlong) j;
}
@@ -3319,12 +3264,7 @@ 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)
- j=sint2korr(ptr);
- else
-#endif
- shortget(j,ptr);
+ j=sint2korr(ptr);
if (unsigned_flag)
length=(uint) cs->cset->long10_to_str(cs, to, mlength, 10,
@@ -3347,18 +3287,8 @@ 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)
- {
- a=sint2korr(a_ptr);
- b=sint2korr(b_ptr);
- }
- else
-#endif
- {
- 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 :
@@ -3368,24 +3298,11 @@ 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 (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
-#endif
- {
- 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
@@ -3600,14 +3517,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;
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- {
- int4store(ptr, store_tmp);
- }
- else
-#endif
- longstore(ptr, store_tmp);
+ int4store(ptr, store_tmp);
return error;
}
@@ -3652,14 +3562,7 @@ 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)
- {
- int4store(ptr,res);
- }
- else
-#endif
- longstore(ptr,res);
+ int4store(ptr,res);
return error;
}
@@ -3705,14 +3608,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);
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- {
- int4store(ptr,res);
- }
- else
-#endif
- longstore(ptr,res);
+ int4store(ptr,res);
return error;
}
@@ -3721,12 +3617,7 @@ double Field_long::val_real(void)
{
ASSERT_COLUMN_MARKED_FOR_READ;
int32 j;
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- j=sint4korr(ptr);
- else
-#endif
- longget(j,ptr);
+ j=sint4korr(ptr);
return unsigned_flag ? (double) (uint32) j : (double) j;
}
@@ -3736,12 +3627,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);
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- j=sint4korr(ptr);
- else
-#endif
- longget(j,ptr);
+ j=sint4korr(ptr);
return unsigned_flag ? (longlong) (uint32) j : (longlong) j;
}
@@ -3755,12 +3641,7 @@ 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)
- j=sint4korr(ptr);
- else
-#endif
- longget(j,ptr);
+ j=sint4korr(ptr);
if (unsigned_flag)
length=cs->cset->long10_to_str(cs,to,mlength, 10,(long) (uint32)j);
@@ -3782,18 +3663,8 @@ 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)
- {
- a=sint4korr(a_ptr);
- b=sint4korr(b_ptr);
- }
- else
-#endif
- {
- 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;
@@ -3801,28 +3672,13 @@ 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 (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
-#endif
- {
- 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];
}
@@ -3856,14 +3712,7 @@ 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)
- {
- int8store(ptr,tmp);
- }
- else
-#endif
- longlongstore(ptr,tmp);
+ int8store(ptr,tmp);
return error;
}
@@ -3879,14 +3728,7 @@ 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)
- {
- int8store(ptr,res);
- }
- else
-#endif
- longlongstore(ptr,res);
+ int8store(ptr,res);
return error;
}
@@ -3910,14 +3752,7 @@ int Field_longlong::store(longlong nr, bool unsigned_val)
}
}
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- {
- int8store(ptr,nr);
- }
- else
-#endif
- longlongstore(ptr,nr);
+ int8store(ptr,nr);
return error;
}
@@ -3926,14 +3761,7 @@ double Field_longlong::val_real(void)
{
ASSERT_COLUMN_MARKED_FOR_READ;
longlong j;
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- {
- j=sint8korr(ptr);
- }
- else
-#endif
- longlongget(j,ptr);
+ j=sint8korr(ptr);
/* The following is open coded to avoid a bug in gcc 3.3 */
if (unsigned_flag)
{
@@ -3948,12 +3776,7 @@ longlong Field_longlong::val_int(void)
{
ASSERT_COLUMN_MARKED_FOR_READ;
longlong j;
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- j=sint8korr(ptr);
- else
-#endif
- longlongget(j,ptr);
+ j=sint8korr(ptr);
return j;
}
@@ -3967,12 +3790,7 @@ 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)
- j=sint8korr(ptr);
- else
-#endif
- longlongget(j,ptr);
+ j=sint8korr(ptr);
length=(uint) (cs->cset->longlong10_to_str)(cs,to,mlength,
unsigned_flag ? 10 : -10, j);
@@ -3993,18 +3811,8 @@ 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)
- {
- a=sint8korr(a_ptr);
- b=sint8korr(b_ptr);
- }
- else
-#endif
- {
- 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;
@@ -4013,36 +3821,17 @@ 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 (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
-#endif
- {
- 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];
}
@@ -4059,43 +3848,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());
-#ifdef WORDS_BIGENDIAN
- if (low_byte_first != table->s->db_low_byte_first)
- {
- const uchar *dptr= from + pack_length();
- while (dptr-- > from)
- *to++ = *dptr;
- DBUG_RETURN(to);
- }
- else
-#endif
- 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");
-#ifdef WORDS_BIGENDIAN
- if (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
-#endif
- DBUG_RETURN(Field::unpack(to, from, param_data, low_byte_first));
-}
-
/****************************************************************************
single precision float
****************************************************************************/
@@ -4134,14 +3886,7 @@ int Field_float::store(double nr)
}
float j= (float)nr;
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- {
- float4store(ptr,j);
- }
- else
-#endif
- memcpy_fixed(ptr,(uchar*) &j,sizeof(j));
+ float4store(ptr,j);
return error;
}
@@ -4157,28 +3902,14 @@ double Field_float::val_real(void)
{
ASSERT_COLUMN_MARKED_FOR_READ;
float j;
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- {
- float4get(j,ptr);
- }
- else
-#endif
- memcpy_fixed((uchar*) &j,ptr,sizeof(j));
+ float4get(j,ptr);
return ((double) j);
}
longlong Field_float::val_int(void)
{
float j;
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- {
- float4get(j,ptr);
- }
- else
-#endif
- memcpy_fixed((uchar*) &j,ptr,sizeof(j));
+ float4get(j,ptr);
return (longlong) rint(j);
}
@@ -4188,14 +3919,7 @@ 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)
- {
- float4get(nr,ptr);
- }
- else
-#endif
- memcpy_fixed((uchar*) &nr,ptr,sizeof(nr));
+ float4get(nr,ptr);
uint to_length=max(field_length,70);
val_buffer->alloc(to_length);
@@ -4270,18 +3994,8 @@ 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)
- {
- float4get(a,a_ptr);
- float4get(b,b_ptr);
- }
- else
-#endif
- {
- 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;
}
@@ -4290,14 +4004,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;
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- {
- float4get(nr,ptr);
- }
- else
-#endif
- memcpy_fixed(&nr,ptr,sizeof(float));
+ float4get(nr,ptr);
uchar *tmp= to;
if (nr == (float) 0.0)
@@ -4406,14 +4113,7 @@ int Field_double::store(double nr)
}
}
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- {
- float8store(ptr,nr);
- }
- else
-#endif
- doublestore(ptr,nr);
+ float8store(ptr,nr);
return error;
}
@@ -4544,14 +4244,7 @@ double Field_double::val_real(void)
{
ASSERT_COLUMN_MARKED_FOR_READ;
double j;
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- {
- float8get(j,ptr);
- }
- else
-#endif
- doubleget(j,ptr);
+ float8get(j,ptr);
return j;
}
@@ -4561,14 +4254,7 @@ longlong Field_double::val_int(void)
double j;
longlong res;
bool error;
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- {
- float8get(j,ptr);
- }
- else
-#endif
- doubleget(j,ptr);
+ float8get(j,ptr);
res= double_to_longlong(j, 0, &error);
if (error)
@@ -4598,14 +4284,7 @@ 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)
- {
- float8get(nr,ptr);
- }
- else
-#endif
- doubleget(nr,ptr);
+ float8get(nr,ptr);
uint to_length= DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE;
val_buffer->alloc(to_length);
@@ -4686,18 +4365,8 @@ 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)
- {
- float8get(a,a_ptr);
- float8get(b,b_ptr);
- }
- else
-#endif
- {
- doubleget(a, a_ptr);
- doubleget(b, b_ptr);
- }
+ float8get(a,a_ptr);
+ float8get(b,b_ptr);
return (a < b) ? -1 : (a > b) ? 1 : 0;
}
@@ -4709,14 +4378,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;
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- {
- float8get(nr,ptr);
- }
- else
-#endif
- doubleget(nr,ptr);
+ float8get(nr,ptr);
change_double_for_sort(nr, to);
}
@@ -4804,12 +4466,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;
@@ -4820,20 +4482,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.
@@ -4868,136 +4516,139 @@ timestamp_auto_set_type Field_timestamp::get_auto_set_type() const
}
}
+my_time_t Field_timestamp::get_timestamp(ulong *sec_part) const
+{
+ ASSERT_COLUMN_MARKED_FOR_READ;
+ *sec_part= 0;
+ return sint4korr(ptr);
+}
-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_OR_COMPUTED;
- MYSQL_TIME l_time;
- my_time_t tmp= 0;
- int error;
- bool have_smth_to_conv;
- my_bool in_dst_time_gap;
- THD *thd= table ? table->in_use : current_thd;
+ uint error = 0;
+ my_time_t timestamp;
- /* 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)))
- {
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_OUT_OF_RANGE,
- from, len, 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,
- from, len, MYSQL_TIMESTAMP_DATETIME, !error);
+ set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, conversion_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->in_use;
+ 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->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,
+ (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_double str(nr);
+ THD *thd= table->in_use;
+ longlong tmp;
+
+ /* We don't want to store invalid or fuzzy datetime values in TIMESTAMP */
+ if (nr < 0 || nr > LONGLONG_MAX)
+ nr= LONGLONG_MAX;
+ 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))*TIME_SECOND_PART_FACTOR);
+ return store_TIME_with_warning(thd, &l_time, &str, error, tmp != -1);
}
int Field_timestamp::store(longlong nr, bool unsigned_val)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
MYSQL_TIME l_time;
- my_time_t timestamp= 0;
int error;
- my_bool in_dst_time_gap;
- THD *thd= table ? table->in_use : current_thd;
+ Lazy_string_num str(nr);
+ 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 &
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 *thd= table->in_use;
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;
+ my_time_t temp= get_timestamp(&sec_part);
- if (temp == 0L) // No time
- return(0); /* purecov: inspected */
+ /*
+ 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);
thd->variables.time_zone->gmt_sec_to_TIME(&time_tmp, (my_time_t)temp);
@@ -5009,10 +4660,9 @@ longlong Field_timestamp::val_int(void)
String *Field_timestamp::val_str(String *val_buffer, String *val_ptr)
{
- ASSERT_COLUMN_MARKED_FOR_READ;
- uint32 temp, temp2;
+ uint32 temp2;
+ THD *thd= table->in_use;
MYSQL_TIME time_tmp;
- THD *thd= table ? table->in_use : current_thd;
char *to;
val_buffer->alloc(field_length+1);
@@ -5020,20 +4670,16 @@ 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;
+ my_time_t 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
-
+
thd->variables.time_zone->gmt_sec_to_TIME(&time_tmp,(my_time_t)temp);
temp= time_tmp.year % 100;
@@ -5082,16 +4728,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 *thd= table->in_use;
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;
+ my_time_t temp= get_timestamp(&sec_part);
+ if (temp == 0 && sec_part == 0)
{ /* Zero time is "000000" */
if (fuzzydate & TIME_NO_ZERO_DATE)
return 1;
@@ -5100,61 +4741,35 @@ bool Field_timestamp::get_date(MYSQL_TIME *ltime, uint fuzzydate)
else
{
thd->variables.time_zone->gmt_sec_to_TIME(ltime, (my_time_t)temp);
+ ltime->second_part= sec_part;
}
return 0;
}
-bool Field_timestamp::get_time(MYSQL_TIME *ltime)
-{
- return Field_timestamp::get_date(ltime,0);
-}
-
bool Field_timestamp::send_binary(Protocol *protocol)
{
- MYSQL_TIME tm;
- Field_timestamp::get_date(&tm, 0);
- return protocol->store(&tm);
+ MYSQL_TIME ltime;
+ Field_timestamp::get_date(&ltime, 0);
+ return protocol->store(&ltime, 0);
}
int Field_timestamp::cmp(const uchar *a_ptr, const uchar *b_ptr)
{
int32 a,b;
-#ifdef WORDS_BIGENDIAN
- if (table && table->s->db_low_byte_first)
- {
- a=sint4korr(a_ptr);
- b=sint4korr(b_ptr);
- }
- else
-#endif
- {
- 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)))
{
-#ifdef WORDS_BIGENDIAN
- if (!table || !table->s->db_low_byte_first)
- {
- to[0] = ptr[0];
- to[1] = ptr[1];
- to[2] = ptr[2];
- to[3] = ptr[3];
- }
- else
-#endif
- {
- 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];
}
@@ -5164,152 +4779,423 @@ 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();
+ THD *thd= table->in_use;
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)
+#ifdef NOT_USED
+static void store_native(ulonglong num, uchar *to, uint bytes)
{
- MYSQL_TIME ltime;
- long tmp;
- int error= 0;
- int warning;
+ switch(bytes) {
+ case 1: *to= (uchar)num; break;
+ case 2: shortstore(to, (ushort)num); break;
+ case 3: int3store(to, num); /* Sic!*/ break;
+ case 4: longstore(to, (ulong)num); break;
+ case 8: longlongstore(to, num); break;
+ default: DBUG_ASSERT(0);
+ }
+}
- if (str_to_time(from, len, &ltime,
- table->in_use->variables.sql_mode &
- (MODE_NO_ZERO_DATE | MODE_NO_ZERO_IN_DATE |
- MODE_INVALID_DATES), &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);
+}
+#endif
+
+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;
+ }
+}
+
+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]);
+}
+
+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);
+ return mi_uint4korr(ptr);
+}
+
+double Field_timestamp_hires::val_real(void)
+{
+ MYSQL_TIME time_tmp;
+ THD *thd= table->in_use;
+
+ thd->time_zone_used= 1;
+ ulong sec_part;
+ my_time_t 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= (ulong)read_bigendian(ptr+4, sec_part_bytes[dec]);
+
+ if (tmp->ptr() == zero_timestamp)
+ return tmp;
-int Field_time::store_time(MYSQL_TIME *ltime, timestamp_type time_type)
+ char *buf= const_cast<char*>(tmp->ptr() + MAX_DATETIME_WIDTH);
+ for (int i=dec; i>0; i--, sec_part/=10)
+ buf[i]= (char)(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->in_use;
+ set_notnull();
+ store_TIME(thd->query_start(), thd->query_start_sec_part());
+ return 0;
+}
-int Field_time::store(double nr)
+bool Field_timestamp_hires::send_binary(Protocol *protocol)
+{
+ MYSQL_TIME ltime;
+ Field_timestamp::get_date(&ltime, 0);
+ return protocol->store(&ltime, dec);
+}
+
+
+int Field_timestamp_hires::cmp(const uchar *a_ptr, const uchar *b_ptr)
+{
+ int32 a,b;
+ ulong a_sec_part, b_sec_part;
+ a= mi_uint4korr(a_ptr);
+ a_sec_part= (ulong)read_bigendian(a_ptr+4, sec_part_bytes[dec]);
+ b= mi_uint4korr(b_ptr);
+ 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;
+}
+
+
+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_OR_COMPUTED;
- long tmp;
- int error= 0;
- 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 if (nr < (double)-TIME_MAX_VALUE)
+ else if (!(was_cut & MYSQL_TIME_WARN_TRUNCATED) &&
+ temporal_type() == MYSQL_TIMESTAMP_DATE &&
+ (ltime->hour || ltime->minute || ltime->second || ltime->second_part))
{
- tmp= -TIME_MAX_VALUE;
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_OUT_OF_RANGE, nr, MYSQL_TIMESTAMP_TIME);
- error= 1;
+ trunc_level= MYSQL_ERROR::WARN_LEVEL_NOTE;
+ was_cut|= MYSQL_TIME_WARN_TRUNCATED;
+ ret= 3;
}
- else
+ else if (!(was_cut & MYSQL_TIME_WARN_TRUNCATED) &&
+ temporal_type() == MYSQL_TIMESTAMP_TIME &&
+ (ltime->year || ltime->month))
{
- 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;
- }
+ ltime->year= ltime->month= ltime->day= 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.
+ */
+ 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->in_use;
+ Lazy_string_str str(from, len);
+
+ func_res= str_to_datetime(from, len, &ltime,
+ (TIME_FUZZY_DATE |
+ (thd->variables.sql_mode &
+ (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
+ MODE_INVALID_DATES))),
+ &error);
+ return store_TIME_with_warning(&ltime, &str, error, func_res > MYSQL_TIMESTAMP_ERROR);
+}
+
+
+int Field_temporal::store(double nr)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
- long tmp;
int error= 0;
- if (nr < (longlong) -TIME_MAX_VALUE && !unsigned_val)
- {
- 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;
- }
- else if (nr > (longlong) TIME_MAX_VALUE || (nr < 0 && unsigned_val))
+ MYSQL_TIME ltime;
+ THD *thd= table->in_use;
+ Lazy_string_double str(nr);
+
+ if (nr < 0 || nr > LONGLONG_MAX)
+ nr= LONGLONG_MAX;
+ longlong tmp= number_to_datetime((longlong) floor(nr), &ltime,
+ (TIME_FUZZY_DATE |
+ (thd->variables.sql_mode &
+ (MODE_NO_ZERO_IN_DATE |
+ MODE_NO_ZERO_DATE |
+ MODE_INVALID_DATES))), &error);
+ ltime.second_part= (ulong)((nr-floor(nr))*TIME_SECOND_PART_FACTOR);
+ return store_TIME_with_warning(&ltime, &str, error, tmp != -1);
+}
+
+
+int Field_temporal::store(longlong nr, bool unsigned_val)
+{
+ int error;
+ MYSQL_TIME ltime;
+ longlong tmp;
+ THD *thd= table->in_use;
+ Lazy_string_num str(nr);
+
+ tmp= number_to_datetime(nr, &ltime, (TIME_FUZZY_DATE |
+ (thd->variables.sql_mode &
+ (MODE_NO_ZERO_IN_DATE |
+ MODE_NO_ZERO_DATE |
+ MODE_INVALID_DATES))), &error);
+
+ return store_TIME_with_warning(&ltime, &str, error, tmp != -1);
+}
+
+
+int Field_temporal::store_time(MYSQL_TIME *ltime,timestamp_type time_type)
+{
+ int error = 0, have_smth_to_conv= 1;
+ MYSQL_TIME l_time= *ltime;
+ Lazy_string_time str(ltime);
+ /*
+ We don't perform range checking here since values stored in TIME
+ structure always fit into DATETIME range.
+ */
+ if (time_type == MYSQL_TIMESTAMP_DATE ||
+ time_type == MYSQL_TIMESTAMP_DATETIME)
{
- tmp= TIME_MAX_VALUE;
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_OUT_OF_RANGE, nr,
- MYSQL_TIMESTAMP_TIME, 1);
- error= 1;
+ have_smth_to_conv= !check_date(&l_time, pack_time(&l_time) != 0,
+ (TIME_FUZZY_DATE |
+ (current_thd->variables.sql_mode &
+ (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
+ MODE_INVALID_DATES))), &error);
}
else
{
- tmp=(long) nr;
- if (tmp % 100 > 59 || tmp/100 % 100 > 59)
- {
- tmp=0;
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_OUT_OF_RANGE, nr,
- MYSQL_TIMESTAMP_TIME, 1);
- error= 1;
- }
+ error= 1;
+ have_smth_to_conv= 0;
}
+ return store_TIME_with_warning(&l_time, &str, error, have_smth_to_conv);
+}
+
+/****************************************************************************
+** time type
+** In string context: HH:MM:SS
+** In number context: HHMMSS
+** Stored as a 3 byte unsigned int
+****************************************************************************/
+
+void Field_time::store_TIME(MYSQL_TIME *ltime)
+{
+ long tmp= (ltime->day*24L+ltime->hour)*10000L +
+ (ltime->minute*100+ltime->second);
+ if (ltime->neg)
+ tmp= -tmp;
int3store(ptr,tmp);
- return error;
+}
+
+int Field_time::store(const char *from,uint len,CHARSET_INFO *cs)
+{
+ MYSQL_TIME ltime;
+ Lazy_string_str str(from, len);
+ int was_cut;
+ int have_smth_to_conv=
+ str_to_time(from, len, &ltime,
+ table->in_use->variables.sql_mode &
+ (MODE_NO_ZERO_DATE | MODE_NO_ZERO_IN_DATE |
+ MODE_INVALID_DATES),
+ &was_cut) > MYSQL_TIMESTAMP_ERROR;
+
+ return store_TIME_with_warning(&ltime, &str, was_cut, have_smth_to_conv);
}
+int Field_time::store_time(MYSQL_TIME *ltime, timestamp_type time_type)
+{
+ MYSQL_TIME l_time= *ltime;
+ Lazy_string_time str(ltime);
+ int was_cut= 0;
+
+ 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);
+}
+
+
+int Field_time::store(double nr)
+{
+ MYSQL_TIME ltime;
+ Lazy_string_double str(nr);
+ int was_cut;
+ int have_smth_to_conv= !number_to_time(nr, &ltime, &was_cut);
+
+ return store_TIME_with_warning(&ltime, &str, was_cut, have_smth_to_conv);
+}
+
+
+int Field_time::store(longlong nr, bool unsigned_val)
+{
+ MYSQL_TIME ltime;
+ Lazy_string_num str(nr);
+ int was_cut;
+ int have_smth_to_conv= !number_to_time((double)nr, &ltime, &was_cut);
+
+ return store_TIME_with_warning(&ltime, &str, was_cut, have_smth_to_conv);
+}
+
+
double Field_time::val_real(void)
{
ASSERT_COLUMN_MARKED_FOR_READ;
@@ -5335,7 +5221,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)
@@ -5343,6 +5228,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);
@@ -5362,8 +5248,8 @@ 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))
+ THD *thd= table->in_use;
+ if (!(fuzzydate & (TIME_FUZZY_DATE|TIME_TIME_ONLY)))
{
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARN_DATA_OUT_OF_RANGE,
@@ -5371,12 +5257,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)
@@ -5397,11 +5277,9 @@ bool Field_time::get_time(MYSQL_TIME *ltime)
bool Field_time::send_binary(Protocol *protocol)
{
- MYSQL_TIME tm;
- Field_time::get_time(&tm);
- tm.day= tm.hour/24; // Move hours to days
- tm.hour-= tm.day*24;
- return protocol->store_time(&tm);
+ MYSQL_TIME ltime;
+ Field_time::get_date(&ltime, TIME_TIME_ONLY);
+ return protocol->store_time(&ltime, 0);
}
@@ -5425,6 +5303,94 @@ 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 time_hires_bytes[dec];
+}
+
+double Field_time_hires::val_real(void)
+{
+ ASSERT_COLUMN_MARKED_FOR_READ;
+ MYSQL_TIME ltime;
+ Field_time_hires::get_date(&ltime, TIME_TIME_ONLY);
+ return TIME_to_double(&ltime);
+}
+
+String *Field_time_hires::val_str(String *str,
+ String *unused __attribute__((unused)))
+{
+ ASSERT_COLUMN_MARKED_FOR_READ;
+ MYSQL_TIME ltime;
+ Field_time_hires::get_date(&ltime, TIME_TIME_ONLY);
+ str->alloc(field_length+1);
+ str->length(my_time_to_str(&ltime, (char*) str->ptr(), dec));
+ str->set_charset(&my_charset_bin);
+ return str;
+}
+
+bool Field_time_hires::get_date(MYSQL_TIME *ltime, uint fuzzydate)
+{
+ 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.
+ To get MYSQL_TIMESTAMP_TIME we few some adjustments
+ */
+ ltime->time_type= MYSQL_TIMESTAMP_TIME;
+ ltime->hour+= (ltime->month*32+ltime->day)*24;
+ ltime->month= ltime->day= 0;
+ return fuzzydate & (TIME_FUZZY_DATE|TIME_TIME_ONLY) ? 0 : 1;
+}
+
+
+bool Field_time_hires::send_binary(Protocol *protocol)
+{
+ MYSQL_TIME ltime;
+ Field_time_hires::get_date(&ltime, TIME_TIME_ONLY);
+ return protocol->store_time(&ltime, dec);
+}
+
+
+int Field_time_hires::cmp(const uchar *a_ptr, const uchar *b_ptr)
+{
+ ulonglong a=read_bigendian(a_ptr, Field_time_hires::pack_length());
+ ulonglong b=read_bigendian(b_ptr, Field_time_hires::pack_length());
+ return (a < b) ? -1 : (a > b) ? 1 : 0;
+}
+
+void Field_time_hires::sort_string(uchar *to,uint length __attribute__((unused)))
+{
+ DBUG_ASSERT(length == Field_time_hires::pack_length());
+ memcpy(to, ptr, length);
+ to[0]^= 128;
+}
+
+void Field_time_hires::sql_type(String &res) const
+{
+ CHARSET_INFO *cs=res.charset();
+ res.length(cs->cset->snprintf(cs, (char*) res.ptr(), res.alloced_length(),
+ "time(%u)", dec));
+}
+
+void Field_time_hires::make_field(Send_field *field)
+{
+ Field::make_field(field);
+ field->decimals= dec;
+}
+
/****************************************************************************
** year type
** Save in a byte the year 0, 1901->2155
@@ -5554,102 +5520,12 @@ 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)
-{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
- 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)
- {
- int4store(ptr,tmp);
- }
- else
-#endif
- longstore(ptr,tmp);
- return error;
-}
-
-
-int Field_date::store(double nr)
+void Field_date::store_TIME(MYSQL_TIME *ltime)
{
- 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_OR_COMPUTED;
- MYSQL_TIME not_used;
- int error;
- longlong initial_nr= nr;
- THD *thd= table ? table->in_use : current_thd;
-
- nr= number_to_datetime(nr, &not_used, (TIME_FUZZY_DATE |
- (thd->variables.sql_mode &
- (MODE_NO_ZERO_IN_DATE |
- MODE_NO_ZERO_DATE |
- MODE_INVALID_DATES))), &error);
-
- if (nr == LL(-1))
- {
- nr= 0;
- error= 2;
- }
-
- if (nr >= 19000000000000.0 && nr <= 99991231235959.0)
- nr= (longlong) floor(nr/1000000.0); // Timestamp to date
-
- if (error)
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- error == 2 ? ER_WARN_DATA_OUT_OF_RANGE :
- WARN_DATA_TRUNCATED, initial_nr,
- MYSQL_TIMESTAMP_DATETIME, 1);
-
-#ifdef WORDS_BIGENDIAN
- if (table && table->s->db_low_byte_first)
- {
- int4store(ptr, nr);
- }
- else
-#endif
- longstore(ptr, nr);
- return error;
+ uint tmp= ltime->year*10000L + ltime->month*100+ltime->day;
+ int4store(ptr,tmp);
}
-
bool Field_date::send_binary(Protocol *protocol)
{
longlong tmp= Field_date::val_int();
@@ -5665,12 +5541,7 @@ double Field_date::val_real(void)
{
ASSERT_COLUMN_MARKED_FOR_READ;
int32 j;
-#ifdef WORDS_BIGENDIAN
- if (table && table->s->db_low_byte_first)
- j=sint4korr(ptr);
- else
-#endif
- longget(j,ptr);
+ j=sint4korr(ptr);
return (double) (uint32) j;
}
@@ -5679,12 +5550,7 @@ longlong Field_date::val_int(void)
{
ASSERT_COLUMN_MARKED_FOR_READ;
int32 j;
-#ifdef WORDS_BIGENDIAN
- if (table && table->s->db_low_byte_first)
- j=sint4korr(ptr);
- else
-#endif
- longget(j,ptr);
+ j=sint4korr(ptr);
return (longlong) (uint32) j;
}
@@ -5694,14 +5560,8 @@ String *Field_date::val_str(String *val_buffer,
{
ASSERT_COLUMN_MARKED_FOR_READ;
MYSQL_TIME ltime;
- val_buffer->alloc(field_length);
int32 tmp;
-#ifdef WORDS_BIGENDIAN
- if (table && table->s->db_low_byte_first)
- tmp=sint4korr(ptr);
- else
-#endif
- longget(tmp,ptr);
+ tmp=sint4korr(ptr);
ltime.neg= 0;
ltime.year= (int) ((uint32) tmp/10000L % 10000);
ltime.month= (int) ((uint32) tmp/100 % 100);
@@ -5711,50 +5571,21 @@ 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)
- {
- a=sint4korr(a_ptr);
- b=sint4korr(b_ptr);
- }
- else
-#endif
- {
- 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)))
{
-#ifdef WORDS_BIGENDIAN
- if (!table || !table->s->db_low_byte_first)
- {
- to[0] = ptr[0];
- to[1] = ptr[1];
- to[2] = ptr[2];
- to[3] = ptr[3];
- }
- else
-#endif
- {
- 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
@@ -5769,153 +5600,10 @@ 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_OR_COMPUTED;
- long tmp;
- MYSQL_TIME l_time;
- int error;
- THD *thd= table ? table->in_use : current_thd;
- enum enum_mysql_timestamp_type ret;
- if ((ret= str_to_datetime(from, len, &l_time,
- (TIME_FUZZY_DATE |
- (thd->variables.sql_mode &
- (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
- MODE_INVALID_DATES))),
- &error)) <= MYSQL_TIMESTAMP_ERROR)
- {
- tmp= 0;
- error= 2;
- }
- else
- {
- tmp= l_time.day + l_time.month*32 + l_time.year*16*32;
- if (!error && (ret != MYSQL_TIMESTAMP_DATE) &&
- (l_time.hour || l_time.minute || l_time.second || l_time.second_part))
- error= 3; // Datetime was cut (note)
- }
-
- if (error)
- set_datetime_warning(error == 3 ? MYSQL_ERROR::WARN_LEVEL_NOTE :
- MYSQL_ERROR::WARN_LEVEL_WARN,
- WARN_DATA_TRUNCATED,
- from, len, MYSQL_TIMESTAMP_DATE, 1);
-
- int3store(ptr, tmp);
- return error;
-}
-
-
-int Field_newdate::store(double nr)
-{
- if (nr < 0.0 || nr > 99991231235959.0)
- {
- int3store(ptr,(int32) 0);
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- WARN_DATA_TRUNCATED, nr, MYSQL_TIMESTAMP_DATE);
- return 1;
- }
- return Field_newdate::store((longlong) rint(nr), FALSE);
-}
-
-
-int Field_newdate::store(longlong nr, bool unsigned_val)
+void Field_newdate::store_TIME(MYSQL_TIME *ltime)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
- 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_OR_COMPUTED;
- 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;
}
@@ -5980,14 +5668,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);
-}
-
-
-bool Field_newdate::get_time(MYSQL_TIME *ltime)
-{
- return Field_newdate::get_date(ltime,0);
+ if (!tmp)
+ return fuzzydate & TIME_NO_ZERO_DATE;
+ if (!ltime->month || !ltime->day)
+ return !(fuzzydate & TIME_FUZZY_DATE);
+ return 0;
}
@@ -6021,150 +5706,20 @@ void Field_newdate::sql_type(String &res) const
** Stored as a 8 byte unsigned int. Should sometimes be change to a 6 byte int.
****************************************************************************/
-int Field_datetime::store(const char *from,uint len,CHARSET_INFO *cs)
+void Field_datetime::store_TIME(MYSQL_TIME *ltime)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
- 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_OR_COMPUTED;
- MYSQL_TIME not_used;
- int error;
- longlong initial_nr= nr;
- THD *thd= table ? table->in_use : current_thd;
-
- nr= number_to_datetime(nr, &not_used, (TIME_FUZZY_DATE |
- (thd->variables.sql_mode &
- (MODE_NO_ZERO_IN_DATE |
- MODE_NO_ZERO_DATE |
- MODE_INVALID_DATES))), &error);
-
- if (nr == LL(-1))
- {
- nr= 0;
- error= 2;
- }
-
- if (error)
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- error == 2 ? ER_WARN_DATA_OUT_OF_RANGE :
- WARN_DATA_TRUNCATED, initial_nr,
- MYSQL_TIMESTAMP_DATETIME, 1);
-
-#ifdef WORDS_BIGENDIAN
- if (table && table->s->db_low_byte_first)
- {
- int8store(ptr,nr);
- }
- else
-#endif
- longlongstore(ptr,nr);
- return error;
-}
-
-
-int Field_datetime::store_time(MYSQL_TIME *ltime,timestamp_type time_type)
-{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
- longlong tmp;
- int error= 0;
- /*
- We don't perform range checking here since values stored in TIME
- structure always fit into DATETIME range.
- */
- if (time_type == MYSQL_TIMESTAMP_DATE ||
- time_type == MYSQL_TIMESTAMP_DATETIME)
- {
- tmp=((ltime->year*10000L+ltime->month*100+ltime->day)*LL(1000000)+
- (ltime->hour*10000L+ltime->minute*100+ltime->second));
- if (check_date(ltime, tmp != 0,
- (TIME_FUZZY_DATE |
- (current_thd->variables.sql_mode &
- (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
- MODE_INVALID_DATES))), &error))
- {
- char buff[MAX_DATE_STRING_REP_LENGTH];
- String str(buff, sizeof(buff), &my_charset_latin1);
- tmp= 0;
- make_datetime((DATE_TIME_FORMAT *) 0, ltime, &str);
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED,
- str.ptr(), str.length(), MYSQL_TIMESTAMP_DATETIME,1);
- }
- }
- else
- {
- tmp=0;
- error= 1;
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1);
- }
-#ifdef WORDS_BIGENDIAN
- if (table && table->s->db_low_byte_first)
- {
- int8store(ptr,tmp);
- }
- else
-#endif
- longlongstore(ptr,tmp);
- return error;
+ ulonglong tmp= TIME_to_ulonglong_datetime(ltime);
+ int8store(ptr,tmp);
}
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);
}
-
-
+
+
double Field_datetime::val_real(void)
{
return (double) Field_datetime::val_int();
@@ -6174,12 +5729,7 @@ longlong Field_datetime::val_int(void)
{
ASSERT_COLUMN_MARKED_FOR_READ;
longlong j;
-#ifdef WORDS_BIGENDIAN
- if (table && table->s->db_low_byte_first)
- j=sint8korr(ptr);
- else
-#endif
- longlongget(j,ptr);
+ j=sint8korr(ptr);
return j;
}
@@ -6187,20 +5737,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
@@ -6249,59 +5795,32 @@ 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;
-}
-
-bool Field_datetime::get_time(MYSQL_TIME *ltime)
-{
- return Field_datetime::get_date(ltime,0);
+ if (!tmp)
+ return (fuzzydate & TIME_NO_ZERO_DATE) != 0;
+ if (!ltime->month || !ltime->day)
+ return !(fuzzydate & TIME_FUZZY_DATE);
+ return 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)
- {
- a=sint8korr(a_ptr);
- b=sint8korr(b_ptr);
- }
- else
-#endif
- {
- 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)))
{
-#ifdef WORDS_BIGENDIAN
- if (!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
-#endif
- {
- 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];
}
@@ -6310,6 +5829,101 @@ 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, pack_length());
+}
+
+int Field_datetime_hires::store_decimal(const my_decimal *d)
+{
+ char buff[DECIMAL_MAX_STR_LENGTH+1];
+ String str(buff, sizeof(buff), &my_charset_bin);
+ my_decimal2string(E_DEC_FATAL_ERROR, d,
+ MAX_DATETIME_COMPRESSED_WIDTH + MAX_DATETIME_PRECISION,
+ 6, '0', &str);
+ return store(str.ptr(), str.length(), str.charset());
+}
+
+bool Field_datetime_hires::send_binary(Protocol *protocol)
+{
+ MYSQL_TIME ltime;
+ Field_datetime_hires::get_date(&ltime, TIME_FUZZY_DATE);
+ return protocol->store(&ltime, dec);
+}
+
+
+double Field_datetime_hires::val_real(void)
+{
+ MYSQL_TIME ltime;
+ Field_datetime_hires::get_date(&ltime, TIME_FUZZY_DATE);
+ return TIME_to_double(&ltime);
+}
+
+longlong Field_datetime_hires::val_int(void)
+{
+ MYSQL_TIME ltime;
+ Field_datetime_hires::get_date(&ltime, TIME_FUZZY_DATE);
+ return TIME_to_ulonglong_datetime(&ltime);
+}
+
+
+String *Field_datetime_hires::val_str(String *str,
+ String *unused __attribute__((unused)))
+{
+ MYSQL_TIME ltime;
+ Field_datetime_hires::get_date(&ltime, TIME_FUZZY_DATE);
+ str->alloc(field_length+1);
+ str->length(field_length);
+ my_datetime_to_str(&ltime, (char*) str->ptr(), dec);
+ str->set_charset(&my_charset_bin);
+ return str;
+}
+
+bool Field_datetime_hires::get_date(MYSQL_TIME *ltime, uint fuzzydate)
+{
+ ulonglong packed= read_bigendian(ptr, pack_length());
+ unpack_time(sec_part_unshift(packed, dec), ltime);
+ 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
+{
+ return datetime_hires_bytes[dec];
+}
+
+int Field_datetime_hires::cmp(const uchar *a_ptr, const uchar *b_ptr)
+{
+ ulonglong a=read_bigendian(a_ptr, pack_length());
+ ulonglong b=read_bigendian(b_ptr, 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 == 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
@@ -6765,9 +6379,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;
@@ -6809,10 +6421,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;
@@ -7274,9 +6883,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);
@@ -7296,8 +6903,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) ?
@@ -7334,8 +6940,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++;
@@ -7362,9 +6967,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);
@@ -7395,9 +6999,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)) ?
@@ -7623,103 +7225,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)
{
- 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);
- }
+ 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)
{
- 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;
- }
+ return (uint32)read_lowendian(pos, packlength_arg);
}
@@ -8058,20 +7572,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*));
@@ -8101,14 +7602,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;
@@ -8119,7 +7617,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.
@@ -8152,18 +7650,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<const char*>(from) + master_packlength,
@@ -8220,8 +7714,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;
@@ -8265,8 +7758,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++;
@@ -8274,7 +7766,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);
/* put the address of the blob buffer or NULL */
if (length)
@@ -8289,9 +7781,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)
@@ -8442,39 +7933,7 @@ 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);
- }
- else
-#endif
- longlongstore(ptr,value); break;
- }
+ store_lowendian(value, ptr, packlength);
}
@@ -8560,46 +8019,7 @@ 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
+ return read_lowendian(ptr, packlength);
}
@@ -9352,8 +8772,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;
@@ -9400,8 +8819,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;
@@ -9858,28 +9276,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)
{
@@ -9927,10 +9331,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:
{
@@ -10050,14 +9466,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
+ ? time_hires_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
+ ? 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;
case MYSQL_TYPE_TINY_BLOB: return 1+portable_sizeof_char_ptr;
@@ -10229,9 +9653,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);
@@ -10242,11 +9669,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);
@@ -10427,7 +9862,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;
@@ -10445,7 +9880,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
@@ -10453,80 +9887,18 @@ 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,
- timestamp_type ts_type, int cuted_increment)
+
+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))
- 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);
- }
-}
-
-
-/**
- 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= my_sprintf(str_nr, (str_nr, "%g", nr));
- make_truncated_value_warning(thd, level, str_nr, str_len, ts_type,
- field_name);
- }
+ make_truncated_value_warning(thd, level, str, ts_type, field_name);
}
diff --git a/sql/field.h b/sql/field.h
index 3e3dcc10970..f5dd5d5ea3f 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -1,4 +1,5 @@
/* Copyright (c) 2000, 2010 Oracle and/or its affiliates.
+ Copyright (c) 2009-2011 Monty Program Ab
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -25,7 +26,6 @@
#endif
#define NOT_FIXED_DEC 31
-#define DATETIME_DEC 6
const uint32 max_field_size= (uint32) 4294967295U;
class Send_field;
@@ -232,7 +232,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 result_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);
@@ -387,14 +386,7 @@ 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 bool special_const_compare() const { return FALSE; }
virtual void free() {}
virtual Field *new_field(MEM_ROOT *root, struct st_table *new_table,
bool keep_type);
@@ -478,44 +470,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;}
@@ -535,7 +522,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; }
@@ -543,16 +530,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);
@@ -648,70 +631,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;
-#ifdef WORDS_BIGENDIAN
- if (low_byte_first_from)
- val = sint4korr(from);
- else
-#endif
- longget(val, from);
-
-#ifdef WORDS_BIGENDIAN
- if (low_byte_first_to)
- int4store(to, val);
- else
-#endif
- 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;
-#ifdef WORDS_BIGENDIAN
- if (low_byte_first_from)
- val = sint8korr(from);
- else
-#endif
- longlongget(val, from);
-
-#ifdef WORDS_BIGENDIAN
- if (low_byte_first_to)
- int8store(to, val);
- else
-#endif
- 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);
}
@@ -779,7 +736,6 @@ public:
bool eq_cmp_as_binary() { return test(flags & BINARY_FLAG); }
};
-
/* base class for Field_string, Field_varstring and Field_blob */
class Field_longstr :public Field_str
@@ -816,10 +772,6 @@ public:
my_decimal *val_decimal(my_decimal *);
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);
};
@@ -848,15 +800,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);
}
};
@@ -909,8 +859,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 *);
};
@@ -943,15 +892,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;
@@ -992,43 +939,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;
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- val = sint2korr(from);
- else
-#endif
- shortget(val, from);
-
-#ifdef WORDS_BIGENDIAN
- if (low_byte_first)
- int2store(to, val);
- else
-#endif
- 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;
-#ifdef WORDS_BIGENDIAN
- if (low_byte_first)
- val = sint2korr(from);
- else
-#endif
- shortget(val, from);
-
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- int2store(to, val);
- else
-#endif
- shortstore(to, val);
+ val = sint2korr(from);
+ int2store(to, val);
return from + sizeof(val);
}
};
@@ -1061,16 +984,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);
}
};
@@ -1108,21 +1029,18 @@ 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);
}
};
-#ifdef HAVE_LONG_LONG
class Field_longlong :public Field_num {
public:
Field_longlong(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
@@ -1159,22 +1077,18 @@ 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)),
- 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);
}
};
-#endif
class Field_float :public Field_real {
@@ -1281,10 +1195,13 @@ 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) {}
};
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,
@@ -1294,11 +1211,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 *);
@@ -1307,9 +1224,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 &&
@@ -1319,42 +1236,63 @@ public:
Field::set_default();
}
/* Get TIMESTAMP field value as seconds since begging of Unix Epoch */
- inline long get_timestamp(bool *null_value)
+ virtual my_time_t 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)
- {
- int4store(ptr,timestamp);
- }
- else
-#endif
- longstore(ptr,(uint32) timestamp);
+ int4store(ptr,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)
+ 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);
+ }
+};
+
+
+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 <= TIME_SECOND_PART_DIGITS);
+ }
+ void sql_type(String &str) 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);
+ 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)
+ { 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); }
+ bool eq_def(Field *field)
{
- return unpack_int32(to, from, low_byte_first);
+ return (Field_str::eq_def(field) &&
+ dec == ((Field_timestamp_hires*) field)->dec);
}
};
@@ -1375,76 +1313,85 @@ public:
longlong val_int(void);
String *val_str(String*,String *);
bool send_binary(Protocol *protocol);
+ uint32 max_display_length() { return field_length; }
+ /* 99 should compare with 1999 */
+ bool special_const_compare() const { return TRUE; }
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);
+ bool special_const_compare() const { return TRUE; }
+};
+
+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)
+ 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);
}
};
-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 *);
@@ -1453,75 +1400,89 @@ 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 <= TIME_SECOND_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 *);
+ uint size_of() const { return sizeof(*this); }
+ bool eq_def(Field *field)
+ {
+ return (Field_str::eq_def(field) &&
+ dec == ((Field_time_hires*) field)->dec);
+ }
+};
-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;
- }
+ uint decimals() const { return 0; }
double val_real(void);
longlong val_int(void);
String *val_str(String*,String *);
@@ -1530,23 +1491,102 @@ 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)
+ 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);
+ }
+};
+
+
+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 <= TIME_SECOND_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)
+ { 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); }
+ bool eq_def(Field *field)
{
- return unpack_int64(to, from, low_byte_first);
+ return (Field_str::eq_def(field) &&
+ dec == ((Field_datetime_hires*) field)->dec);
}
};
+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)
+ return new Field_timestamp(ptr, MAX_DATETIME_WIDTH, null_ptr, null_bit,
+ unireg_check, field_name, share, 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 *
+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)
+ return new Field_time(ptr, MIN_TIME_WIDTH, null_ptr, null_bit,
+ unireg_check, field_name, 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 *
+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)
+ return new Field_datetime(ptr, MAX_DATETIME_WIDTH, null_ptr, null_bit,
+ unireg_check, field_name, 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 {
public:
@@ -1592,9 +1632,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));
@@ -1679,15 +1718,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,
bool insert_or_update);
int pack_cmp(const uchar *b, uint key_length,bool insert_or_update);
@@ -1795,14 +1830,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(); }
-#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)
- {
- 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);
@@ -1816,38 +1844,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); }
- void put_length(uchar *pos, uint32 length);
+ { 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;
@@ -1864,21 +1891,17 @@ 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,
bool insert_or_update);
int pack_cmp(const uchar *b, uint key_length,bool insert_or_update);
uint packed_col_length(const uchar *col_ptr, uint length);
uint max_packed_col_length(uint max_length);
+ /* Set if we should convert constant item's with convert_const_item */
void free() { value.free(); }
inline void clear_temporary() { bzero((uchar*) &value,sizeof(value)); }
friend int field_conv(Field *to,Field *from);
@@ -1945,7 +1968,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);
@@ -2075,10 +2097,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 3e52e67f2d9..2a597194a5c 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(&ltime, TIME_FUZZY_DATE);
+ copy->to_field->store_time(&ltime, ltime.time_type);
+}
+
+
/**
string copy for single byte characters set when to string is shorter than
from string.
@@ -561,7 +569,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:
@@ -638,13 +646,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;
@@ -659,6 +665,19 @@ 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) // TODO; Optimize this
+ {
+ /* If types are not 100 % identical then convert trough get_date() */
+ if (!to->eq_def(from) ||
+ (((to->table->in_use->variables.sql_mode &
+ (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
+ MODE_INVALID_DATES))) &&
+ (to->type() == MYSQL_TYPE_DATE ||
+ to->type() == MYSQL_TYPE_DATETIME)))
+ return do_field_temporal;
+ /* Do binary copy */
+ }
+
// Check if identical fields
if (from->result_type() == STRING_RESULT)
{
@@ -675,12 +694,7 @@ Copy_field::get_copy_func(Field *to,Field *from)
If we are copying date or datetime's we have to check the dates
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 ||
- to->type() == MYSQL_TYPE_DATETIME)))
+ if (to->real_type() != from->real_type())
{
if (from->real_type() == MYSQL_TYPE_ENUM ||
from->real_type() == MYSQL_TYPE_SET)
@@ -727,8 +741,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)
@@ -739,7 +752,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;
@@ -772,14 +785,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/filesort.cc b/sql/filesort.cc
index 3f69083fc8d..10991d1dcfb 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -873,25 +873,28 @@ 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;
+ 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)
{
- *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);
@@ -903,15 +906,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:
@@ -921,8 +915,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;
@@ -1566,9 +1559,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;
@@ -1586,12 +1577,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=
@@ -1666,6 +1654,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/ha_partition.cc b/sql/ha_partition.cc
index 6cd735ddd4b..6a72623ce5d 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -268,7 +268,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;
@@ -417,18 +416,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 49aa7103e1c..2d82ec721b5 100644
--- a/sql/ha_partition.h
+++ b/sql/ha_partition.h
@@ -110,7 +110,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,
@@ -907,12 +906,6 @@ public:
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 919e063e1cf..4707aabbd52 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -2234,7 +2234,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/item.cc b/sql/item.cc
index 6ee656b9147..b73008fad9f 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -197,10 +197,12 @@ bool Item::val_bool()
case STRING_RESULT:
return val_real() != 0.0;
case ROW_RESULT:
- default:
+ case TIME_RESULT:
+ case IMPOSSIBLE_RESULT:
DBUG_ASSERT(0);
return 0; // Wrong (but safe)
}
+ return 0; // Wrong (but safe)
}
@@ -471,6 +473,33 @@ 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()) {
+ case STRING_RESULT:
+ 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:
+ case IMPOSSIBLE_RESULT:
+ DBUG_ASSERT(0);
+ }
+ }
+}
+
+
void Item::cleanup()
{
DBUG_ENTER("Item::cleanup");
@@ -515,6 +544,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:
+ 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_ENUM:
+ case MYSQL_TYPE_SET:
+ 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).
@@ -989,7 +1057,17 @@ bool Item_string::eq(const Item *item, bool binary_cmp) const
bool Item::get_date(MYSQL_TIME *ltime,uint fuzzydate)
{
- switch (result_type()) {
+ Item_result res_type;
+
+ if (field_type() == MYSQL_TYPE_TIME)
+ fuzzydate|= TIME_TIME_ONLY;
+
+ /* This function only supports time with strings */
+ res_type= result_type();
+ if (fuzzydate & TIME_TIME_ONLY)
+ res_type= STRING_RESULT;
+
+ switch (res_type) {
case INT_RESULT:
{
int was_cut;
@@ -998,11 +1076,9 @@ bool Item::get_date(MYSQL_TIME *ltime,uint fuzzydate)
goto err;
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);
null_value= 1;
goto err;
}
@@ -1058,28 +1134,36 @@ err:
}
/**
- Get time of first argument.\
-
- As a extra convenience the time structure is reset on error!
+ Get time of first argument.
*/
bool Item::get_time(MYSQL_TIME *ltime)
{
char buff[40];
String tmp(buff,sizeof(buff),&my_charset_bin),*res;
+
+ if (cmp_type() == TIME_RESULT)
+ {
+ /*
+ This is true for functions like Item_date_typecast() which
+ doesn't have a explicit get_time() function.
+ */
+ return (get_date(ltime, TIME_TIME_ONLY | TIME_FUZZY_DATE |
+ sql_mode_for_dates()));
+ }
+
if (!(res=val_str(&tmp)) ||
str_to_time_with_warn(res->ptr(), res->length(), ltime,
- TIME_FUZZY_DATE |
- (current_thd->variables.sql_mode &
- (MODE_NO_ZERO_DATE | MODE_NO_ZERO_IN_DATE |
- MODE_INVALID_DATES))))
+ TIME_FUZZY_DATE | sql_mode_for_dates()))
{
- bzero((char*) ltime,sizeof(*ltime));
+ bzero((char*) ltime,sizeof(*ltime)); // Safety
+ null_value= 1;
return 1;
}
return 0;
}
+
CHARSET_INFO *Item::default_charset()
{
return current_thd->variables.collation_connection;
@@ -1103,6 +1187,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;
@@ -2212,16 +2297,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;
-}
-
void Item_field::save_result(Field *to)
{
save_field_in_field(result_field, &null_value, to, TRUE);
@@ -2270,10 +2345,12 @@ bool Item_field::val_bool_result()
case STRING_RESULT:
return result_field->val_real() != 0.0;
case ROW_RESULT:
- default:
+ case TIME_RESULT:
+ case IMPOSSIBLE_RESULT:
DBUG_ASSERT(0);
return 0; // Shut up compiler
}
+ return 0;
}
@@ -2854,19 +2931,19 @@ void Item_param::set_time(MYSQL_TIME *tm, timestamp_type time_type,
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 > TIME_MAX_SECOND_PART)
{
- char buff[MAX_DATE_STRING_REP_LENGTH];
- uint length= my_TIME_to_str(&value.time, buff);
+ 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);
}
state= TIME_VALUE;
maybe_null= 0;
max_length= max_length_arg;
- decimals= 0;
+ decimals= tm->second_part > 0 ? TIME_SECOND_PART_DIGITS : 0;
DBUG_VOID_RETURN;
}
@@ -2953,10 +3030,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:
{
@@ -2979,6 +3058,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);
@@ -2994,9 +3074,12 @@ 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:
+ case ROW_RESULT:
+ case TIME_RESULT:
+ case IMPOSSIBLE_RESULT:
DBUG_ASSERT(0);
set_null();
}
@@ -3074,21 +3157,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)
@@ -3218,7 +3286,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;
}
@@ -3270,7 +3339,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;
@@ -3464,6 +3533,7 @@ Item_param::set_param_type_and_swap_value(Item_param *src)
/****************************************************************************
Item_copy
****************************************************************************/
+
Item_copy *Item_copy::create (Item *item)
{
switch (item->result_type())
@@ -3477,7 +3547,9 @@ 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:
+ case IMPOSSIBLE_RESULT:
DBUG_ASSERT (0);
}
/* should not happen */
@@ -3550,8 +3622,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)
{
@@ -4844,12 +4915,8 @@ 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 && field->type() != FIELD_TYPE_TIMESTAMP &&
+ cmp_context != INT_RESULT)
convert_zerofill_number_to_string(&item, (Field_num *)field);
else
item= this;
@@ -4972,25 +5039,12 @@ 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:
+ case IMPOSSIBLE_RESULT:
DBUG_ASSERT(0);
return MYSQL_TYPE_VARCHAR;
}
-}
-
-
-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;
+ return MYSQL_TYPE_VARCHAR;
}
@@ -5170,16 +5224,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,
@@ -5416,12 +5473,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)
{
@@ -5438,6 +5489,22 @@ int Item_int::save_in_field(Field *field, bool no_conversions)
}
+void Item_datetime::set(longlong packed)
+{
+ unpack_time(packed, &ltime);
+}
+
+int Item_datetime::save_in_field(Field *field, bool no_conversions)
+{
+ field->set_notnull();
+ return field->store_time(&ltime, ltime.time_type);
+}
+
+longlong Item_datetime::val_int()
+{
+ return TIME_to_ulonglong(&ltime);
+}
+
int Item_decimal::save_in_field(Field *field, bool no_conversions)
{
field->set_notnull();
@@ -5455,7 +5522,9 @@ bool Item_int::eq(const Item *arg, bool binary_cmp) const
a basic constant.
*/
Item *item= (Item*) arg;
- return item->val_int() == value && item->unsigned_flag == unsigned_flag;
+ return (item->val_int() == value &&
+ ((longlong) value >= 0 ||
+ (item->unsigned_flag == unsigned_flag)));
}
return FALSE;
}
@@ -5869,7 +5938,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;
}
@@ -5878,7 +5947,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;
}
}
@@ -5959,17 +6028,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);
@@ -6583,7 +6642,8 @@ bool Item_ref::val_bool_result()
case STRING_RESULT:
return result_field->val_real() != 0.0;
case ROW_RESULT:
- default:
+ case TIME_RESULT:
+ case IMPOSSIBLE_RESULT:
DBUG_ASSERT(0);
}
}
@@ -7841,6 +7901,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;
@@ -7854,11 +7916,20 @@ 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:
+ {
+ 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);
+ break;
+ }
case STRING_RESULT:
{
char buff[MAX_FIELD_WIDTH];
@@ -7933,8 +8004,9 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item)
(Item*) new Item_decimal(name, result, length, decimals));
break;
}
- default:
+ case IMPOSSIBLE_RESULT:
DBUG_ASSERT(0);
+ break;
}
if (new_item)
thd->change_item_tree(ref, new_item);
@@ -7954,6 +8026,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)
@@ -8009,6 +8084,25 @@ 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);
+ }
double result= item->val_real();
if (item->null_value)
return 0;
@@ -8048,11 +8142,14 @@ 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();
- default:
- // should never be in real life
+ case TIME_RESULT:
+ /* this item will store a packed datetime value as an integer */
+ return new Item_cache_int(MYSQL_TYPE_DATETIME);
+ case IMPOSSIBLE_RESULT:
DBUG_ASSERT(0);
- return 0;
+ break;
}
+ return 0; // Impossible
}
void Item_cache::store(Item *item)
@@ -8065,6 +8162,11 @@ void Item_cache::store(Item *item)
void Item_cache::print(String *str, enum_query_type query_type)
{
+ if (value_cached)
+ {
+ print_value(str);
+ return;
+ }
str->append(STRING_WITH_LEN("<cache>("));
if (example)
example->print(str, query_type);
@@ -8142,6 +8244,57 @@ 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()) || null_value)
+ return set_field_to_null_with_conversions(field, no_conversions);
+
+ field->set_notnull();
+ if (cmp_type() == TIME_RESULT)
+ {
+ MYSQL_TIME ltime;
+ unpack_time(value, &ltime);
+ ltime.time_type= mysql_type_to_time_type(field_type());
+ error= field->store_time(&ltime, 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)
@@ -8347,11 +8500,8 @@ my_decimal *Item_cache_str::val_decimal(my_decimal *decimal_val)
int Item_cache_str::save_in_field(Field *field, bool no_conversions)
{
if ((!value_cached && !cache_value()) || null_value)
- {
- field->set_notnull();
- null_value= TRUE;
- return 0;
- }
+ return set_field_to_null_with_conversions(field, no_conversions);
+
int res= Item_cache::save_in_field(field, no_conversions);
return (is_varbinary && field->type() == MYSQL_TYPE_STRING &&
value->length() < field->field_length) ? 1 : res;
@@ -8510,7 +8660,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;
@@ -8552,7 +8702,8 @@ 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:
+ case IMPOSSIBLE_RESULT:
DBUG_ASSERT(0);
return MYSQL_TYPE_VAR_STRING;
}
diff --git a/sql/item.h b/sql/item.h
index 9bb00c5db84..2c26f8c4ef8 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2011, Oracle and/or its affiliates.
-
+ Copyright (c) 2009-2011 Monty Program Ab
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
@@ -642,8 +642,11 @@ 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; }
- virtual Item_result cast_to_int_type() const { return result_type(); }
+ /* ... 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;
virtual enum_field_types field_type() const;
virtual enum Type type() const =0;
@@ -821,6 +824,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
@@ -900,6 +905,7 @@ public:
}
void print_item_w_name(String *, enum_query_type query_type);
+ void print_value(String *);
virtual void update_used_tables() {}
virtual void split_sum_func(THD *thd, Item **ref_pointer_array,
List<Item> &fields) {}
@@ -907,7 +913,7 @@ public:
void split_sum_func2(THD *thd, Item **ref_pointer_array, List<Item> &fields,
Item **ref, bool skip_registered);
virtual bool get_date(MYSQL_TIME *ltime,uint fuzzydate);
- virtual bool get_time(MYSQL_TIME *ltime);
+ bool get_time(MYSQL_TIME *ltime);
virtual bool get_date_result(MYSQL_TIME *ltime,uint fuzzydate)
{ return get_date(ltime,fuzzydate); }
/*
@@ -1208,15 +1214,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();
/*
Test whether an expression is expensive to compute. Used during
@@ -1752,7 +1749,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
{
@@ -1767,7 +1764,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);
@@ -1781,10 +1777,6 @@ public:
bool check_vcol_func_processor(uchar *arg) { return FALSE;}
bool enumerate_field_refs_processor(uchar *arg);
void cleanup();
- bool result_as_longlong()
- {
- return field->can_be_compared_as_longlong();
- }
Item_equal *get_item_equal() { return item_equal; }
void set_item_equal(Item_equal *item_eq) { item_equal= item_eq; }
Item_equal *find_item_equal(COND_EQUAL *cond_equal);
@@ -1936,6 +1928,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; }
@@ -1943,7 +1936,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);
@@ -2044,19 +2036,31 @@ 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; }
};
+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 (double)val_int(); }
+ void set(longlong packed);
+};
+
+
/* decimal (fixed point) constant */
class Item_decimal :public Item_num
{
@@ -2349,10 +2353,11 @@ 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)
- { }
+ { decimals= 0; }
enum_field_types field_type() const { return date_time_field_type; }
};
@@ -2592,10 +2597,6 @@ public:
(*ref)->restore_to_before_no_rows_in_result();
}
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(); }
@@ -2632,11 +2633,6 @@ public:
{
return trace_unsupported_by_check_vcol_func_processor("ref");
}
- bool get_time(MYSQL_TIME *ltime)
- {
- DBUG_ASSERT(fixed);
- return (*ref)->get_time(ltime);
- }
};
@@ -2805,7 +2801,6 @@ public:
}
bool enumerate_field_refs_processor(uchar *arg)
{ return orig_item->enumerate_field_refs_processor(arg); }
- bool result_as_longlong() { return orig_item->result_as_longlong(); }
Item_field *filed_for_view_update()
{ return orig_item->filed_for_view_update(); }
@@ -3562,7 +3557,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) {}
@@ -3574,8 +3569,20 @@ 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();
+ 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);
+ item->store_longlong(this, value);
+ return item;
+ }
};
@@ -3583,7 +3590,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();
@@ -3600,7 +3607,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 9b12e5c844c..9b1d473bb4d 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
@@ -412,7 +409,8 @@ static bool convert_constant_item(THD *thd, Item_field *field_item,
LINT_INIT(old_maps[0]);
LINT_INIT(old_maps[1]);
- if (table)
+ /* table->read_set may not be set if we come here from a CREATE TABLE */
+ if (table && table->read_set)
dbug_tmp_use_all_columns(table, old_maps,
table->read_set, table->write_set);
/* For comparison purposes allow invalid dates like 2000-01-32 */
@@ -448,7 +446,7 @@ static bool convert_constant_item(THD *thd, Item_field *field_item,
}
thd->variables.sql_mode= orig_sql_mode;
thd->count_cuted_fields= orig_count_cuted_fields;
- if (table)
+ if (table && table->read_set)
dbug_tmp_restore_column_maps(table->read_set, table->write_set, old_maps);
}
return result;
@@ -479,7 +477,6 @@ void Item_bool_func2::fix_length_and_dec()
to the collation of A.
*/
-
DTCollation coll;
if (args[0]->result_type() == STRING_RESULT &&
args[1]->result_type() == STRING_RESULT &&
@@ -488,48 +485,29 @@ 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->lex->is_ps_or_view_context_analysis())
+ if (functype() != LIKE_FUNC && !thd->lex->is_ps_or_view_context_analysis())
{
- 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 &&
+ (field_item->field->special_const_compare() ||
+ args[!field]->result_type() == STRING_RESULT) &&
+ convert_constant_item(thd, field_item, &args[!field]))
+ args[0]->cmp_context= args[1]->cmp_context= INT_RESULT;
}
}
set_cmp_func();
@@ -543,6 +521,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();
@@ -636,8 +616,9 @@ int Arg_comparator::set_compare_func(Item_result_field *item, Item_result type)
}
break;
}
- default:
+ case IMPOSSIBLE_RESULT:
DBUG_ASSERT(0);
+ break;
}
return 0;
}
@@ -651,12 +632,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.
@@ -669,16 +652,15 @@ 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;
+
+ 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,238 +708,35 @@ 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->lex->is_ps_or_view_context_analysis() &&
- 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;
+ return pack_time(&l_time);
}
-/*
- 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
+/**
+ Prepare the comparator (set the comparison function) for comparing
+ items *a1 and *a2 in the context of 'type'.
- 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.
+ @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
- RETURN
- obtained value
+ Both *a1 and *a2 can be replaced by this method - typically by constant
+ items, holding the cached converted value of the original (constant) item.
*/
-longlong
-get_time_value(THD *thd, Item ***item_arg, Item **cache_arg,
- Item *warn_item, bool *is_null)
-{
- longlong value;
- Item *item= **item_arg;
- MYSQL_TIME ltime;
-
- if (item->result_as_longlong())
- {
- value= item->val_int();
- *is_null= item->null_value;
- }
- else
- {
- *is_null= item->get_time(&ltime);
- value= !*is_null ? (longlong) TIME_to_ulonglong_datetime(&ltime) : 0;
- }
- /*
- Do not cache GET_USER_VAR() function as its const_item() may return TRUE
- for the current thread but it still may change during the execution.
- */
- if (item->const_item() && cache_arg && (item->type() != Item::FUNC_ITEM ||
- ((Item_func*)item)->functype() != Item_func::GUSERVAR_FUNC))
- {
- Query_arena backup;
- Query_arena *save_arena= thd->switch_to_arena_for_cached_items(&backup);
- Item_cache_int *cache= new Item_cache_int();
- if (save_arena)
- thd->set_query_arena(save_arena);
-
- /* Mark the cache as non-const to prevent re-caching. */
- cache->set_used_tables(1);
- cache->store_longlong(item, value);
- *cache_arg= cache;
- *item_arg= cache_arg;
- }
- return value;
-}
-
-
int Arg_comparator::set_cmp_func(Item_result_field *owner_arg,
Item **a1, Item **a2,
Item_result 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 (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.
- */
- Query_arena backup;
- Query_arena *save_arena= thd->switch_to_arena_for_cached_items(&backup);
- Item_cache_int *cache= new Item_cache_int(MYSQL_TYPE_DATETIME);
- if (save_arena)
- thd->set_query_arena(save_arena);
-
- /* Mark the cache as non-const to prevent re-caching. */
- cache->set_used_tables(1);
- if (!(*a)->is_datetime())
- {
- cache->store_longlong((*a), const_value);
- a_cache= cache;
- a= (Item **)&a_cache;
- }
- else
- {
- cache->store_longlong((*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);
@@ -965,8 +744,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);
@@ -974,45 +755,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.
@@ -1034,9 +776,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->lex->is_ps_or_view_context_analysis() &&
- (*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);
@@ -1054,111 +801,168 @@ 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()];
}
-
-/*
+/**
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.
- 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).
- RETURN
- obtained value
+ 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)
+
+ 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.
*/
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;
+ enum_field_types f_type= warn_item->field_type();
- if (item->result_as_longlong())
- {
+ 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;
+ 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;
+ 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)
+ {
+ /*
+ 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->max_length == 2)
+ {
+ if (value < 70)
+ value+= 100;
+ if (value <= 1900)
+ value+= 1900;
+ }
+ value*= 13ULL * 32ULL * 24ULL * 60ULL * 60ULL * 1000000ULL;
+ }
+ else
+ {
+ MYSQL_TIME buf;
+ int was_cut;
+ longlong res;
+
+ 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,
+ &was_cut);
+ if (res == -1)
+ {
+ const Lazy_string_num str(value);
+ 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
+ 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 cannot 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,
+ 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,
+ 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;
+ }
+ case ROW_RESULT:
+ case IMPOSSIBLE_RESULT:
+ 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)
+ if (cache_arg && item->const_item())
{
- 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.
+ 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.
*/
- }
- /*
- 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))
- {
Query_arena backup;
Query_arena *save_arena= thd->switch_to_arena_for_cached_items(&backup);
- Item_cache_int *cache= new Item_cache_int(MYSQL_TYPE_DATETIME);
+ Item_cache_int *cache= new Item_cache_int(f_type);
if (save_arena)
thd->set_query_arena(save_arena);
-
- /* Mark the cache as non-const to prevent re-caching. */
- cache->set_used_tables(1);
+
cache->store_longlong(item, value);
*cache_arg= cache;
*item_arg= cache_arg;
@@ -1168,67 +972,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();
- Field *field= NULL;
- if (real_item->type() == Item::FIELD_ITEM)
- field= ((Item_field *)real_item)->field;
- else if (real_item->type() == Item::CACHE_ITEM)
- field= ((Item_cache *)real_item)->field();
- if (!(field && field->type() == MYSQL_TYPE_YEAR && field->field_length == 4))
- {
- if (value < 70)
- value+= 100;
- if (value <= 1900)
- value+= 1900;
- }
- /* Convert year to DATETIME of form YYYY-00-00 00:00:00 (YYYY0000000000). */
- value*= 10000000000LL;
-
- return value;
-}
-
-
-/*
Compare items values as dates.
SYNOPSIS
@@ -1240,18 +983,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()
@@ -1259,34 +993,40 @@ 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;
+
+ /* 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()
{
@@ -2411,12 +2151,9 @@ bool Item_func_between::fix_fields(THD *thd, Item **ref)
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;
THD *thd= current_thd;
+ max_length= 1;
+ compare_as_dates= 0;
/*
As some compare functions are generated after sql_yacc,
@@ -2431,51 +2168,44 @@ 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() 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
+ strings as.
*/
- if (cmp_type == STRING_RESULT)
+ if (cmp_type == TIME_RESULT)
{
- for (i= 0; i < 3; i++)
+ for (int 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->lex->is_ps_or_view_context_analysis())
{
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 special= field_item->field->special_const_compare();
/*
The following can't be recoded with || as convert_constant_item
changes the argument
*/
- if (convert_constant_item(thd, field_item, &args[1]))
+ if ((special || args[1]->result_type() == STRING_RESULT) &&
+ convert_constant_item(thd, field_item, &args[1]))
cmp_type=INT_RESULT; // Works for all types.
- if (convert_constant_item(thd, field_item, &args[2]))
+ if ((special || args[2]->result_type() == STRING_RESULT) &&
+ convert_constant_item(thd, field_item, &args[2]))
cmp_type=INT_RESULT; // Works for all types.
}
}
@@ -2483,29 +2213,48 @@ 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);
@@ -2529,8 +2278,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))
@@ -2549,8 +2299,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;
@@ -2567,8 +2318,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))
@@ -2587,6 +2339,13 @@ longlong Item_func_between::val_int()
{
null_value= value >= a;
}
+ break;
+ }
+ case ROW_RESULT:
+ case IMPOSSIBLE_RESULT:
+ DBUG_ASSERT(0);
+ null_value= 1;
+ return 0;
}
return (longlong) (!null_value && negated);
}
@@ -2637,7 +2396,8 @@ Item_func_ifnull::fix_length_and_dec()
decimals= 0;
break;
case ROW_RESULT:
- default:
+ case TIME_RESULT:
+ case IMPOSSIBLE_RESULT:
DBUG_ASSERT(0);
}
cached_field_type= agg_field_type(args, 2);
@@ -3349,6 +3109,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 1;
+}
+
+
my_decimal *Item_func_coalesce::decimal_op(my_decimal *decimal_value)
{
DBUG_ASSERT(fixed == 1);
@@ -3368,6 +3143,14 @@ 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);
+ ///< @todo let result_type() return TIME_RESULT and remove this special case
+ if (cmp_type == TIME_RESULT)
+ {
+ count_real_length();
+ return;
+ }
switch (hybrid_type) {
case STRING_RESULT:
count_only_length();
@@ -3385,7 +3168,8 @@ void Item_func_coalesce::fix_length_and_dec()
decimals= 0;
break;
case ROW_RESULT:
- default:
+ case TIME_RESULT:
+ case IMPOSSIBLE_RESULT:
DBUG_ASSERT(0);
}
}
@@ -3714,7 +3498,8 @@ 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:
+ case IMPOSSIBLE_RESULT:
DBUG_ASSERT(0);
break;
}
@@ -4065,7 +3850,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;
/*
@@ -4121,19 +3906,22 @@ 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 &&
+ !thd->lex->is_ps_or_view_context_analysis() &&
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 special= field_item->field->special_const_compare();
bool all_converted= TRUE;
for (arg=args+1, arg_end=args+arg_count; arg != arg_end ; arg++)
{
- if (!convert_constant_item (thd, field_item, &arg[0]))
+ if (!(special || arg[0]->result_type() == STRING_RESULT) ||
+ !convert_constant_item(thd, field_item, &arg[0]))
all_converted= FALSE;
}
if (all_converted)
@@ -4162,9 +3950,10 @@ void Item_func_in::fix_length_and_dec()
case DECIMAL_RESULT:
array= new in_decimal(arg_count - 1);
break;
- default:
+ case TIME_RESULT:
+ case IMPOSSIBLE_RESULT:
DBUG_ASSERT(0);
- return;
+ break;
}
}
if (array && !(thd->is_fatal_error)) // If not EOM
@@ -5556,9 +5345,9 @@ Item_equal::Item_equal(Item *f1, Item *f2, bool with_const_item)
{
const_item_cache= 0;
with_const= with_const_item;
- compare_as_dates= with_const_item && f2->is_datetime();
equal_items.push_back(f1);
equal_items.push_back(f2);
+ compare_as_dates= with_const_item && f2->cmp_type() == TIME_RESULT;
}
@@ -5615,7 +5404,7 @@ void Item_equal::add_const(Item *c, Item *f)
{
with_const= TRUE;
if (f)
- compare_as_dates= f->is_datetime();
+ compare_as_dates= f->cmp_type() == TIME_RESULT;
equal_items.push_front(c);
return;
}
@@ -5636,7 +5425,6 @@ void Item_equal::add_const(Item *c, Item *f)
const_item_cache= 1;
}
-
/**
@brief
Check whether a field is referred to in the multiple equality
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index e4e6cd391a8..c6d2e929530 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -34,32 +34,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)
@@ -76,8 +66,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)(); }
@@ -100,14 +90,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 &&
@@ -636,9 +624,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();
@@ -711,6 +697,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);
};
@@ -916,6 +903,16 @@ public:
lval_cache(0) {};
void set(uint pos,Item *item);
uchar *get_value(Item *item);
+ Item* create_item()
+ {
+ return new Item_datetime();
+ }
+ void value_to_item(uint pos, Item *item)
+ {
+ packed_longlong *val= reinterpret_cast<packed_longlong*>(base)+pos;
+ Item_datetime *dt= reinterpret_cast<Item_datetime*>(item);
+ dt->set(val->val);
+ }
friend int cmp_longlong(void *cmp_arg, packed_longlong *a,packed_longlong *b);
};
diff --git a/sql/item_create.cc b/sql/item_create.cc
index 9c66c94382d..519599bbde0 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -31,7 +31,28 @@
=============================================================================
*/
-/*
+static 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();
+}
+
+
+static void wrong_precision_error(uint errcode, Item *a,
+ ulonglong number, ulong maximum)
+{
+ char buff[1024];
+ String buf(buff, sizeof(buff), system_charset_info);
+
+ my_error(errcode, MYF(0), (uint) min(number, UINT_MAX32),
+ item_name(a, &buf), maximum);
+}
+
+
+/**
Get precision and scale for a declaration
return
@@ -42,18 +63,16 @@
bool get_length_and_scale(ulonglong length, ulonglong decimals,
ulong *out_length, uint *out_decimals,
uint max_precision, uint max_scale,
- const char *name)
+ Item *a)
{
if (length > (ulonglong) max_precision)
{
- my_error(ER_TOO_BIG_PRECISION, MYF(0), (int) length, name,
- max_precision);
+ wrong_precision_error(ER_TOO_BIG_PRECISION, a, length, max_precision);
return 1;
}
if (decimals > (ulonglong) max_scale)
{
- my_error(ER_TOO_BIG_SCALE, MYF(0), (int) decimals, name,
- DECIMAL_MAX_SCALE);
+ wrong_precision_error(ER_TOO_BIG_SCALE, a, decimals, max_scale);
return 1;
}
@@ -5124,10 +5143,22 @@ 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);
+ if (decimals > MAX_DATETIME_PRECISION)
+ {
+ wrong_precision_error(ER_TOO_BIG_PRECISION, a, decimals,
+ MAX_DATETIME_PRECISION);
+ return 0;
+ }
+ res= new (thd->mem_root) Item_time_typecast(a, (uint) decimals);
break;
case ITEM_CAST_DATETIME:
- res= new (thd->mem_root) Item_datetime_typecast(a);
+ if (decimals > MAX_DATETIME_PRECISION)
+ {
+ wrong_precision_error(ER_TOO_BIG_PRECISION, a, decimals,
+ MAX_DATETIME_PRECISION);
+ return 0;
+ }
+ res= new (thd->mem_root) Item_datetime_typecast(a, (uint) decimals);
break;
case ITEM_CAST_DECIMAL:
{
@@ -5135,7 +5166,7 @@ create_func_cast(THD *thd, Item *a, Cast_target cast_type,
uint dec;
if (get_length_and_scale(length, decimals, &len, &dec,
DECIMAL_MAX_PRECISION, DECIMAL_MAX_SCALE,
- a->name))
+ a))
return NULL;
res= new (thd->mem_root) Item_decimal_typecast(a, len, dec);
break;
@@ -5152,7 +5183,7 @@ create_func_cast(THD *thd, Item *a, Cast_target cast_type,
}
else if (get_length_and_scale(length, decimals, &len, &dec,
DECIMAL_MAX_PRECISION, NOT_FIXED_DEC-1,
- a->name))
+ a))
return NULL;
res= new (thd->mem_root) Item_double_typecast(a, (uint) length,
(uint) decimals);
@@ -5166,7 +5197,9 @@ create_func_cast(THD *thd, Item *a, Cast_target cast_type,
{
if (length > MAX_FIELD_BLOBLENGTH)
{
- my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), "cast as char",
+ 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;
}
diff --git a/sql/item_func.cc b/sql/item_func.cc
index c0c18167796..fb4bca2f671 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -505,7 +505,8 @@ Field *Item_func::tmp_table_field(TABLE *table)
field= Field_new_decimal::create_from_item(this);
break;
case ROW_RESULT:
- default:
+ case TIME_RESULT:
+ case IMPOSSIBLE_RESULT:
// This case should never be chosen
DBUG_ASSERT(0);
field= 0;
@@ -763,7 +764,9 @@ void Item_func_num1::find_num_type()
break;
case DECIMAL_RESULT:
break;
- default:
+ case TIME_RESULT:
+ case ROW_RESULT:
+ case IMPOSSIBLE_RESULT:
DBUG_ASSERT(0);
}
DBUG_PRINT("info", ("Type: %s",
@@ -820,7 +823,9 @@ String *Item_func_numhybrid::val_str(String *str)
}
case STRING_RESULT:
return str_op(&str_value);
- default:
+ case TIME_RESULT:
+ case ROW_RESULT:
+ case IMPOSSIBLE_RESULT:
DBUG_ASSERT(0);
}
return str;
@@ -855,7 +860,9 @@ 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:
+ case IMPOSSIBLE_RESULT:
DBUG_ASSERT(0);
}
return 0.0;
@@ -890,7 +897,9 @@ longlong Item_func_numhybrid::val_int()
CHARSET_INFO *cs= res->charset();
return (*(cs->cset->strtoll10))(cs, res->ptr(), &end, &err_not_used);
}
- default:
+ case TIME_RESULT:
+ case ROW_RESULT:
+ case IMPOSSIBLE_RESULT:
DBUG_ASSERT(0);
}
return 0;
@@ -928,7 +937,8 @@ my_decimal *Item_func_numhybrid::val_decimal(my_decimal *decimal_value)
break;
}
case ROW_RESULT:
- default:
+ case TIME_RESULT:
+ case IMPOSSIBLE_RESULT:
DBUG_ASSERT(0);
}
return val;
@@ -987,8 +997,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;
@@ -1051,8 +1060,7 @@ longlong Item_func_unsigned::val_int()
goto err; // Warn about overflow
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;
@@ -1445,7 +1453,7 @@ void Item_func_div::fix_length_and_dec()
DBUG_ENTER("Item_func_div::fix_length_and_dec");
prec_increment= current_thd->variables.div_precincrement;
Item_num_op::fix_length_and_dec();
- switch(hybrid_type) {
+ switch (hybrid_type) {
case REAL_RESULT:
{
decimals=max(args[0]->decimals,args[1]->decimals)+prec_increment;
@@ -1468,7 +1476,10 @@ void Item_func_div::fix_length_and_dec()
case DECIMAL_RESULT:
result_precision();
break;
- default:
+ case STRING_RESULT:
+ case ROW_RESULT:
+ case TIME_RESULT:
+ case IMPOSSIBLE_RESULT:
DBUG_ASSERT(0);
}
maybe_null= 1; // devision by zero
@@ -1938,8 +1949,7 @@ void Item_func_int_val::find_num_type()
{
DBUG_ENTER("Item_func_int_val::find_num_type");
DBUG_PRINT("info", ("name %s", func_name()));
- switch(hybrid_type= args[0]->result_type())
- {
+ switch (hybrid_type= args[0]->result_type()) {
case STRING_RESULT:
case REAL_RESULT:
hybrid_type= REAL_RESULT;
@@ -1962,7 +1972,9 @@ void Item_func_int_val::find_num_type()
hybrid_type= INT_RESULT;
}
break;
- default:
+ case ROW_RESULT:
+ case TIME_RESULT:
+ case IMPOSSIBLE_RESULT:
DBUG_ASSERT(0);
}
DBUG_PRINT("info", ("Type: %s",
@@ -2138,7 +2150,9 @@ void Item_func_round::fix_length_and_dec()
unsigned_flag);
break;
}
- default:
+ case ROW_RESULT:
+ case TIME_RESULT:
+ case IMPOSSIBLE_RESULT:
DBUG_ASSERT(0); /* This result type isn't handled */
}
}
@@ -2346,10 +2360,10 @@ 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;
+ thd= current_thd;
cmp_type=args[0]->result_type();
for (uint i=0 ; i < arg_count ; i++)
@@ -2358,23 +2372,17 @@ 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());
- if (args[i]->result_type() != ROW_RESULT && args[i]->is_datetime())
+ maybe_null= 1;
+ cmp_type= item_cmp_type(cmp_type,args[i]->result_type());
+ 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)
- {
- 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 +
@@ -2382,61 +2390,69 @@ 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);
}
/*
Compare item arguments in the DATETIME context.
- 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::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
{
longlong UNINIT_VAR(min_max);
- uint min_max_idx= 0;
+ 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);
+
+ null_value= 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())
+ /* Check if we need to stop (because of error or KILL) and stop the loop */
+ if (thd->is_error() || args[i]->null_value)
{
null_value= 1;
- return 0;
+ return 1;
}
- if ((null_value= args[i]->null_value))
- return 0;
if (i == 0 || (res < min_max ? cmp_sign : -cmp_sign) > 0)
- {
min_max= res;
- min_max_idx= i;
- }
}
- if (value)
+ unpack_time(min_max, ltime);
+ if (compare_as_dates->field_type() == MYSQL_TYPE_DATE)
{
- *value= min_max;
- if (datetime_item->field_type() == MYSQL_TYPE_DATE)
- *value/= 1000000L;
+ ltime->time_type= MYSQL_TIMESTAMP_DATE;
+ ltime->hour= ltime->minute= ltime->second= ltime->second_part= 0;
}
- return min_max_idx;
+
+ return 0;
}
@@ -2445,19 +2461,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 (get_date(&ltime, TIME_FUZZY_DATE))
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;
+
+ str->alloc(MAX_DATE_STRING_REP_LENGTH);
+ str->set_charset(collation.collation);
+ str->length(my_TIME_to_str(&ltime, const_cast<char*>(str->ptr()), decimals));
+ return str;
}
switch (cmp_type) {
case INT_RESULT:
@@ -2509,9 +2520,9 @@ String *Item_func_min_max::val_str(String *str)
return res;
}
case ROW_RESULT:
- default:
- // This case should never be chosen
- DBUG_ASSERT(0);
+ case TIME_RESULT:
+ case IMPOSSIBLE_RESULT:
+ DBUG_ASSERT(0); // This case should never be chosen
return 0;
}
return 0; // Keep compiler happy
@@ -2524,9 +2535,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 (get_date(&ltime, TIME_FUZZY_DATE))
+ return 0;
+
+ return TIME_to_double(&ltime);
}
for (uint i=0; i < arg_count ; i++)
{
@@ -2551,9 +2564,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 (get_date(&ltime, TIME_FUZZY_DATE))
+ return 0;
+
+ return TIME_to_ulonglong(&ltime);
}
for (uint i=0; i < arg_count ; i++)
{
@@ -2579,10 +2594,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 (get_date(&ltime, TIME_FUZZY_DATE))
+ return 0;
+
+ return date2my_decimal(&ltime, dec);
}
for (uint i=0; i < arg_count ; i++)
{
@@ -3065,8 +3081,7 @@ udf_handler::fix_fields(THD *thd, Item_result_field *func,
if (arguments[i]->const_item())
{
- switch (arguments[i]->result_type())
- {
+ switch (arguments[i]->result_type()) {
case STRING_RESULT:
case DECIMAL_RESULT:
{
@@ -3092,9 +3107,9 @@ udf_handler::fix_fields(THD *thd, Item_result_field *func,
to+= ALIGN_SIZE(sizeof(double));
break;
case ROW_RESULT:
- default:
- // This case should never be chosen
- DBUG_ASSERT(0);
+ case TIME_RESULT:
+ case IMPOSSIBLE_RESULT:
+ DBUG_ASSERT(0); // This case should never be chosen
break;
}
}
@@ -3167,9 +3182,9 @@ bool udf_handler::get_arguments()
}
break;
case ROW_RESULT:
- default:
- // This case should never be chosen
- DBUG_ASSERT(0);
+ case TIME_RESULT:
+ case IMPOSSIBLE_RESULT:
+ DBUG_ASSERT(0); // This case should never be chosen
break;
}
}
@@ -3789,9 +3804,9 @@ longlong Item_func_benchmark::val_int()
(void) args[1]->val_decimal(&tmp_decimal);
break;
case ROW_RESULT:
- default:
- // This case should never be chosen
- DBUG_ASSERT(0);
+ case TIME_RESULT:
+ case IMPOSSIBLE_RESULT:
+ DBUG_ASSERT(0); // This case should never be chosen
return 0;
}
}
@@ -4145,6 +4160,7 @@ double user_var_entry::val_real(bool *null_value)
case STRING_RESULT:
return my_atof(value); // This is null terminated
case ROW_RESULT:
+ case TIME_RESULT:
case IMPOSSIBLE_RESULT:
DBUG_ASSERT(0); // Impossible
break;
@@ -4177,6 +4193,7 @@ longlong user_var_entry::val_int(bool *null_value) const
return my_strtoll10(value, (char**) 0, &error);// String is null terminated
}
case ROW_RESULT:
+ case TIME_RESULT:
case IMPOSSIBLE_RESULT:
DBUG_ASSERT(0); // Impossible
break;
@@ -4211,6 +4228,7 @@ String *user_var_entry::val_str(bool *null_value, String *str,
str= 0; // EOM error
break;
case ROW_RESULT:
+ case TIME_RESULT:
case IMPOSSIBLE_RESULT:
DBUG_ASSERT(0); // Impossible
break;
@@ -4239,6 +4257,7 @@ my_decimal *user_var_entry::val_decimal(bool *null_value, my_decimal *val)
str2my_decimal(E_DEC_FATAL_ERROR, value, length, collation.collation, val);
break;
case ROW_RESULT:
+ case TIME_RESULT:
case IMPOSSIBLE_RESULT:
DBUG_ASSERT(0); // Impossible
break;
@@ -4278,8 +4297,9 @@ Item_func_set_user_var::check(bool use_result_field)
{
save_result.vint= use_result_field ? result_field->val_int() :
args[0]->val_int();
- unsigned_flag= use_result_field ? ((Field_num*)result_field)->unsigned_flag:
- args[0]->unsigned_flag;
+ unsigned_flag= (use_result_field ?
+ ((Field_num*)result_field)->unsigned_flag:
+ args[0]->unsigned_flag);
break;
}
case STRING_RESULT:
@@ -4296,9 +4316,9 @@ Item_func_set_user_var::check(bool use_result_field)
break;
}
case ROW_RESULT:
- default:
- // This case should never be chosen
- DBUG_ASSERT(0);
+ case TIME_RESULT:
+ case IMPOSSIBLE_RESULT:
+ DBUG_ASSERT(0); // This case should never be chosen
break;
}
DBUG_RETURN(FALSE);
@@ -4331,9 +4351,9 @@ 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:
- // Should never happen
- DBUG_ASSERT(0);
+ case TIME_RESULT:
+ case IMPOSSIBLE_RESULT:
+ DBUG_ASSERT(0); // This case should never be chosen
break;
}
DBUG_VOID_RETURN;
@@ -4399,9 +4419,9 @@ Item_func_set_user_var::update()
break;
}
case ROW_RESULT:
- default:
- // This case should never be chosen
- DBUG_ASSERT(0);
+ case TIME_RESULT:
+ case IMPOSSIBLE_RESULT:
+ DBUG_ASSERT(0); // This case should never be chosen
break;
}
DBUG_RETURN(res);
@@ -4834,7 +4854,7 @@ void Item_func_get_user_var::fix_length_and_dec()
max_length= var_entry->length;
collation.set(var_entry->collation);
- switch(m_cached_result_type) {
+ switch (m_cached_result_type) {
case REAL_RESULT:
max_length= DBL_DIG + 8;
break;
@@ -4850,8 +4870,9 @@ void Item_func_get_user_var::fix_length_and_dec()
decimals= DECIMAL_MAX_SCALE;
break;
case ROW_RESULT: // Keep compiler happy
- default:
- DBUG_ASSERT(0);
+ case TIME_RESULT:
+ case IMPOSSIBLE_RESULT:
+ DBUG_ASSERT(0); // This case should never be chosen
break;
}
}
diff --git a/sql/item_func.h b/sql/item_func.h
index 90dbffb0a05..09b5ef9c0ec 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -323,6 +323,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)
@@ -868,25 +870,21 @@ class Item_func_min_max :public Item_func
Item_result cmp_type;
String tmp_value;
int cmp_sign;
- /* TRUE <=> arguments should be compared in the DATETIME context. */
- bool compare_as_dates;
/* An item used for issuing warnings while string to DATETIME conversion. */
- Item *datetime_item;
+ Item *compare_as_dates;
THD *thd;
protected:
enum_field_types cached_field_type;
public:
Item_func_min_max(List<Item> &list,int cmp_sign_arg) :Item_func(list),
- cmp_type(INT_RESULT), cmp_sign(cmp_sign_arg), compare_as_dates(FALSE),
- datetime_item(0) {}
+ cmp_type(INT_RESULT), cmp_sign(cmp_sign_arg), compare_as_dates(FALSE) {}
double val_real();
longlong val_int();
String *val_str(String *);
my_decimal *val_decimal(my_decimal *);
+ bool get_date(MYSQL_TIME *res, uint fuzzy_date);
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);
enum_field_types field_type() const { return cached_field_type; }
};
diff --git a/sql/item_row.h b/sql/item_row.h
index c7fb8d59220..0b43309391d 100644
--- a/sql/item_row.h
+++ b/sql/item_row.h
@@ -66,6 +66,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_strfunc.cc b/sql/item_strfunc.cc
index e7e77fb58b6..69eea97bd09 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -3944,8 +3944,14 @@ String *Item_dyncol_get::val_str(String *str_result)
case DYN_COL_TIME:
{
int length;
+ /*
+ We use AUTO_SEC_PART_DIGITS here to ensure that we do not loose
+ any microseconds from the data. This is safe to do as we are
+ asked to return the time argument as a string.
+ */
if (str_result->alloc(MAX_DATE_STRING_REP_LENGTH) ||
- !(length= my_TIME_to_str(&val.time_value, (char*) str_result->ptr())))
+ !(length= my_TIME_to_str(&val.time_value, (char*) str_result->ptr(),
+ AUTO_SEC_PART_DIGITS)))
goto null;
str_result->set_charset(&my_charset_latin1);
str_result->length(length);
@@ -4086,7 +4092,7 @@ double Item_dyncol_get::val_real()
case DYN_COL_DATE:
case DYN_COL_TIME:
return (ulonglong2double(TIME_to_ulonglong(&val.time_value)) +
- val.time_value.second_part / (double) TIME_SUBSECOND_RANGE);
+ val.time_value.second_part / (double) TIME_SECOND_PART_FACTOR);
}
null:
@@ -4145,10 +4151,12 @@ my_decimal *Item_dyncol_get::val_decimal(my_decimal *decimal_value)
case DYN_COL_DATE:
case DYN_COL_TIME:
{
- double tmp= (ulonglong2double(TIME_to_ulonglong(&val.time_value)) +
- val.time_value.second_part / (double) TIME_SUBSECOND_RANGE);
- /* This can't overflow as time is always in the range of decimal */
- double2my_decimal(E_DEC_FATAL_ERROR, tmp, decimal_value);
+ my_decimal time_part, sub_second, fractions;
+ longlong2decimal(TIME_to_ulonglong(&val.time_value), &time_part);
+ longlong2decimal(val.time_value.second_part, &sub_second);
+ my_decimal_div(E_DEC_FATAL_ERROR, &fractions, &sub_second,
+ &time_second_part_factor, TIME_SECOND_PART_DIGITS);
+ my_decimal_add(E_DEC_FATAL_ERROR, decimal_value, &time_part, &fractions);
break;
}
}
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 2479f8ea92a..123289f52e7 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -652,17 +652,30 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref)
Setup cache/comparator of MIN/MAX functions. When called by the
copy_or_same function value_arg parameter contains calculated value
of the original MIN/MAX object and it is saved in this object's cache.
+
+ We mark the value and arg_cache with 'RAND_TABLE_BIT' to ensure
+ that Arg_comparator::compare_datetime() doesn't allocate new
+ item inside of Arg_comparator. This would cause compare_datetime()
+ and Item_sum_min::add() to use different values!
*/
void Item_sum_hybrid::setup_hybrid(Item *item, Item *value_arg)
{
- value= Item_cache::get_cache(item);
+ if (!(value= Item_cache::get_cache(item)))
+ return;
value->setup(item);
value->store(value_arg);
- arg_cache= Item_cache::get_cache(item);
+ /* Don't cache value, as it will change */
+ if (!item->const_item())
+ value->set_used_tables(RAND_TABLE_BIT);
+ if (!(arg_cache= Item_cache::get_cache(item)))
+ return;
arg_cache->setup(item);
- cmp= new Arg_comparator();
- cmp->set_cmp_func(this, (Item**)&arg_cache, (Item**)&value, FALSE);
+ /* Don't cache value, as it will change */
+ if (!item->const_item())
+ arg_cache->set_used_tables(RAND_TABLE_BIT);
+ if (cmp= new Arg_comparator())
+ cmp->set_cmp_func(this, (Item**)&arg_cache, (Item**)&value, FALSE);
collation.set(item->collation);
}
@@ -687,14 +700,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 76a3fed3d49..e4a2595efed 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)
+static bool make_datetime(MYSQL_TIME *ltime, String *str, uint decimals)
{
- 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)
-{
- int warning= 0;
-
- if (make_datetime(format, ltime, str))
- return 1;
- if (check_time_range(ltime, &warning))
- return 1;
- if (!warning)
- return 0;
-
- make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- str->ptr(), str->length(),
- MYSQL_TIMESTAMP_TIME, NullS);
- return make_datetime(format, ltime, str);
-}
-
-
-/*
- Wrapper over make_time() with validation of the input MYSQL_TIME value
-
- NOTE
- see make_time() for more info
-
- RETURN
- 1 if there was an error during conversion
- 0 otherwise
-*/
-
-static bool make_time_with_warn(const DATE_TIME_FORMAT *format,
- MYSQL_TIME *l_time, String *str)
-{
- int warning= 0;
- make_time(format, l_time, str);
- if (check_time_range(l_time, &warning))
+ if (str->alloc(MAX_DATE_STRING_REP_LENGTH))
return 1;
- if (warning)
- {
- make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- str->ptr(), str->length(),
- MYSQL_TIMESTAMP_TIME, NullS);
- make_time(format, l_time, str);
- }
-
+ str->length(my_TIME_to_str(ltime, const_cast<char*>(str->ptr()), decimals));
+ str->set_charset(&my_charset_bin);
return 0;
}
@@ -167,7 +51,6 @@ static bool make_time_with_warn(const DATE_TIME_FORMAT *format,
SYNOPSIS:
sec_to_time()
seconds number of seconds
- unsigned_flag 1, if 'seconds' is unsigned, 0, otherwise
ltime output MYSQL_TIME value
DESCRIPTION
@@ -181,43 +64,53 @@ 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)
+bool Item_func_sec_to_time::sec_to_time(my_decimal *seconds, MYSQL_TIME *ltime)
{
+ Lazy_string_decimal str(*seconds);
uint sec;
+ longlong full_seconds;
+ my_decimal tmp, sub_seconds;
bzero((char *)ltime, sizeof(*ltime));
+
+ ltime->time_type= MYSQL_TIMESTAMP_TIME;
- if (seconds < 0)
+ if (seconds->sign())
{
- if (unsigned_flag)
- goto overflow;
ltime->neg= 1;
- if (seconds < -3020399)
- goto overflow;
- seconds= -seconds;
+ seconds->sign(0);
}
- else if (seconds > 3020399)
+ if (my_decimal_cmp(seconds, &max_seconds_for_time_type) > 0)
goto overflow;
+
+ /* We don't call my_decimal2int() here as we don't want rounding */
+ (void) decimal2longlong(seconds, &full_seconds);
- sec= (uint) ((ulonglong) seconds % 3600);
- ltime->hour= (uint) (seconds/3600);
+ sec= (uint) (full_seconds % 3600);
+ ltime->hour= (uint) (full_seconds/3600);
ltime->minute= sec/60;
ltime->second= sec % 60;
+ /*
+ Calculate second_part
+ ltime->second_part= (seconds - floor(seconds)) * TIME_SECOND_PART_FACTOR
+ */
+ my_decimal_floor(E_DEC_FATAL_ERROR, seconds, &tmp);
+ my_decimal_sub(E_DEC_FATAL_ERROR, &sub_seconds, seconds, &tmp);
+ my_decimal_mul(E_DEC_FATAL_ERROR, &tmp, &sub_seconds,
+ &time_second_part_factor);
+ (void) decimal2longlong(&tmp, &full_seconds);
+ ltime->second_part= full_seconds;
+
return 0;
overflow:
- ltime->hour= TIME_MAX_HOUR;
- 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);
+ /* 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;
}
@@ -270,7 +163,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 +185,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 +360,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 +368,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;
@@ -579,6 +475,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
@@ -1025,7 +925,7 @@ longlong Item_func_dayofyear::val_int()
{
DBUG_ASSERT(fixed == 1);
MYSQL_TIME ltime;
- if (get_arg0_date(&ltime,TIME_NO_ZERO_DATE))
+ if (get_arg0_date(&ltime, 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;
@@ -1294,21 +1194,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;
- my_bool 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)
- return ((Field_timestamp*) field)->get_timestamp(&null_value);
+ {
+ if ((null_value= field->is_null()))
+ return 1;
+ *seconds= ((Field_timestamp*)field)->get_timestamp(second_part);
+ return 0;
+ }
}
-
+
+ MYSQL_TIME ltime;
if (get_arg0_date(&ltime, 0))
{
/*
@@ -1317,14 +1219,42 @@ longlong Item_func_unix_timestamp::val_int()
this case).
*/
null_value= args[0]->null_value;
- return 0;
+ return 1;
}
+
+ uint error_code;
+ *seconds= TIME_to_timestamp(current_thd, &ltime, &error_code);
+ *second_part= ltime.second_part;
+ return (null_value= (error_code == ER_WARN_DATA_OUT_OF_RANGE));
+}
+
+
+longlong Item_func_unix_timestamp::int_op()
+{
+ if (arg_count == 0)
+ return (longlong) current_thd->query_start();
- return (longlong) TIME_to_timestamp(current_thd, &ltime, &not_used);
+ ulong second_part;
+ my_time_t seconds;
+ if (get_timestamp_value(&seconds, &second_part))
+ return 0;
+
+ return seconds;
}
-longlong Item_func_time_to_sec::val_int()
+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;
@@ -1335,6 +1265,17 @@ longlong Item_func_time_to_sec::val_int()
}
+double Item_func_time_to_sec::real_op()
+{
+ DBUG_ASSERT(fixed == 1);
+ MYSQL_TIME ltime;
+ double seconds;
+ (void) get_arg0_time(&ltime);
+ seconds=ltime.hour*3600L+ltime.minute*60+ltime.second+ltime.second_part/1e6;
+ return ltime.neg ? -seconds : seconds;
+}
+
+
/**
Convert a string to a interval value.
@@ -1493,32 +1434,62 @@ bool get_interval_value(Item *args,interval_type int_type,
}
-String *Item_date::val_str(String *str)
+String *Item_temporal_func::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
MYSQL_TIME ltime;
if (get_date(&ltime, TIME_FUZZY_DATE))
return (String *) 0;
- if (str->alloc(MAX_DATE_STRING_REP_LENGTH))
+ if (make_datetime(&ltime, str, decimals))
{
null_value= 1;
return (String *) 0;
}
- make_date((DATE_TIME_FORMAT *) 0, &ltime, str);
return str;
}
-longlong Item_date::val_int()
+longlong Item_temporal_func::val_int()
{
DBUG_ASSERT(fixed == 1);
MYSQL_TIME ltime;
if (get_date(&ltime, TIME_FUZZY_DATE))
return 0;
- return (longlong) (ltime.year*10000L+ltime.month*100+ltime.day);
+ return (longlong)TIME_to_ulonglong(&ltime);
+}
+
+
+double Item_temporal_func::val_real()
+{
+ DBUG_ASSERT(fixed == 1);
+ MYSQL_TIME ltime;
+ if (get_date(&ltime, TIME_FUZZY_DATE))
+ return 0;
+ return TIME_to_double(&ltime);
+}
+
+
+bool Item_temporal_func::get_time(MYSQL_TIME *ltime)
+{
+ /*
+ All temporal functions have a get_date() function which also
+ returns the time.
+ */
+ if (get_date(ltime, TIME_TIME_ONLY | TIME_FUZZY_DATE |
+ sql_mode_for_dates()))
+ return 1;
+ /* Convert date to time */
+ if (ltime->time_type == MYSQL_TIMESTAMP_DATE ||
+ ltime->time_type == MYSQL_TIMESTAMP_DATETIME)
+ {
+ ltime->year= ltime->month= ltime->day= 0;
+ ltime->time_type= MYSQL_TIMESTAMP_TIME;
+ }
+ return 0;
}
+
bool Item_func_from_days::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
{
longlong value=args[0]->val_int();
@@ -1533,28 +1504,13 @@ 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(&ltime);
/* We don't need to set second_part and neg because they already 0 */
ltime.hour= ltime.minute= ltime.second= 0;
ltime.time_type= MYSQL_TIMESTAMP_DATE;
- value= (longlong) TIME_to_ulonglong_date(&ltime);
-}
-
-String *Item_func_curdate::val_str(String *str)
-{
- DBUG_ASSERT(fixed == 1);
- if (str->alloc(MAX_DATE_STRING_REP_LENGTH))
- {
- null_value= 1;
- return (String *) 0;
- }
- make_date((DATE_TIME_FORMAT *) 0, &ltime, str);
- return str;
+ Item_datefunc::fix_length_and_dec();
+ maybe_null= 0;
}
/**
@@ -1564,8 +1520,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;
}
@@ -1576,8 +1531,8 @@ 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());
/*
We are not flagging this query as using time zone, since it uses fixed
UTC-SYSTEM time-zone.
@@ -1593,26 +1548,35 @@ 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 > TIME_SECOND_PART_DIGITS)
+ {
+ my_error(ER_TOO_BIG_PRECISION, MYF(0), decimals, func_name(),
+ TIME_SECOND_PART_DIGITS);
+ return 1;
+ }
+ return Item_timefunc::fix_fields(thd, items);
}
-
-void Item_func_curtime::fix_length_and_dec()
+bool Item_func_curtime::get_date(MYSQL_TIME *res,
+ uint fuzzy_date __attribute__((unused)))
{
- MYSQL_TIME ltime;
-
- decimals= DATETIME_DEC;
- collation.set(&my_charset_bin);
- store_now_in_TIME(&ltime);
- value= TIME_to_ulonglong_time(&ltime);
- buff_length= (uint) my_time_to_str(&ltime, buff);
- max_length= buff_length;
+ *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 <= TIME_SECOND_PART_DIGITS);
+ if (item->decimals)
+ {
+ ltime->second_part= sec_part;
+ if (item->decimals < TIME_SECOND_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
@@ -1621,8 +1585,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;
}
@@ -1633,36 +1599,28 @@ 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;
-}
-
-
-void Item_func_now::fix_length_and_dec()
-{
- decimals= DATETIME_DEC;
- collation.set(&my_charset_bin);
-
- store_now_in_TIME(&ltime);
- value= (longlong) TIME_to_ulonglong_datetime(&ltime);
-
- buff_length= (uint) my_datetime_to_str(&ltime, buff);
- max_length= buff_length;
+ if (decimals > TIME_SECOND_PART_DIGITS)
+ {
+ 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);
}
-
/**
Converts current time in my_time_t to MYSQL_TIME represenatation for local
time zone. Defines time zone (local) used for whole NOW function.
@@ -1670,8 +1628,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;
}
@@ -1682,8 +1640,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.
@@ -1699,13 +1658,6 @@ bool Item_func_now::get_date(MYSQL_TIME *res,
}
-int Item_func_now::save_in_field(Field *to, bool no_conversions)
-{
- to->set_notnull();
- return to->store_time(&ltime, MYSQL_TIMESTAMP_DATETIME);
-}
-
-
/**
Converts current time in my_time_t to MYSQL_TIME represenatation for local
time zone. Defines time zone (local) used for whole SYSDATE function.
@@ -1713,99 +1665,34 @@ 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_my_time(now));
+ set_sec_part(hrtime_sec_part(now), now_time, this);
thd->time_zone_used= 1;
}
-String *Item_func_sysdate_local::val_str(String *str)
-{
- DBUG_ASSERT(fixed == 1);
- store_now_in_TIME(&ltime);
- buff_length= (uint) my_datetime_to_str(&ltime, buff);
- str_value.set(buff, buff_length, &my_charset_bin);
- return &str_value;
-}
-
-
-longlong Item_func_sysdate_local::val_int()
-{
- DBUG_ASSERT(fixed == 1);
- store_now_in_TIME(&ltime);
- return (longlong) TIME_to_ulonglong_datetime(&ltime);
-}
-
-
-double Item_func_sysdate_local::val_real()
-{
- DBUG_ASSERT(fixed == 1);
- store_now_in_TIME(&ltime);
- return ulonglong2double(TIME_to_ulonglong_datetime(&ltime));
-}
-
-
-void Item_func_sysdate_local::fix_length_and_dec()
-{
- decimals= 0;
- collation.set(&my_charset_bin);
- max_length= MAX_DATETIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
-}
-
-
bool Item_func_sysdate_local::get_date(MYSQL_TIME *res,
uint fuzzy_date __attribute__((unused)))
{
- store_now_in_TIME(&ltime);
- *res= ltime;
- return 0;
-}
-
-
-int Item_func_sysdate_local::save_in_field(Field *to, bool no_conversions)
-{
- store_now_in_TIME(&ltime);
- to->set_notnull();
- to->store_time(&ltime, MYSQL_TIMESTAMP_DATETIME);
+ store_now_in_TIME(res);
return 0;
}
-String *Item_func_sec_to_time::val_str(String *str)
+bool Item_func_sec_to_time::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
{
DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
- longlong arg_val= args[0]->val_int();
-
- if ((null_value=args[0]->null_value) ||
- str->alloc(MAX_DATE_STRING_REP_LENGTH))
- {
- null_value= 1;
- return (String*) 0;
- }
-
- sec_to_time(arg_val, args[0]->unsigned_flag, &ltime);
+ my_decimal tmp_buff, *tmp= args[0]->val_decimal(&tmp_buff);
- make_time((DATE_TIME_FORMAT *) 0, &ltime, str);
- return str;
-}
-
+ if ((null_value= args[0]->null_value))
+ return 1;
-longlong Item_func_sec_to_time::val_int()
-{
- DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
- longlong arg_val= args[0]->val_int();
+ sec_to_time(tmp, ltime);
- if ((null_value=args[0]->null_value))
- return 0;
-
- sec_to_time(arg_val, args[0]->unsigned_flag, &ltime);
-
- return (ltime.neg ? -1 : 1) *
- ((ltime.hour)*10000 + ltime.minute*100 + ltime.second);
+ return 0;
}
-
void Item_func_date_format::fix_length_and_dec()
{
THD* thd= current_thd;
@@ -1941,27 +1828,12 @@ 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,
- current_thd->variables.sql_mode &
- (MODE_NO_ZERO_DATE | MODE_NO_ZERO_IN_DATE |
- MODE_INVALID_DATES))))
- 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;
@@ -1999,100 +1871,31 @@ null_date:
void Item_func_from_unixtime::fix_length_and_dec()
{
thd= current_thd;
- collation.set(&my_charset_bin);
- decimals= DATETIME_DEC;
- max_length=MAX_DATETIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
- maybe_null= 1;
thd->time_zone_used= 1;
+ decimals= args[0]->decimals;
+ Item_temporal_func::fix_length_and_dec();
}
-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)))
{
- 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);
}
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;
- 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);
+ decimals= args[0]->decimals;
+ Item_temporal_func::fix_length_and_dec();
}
@@ -2115,7 +1918,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;
@@ -2124,9 +1928,12 @@ bool Item_func_convert_tz::get_date(MYSQL_TIME *ltime,
{
my_bool not_used;
my_time_tmp= from_tz->TIME_to_gmt_sec(ltime, &not_used);
+ ulong sec_part= ltime->second_part;
/* my_time_tmp is guranteed to be in the allowed range */
if (my_time_tmp)
to_tz->gmt_sec_to_TIME(ltime, my_time_tmp);
+ /* we rely on the fact that no timezone conversion can change sec_part */
+ ltime->second_part= sec_part;
}
null_value= 0;
@@ -2137,7 +1944,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();
}
@@ -2145,21 +1952,20 @@ 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_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
- value.alloc(max_length);
-
/*
The field type for the result of an Item_date function is defined as
follows:
- 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)
+ (This is because you can't know if the string contains a DATE,
+ MYSQL_TIME or DATETIME argument)
*/
cached_field_type= MYSQL_TYPE_STRING;
arg0_field_type= args[0]->field_type();
@@ -2173,6 +1979,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;
+
+ Item_temporal_func::fix_length_and_dec();
+ value.alloc(max_length);
}
@@ -2182,7 +2002,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);
@@ -2195,44 +2015,6 @@ bool Item_date_add_interval::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
}
-String *Item_date_add_interval::val_str(String *str)
-{
- DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
- enum date_time_format_types format;
-
- if (Item_date_add_interval::get_date(&ltime, TIME_NO_ZERO_DATE))
- return 0;
-
- if (ltime.time_type == MYSQL_TIMESTAMP_DATE)
- format= DATE_ONLY;
- else if (ltime.second_part)
- format= DATE_TIME_MICROSECOND;
- else
- format= DATE_TIME;
-
- if (!make_datetime(format, &ltime, str))
- return str;
-
- null_value=1;
- return 0;
-}
-
-
-longlong Item_date_add_interval::val_int()
-{
- DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
- longlong date;
- if (Item_date_add_interval::get_date(&ltime, TIME_NO_ZERO_DATE))
- return (longlong) 0;
- date = (ltime.year*100L + ltime.month)*100L + ltime.day;
- return ltime.time_type == MYSQL_TIMESTAMP_DATE ? date :
- ((date*100L + ltime.hour)*100L+ ltime.minute)*100L + ltime.second;
-}
-
-
-
bool Item_date_add_interval::eq(const Item *item, bool binary_cmp) const
{
Item_date_add_interval *other= (Item_date_add_interval*) item;
@@ -2314,29 +2096,12 @@ longlong Item_extract::val_int()
uint year;
ulong week_format;
long neg;
- if (date_value)
- {
- if (get_arg0_date(&ltime, TIME_FUZZY_DATE))
- return 0;
- neg=1;
- }
- else
- {
- char buf[40];
- String value(buf, sizeof(buf), &my_charset_bin);;
- String *res= args[0]->val_str(&value);
- if (!res ||
- str_to_time_with_warn(res->ptr(), res->length(), &ltime,
- current_thd->variables.sql_mode &
- (MODE_NO_ZERO_DATE | MODE_NO_ZERO_IN_DATE |
- MODE_INVALID_DATES)))
- {
- null_value=1;
- return 0;
- }
- neg= ltime.neg ? -1 : 1;
- null_value=0;
- }
+ int is_time_flag = date_value ? 0 : TIME_TIME_ONLY;
+
+ if (get_arg0_date(&ltime, TIME_FUZZY_DATE | is_time_flag))
+ return 0;
+ neg= ltime.neg ? -1 : 1;
+
switch (int_type) {
case INTERVAL_YEAR: return ltime.year;
case INTERVAL_YEAR_MONTH: return ltime.year*100L+ltime.month;
@@ -2419,7 +2184,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);
@@ -2434,13 +2199,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<ulonglong>(cast_length), &my_charset_bin);
str->append(st);
str->append(')');
}
@@ -2492,7 +2257,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
@@ -2512,16 +2277,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);
}
}
@@ -2571,142 +2335,75 @@ 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);
+ (cast_cs == &my_charset_bin ? 1 :
+ args[0]->collation.collation->mbmaxlen));
max_length= char_length * cast_cs->mbmaxlen;
}
-String *Item_datetime_typecast::val_str(String *str)
-{
- DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
-
- if (!get_arg0_date(&ltime, TIME_FUZZY_DATE) &&
- !make_datetime(ltime.second_part ? DATE_TIME_MICROSECOND : DATE_TIME,
- &ltime, str))
- return str;
-
- null_value=1;
- return 0;
-}
-
-
-longlong Item_datetime_typecast::val_int()
-{
- DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
- if (get_arg0_date(&ltime,1))
- {
- null_value= 1;
- return 0;
- }
-
- return TIME_to_ulonglong_datetime(&ltime);
-}
-
-
-bool Item_time_typecast::get_time(MYSQL_TIME *ltime)
+bool Item_time_typecast::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
{
- bool res= get_arg0_time(ltime);
+ if (get_arg0_time(ltime))
+ return 1;
/*
- 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;
-}
-
-bool Item_time_typecast::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
-{
- return get_time(ltime);
-}
-
-
-longlong Item_time_typecast::val_int()
-{
- MYSQL_TIME ltime;
- if (get_time(&ltime))
- {
- null_value= 1;
- return 0;
- }
- return ltime.hour * 10000L + ltime.minute * 100 + ltime.second;
-}
-
-String *Item_time_typecast::val_str(String *str)
-{
- DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
-
- if (!get_time(&ltime) &&
- !make_datetime(ltime.second_part ? TIME_MICROSECOND : TIME_ONLY,
- &ltime, str))
- return str;
-
- null_value=1;
return 0;
}
bool Item_date_typecast::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
{
- bool res= get_arg0_date(ltime, TIME_FUZZY_DATE);
+ 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;
- return res;
-}
-
-
-bool Item_date_typecast::get_time(MYSQL_TIME *ltime)
-{
- bzero((char *)ltime, sizeof(MYSQL_TIME));
- return args[0]->null_value;
+ return 0;
}
-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, fuzzy_date & ~TIME_TIME_ONLY))
+ return 1;
- if (!get_arg0_date(&ltime, TIME_FUZZY_DATE) &&
- !str->alloc(MAX_DATE_STRING_REP_LENGTH))
+ /*
+ ltime is valid MYSQL_TYPE_TIME (according to fuzzy_date).
+ But not every valid TIME value is a valid DATETIME value!
+ */
+ if (ltime->time_type == MYSQL_TIMESTAMP_TIME && ltime->hour >= 24)
{
- make_date((DATE_TIME_FORMAT *) 0, &ltime, str);
- return str;
+ Lazy_string_time str(ltime);
+ make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ &str, MYSQL_TIMESTAMP_DATETIME, 0);
+ return (null_value= 1);
}
- null_value=1;
+ ltime->time_type= MYSQL_TIMESTAMP_DATETIME;
return 0;
}
-longlong Item_date_typecast::val_int()
-{
- DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
- if ((null_value= args[0]->get_date(&ltime, TIME_FUZZY_DATE)))
- return 0;
- return (longlong) (ltime.year * 10000L + ltime.month * 100 + ltime.day);
-}
/**
MAKEDATE(a,b) is a date function that creates a date value
from a year and day value.
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
+ 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
*/
-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;
@@ -2722,66 +2419,21 @@ String *Item_func_makedate::val_str(String *str)
/* Day number from year 0 to 9999-12-31 */
if (days >= 0 && days <= MAX_DAY_NUMBER)
{
- null_value=0;
- get_date_from_daynr(days,&l_time.year,&l_time.month,&l_time.day);
- if (str->alloc(MAX_DATE_STRING_REP_LENGTH))
- goto err;
- make_date((DATE_TIME_FORMAT *) 0, &l_time, str);
- return str;
- }
-
-err:
- null_value=1;
- return 0;
-}
-
-
-/*
- MAKEDATE(a,b) is a date function that creates a date value
- from a year and day value.
-
- NOTES:
- As arguments are integers, we can't know if the year is a 2 digit or 4 digit year.
- In this case we treat all years < 100 as 2 digit years. Ie, this is not safe
- for dates between 0000-01-01 and 0099-12-31
-*/
-
-longlong Item_func_makedate::val_int()
-{
- DBUG_ASSERT(fixed == 1);
- MYSQL_TIME l_time;
- long daynr= (long) args[1]->val_int();
- long year= (long) args[0]->val_int();
- long days;
-
- if (args[0]->null_value || args[1]->null_value ||
- year < 0 || daynr <= 0)
- goto err;
-
- if (year < 100)
- year= year_2000_handling(year);
-
- days= calc_daynr(year,1,1) + daynr - 1;
- /* Day number from year 0 to 9999-12-31 */
- if (days >= 0 && days < MAX_DAY_NUMBER)
- {
- null_value=0;
- get_date_from_daynr(days,&l_time.year,&l_time.month,&l_time.day);
- return (longlong) (l_time.year * 10000L + l_time.month * 100 + l_time.day);
+ bzero(ltime, sizeof(*ltime));
+ ltime->time_type= MYSQL_TIMESTAMP_DATE;
+ get_date_from_daynr(days, &ltime->year, &ltime->month, &ltime->day);
+ return (null_value= 0);
}
err:
- null_value= 1;
- return 0;
+ return (null_value= 1);
}
void Item_func_add_time::fix_length_and_dec()
{
enum_field_types arg0_field_type;
- decimals=0;
- max_length=MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
- maybe_null= 1;
+ decimals= max(args[0]->decimals, args[1]->decimals);
/*
The field type for the result of an Item_func_add_time function is defined
@@ -2801,6 +2453,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;
+ Item_temporal_func::fix_length_and_dec();
}
/**
@@ -2813,38 +2466,38 @@ void Item_func_add_time::fix_length_and_dec()
Result: Time value or datetime value
*/
-String *Item_func_add_time::val_str(String *str)
+bool Item_func_add_time::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
{
DBUG_ASSERT(fixed == 1);
- MYSQL_TIME l_time1, l_time2, l_time3;
+ MYSQL_TIME l_time1, l_time2;
bool is_time= 0;
long days, microseconds;
longlong seconds;
- int l_sign= sign;
+ int l_sign= sign, was_cut= 0;
+ uint dec= decimals;
- null_value=0;
if (is_date) // TIMESTAMP function
{
if (get_arg0_date(&l_time1, TIME_FUZZY_DATE) ||
args[1]->get_time(&l_time2) ||
l_time1.time_type == MYSQL_TIMESTAMP_TIME ||
l_time2.time_type != MYSQL_TIMESTAMP_TIME)
- goto null_date;
+ return (null_value= 1);
}
else // ADDTIME function
{
if (args[0]->get_time(&l_time1) ||
args[1]->get_time(&l_time2) ||
l_time2.time_type == MYSQL_TIMESTAMP_DATETIME)
- goto null_date;
+ return (null_value= 1);
is_time= (l_time1.time_type == MYSQL_TIMESTAMP_TIME);
}
if (l_time1.neg != l_time2.neg)
l_sign= -l_sign;
- bzero((char *)&l_time3, sizeof(l_time3));
+ bzero(ltime, sizeof(*ltime));
- l_time3.neg= calc_time_diff(&l_time1, &l_time2, -l_sign,
+ ltime->neg= calc_time_diff(&l_time1, &l_time2, -l_sign,
&seconds, &microseconds);
/*
@@ -2852,35 +2505,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= TIME_SECOND_PART_DIGITS;
if (!is_time)
{
- get_date_from_daynr(days,&l_time3.year,&l_time3.month,&l_time3.day);
- if (l_time3.day &&
- !make_datetime(l_time1.second_part || l_time2.second_part ?
- DATE_TIME_MICROSECOND : DATE_TIME,
- &l_time3, str))
- return str;
- goto null_date;
+ get_date_from_daynr(days,&ltime->year,&ltime->month,&ltime->day);
+ if (!ltime->day)
+ return (null_value= 1);
+ return (null_value= 0);
}
- l_time3.hour+= days*24;
- if (!make_datetime_with_warn(l_time1.second_part || l_time2.second_part ?
- TIME_MICROSECOND : TIME_ONLY,
- &l_time3, str))
- return str;
+ ltime->hour+= days*24;
-null_date:
- null_value=1;
- return 0;
+ MYSQL_TIME copy= *ltime;
+ Lazy_string_time str(&copy);
+
+ check_time_range(ltime, decimals, &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);
}
@@ -2913,15 +2571,19 @@ 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);
+
+ /* the following may be true in, for example, date_add(timediff(...), ... */
+ if (fuzzy_date & TIME_NO_ZERO_IN_DATE)
+ goto null_date;
- null_value= 0;
if (args[0]->get_time(&l_time1) ||
args[1]->get_time(&l_time2) ||
l_time1.time_type != l_time2.time_type)
@@ -2943,16 +2605,30 @@ String *Item_func_timediff::val_str(String *str)
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 (!make_datetime_with_warn(l_time1.second_part || l_time2.second_part ?
- TIME_MICROSECOND : TIME_ONLY,
- &l_time3, str))
- return str;
+ if ((fuzzy_date & TIME_NO_ZERO_DATE) && (seconds == 0) &&
+ (microseconds == 0))
+ goto null_date;
+
+ *ltime= l_time3;
+ 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);
+ return (null_value= 0);
null_date:
- null_value=1;
- return 0;
+ return (null_value= 1);
}
/**
@@ -2961,10 +2637,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();
@@ -2975,12 +2650,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))))
- return 0;
+ second < 0 || second > 59)))
+ return 1;
- bzero((char *)&ltime, sizeof(ltime));
- ltime.neg= 0;
+ bzero(ltime, sizeof(*ltime));
+ ltime->time_type= MYSQL_TIMESTAMP_TIME;
/* Check for integer overflows */
if (hour < 0)
@@ -2988,22 +2662,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) +
@@ -3013,12 +2687,7 @@ String *Item_func_maketime::val_str(String *str)
NullS);
}
- if (make_time_with_warn((DATE_TIME_FORMAT *) 0, &ltime, str))
- {
- null_value= 1;
- return 0;
- }
- return str;
+ return 0;
}
@@ -3049,8 +2718,8 @@ longlong Item_func_timestamp_diff::val_int()
int neg= 1;
null_value= 0;
- if (args[0]->get_date(&ltime1, TIME_NO_ZERO_DATE) ||
- args[1]->get_date(&ltime2, TIME_NO_ZERO_DATE))
+ if (args[0]->get_date(&ltime1, TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE) ||
+ args[1]->get_date(&ltime2, TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE))
goto null_date;
if (calc_time_diff(&ltime2,&ltime1, 1,
@@ -3300,9 +2969,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)
@@ -3319,40 +2988,39 @@ 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_format_type= DATE_TIME;
cached_field_type= MYSQL_TYPE_DATETIME;
- max_length= MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
- cached_timestamp_type= MYSQL_TIMESTAMP_NONE;
+ decimals= NOT_FIXED_DEC;
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:
- cached_timestamp_type= MYSQL_TIMESTAMP_TIME;
+ decimals= 6;
+ /* fall through */
+ case TIME_ONLY:
cached_field_type= MYSQL_TYPE_TIME;
- max_length= MAX_TIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN;
break;
- default:
- cached_timestamp_type= MYSQL_TIMESTAMP_DATETIME;
+ case DATE_TIME_MICROSECOND:
+ decimals= 6;
+ /* fall through */
+ case DATE_TIME:
cached_field_type= MYSQL_TYPE_DATETIME;
break;
}
}
}
+ cached_timestamp_type= mysql_type_to_time_type(cached_field_type);
+ Item_temporal_func::fix_length_and_dec();
}
@@ -3361,21 +3029,19 @@ bool Item_func_str_to_date::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
DATE_TIME_FORMAT date_time_format;
char val_buff[64], format_buff[64];
String val_string(val_buff, sizeof(val_buff), &my_charset_bin), *val;
- String format_str(format_buff, sizeof(format_buff), &my_charset_bin), *format;
+ String format_str(format_buff, sizeof(format_buff), &my_charset_bin),
+ *format;
val= args[0]->val_str(&val_string);
format= args[1]->val_str(&format_str);
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)
{
@@ -3387,6 +3053,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:
@@ -3394,22 +3061,6 @@ null_date:
}
-String *Item_func_str_to_date::val_str(String *str)
-{
- DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
-
- if (Item_func_str_to_date::get_date(&ltime, TIME_FUZZY_DATE))
- return 0;
-
- if (!make_datetime((const_item ? cached_format_type :
- (ltime.second_part ? DATE_TIME_MICROSECOND : DATE_TIME)),
- &ltime, str))
- return str;
- return 0;
-}
-
-
bool Item_func_last_day::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
{
if (get_arg0_date(ltime, fuzzy_date & ~TIME_FUZZY_DATE) ||
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
index 27c3401a6a9..d9559794c00 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -358,15 +358,38 @@ 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)
@@ -376,11 +399,6 @@ public:
{
return !has_timestamp_args();
}
- void fix_length_and_dec()
- {
- decimals=0;
- max_length=10*MY_CHARSET_BIN_MB_MAXLEN;
- }
bool check_vcol_func_processor(uchar *int_arg)
{
/*
@@ -389,20 +407,21 @@ public:
*/
return trace_unsupported_by_check_vcol_func_processor(func_name());
}
+ longlong int_op();
+ double real_op();
};
-class Item_func_time_to_sec :public Item_int_func
+
+class Item_func_time_to_sec :public Item_func_seconds_hybrid
{
public:
- Item_func_time_to_sec(Item *item) :Item_int_func(item) {}
- longlong val_int();
+ Item_func_time_to_sec(Item *item) :Item_func_seconds_hybrid(item) {}
const char *func_name() const { return "time_to_sec"; }
- void fix_length_and_dec()
+ void fix_num_length_and_dec()
{
- maybe_null= TRUE;
- decimals=0;
- max_length=10*MY_CHARSET_BIN_MB_MAXLEN;
+ maybe_null= true;
+ Item_func_seconds_hybrid::fix_num_length_and_dec();
}
bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
bool check_vcol_func_processor(uchar *int_arg) { return FALSE;}
@@ -410,126 +429,101 @@ public:
{
return !has_time_args();
}
+ longlong int_op();
+ double real_op();
};
-/*
- 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; }
+ bool get_time(MYSQL_TIME *res);
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); }
+ 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;
+ }
+ }
+ /*
+ We set maybe_null to 1 as default as any bad argument with date or
+ time can get us to return NULL.
+ */
+ maybe_null= 1;
}
};
-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); }
};
-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);
- }
- 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);
- void fix_length_and_dec();
+ Item_func_curtime(uint dec) :Item_timefunc() { decimals= dec; }
+ bool fix_fields(THD *, Item **);
+ void fix_length_and_dec()
+ {
+ store_now_in_TIME(&ltime);
+ Item_timefunc::fix_length_and_dec();
+ maybe_null= 0;
+ }
+ 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; }
bool check_vcol_func_processor(uchar *int_arg)
{
return trace_unsupported_by_check_vcol_func_processor(func_name());
@@ -540,8 +534,7 @@ public:
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);
};
@@ -550,8 +543,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);
};
@@ -559,14 +551,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;
@@ -597,21 +586,19 @@ 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);
- void fix_length_and_dec();
+ Item_func_now(uint dec) :Item_temporal_func() { decimals= dec; }
+ bool fix_fields(THD *, Item **);
+ void fix_length_and_dec()
+ {
+ store_now_in_TIME(&ltime);
+ Item_temporal_func::fix_length_and_dec();
+ maybe_null= 0;
+ }
bool get_date(MYSQL_TIME *res, uint fuzzy_date);
virtual void store_now_in_TIME(MYSQL_TIME *now_time)=0;
bool check_vcol_func_processor(uchar *int_arg)
@@ -624,8 +611,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; }
@@ -635,8 +621,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);
};
@@ -649,16 +634,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()
{
@@ -668,10 +647,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;}
@@ -700,13 +679,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);
@@ -727,7 +704,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
@@ -739,9 +716,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);
@@ -749,29 +724,22 @@ 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
{
+ bool sec_to_time(my_decimal *seconds, MYSQL_TIME *ltime);
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;
+ 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;
@@ -780,12 +748,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);
@@ -846,184 +812,84 @@ 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;
+ 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_typecast(a), cast_length(length_arg), cast_cs(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;
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_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()
+ {
+ if (decimals == NOT_FIXED_DEC)
+ decimals= args[0]->decimals;
+ Item_temporal_func::fix_length_and_dec();
+ }
+};
+
+class Item_date_typecast :public Item_temporal_typecast
{
public:
- Item_date_typecast(Item *a) :Item_typecast_maybe_null(a) {}
+ 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;
- 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"; }
bool get_date(MYSQL_TIME *ltime, uint fuzzy_date);
- String *val_str(String *str);
- bool get_time(MYSQL_TIME *ltime);
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);
- }
- void fix_length_and_dec()
- {
- collation.set(&my_charset_bin);
- max_length= 17;
- maybe_null= 1;
- }
- 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)
- {
- return save_time_in_field(field);
- }
};
-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);
- }
- 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);
- }
+ bool get_date(MYSQL_TIME *ltime, uint fuzzy_date);
};
-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()
- {
- 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;
- }
- 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;
@@ -1031,63 +897,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();
- maybe_null= 1;
+ decimals= max(args[0]->decimals, args[1]->decimals);
+ Item_timefunc::fix_length_and_dec();
}
+ 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)
- {
- maybe_null= TRUE;
- }
- String *val_str(String *str);
+ :Item_timefunc(a, b, c)
+ {}
const char *func_name() const { return "maketime"; }
+ bool get_date(MYSQL_TIME *ltime, uint fuzzy_date);
};
+
class Item_func_microsecond :public Item_int_func
{
public:
@@ -1149,32 +991,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 1aeac1814af..56a3647ce97 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -396,7 +396,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,
@@ -478,8 +478,8 @@ 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(
+ 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) ||
@@ -543,7 +543,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
@@ -566,7 +565,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)
@@ -580,6 +579,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);
@@ -621,45 +625,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_timestamp((my_time_t)
- current_time);
+ ((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)
{
@@ -796,14 +789,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);
@@ -818,7 +811,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,
@@ -826,7 +819,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();
@@ -1035,8 +1029,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;
@@ -1056,16 +1048,12 @@ 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);
- }
- else
- {
- query_utime= lock_utime= 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)
{
@@ -1086,7 +1074,7 @@ 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,
user_host_buff, user_host_len,
query_utime, lock_utime, is_command,
query, query_length) || error;
@@ -1104,7 +1092,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);
@@ -1121,7 +1109,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,
@@ -2367,7 +2355,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
@@ -2389,7 +2376,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 6437046b17b..3a6c484a55b 100644
--- a/sql/log.h
+++ b/sql/log.h
@@ -281,7 +281,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);
@@ -581,14 +581,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,
@@ -610,14 +610,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,
@@ -642,14 +642,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,
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 3219f770858..3dad0c87e00 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -713,7 +713,8 @@ Log_event::Log_event(THD* thd_arg, uint16 flags_arg, bool using_trans)
checksum_alg(BINLOG_CHECKSUM_ALG_UNDEF)
{
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;
}
@@ -735,7 +736,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 */
@@ -754,6 +756,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)
@@ -842,21 +845,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
}
@@ -1097,7 +1092,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
@@ -2020,6 +2015,7 @@ beg:
uint64 i64= uint8korr(ptr); /* YYYYMMDDhhmmss */
d= (ulong) (i64 / 1000000);
t= (ulong) (i64 % 1000000);
+
my_b_printf(file, "%04d-%02d-%02d %02d:%02d:%02d",
(int) (d / 10000), (int) (d % 10000) / 100, (int) (d % 100),
(int) (t / 10000), (int) (t % 10000) / 100, (int) t % 100);
@@ -2275,12 +2271,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,
@@ -2363,15 +2357,13 @@ 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;
-#ifdef MYSQL_SERVER // This is always false
- struct tm tm_tmp;
- localtime_r(ts,(res= &tm_tmp));
-#else
+ {
+ ts = &my_when;
+ }
res=localtime(ts);
-#endif
my_b_printf(file,"%02d%02d%02d %2d:%02d:%02d",
res->tm_year % 100,
@@ -2655,6 +2647,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
@@ -2748,7 +2749,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
@@ -2883,6 +2884,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;
@@ -3099,6 +3101,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 */
@@ -3178,7 +3188,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;
@@ -3205,6 +3215,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));
@@ -3466,7 +3481,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();
@@ -3913,7 +3928,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(); // this sets when and when_sec_part as a side effect
int4store(buff + ST_CREATED_OFFSET,created);
return (write_header(file, sizeof(buff)) ||
wrapper_my_b_safe_write(file, (uchar*) buff, sizeof(buff)) ||
@@ -4337,7 +4352,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,
@@ -5145,7 +5160,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));
@@ -7991,7 +8006,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 53fc8f986b4..4053db4e3e7 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -267,6 +267,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 */ \
@@ -338,6 +339,8 @@ struct sql_ex_info
#define Q_INVOKER 11
+#define Q_HRNOW 128
+
/* Intvar event post-header */
/* Intvar event data */
@@ -920,7 +923,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 */
@@ -1071,16 +1075,28 @@ 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;
+ }
+ /* thd will only be 0 here at time of log creation */
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_my_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 1c46e31d128..06ad5cc3f93 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
@@ -1660,7 +1660,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 36cbbe71f80..29b6aa88740 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -830,9 +830,95 @@ typedef my_bool (*qc_engine_callback)(THD *thd, char *table_key,
uint key_length,
ulonglong *engine_data);
#include "sql_string.h"
+#include "my_decimal.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_to(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_to(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_to(String *dst) const { dst->set(num, &my_charset_bin); }
+};
+
+class Lazy_string_decimal : public Lazy_string
+{
+ my_decimal num;
+public:
+ Lazy_string_decimal(my_decimal num_arg) : Lazy_string(), num(num_arg)
+ {
+ num.fix_buffer_pointer();
+ }
+ void copy_to(String *dst) const
+ {
+ my_decimal2string(E_DEC_FATAL_ERROR, &num, 0, 0, '0', dst);
+ }
+};
+
+class Lazy_string_double: public Lazy_string
+{
+ double num;
+public:
+ Lazy_string_double(double num_arg) : Lazy_string(), num(num_arg) {}
+ void copy_to(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_to(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);
+ }
+};
+
+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"
#include "handler.h"
#include "parse_file.h"
#include "table.h"
@@ -856,6 +942,7 @@ typedef Comp_creator* (*chooser_compare_func_creator)(bool invert);
#endif
#include "item.h"
extern my_decimal decimal_zero;
+extern my_decimal max_seconds_for_time_type, time_second_part_factor;
/* sql_parse.cc */
void free_items(Item *item);
@@ -2357,7 +2444,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);
bool str_to_time_with_warn(const char *str,uint length,MYSQL_TIME *l_time,
ulong fuzzydate);
timestamp_type str_to_datetime_with_warn(const char *str, uint length,
@@ -2367,14 +2454,23 @@ 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);
bool double_to_datetime_with_warn(double value, MYSQL_TIME *ltime,
ulong fuzzy_date);
bool decimal_to_datetime_with_warn(decimal_t *value, MYSQL_TIME *ltime,
ulong fuzzy_date);
+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 9fb9e2bd1c9..9ab78bf3543 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -151,6 +151,7 @@ static event_handle_t eh;
static Report_t ref;
static void *refneb= NULL;
my_bool event_flag= FALSE;
+
static int volumeid= -1;
/* NEB event callback */
@@ -433,12 +434,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 };
@@ -457,6 +459,13 @@ static my_bool opt_debugging= 0, opt_external_locking= 0, opt_console= 0;
static my_bool opt_short_log_format= 0;
static my_bool opt_ignore_wrong_options= 0, opt_expect_abort= 0;
static my_bool opt_sync= 0, opt_thread_alarm;
+/*
+ Set this to 1 if you want to that 'strict mode' should affect all date
+ operations. If this is 0, then date checking is only done when storing
+ dates into a table.
+*/
+my_bool strict_date_checking= 0;
+
static uint kill_cached_threads, wake_thread;
ulong thread_created;
uint thread_handling;
@@ -710,6 +719,8 @@ const char *in_additional_cond= "<IN COND>";
const char *in_having_cond= "<IN HAVING>";
my_decimal decimal_zero;
+my_decimal max_seconds_for_time_type, time_second_part_factor;
+
/* classes for comparation parsing/processing */
Eq_creator eq_creator;
Ne_creator ne_creator;
@@ -2112,7 +2123,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);
}
@@ -3469,7 +3480,6 @@ static int init_common_variables(const char *conf_file_name, int argc,
char buff[FN_REFLEN], *s;
const char *basename;
umask(((~my_umask) & 0666));
- my_decimal_set_zero(&decimal_zero); // set decimal_zero constant;
tzset(); // Set tzname
max_system_variables.pseudo_thread_id= (ulong)~0;
@@ -5183,9 +5193,9 @@ void handle_connection_in_main_thread(THD *thd)
safe_mutex_assert_owner(&LOCK_thread_count);
thread_cache_size=0; // Safety
threads.append(thd);
- thd->start_utime= my_micro_time();
+ thd->set_time(my_hrtime());
pthread_mutex_unlock(&LOCK_thread_count);
- thd->start_utime= my_micro_time();
+ thd->start_utime= microsecond_interval_timer();
handle_one_connection(thd);
}
@@ -5211,7 +5221,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)))
@@ -8503,6 +8513,13 @@ static int mysql_init_variables(void)
/* set key_cache_hash.default_value = dflt_key_cache */
multi_keycache_init();
+ /* Useful MariaDB variables */
+ double2decimal((double) TIME_MAX_VALUE_SECONDS +
+ TIME_MAX_SECOND_PART/(double)TIME_SECOND_PART_FACTOR,
+ &max_seconds_for_time_type);
+ longlong2decimal(TIME_SECOND_PART_FACTOR, &time_second_part_factor);
+ my_decimal_set_zero(&decimal_zero); // set decimal_zero constant;
+
/* Set directory paths */
strmake(language, LANGUAGE, sizeof(language)-1);
strmake(mysql_real_data_home, get_relative_path(MYSQL_DATADIR),
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 13afffd6ba9..fba2fb7d7c0 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -7392,7 +7392,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");
@@ -7560,16 +7559,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)
{
@@ -7581,7 +7572,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
@@ -7615,10 +7605,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;
- }
}
}
@@ -7641,12 +7628,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/opt_subselect.cc b/sql/opt_subselect.cc
index dfb7e8abfa1..6f980695020 100644
--- a/sql/opt_subselect.cc
+++ b/sql/opt_subselect.cc
@@ -356,29 +356,27 @@ bool subquery_types_allow_materialization(Item_in_subselect *in_subs)
Item *inner= it++;
all_are_fields &= (outer->real_item()->type() == Item::FIELD_ITEM &&
inner->real_item()->type() == Item::FIELD_ITEM);
- if (outer->result_type() != inner->result_type())
+ if (outer->cmp_type() != inner->cmp_type())
DBUG_RETURN(FALSE);
- switch (outer->result_type()) {
+ switch (outer->cmp_type()) {
case STRING_RESULT:
- if (outer->is_datetime() != inner->is_datetime())
+ if (!(outer->collation.collation == inner->collation.collation))
DBUG_RETURN(FALSE);
-
- if (!(outer->collation.collation == inner->collation.collation
- /*&& outer->max_length <= inner->max_length */))
+ // Materialization does not work with BLOB columns
+ if (inner->field_type() == MYSQL_TYPE_BLOB ||
+ inner->field_type() == MYSQL_TYPE_GEOMETRY)
+ DBUG_RETURN(FALSE);
+ break;
+ case TIME_RESULT:
+ if (mysql_type_to_time_type(outer->field_type()) !=
+ mysql_type_to_time_type(outer->field_type()))
DBUG_RETURN(FALSE);
- /*case INT_RESULT:
- if (!(outer->unsigned_flag ^ inner->unsigned_flag))
- DBUG_RETURN(FALSE); */
default:
- ;/* suitable for materialization */
+ /* suitable for materialization */
+ break;
}
-
- // Materialization does not work with BLOB columns
- if (inner->field_type() == MYSQL_TYPE_BLOB ||
- inner->field_type() == MYSQL_TYPE_GEOMETRY)
- DBUG_RETURN(FALSE);
}
-
+
in_subs->types_allow_materialization= TRUE;
in_subs->sjm_scan_allowed= all_are_fields;
DBUG_PRINT("info",("subquery_types_allow_materialization: ok, allowed"));
@@ -2746,7 +2744,6 @@ TABLE *create_duplicate_weedout_tmp_table(THD *thd,
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= NULL;
share->primary_key= MAX_KEY; // Indicate no primary key
share->keys_for_keyread.init();
diff --git a/sql/protocol.cc b/sql/protocol.cc
index 4a3220b96fc..a0e14423b73 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -1041,13 +1041,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 ||
@@ -1055,18 +1049,8 @@ bool Protocol_text::store(MYSQL_TIME *tm)
field_types[field_pos] == MYSQL_TYPE_TIMESTAMP);
field_pos++;
#endif
- char buff[40];
- uint length;
- length= my_sprintf(buff,(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+= my_sprintf(buff+length,(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);
}
@@ -1084,29 +1068,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= my_sprintf(buff,(buff, "%s%02ld:%02d:%02d",
- tm->neg ? "-" : "",
- (long) day*24L+(long) tm->hour,
- (int) tm->minute,
- (int) tm->second));
- if (tm->second_part)
- length+= my_sprintf(buff+length,(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);
}
@@ -1263,7 +1233,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;
@@ -1276,6 +1246,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 <= 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);
if (tm->second_part)
length=11;
@@ -1293,11 +1267,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;
@@ -1306,7 +1280,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;
@@ -1315,6 +1288,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 <= 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);
if (tm->second_part)
length=12;
diff --git a/sql/protocol.h b/sql/protocol.h
index 3eb5091a7c7..4ab5c169928 100644
--- a/sql/protocol.h
+++ b/sql/protocol.h
@@ -91,9 +91,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();
@@ -130,9 +130,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);
@@ -165,9 +165,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_record.cc b/sql/rpl_record.cc
index 35e283a886e..d07aeddc5b9 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,
@@ -269,7 +269,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_rli.cc b/sql/rpl_rli.cc
index c11bd268256..c88a0908356 100644
--- a/sql/rpl_rli.cc
+++ b/sql/rpl_rli.cc
@@ -1175,11 +1175,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/rpl_utility.cc b/sql/rpl_utility.cc
index c301dabcdb7..68dd0e13c25 100644
--- a/sql/rpl_utility.cc
+++ b/sql/rpl_utility.cc
@@ -135,7 +135,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/set_var.cc b/sql/set_var.cc
index 53205c48a1d..aac6746da82 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -2911,38 +2911,37 @@ int set_var_collation_client::update(THD *thd)
bool sys_var_timestamp::check(THD *thd, set_var *var)
{
- longlong val;
- var->save_result.ulonglong_value= var->value->val_int();
- val= (longlong) var->save_result.ulonglong_value;
- if (val != 0 && // this is how you set the default value
- (val < TIMESTAMP_MIN_VALUE || val > TIMESTAMP_MAX_VALUE))
+ double val= var->value->val_real();
+ if (val < 0 || val > MY_TIME_T_MAX)
{
char buf[64];
my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), "timestamp", llstr(val, buf));
return TRUE;
}
+ var->save_result.ulonglong_value= hrtime_from_time(val);
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;
}
@@ -3195,7 +3194,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
@@ -3241,10 +3240,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 d2bb1e94d33..c591ab5b866 100644
--- a/sql/set_var.h
+++ b/sql/set_var.h
@@ -680,8 +680,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 4e8d416ac25..b0989388028 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 '%-.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 %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 '%-.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')"
@@ -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/slave.cc b/sql/slave.cc
index 4f3b0370744..cfa6c9fdc56 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -2260,7 +2260,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_my_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 dbaeb9467ae..8f9ff5512c5 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 17fffffa227..cf52b4008f3 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -663,7 +663,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),
@@ -705,7 +705,7 @@ THD::THD()
main_security_ctx.init();
security_ctx= &main_security_ctx;
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;
@@ -722,7 +722,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;
@@ -986,7 +986,6 @@ void THD::update_stats(void)
void THD::update_all_stats()
{
- time_t save_time;
ulonglong end_cpu_time, end_utime;
double busy_time, cpu_time;
@@ -995,8 +994,8 @@ void THD::update_all_stats()
return;
end_cpu_time= my_getcputime();
- end_utime= my_micro_time_and_time(&save_time);
- busy_time= (end_utime - start_utime) / 1000000.0;
+ end_utime= microsecond_interval_timer();
+ busy_time= (end_utime - start_utime) / 1000000.0;
cpu_time= (end_cpu_time - start_cpu_time) / 10000000.0;
/* In case there are bad values, 2629743 is the #seconds in a month. */
if (cpu_time > 2629743.0)
@@ -1004,7 +1003,8 @@ void THD::update_all_stats()
status_var_add(status_var.cpu_time, cpu_time);
status_var_add(status_var.busy_time, busy_time);
- update_global_user_stats(this, TRUE, save_time);
+ update_global_user_stats(this, TRUE, my_time(0));
+ // Has to be updated after update_global_user_stats()
userstat_running= 0;
}
@@ -2564,6 +2564,7 @@ int select_max_min_finder_subselect::send_data(List<Item> &items)
op= &select_max_min_finder_subselect::cmp_decimal;
break;
case ROW_RESULT:
+ case TIME_RESULT:
case IMPOSSIBLE_RESULT:
// This case should never be choosen
DBUG_ASSERT(0);
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 958e16b9361..23541f20b09 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1525,7 +1525,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;
@@ -1549,7 +1548,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;
@@ -1984,6 +1985,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;
@@ -2044,6 +2046,7 @@ public:
long long_value;
ulong ulong_value;
ulonglong ulonglong_value;
+ double double_value;
} sys_var_tmp;
struct {
@@ -2182,30 +2185,41 @@ 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_current_time()
+ {
+ my_hrtime_t hrtime= my_hrtime();
+ start_time= hrtime_to_my_time(hrtime);
+ start_time_sec_part= hrtime_sec_part(hrtime);
+ }
inline void set_time()
{
- if (user_time)
+ if (user_time.val)
{
- start_time= user_time;
- start_utime= utime_after_lock= my_micro_time();
+ start_time= hrtime_to_my_time(user_time);
+ start_time_sec_part= hrtime_sec_part(user_time);
}
else
- start_utime= utime_after_lock= my_micro_time_and_time(&start_time);
+ set_current_time();
+ start_utime= utime_after_lock= microsecond_interval_timer();
}
- inline void set_current_time() { start_time= my_time(MY_WME); }
- inline void set_time(time_t t)
+ inline void set_time(my_hrtime_t t)
{
- start_time= user_time= t;
- start_utime= utime_after_lock= my_micro_time();
+ 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= microsecond_interval_timer();
}
- /*TODO: this will be obsolete when we have support for 64 bit my_time_t */
- inline bool is_valid_time()
- {
- return (IS_TIME_T_VALID_FOR_TIMESTAMP(start_time));
+ 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;
@@ -2642,6 +2656,27 @@ my_eof(THD *thd)
/*
+ These functions are for making it later easy to add strict
+ checking for all date handling.
+*/
+
+extern my_bool strict_date_checking;
+
+inline ulong sql_mode_for_dates(THD *thd)
+{
+ if (unlikely(strict_date_checking))
+ return (thd->variables.sql_mode &
+ (MODE_NO_ZERO_DATE | MODE_NO_ZERO_IN_DATE |
+ MODE_INVALID_DATES));
+ return (thd->variables.sql_mode & MODE_INVALID_DATES);
+}
+
+inline ulong sql_mode_for_dates()
+{
+ return sql_mode_for_dates(current_thd);
+}
+
+/*
Used to hold information about file and file structure in exchange
via non-DB file (...INTO OUTFILE..., ...LOAD DATA...)
XXX: We never call destructor for objects of this class.
diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc
index def0c8dd951..05e33826da9 100644
--- a/sql/sql_connect.cc
+++ b/sql/sql_connect.cc
@@ -1121,7 +1121,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_insert.cc b/sql/sql_insert.cc
index bd28ab6e9b2..65066a878ee 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -1730,10 +1730,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;
@@ -2234,8 +2235,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
@@ -2693,6 +2696,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).
@@ -3590,9 +3595,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= 0;
tmp_table.maybe_null= 0;
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index a1a654264a5..f73ddf920bf 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1021,18 +1021,6 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
thd->query_plan_flags= QPLAN_INIT;
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;
@@ -1435,10 +1423,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)
@@ -5792,6 +5777,7 @@ void mysql_reset_thd_for_next_command(THD *thd, my_bool calculate_userstat)
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
@@ -6251,17 +6237,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 2b478508170..85a97386712 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -491,8 +491,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_profile.cc b/sql/sql_profile.cc
index 7bfb127815d..5d5cb6a764e 100644
--- a/sql/sql_profile.cc
+++ b/sql/sql_profile.cc
@@ -235,7 +235,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);
#elif defined(__WIN__)
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 66be0a2e4c2..24f7ff129b1 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -3704,30 +3704,21 @@ add_key_field(JOIN *join,
(*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
+ 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 (!eq_func)
return;
- if (field->result_type() == STRING_RESULT)
+
+ if (field->cmp_type() == STRING_RESULT)
{
- if ((*value)->result_type() != STRING_RESULT)
- {
- if (field->cmp_type() != (*value)->result_type())
+ if ((*value)->cmp_type() != STRING_RESULT)
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())
- return;
- }
+ if (((Field_str*)field)->charset() != cond->compare_collation())
+ return;
}
}
}
@@ -3856,7 +3847,6 @@ is_local_field (Item *field)
The primary reason for having and_level attribute is the OR operation which
uses and_level to mark KEY_FIELDs that should get into the result of the OR
operation
-
*/
static void
@@ -11555,36 +11545,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. <expr> == <const>).
- Arguments must be of the same type because e.g.
- <string_field> = <int_const> 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. <expr> == <const>).
+ Arguments must be of the same type because e.g.
+ <string_field> = <int_const> 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 */
- (Arg_comparator::can_compare_as_dates(l, r, 0) ||
- /* or of the same result type */
+ /* the field is a date (the const will be converted to a date) */
+ (l->cmp_type() == TIME_RESULT ||
+ /* 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 ||
@@ -11770,15 +11760,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
@@ -12240,7 +12227,6 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &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, MyISAM and Maria
share->table_charset= param->table_charset;
share->primary_key= MAX_KEY; // Indicate no primary key
share->keys_for_keyread.init();
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 18e5189f3ca..2eecae26506 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -2000,7 +2000,7 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond)
TABLE *table= tables->table;
CHARSET_INFO *cs= system_charset_info;
char *user;
- ulonglong unow= my_micro_time();
+ my_hrtime_t unow= my_hrtime();
DBUG_ENTER("fill_process_list");
user= thd->security_ctx->master_access & PROCESS_ACL ?
@@ -2058,8 +2058,10 @@ 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 */
- const ulonglong utime= tmp->start_utime ? unow - tmp->start_utime : 0;
- table->field[5]->store(utime / 1000000, TRUE);
+ const ulonglong utime= (tmp->start_time ?
+ (unow.val - tmp->start_time * HRTIME_RESOLUTION -
+ tmp->start_time_sec_part) : 0);
+ table->field[5]->store(utime / HRTIME_RESOLUTION, TRUE);
/* STATE */
#ifndef EMBEDDED_LIBRARY
val= (char*) (tmp->net.reading_or_writing ?
@@ -2096,7 +2098,7 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond)
pthread_mutex_unlock(&tmp->LOCK_thd_data);
/* TIME_MS */
- table->field[8]->store((double)(utime / 1000.0));
+ table->field[8]->store((double)(utime / (HRTIME_RESOLUTION / 1000.0)));
if (schema_table_store_record(thd, table))
{
@@ -4342,7 +4344,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);
@@ -4351,7 +4353,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].
@@ -4398,6 +4400,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:
@@ -4426,8 +4429,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;
}
@@ -4435,40 +4443,40 @@ 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);
if (field->vcol_info)
- table->field[16]->store(STRING_WITH_LEN("VIRTUAL"), cs);
+ table->field[17]->store(STRING_WITH_LEN("VIRTUAL"), 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);
}
@@ -6212,14 +6220,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:
@@ -6405,7 +6422,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;
@@ -6413,9 +6430,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);
@@ -6884,6 +6901,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_string.cc b/sql/sql_string.cc
index 6f40d797a5c..56702a2308f 100644
--- a/sql/sql_string.cc
+++ b/sql/sql_string.cc
@@ -577,7 +577,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 e4cce7b5527..61198af1261 100644
--- a/sql/sql_string.h
+++ b/sql/sql_string.h
@@ -343,7 +343,7 @@ public:
friend String *copy_if_not_alloced(String *a,String *b,uint32 arg_length);
friend class Field;
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/sql_table.cc b/sql/sql_table.cc
index c857fb3de8c..d9d36c260fd 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -36,17 +36,15 @@ const char *primary_key_name="PRIMARY";
static bool check_if_keyname_exists(const char *name,KEY *start, KEY *end);
static char *make_unique_key_name(const char *field_name,KEY *start,KEY *end);
-static int copy_data_between_tables(TABLE *from,TABLE *to,
- List<Create_field> &create, bool ignore,
- uint order_num, ORDER *order,
- ha_rows *copied,ha_rows *deleted,
- enum enum_enable_or_disable keys_onoff,
- bool error_if_not_empty);
+static int copy_data_between_tables(TABLE *,TABLE *, List<Create_field> &, bool,
+ uint, ORDER *, ha_rows *,ha_rows *,
+ enum enum_enable_or_disable, bool);
static bool prepare_blob_field(THD *thd, Create_field *sql_field);
static bool check_engine(THD *, const char *, HA_CREATE_INFO *);
static int mysql_prepare_create_table(THD *, HA_CREATE_INFO *, Alter_info *,
- bool, uint *, handler *, KEY **, uint *, int);
+ bool, uint *, handler *, KEY **, uint *,
+ int);
static bool mysql_prepare_alter_table(THD *, TABLE *, HA_CREATE_INFO *,
Alter_info *);
static bool admin_recreate_table(THD *thd, TABLE_LIST *table_list);
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 71dcd637d64..8173fdd60f2 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -682,10 +682,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.
@@ -1348,6 +1348,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
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
optional_flush_tables_arguments opt_dyncol_type dyncol_type
+ opt_time_precision
%type <ulong_num>
ulong_num real_ulong_num merge_insert_types
@@ -2083,7 +2084,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;
@@ -5215,7 +5216,7 @@ type:
{ $$=MYSQL_TYPE_YEAR; }
| DATE_SYM
{ $$=MYSQL_TYPE_DATE; }
- | TIME_SYM
+ | TIME_SYM opt_field_length
{ $$=MYSQL_TYPE_TIME; }
| TIMESTAMP opt_field_length
{
@@ -5230,7 +5231,7 @@ type:
$$=MYSQL_TYPE_TIMESTAMP;
}
}
- | DATETIME
+ | DATETIME opt_field_length
{ $$=MYSQL_TYPE_DATETIME; }
| TINYBLOB
{
@@ -5423,9 +5424,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;
@@ -5495,9 +5496,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;
}
@@ -7104,6 +7105,12 @@ select_alias:
| TEXT_STRING_sys { $$=$1; }
;
+opt_time_precision:
+ /* empty */ { $$= 0; }
+ | '(' ')' { $$= 0; }
+ | '(' real_ulong_num ')' { $$= $2; };
+ ;
+
optional_braces:
/* empty */ {}
| '(' ')' {}
@@ -7591,19 +7598,21 @@ dyncol_type:
lex->charset= NULL;
lex->length= lex->dec= 0;
}
- | TIME_SYM
+ | TIME_SYM opt_field_length
{
LEX *lex= Lex;
$$= DYN_COL_TIME;
lex->charset= NULL;
- lex->length= lex->dec= 0;
+ lex->dec= lex->length;
+ lex->length= 0;
}
- | DATETIME
+ | DATETIME opt_field_length
{
LEX *lex= Lex;
$$= DYN_COL_DATETIME;
lex->charset= NULL;
- lex->length= lex->dec= 0;
+ lex->dec= lex->length;
+ lex->length= 0;
}
;
@@ -7907,13 +7916,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;
}
@@ -8020,16 +8029,9 @@ function_call_nonkeyword:
MYSQL_YYABORT;
Lex->safe_to_cache_query=0;
}
- | CURTIME optional_braces
+ | CURTIME opt_time_precision
{
- $$= new (YYTHD->mem_root) Item_func_curtime_local();
- if ($$ == NULL)
- MYSQL_YYABORT;
- Lex->safe_to_cache_query=0;
- }
- | CURTIME '(' expr ')'
- {
- $$= 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;
@@ -8060,16 +8062,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;
@@ -8117,7 +8112,7 @@ function_call_nonkeyword:
if ($$ == NULL)
MYSQL_YYABORT;
}
- | SYSDATE optional_braces
+ | SYSDATE opt_time_precision
{
/*
Unlike other time-related functions, SYSDATE() is
@@ -8128,19 +8123,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;
@@ -8164,16 +8149,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;
@@ -8836,10 +8821,18 @@ 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 *lex= Lex;
+ lex->charset= NULL; lex->dec= lex->length; lex->length= (char*)0;
+ }
+ | DATETIME opt_field_length
+ {
+ $$=ITEM_CAST_DATETIME;
+ LEX *lex= Lex;
+ lex->charset= NULL; lex->dec= lex->length; lex->length= (char*)0;
+ }
| DECIMAL_SYM float_options
{ $$=ITEM_CAST_DECIMAL; Lex->charset= NULL; }
| DOUBLE_SYM
diff --git a/sql/table.cc b/sql/table.cc
index 96a64cdeba2..0451c47eeb8 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -776,8 +776,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);
@@ -1696,7 +1694,6 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
share->can_cmp_whole_record= (share->blob_fields == 0 &&
share->varchar_fields == 0);
- 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,
@@ -1994,7 +1991,12 @@ bool unpack_vcol_info_from_frm(THD *thd,
vcol_arena= table->expr_arena;
if (!vcol_arena)
{
- Query_arena expr_arena(&table->mem_root, Query_arena::INITIALIZED);
+ /*
+ We need to use CONVENTIONAL_EXECUTION here to ensure that
+ any new items created by fix_fields() are not reverted.
+ */
+ Query_arena expr_arena(&table->mem_root,
+ Query_arena::CONVENTIONAL_EXECUTION);
if (!(vcol_arena= (Query_arena *) alloc_root(&table->mem_root,
sizeof(Query_arena))))
goto err;
diff --git a/sql/table.h b/sql/table.h
index ca4e50d99e1..4278c3c9c35 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -440,7 +440,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/time.cc b/sql/time.cc
index a3b78eb5e62..60cf4631b6f 100644
--- a/sql/time.cc
+++ b/sql/time.cc
@@ -1,4 +1,5 @@
/* Copyright (C) 2000-2006 MySQL AB
+ Copyright (c) 2009-2011 Monty Program Ab
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -230,14 +231,12 @@ str_to_datetime_with_warn(const char *str, uint length, MYSQL_TIME *l_time,
timestamp_type ts_type;
ts_type= str_to_datetime(str, length, l_time,
- (flags | (thd->variables.sql_mode &
- (MODE_INVALID_DATES |
- MODE_NO_ZERO_IN_DATE |
- MODE_NO_ZERO_DATE))),
+ (flags | (sql_mode_for_dates(thd))),
&was_cut);
if (was_cut || ts_type <= MYSQL_TIMESTAMP_ERROR)
make_truncated_value_warning(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;
}
@@ -269,37 +268,45 @@ bool decimal_to_datetime_with_warn(decimal_t *value, MYSQL_TIME *ltime,
}
/*
- Convert a datetime from broken-down MYSQL_TIME representation to corresponding
- TIMESTAMP value.
+ Convert a datetime from broken-down MYSQL_TIME representation to
+ corresponding TIMESTAMP value.
SYNOPSIS
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);
- if (timestamp)
+ timestamp= thd->variables.time_zone->TIME_to_gmt_sec(t, &in_dst_time_gap);
+
+ /* In case of error, timestamp == 0 and in_dst_time_gap is != 0 */
+ if (timestamp || ! in_dst_time_gap)
{
+ 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;
}
@@ -309,13 +316,19 @@ my_time_t TIME_to_timestamp(THD *thd, const MYSQL_TIME *t, my_bool *in_dst_time_
NOTE
See str_to_time() for more info.
+
+ RETURN
+ 0 ok
+ 1 wrong time value
*/
+
bool
str_to_time_with_warn(const char *str, uint length, MYSQL_TIME *l_time,
ulong fuzzydate)
{
int warning;
- bool ret_val= str_to_time(str, length, l_time, fuzzydate, &warning);
+ bool ret_val= (str_to_time(str, length, l_time, fuzzydate, &warning) ==
+ MYSQL_TIMESTAMP_ERROR);
if (ret_val || warning)
make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
str, length, MYSQL_TIMESTAMP_TIME, NullS);
@@ -715,15 +728,14 @@ 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());
+ 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);
}
@@ -732,6 +744,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);
@@ -741,7 +754,8 @@ 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());
+ 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);
}
@@ -749,8 +763,8 @@ void make_datetime(const DATE_TIME_FORMAT *format __attribute__((unused)),
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];
@@ -758,8 +772,7 @@ void make_truncated_value_warning(THD *thd,
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_to(&str);
switch (time_type) {
case MYSQL_TIMESTAMP_DATE:
@@ -776,17 +789,17 @@ void make_truncated_value_warning(THD *thd,
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);
@@ -795,14 +808,17 @@ void make_truncated_value_warning(THD *thd,
/* 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)
+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:
@@ -819,35 +835,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 (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= usec/1000000/24/60/60;
+
/* Day number from year 0 to 9999-12-31 */
if ((ulonglong) daynr > MAX_DAY_NUMBER)
goto invalid_date;
@@ -855,7 +865,6 @@ bool date_add_interval(MYSQL_TIME *ltime, interval_type int_type, INTERVAL inter
&ltime->day);
break;
}
- case INTERVAL_DAY:
case INTERVAL_WEEK:
period= (calc_daynr(ltime->year,ltime->month,ltime->day) +
sign * (long) interval.day);
@@ -999,19 +1008,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/tztime.cc b/sql/tztime.cc
index 25b3b0c8994..1334d872510 100644
--- a/sql/tztime.cc
+++ b/sql/tztime.cc
@@ -214,7 +214,7 @@ tz_load(const char *name, TIME_ZONE_INFO *sp, MEM_ROOT *storage)
ALIGN_SIZE(sp->typecnt *
sizeof(TRAN_TYPE_INFO)) +
#ifdef ABBR_ARE_USED
- ALIGN_SIZE(sp->charcnt) +
+ ALIGN_SIZE(sp->charcnt+1) +
#endif
sp->leapcnt * sizeof(LS_INFO))))
return 1;
@@ -227,7 +227,7 @@ tz_load(const char *name, TIME_ZONE_INFO *sp, MEM_ROOT *storage)
tzinfo_buf+= ALIGN_SIZE(sp->typecnt * sizeof(TRAN_TYPE_INFO));
#ifdef ABBR_ARE_USED
sp->chars= tzinfo_buf;
- tzinfo_buf+= ALIGN_SIZE(sp->charcnt);
+ tzinfo_buf+= ALIGN_SIZE(sp->charcnt+1);
#endif
sp->lsis= (LS_INFO *)tzinfo_buf;
@@ -877,8 +877,9 @@ sec_since_epoch(int year, int mon, int mday, int hour, int min ,int sec)
RETURN VALUE
Seconds in UTC since Epoch.
- 0 in case of error.
+ 0 in case of error. In this case *in_dst_time_gap is also set
*/
+
static my_time_t
TIME_to_gmt_sec(const MYSQL_TIME *t, const TIME_ZONE_INFO *sp,
my_bool *in_dst_time_gap)
@@ -887,12 +888,14 @@ TIME_to_gmt_sec(const MYSQL_TIME *t, const TIME_ZONE_INFO *sp,
uint saved_seconds;
uint i;
int shift= 0;
-
DBUG_ENTER("TIME_to_gmt_sec");
+ *in_dst_time_gap= 0;
if (!validate_timestamp_range(t))
+ {
+ *in_dst_time_gap= 1; // Mark error
DBUG_RETURN(0);
-
+ }
/* We need this for correct leap seconds handling */
if (t->second < SECS_PER_MIN)
@@ -936,6 +939,7 @@ TIME_to_gmt_sec(const MYSQL_TIME *t, const TIME_ZONE_INFO *sp,
This means that source time can't be represented as my_time_t due to
limited my_time_t range.
*/
+ *in_dst_time_gap= 1; // Mark error
DBUG_RETURN(0);
}
@@ -952,6 +956,7 @@ TIME_to_gmt_sec(const MYSQL_TIME *t, const TIME_ZONE_INFO *sp,
if (local_t > (my_time_t) (TIMESTAMP_MAX_VALUE - shift * SECS_PER_DAY +
sp->revtis[i].rt_offset - saved_seconds))
{
+ *in_dst_time_gap= 1; // Mark error
DBUG_RETURN(0); /* my_time_t overflow */
}
local_t+= shift * SECS_PER_DAY;
@@ -973,7 +978,10 @@ TIME_to_gmt_sec(const MYSQL_TIME *t, const TIME_ZONE_INFO *sp,
/* check for TIMESTAMP_MAX_VALUE was already done above */
if (local_t < TIMESTAMP_MIN_VALUE)
+ {
local_t= 0;
+ *in_dst_time_gap= 1; // Mark error
+ }
DBUG_RETURN(local_t);
}
@@ -1336,24 +1344,31 @@ Time_zone_offset::Time_zone_offset(long tz_offset_arg):
datetime value passed doesn't really exist
(i.e. falls into spring time-gap) and is not
touched otherwise.
- It is not really used in this class.
+ It is not really used in this class, except
+ for indicating error
RETURN VALUE
- Corresponding my_time_t value or 0 in case of error
+ Corresponding my_time_t value or 0 in case of error. In case of error
+ *in_dst_time_gap is also set.
*/
+
my_time_t
-Time_zone_offset::TIME_to_gmt_sec(const MYSQL_TIME *t, my_bool *in_dst_time_gap) const
+Time_zone_offset::TIME_to_gmt_sec(const MYSQL_TIME *t,
+ my_bool *in_dst_time_gap) const
{
my_time_t local_t;
int shift= 0;
+ *in_dst_time_gap= 0; // Reset
/*
Check timestamp range.we have to do this as calling function relies on
us to make all validation checks here.
*/
if (!validate_timestamp_range(t))
+ {
+ *in_dst_time_gap= 1; // Mark error
return 0;
-
+ }
/*
Do a temporary shift of the boundary dates to avoid
overflow of my_time_t if the time value is near it's
@@ -1376,6 +1391,7 @@ Time_zone_offset::TIME_to_gmt_sec(const MYSQL_TIME *t, my_bool *in_dst_time_gap)
return local_t;
/* range error*/
+ *in_dst_time_gap= 1; // Mark error
return 0;
}
diff --git a/sql/unireg.cc b/sql/unireg.cc
index 9859d27dd3b..acd3c8bdd7c 100644
--- a/sql/unireg.cc
+++ b/sql/unireg.cc
@@ -1043,7 +1043,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;
diff --git a/sql/unireg.h b/sql/unireg.h
index ccdbb650485..8fe37040196 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))