diff options
author | Michael Widenius <monty@askmonty.org> | 2011-05-28 06:00:22 +0300 |
---|---|---|
committer | Michael Widenius <monty@askmonty.org> | 2011-05-28 06:00:22 +0300 |
commit | 152dfe58678af35769ca3cd66db592d129b4c08b (patch) | |
tree | a9534d5c69046eee9e4474bcae0a3a76711eb323 /sql/field.cc | |
parent | 9ace4da57156d4fccbba1ef34b43418e2cb65d4d (diff) | |
parent | 2894d50e3e2e3ae161cd1429bc2f7d78af212d27 (diff) | |
download | mariadb-git-152dfe58678af35769ca3cd66db592d129b4c08b.tar.gz |
Automatic merge
Diffstat (limited to 'sql/field.cc')
-rw-r--r-- | sql/field.cc | 2398 |
1 files changed, 885 insertions, 1513 deletions
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(<ime, 0); + return protocol->store(<ime, 0); } int Field_timestamp::cmp(const uchar *a_ptr, const uchar *b_ptr) { int32 a,b; -#ifdef WORDS_BIGENDIAN - if (table && table->s->db_low_byte_first) - { - 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, <ime, - 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(<ime, 0); + return protocol->store(<ime, dec); +} + + +int Field_timestamp_hires::cmp(const uchar *a_ptr, const uchar *b_ptr) +{ + int32 a,b; + ulong a_sec_part, b_sec_part; + a= mi_uint4korr(a_ptr); + a_sec_part= (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, <ime, + (TIME_FUZZY_DATE | + (thd->variables.sql_mode & + (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE | + MODE_INVALID_DATES))), + &error); + return store_TIME_with_warning(<ime, &str, error, func_res > MYSQL_TIMESTAMP_ERROR); +} + + +int Field_temporal::store(double nr) { - ASSERT_COLUMN_MARKED_FOR_WRITE_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), <ime, + (TIME_FUZZY_DATE | + (thd->variables.sql_mode & + (MODE_NO_ZERO_IN_DATE | + MODE_NO_ZERO_DATE | + MODE_INVALID_DATES))), &error); + ltime.second_part= (ulong)((nr-floor(nr))*TIME_SECOND_PART_FACTOR); + return store_TIME_with_warning(<ime, &str, error, tmp != -1); +} + + +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, <ime, (TIME_FUZZY_DATE | + (thd->variables.sql_mode & + (MODE_NO_ZERO_IN_DATE | + MODE_NO_ZERO_DATE | + MODE_INVALID_DATES))), &error); + + return store_TIME_with_warning(<ime, &str, error, tmp != -1); +} + + +int Field_temporal::store_time(MYSQL_TIME *ltime,timestamp_type time_type) +{ + int error = 0, have_smth_to_conv= 1; + MYSQL_TIME l_time= *ltime; + Lazy_string_time str(ltime); + /* + We don't perform range checking here since values stored in TIME + structure always fit into DATETIME range. + */ + if (time_type == MYSQL_TIMESTAMP_DATE || + time_type == MYSQL_TIMESTAMP_DATETIME) { - tmp= TIME_MAX_VALUE; - set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, - ER_WARN_DATA_OUT_OF_RANGE, nr, - MYSQL_TIMESTAMP_TIME, 1); - error= 1; + have_smth_to_conv= !check_date(&l_time, pack_time(&l_time) != 0, + (TIME_FUZZY_DATE | + (current_thd->variables.sql_mode & + (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE | + MODE_INVALID_DATES))), &error); } else { - tmp=(long) nr; - if (tmp % 100 > 59 || tmp/100 % 100 > 59) - { - tmp=0; - set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, - ER_WARN_DATA_OUT_OF_RANGE, nr, - MYSQL_TIMESTAMP_TIME, 1); - error= 1; - } + error= 1; + have_smth_to_conv= 0; } + return store_TIME_with_warning(&l_time, &str, error, have_smth_to_conv); +} + +/**************************************************************************** +** time type +** In string context: HH:MM:SS +** In number context: HHMMSS +** Stored as a 3 byte unsigned int +****************************************************************************/ + +void Field_time::store_TIME(MYSQL_TIME *ltime) +{ + long tmp= (ltime->day*24L+ltime->hour)*10000L + + (ltime->minute*100+ltime->second); + if (ltime->neg) + tmp= -tmp; int3store(ptr,tmp); - return error; +} + +int Field_time::store(const char *from,uint len,CHARSET_INFO *cs) +{ + MYSQL_TIME ltime; + Lazy_string_str str(from, len); + int was_cut; + int have_smth_to_conv= + str_to_time(from, len, <ime, + 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(<ime, &str, was_cut, have_smth_to_conv); } +int Field_time::store_time(MYSQL_TIME *ltime, timestamp_type time_type) +{ + MYSQL_TIME l_time= *ltime; + Lazy_string_time str(ltime); + int was_cut= 0; + + 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, <ime, &was_cut); + + return store_TIME_with_warning(<ime, &str, was_cut, have_smth_to_conv); +} + + +int Field_time::store(longlong nr, bool unsigned_val) +{ + MYSQL_TIME ltime; + Lazy_string_num str(nr); + int was_cut; + int have_smth_to_conv= !number_to_time((double)nr, <ime, &was_cut); + + return store_TIME_with_warning(<ime, &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(<ime, TIME_TIME_ONLY); + return protocol->store_time(<ime, 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(<ime, TIME_TIME_ONLY); + return TIME_to_double(<ime); +} + +String *Field_time_hires::val_str(String *str, + String *unused __attribute__((unused))) +{ + ASSERT_COLUMN_MARKED_FOR_READ; + MYSQL_TIME ltime; + Field_time_hires::get_date(<ime, TIME_TIME_ONLY); + str->alloc(field_length+1); + str->length(my_time_to_str(<ime, (char*) str->ptr(), dec)); + str->set_charset(&my_charset_bin); + return str; +} + +bool Field_time_hires::get_date(MYSQL_TIME *ltime, uint fuzzydate) +{ + 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(<ime, TIME_TIME_ONLY); + return protocol->store_time(<ime, dec); +} + + +int Field_time_hires::cmp(const uchar *a_ptr, const uchar *b_ptr) +{ + ulonglong a=read_bigendian(a_ptr, Field_time_hires::pack_length()); + ulonglong b=read_bigendian(b_ptr, Field_time_hires::pack_length()); + return (a < b) ? -1 : (a > b) ? 1 : 0; +} + +void Field_time_hires::sort_string(uchar *to,uint length __attribute__((unused))) +{ + DBUG_ASSERT(length == Field_time_hires::pack_length()); + memcpy(to, ptr, length); + to[0]^= 128; +} + +void Field_time_hires::sql_type(String &res) const +{ + CHARSET_INFO *cs=res.charset(); + res.length(cs->cset->snprintf(cs, (char*) res.ptr(), res.alloced_length(), + "time(%u)", dec)); +} + +void Field_time_hires::make_field(Send_field *field) +{ + Field::make_field(field); + field->decimals= dec; +} + /**************************************************************************** ** year type ** Save in a byte the year 0, 1901->2155 @@ -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, ¬_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, ¬_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(<ime, TIME_FUZZY_DATE); + return protocol->store(<ime, dec); +} + + +double Field_datetime_hires::val_real(void) +{ + MYSQL_TIME ltime; + Field_datetime_hires::get_date(<ime, TIME_FUZZY_DATE); + return TIME_to_double(<ime); +} + +longlong Field_datetime_hires::val_int(void) +{ + MYSQL_TIME ltime; + Field_datetime_hires::get_date(<ime, TIME_FUZZY_DATE); + return TIME_to_ulonglong_datetime(<ime); +} + + +String *Field_datetime_hires::val_str(String *str, + String *unused __attribute__((unused))) +{ + MYSQL_TIME ltime; + Field_datetime_hires::get_date(<ime, TIME_FUZZY_DATE); + str->alloc(field_length+1); + str->length(field_length); + my_datetime_to_str(<ime, (char*) str->ptr(), dec); + str->set_charset(&my_charset_bin); + return str; +} + +bool Field_datetime_hires::get_date(MYSQL_TIME *ltime, uint fuzzydate) +{ + ulonglong packed= read_bigendian(ptr, 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); } |