maria-developers team mailing list archive
-
maria-developers team
-
Mailing list archive
-
Message #05806
Re: merge for MySQL56 FSP data types
Hi Sergei,
Thanks for review.
This is a new version of the patch. I tried to address most of your
suggestions.
Please see comments inline.
(I wrote some of them in a earlier letter, but will repeat just in case)
Thanks.
On 06/26/2013 11:11 PM, Sergei Golubchik wrote:
Hi, Alexander!
On Jun 19, Alexander Barkov wrote:
Hi Serg,
Please review the patch merging MySQL-5.6 fractional second precision
enabled data types.
Thanks.
Here you are, my comments are below:
=== modified file 'include/my_time.h'
--- include/my_time.h 2013-05-24 15:09:59 +0000
+++ include/my_time.h 2013-06-19 11:13:13 +0000
@@ -107,10 +107,37 @@ ulonglong TIME_to_ulonglong_time(const M
ulonglong TIME_to_ulonglong(const MYSQL_TIME *);
double TIME_to_double(const MYSQL_TIME *my_time);
+/** MySQL56 routines and macros **/
+#define MY_PACKED_TIME_GET_INT_PART(x) ((x) >> 24)
+#define MY_PACKED_TIME_GET_FRAC_PART(x) ((x) % (1LL << 24))
+#define MY_PACKED_TIME_MAKE(i, f) ((((longlong) (i)) << 24) + (f))
+#define MY_PACKED_TIME_MAKE_INT(i) ((((longlong) (i)) << 24))
+
+longlong TIME_to_longlong_datetime_packed(const MYSQL_TIME *);
+longlong TIME_to_longlong_time_packed(const MYSQL_TIME *);
+
+void TIME_from_longlong_datetime_packed(MYSQL_TIME *ltime, longlong nr);
+void TIME_from_longlong_time_packed(MYSQL_TIME *ltime, longlong nr);
+
+void my_datetime_packed_to_binary(longlong nr, uchar *ptr, uint dec);
+longlong my_datetime_packed_from_binary(const uchar *ptr, uint dec);
+uint my_datetime_binary_length(uint dec);
+
+void my_time_packed_to_binary(longlong nr, uchar *ptr, uint dec);
+longlong my_time_packed_from_binary(const uchar *ptr, uint dec);
+uint my_time_binary_length(uint dec);
+
+void my_timestamp_to_binary(const struct timeval *tm, uchar *ptr, uint dec);
+void my_timestamp_from_binary(struct timeval *tm, const uchar *ptr, uint dec);
+uint my_timestamp_binary_length(uint dec);
+/** End of MySQL routines and macros **/
I don't think we need these macros and related functions in include/ and
sql-commont (that is, in the client). These belong in sql/
as they're only used for reading MySQL data files and for RBR.
if you'd like you can even put them in a separate file, sql/compat65.cc
Good idea. Moved to sql/compat56.cc and sql/compat56.h
+
longlong pack_time(MYSQL_TIME *my_time);
MYSQL_TIME *unpack_time(longlong packed, MYSQL_TIME *my_time);
int check_time_range(struct st_mysql_time *my_time, uint dec, int *warning);
+my_bool check_datetime_range(const MYSQL_TIME *ltime);
+
long calc_daynr(uint year,uint month,uint day);
uint calc_days_in_year(uint year);
=== modified file 'include/mysql_com.h'
--- include/mysql_com.h 2013-06-06 19:32:29 +0000
+++ include/mysql_com.h 2013-06-18 10:35:35 +0000
@@ -400,6 +400,9 @@ enum enum_field_types { MYSQL_TYPE_DECIM
MYSQL_TYPE_DATETIME, MYSQL_TYPE_YEAR,
MYSQL_TYPE_NEWDATE, MYSQL_TYPE_VARCHAR,
MYSQL_TYPE_BIT,
+ MYSQL_TYPE_TIMESTAMP2,
+ MYSQL_TYPE_DATETIME2,
+ MYSQL_TYPE_TIME2,
Add a comment about these types please.
Done.
MYSQL_TYPE_NEWDECIMAL=246,
MYSQL_TYPE_ENUM=247,
MYSQL_TYPE_SET=248,
=== added file 'mysql-test/t/type_temporal_mysql56.test'
--- mysql-test/t/type_temporal_mysql56.test 1970-01-01 00:00:00 +0000
+++ mysql-test/t/type_temporal_mysql56.test 2013-06-19 09:01:02 +0000
@@ -0,0 +1,23 @@
+
+let $MYSQLD_DATADIR= `select @@datadir`;
+--copy_file std_data/mysql56time.frm $MYSQLD_DATADIR/test/mysql56time.frm
+--copy_file std_data/mysql56time.MYD $MYSQLD_DATADIR/test/mysql56time.MYD
+--copy_file std_data/mysql56time.MYI $MYSQLD_DATADIR/test/mysql56time.MYI
+SHOW CREATE TABLE mysql56time;
+--query_vertical SELECT * FROM mysql56time;
generally, you either start mysqltest command with -- (dash-dash)
OR you end it with a semicolon.
If you do both - as above - you end up with two semicolons,
see the result file
Fixed.
+DROP TABLE mysql56time;
+
+--copy_file std_data/mysql56datetime.frm $MYSQLD_DATADIR/test/mysql56datetime.frm
+--copy_file std_data/mysql56datetime.MYD $MYSQLD_DATADIR/test/mysql56datetime.MYD
+--copy_file std_data/mysql56datetime.MYI $MYSQLD_DATADIR/test/mysql56datetime.MYI
+SHOW CREATE TABLE mysql56datetime;
+--query_vertical SELECT * FROM mysql56datetime;
+DROP TABLE mysql56datetime;
+
+--copy_file std_data/mysql56timestamp.frm $MYSQLD_DATADIR/test/mysql56timestamp.frm
+--copy_file std_data/mysql56timestamp.MYD $MYSQLD_DATADIR/test/mysql56timestamp.MYD
+--copy_file std_data/mysql56timestamp.MYI $MYSQLD_DATADIR/test/mysql56timestamp.MYI
+SET TIME_ZONE='+00:00';
+SHOW CREATE TABLE mysql56timestamp;
+--query_vertical SELECT * FROM mysql56timestamp;
+DROP TABLE mysql56timestamp;
=== modified file 'sql-common/my_time.c'
--- sql-common/my_time.c 2013-04-07 12:00:16 +0000
+++ sql-common/my_time.c 2013-06-19 11:59:45 +0000
@@ -1346,6 +1396,432 @@ ulonglong TIME_to_ulonglong(const MYSQL_
return 0;
}
+
+/*** MySQL56 TIME low-level memory and disk representation routines ***/
As I wrote above, I'd prefer to remove them from the client library
and move to sql/
Done.
+
+/*
+ In-memory format:
+
+ 1 bit sign (Used for sign, when on disk)
+ 1 bit unused (Reserved for wider hour range, e.g. for intervals)
+ 10 bit hour (0-836)
+ 6 bit minute (0-59)
+ 6 bit second (0-59)
+ 24 bits microseconds (0-999999)
+
+ Total: 48 bits = 6 bytes
+ Suhhhhhh.hhhhmmmm.mmssssss.ffffffff.ffffffff.ffffffff
+*/
+
+
+/**
+ Convert time value to MySQL56 numeric packed representation.
+
+ @param ltime The value to convert.
+ @return Numeric packed representation.
+*/
+longlong TIME_to_longlong_time_packed(const MYSQL_TIME *ltime)
+{
+ /* If month is 0, we mix day with hours: "1 00:10:10" -> "24:00:10" */
+ long hms= (((ltime->month ? 0 : ltime->day * 24) + ltime->hour) << 12) |
+ (ltime->minute << 6) | ltime->second;
+ longlong tmp= MY_PACKED_TIME_MAKE(hms, ltime->second_part);
+ return ltime->neg ? -tmp : tmp;
+}
+
+
+
+/**
+ Convert MySQL56 time packed numeric representation to time.
+
+ @param OUT ltime The MYSQL_TIME variable to set.
+ @param tmp The packed numeric representation.
+*/
+void TIME_from_longlong_time_packed(MYSQL_TIME *ltime, longlong tmp)
+{
+ long hms;
+ if ((ltime->neg= (tmp < 0)))
+ tmp= -tmp;
+ hms= MY_PACKED_TIME_GET_INT_PART(tmp);
+ ltime->year= (uint) 0;
+ ltime->month= (uint) 0;
+ ltime->day= (uint) 0;
+ ltime->hour= (uint) (hms >> 12) % (1 << 10); /* 10 bits starting at 12th */
+ ltime->minute= (uint) (hms >> 6) % (1 << 6); /* 6 bits starting at 6th */
+ ltime->second= (uint) hms % (1 << 6); /* 6 bits starting at 0th */
+ ltime->second_part= MY_PACKED_TIME_GET_FRAC_PART(tmp);
+ ltime->time_type= MYSQL_TIMESTAMP_TIME;
+}
+
+
+/**
+ Calculate binary size of MySQL56 packed numeric time representation.
+
+ @param dec Precision.
+*/
+uint my_time_binary_length(uint dec)
+{
+ DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS);
+ return 3 + (dec + 1) / 2;
+}
+
+
+/*
+ On disk we convert from signed representation to unsigned
+ representation using TIMEF_OFS, so all values become binary comparable.
+*/
+#define TIMEF_OFS 0x800000000000LL
+#define TIMEF_INT_OFS 0x800000LL
+
+
+/**
+ Convert MySQL56 in-memory numeric time representation to on-disk representation
+
+ @param nr Value in packed numeric time format.
+ @param OUT ptr The buffer to put value at.
+ @param dec Precision.
+*/
+void my_time_packed_to_binary(longlong nr, uchar *ptr, uint dec)
+{
+ DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS);
+ /* Make sure the stored value was previously properly rounded or truncated */
+ DBUG_ASSERT((MY_PACKED_TIME_GET_FRAC_PART(nr) %
+ (int) log_10_int[TIME_SECOND_PART_DIGITS - dec]) == 0);
+
+ switch (dec)
+ {
+ case 0:
+ default:
+ mi_int3store(ptr, TIMEF_INT_OFS + MY_PACKED_TIME_GET_INT_PART(nr));
+ break;
+
+ case 1:
+ case 2:
+ mi_int3store(ptr, TIMEF_INT_OFS + MY_PACKED_TIME_GET_INT_PART(nr));
+ ptr[3]= (unsigned char) (char) (MY_PACKED_TIME_GET_FRAC_PART(nr) / 10000);
+ break;
+
+ case 4:
+ case 3:
+ mi_int3store(ptr, TIMEF_INT_OFS + MY_PACKED_TIME_GET_INT_PART(nr));
+ mi_int2store(ptr + 3, MY_PACKED_TIME_GET_FRAC_PART(nr) / 100);
+ break;
+
+ case 5:
+ case 6:
+ mi_int6store(ptr, nr + TIMEF_OFS);
+ break;
+ }
+}
+
+
+/**
+ Convert MySQL56 on-disk time representation to in-memory packed numeric
+ representation.
+
+ @param ptr The pointer to read the value at.
+ @param dec Precision.
+ @return Packed numeric time representation.
+*/
+longlong my_time_packed_from_binary(const uchar *ptr, uint dec)
+{
+ DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS);
+
+ switch (dec)
+ {
+ case 0:
+ default:
+ {
+ longlong intpart= mi_uint3korr(ptr) - TIMEF_INT_OFS;
+ return MY_PACKED_TIME_MAKE_INT(intpart);
+ }
+ case 1:
+ case 2:
+ {
+ longlong intpart= mi_uint3korr(ptr) - TIMEF_INT_OFS;
+ int frac= (uint) ptr[3];
+ if (intpart < 0 && frac)
+ {
+ /*
+ Negative values are stored with reverse fractional part order,
+ for binary sort compatibility.
+
+ Disk value intpart frac Time value Memory value
+ 800000.00 0 0 00:00:00.00 0000000000.000000
+ 7FFFFF.FF -1 255 -00:00:00.01 FFFFFFFFFF.FFD8F0
+ 7FFFFF.9D -1 99 -00:00:00.99 FFFFFFFFFF.F0E4D0
+ 7FFFFF.00 -1 0 -00:00:01.00 FFFFFFFFFF.000000
+ 7FFFFE.FF -1 255 -00:00:01.01 FFFFFFFFFE.FFD8F0
+ 7FFFFE.F6 -2 246 -00:00:01.10 FFFFFFFFFE.FE7960
+
+ Formula to convert fractional part from disk format
+ (now stored in "frac" variable) to absolute value: "0x100 - frac".
+ To reconstruct in-memory value, we shift
+ to the next integer value and then substruct fractional part.
+ */
+ intpart++; /* Shift to the next integer value */
+ frac-= 0x100; /* -(0x100 - frac) */
+ }
+ return MY_PACKED_TIME_MAKE(intpart, frac * 10000);
+ }
+
+ case 3:
+ case 4:
+ {
+ longlong intpart= mi_uint3korr(ptr) - TIMEF_INT_OFS;
+ int frac= mi_uint2korr(ptr + 3);
+ if (intpart < 0 && frac)
+ {
+ /*
+ Fix reverse fractional part order: "0x10000 - frac".
+ See comments for FSP=1 and FSP=2 above.
+ */
+ intpart++; /* Shift to the next integer value */
+ frac-= 0x10000; /* -(0x10000-frac) */
+ }
+ return MY_PACKED_TIME_MAKE(intpart, frac * 100);
+ }
+
+ case 5:
+ case 6:
+ return ((longlong) mi_uint6korr(ptr)) - TIMEF_OFS;
+ }
+}
+
+
+/*** MySQL56 DATETIME low-level memory and disk representation routines ***/
+
+/*
+ 1 bit sign (used when on disk)
+ 17 bits year*13+month (year 0-9999, month 0-12)
+ 5 bits day (0-31)
+ 5 bits hour (0-23)
+ 6 bits minute (0-59)
+ 6 bits second (0-59)
+ 24 bits microseconds (0-999999)
+
+ Total: 64 bits = 8 bytes
+
+ SYYYYYYY.YYYYYYYY.YYdddddh.hhhhmmmm.mmssssss.ffffffff.ffffffff.ffffffff
+*/
+
+/**
+ Convert datetime to MySQL56 packed numeric datetime representation.
+ @param ltime The value to convert.
+ @return Packed numeric representation of ltime.
+*/
+longlong TIME_to_longlong_datetime_packed(const MYSQL_TIME *ltime)
+{
+ longlong ymd= ((ltime->year * 13 + ltime->month) << 5) | ltime->day;
+ longlong hms= (ltime->hour << 12) | (ltime->minute << 6) | ltime->second;
+ longlong tmp= MY_PACKED_TIME_MAKE(((ymd << 17) | hms), ltime->second_part);
+ DBUG_ASSERT(!check_datetime_range(ltime)); /* Make sure no overflow */
+ return ltime->neg ? -tmp : tmp;
+}
+
+
+/**
+ Convert MySQL56 packed numeric datetime representation to MYSQL_TIME.
+ @param OUT ltime The datetime variable to convert to.
+ @param tmp The packed numeric datetime value.
+*/
+void TIME_from_longlong_datetime_packed(MYSQL_TIME *ltime, longlong tmp)
+{
+ longlong ymd, hms;
+ longlong ymdhms, ym;
+ if ((ltime->neg= (tmp < 0)))
+ tmp= -tmp;
+
+ ltime->second_part= MY_PACKED_TIME_GET_FRAC_PART(tmp);
+ ymdhms= MY_PACKED_TIME_GET_INT_PART(tmp);
+
+ ymd= ymdhms >> 17;
+ ym= ymd >> 5;
+ hms= ymdhms % (1 << 17);
+
+ ltime->day= ymd % (1 << 5);
+ ltime->month= ym % 13;
+ ltime->year= ym / 13;
+
+ ltime->second= hms % (1 << 6);
+ ltime->minute= (hms >> 6) % (1 << 6);
+ ltime->hour= (hms >> 12);
+
+ ltime->time_type= MYSQL_TIMESTAMP_DATETIME;
+}
+
+
+/**
+ Calculate binary size of MySQL56 packed datetime representation.
+ @param dec Precision.
+*/
+uint my_datetime_binary_length(uint dec)
+{
+ DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS);
+ return 5 + (dec + 1) / 2;
+}
+
+
+/*
+ On disk we store as unsigned number with DATETIMEF_INT_OFS offset,
+ for HA_KETYPE_BINARY compatibilty purposes.
+*/
+#define DATETIMEF_INT_OFS 0x8000000000LL
+
+
+/**
+ Convert MySQL56 on-disk datetime representation
+ to in-memory packed numeric representation.
+
+ @param ptr The pointer to read value at.
+ @param dec Precision.
+ @return In-memory packed numeric datetime representation.
+*/
+longlong my_datetime_packed_from_binary(const uchar *ptr, uint dec)
+{
+ longlong intpart= mi_uint5korr(ptr) - DATETIMEF_INT_OFS;
+ int frac;
+ DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS);
+ switch (dec)
+ {
+ case 0:
+ default:
+ return MY_PACKED_TIME_MAKE_INT(intpart);
+ case 1:
+ case 2:
+ frac= ((int) (signed char) ptr[5]) * 10000;
+ break;
+ case 3:
+ case 4:
+ frac= mi_sint2korr(ptr + 5) * 100;
+ break;
+ case 5:
+ case 6:
+ frac= mi_sint3korr(ptr + 5);
+ break;
+ }
+ return MY_PACKED_TIME_MAKE(intpart, frac);
+}
+
+
+/**
+ Store MySQL56 in-memory numeric packed datetime representation to disk.
+
+ @param nr In-memory numeric packed datetime representation.
+ @param OUT ptr The pointer to store at.
+ @param dec Precision, 1-6.
+*/
+void my_datetime_packed_to_binary(longlong nr, uchar *ptr, uint dec)
+{
+ DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS);
+ /* The value being stored must have been properly rounded or truncated */
+ DBUG_ASSERT((MY_PACKED_TIME_GET_FRAC_PART(nr) %
+ (int) log_10_int[TIME_SECOND_PART_DIGITS - dec]) == 0);
+
+ mi_int5store(ptr, MY_PACKED_TIME_GET_INT_PART(nr) + DATETIMEF_INT_OFS);
+ switch (dec)
+ {
+ case 0:
+ default:
+ break;
+ case 1:
+ case 2:
+ ptr[5]= (unsigned char) (char) (MY_PACKED_TIME_GET_FRAC_PART(nr) / 10000);
+ break;
+ case 3:
+ case 4:
+ mi_int2store(ptr + 5, MY_PACKED_TIME_GET_FRAC_PART(nr) / 100);
+ break;
+ case 5:
+ case 6:
+ mi_int3store(ptr + 5, MY_PACKED_TIME_GET_FRAC_PART(nr));
+ }
+}
+
+
+/*** MySQL56 TIMESTAMP low-level memory and disk representation routines ***/
+
+/**
+ Calculate on-disk size of a timestamp value.
+
+ @param dec Precision.
+*/
+uint my_timestamp_binary_length(uint dec)
+{
+ DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS);
+ return 4 + (dec + 1) / 2;
+}
+
+
+/**
+ Convert MySQL56 binary timestamp representation to in-memory representation.
+
+ @param OUT tm The variable to convert to.
+ @param ptr The pointer to read the value from.
+ @param dec Precision.
+*/
+void my_timestamp_from_binary(struct timeval *tm, const uchar *ptr, uint dec)
+{
+ DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS);
+ tm->tv_sec= mi_uint4korr(ptr);
+ switch (dec)
+ {
+ case 0:
+ default:
+ tm->tv_usec= 0;
+ break;
+ case 1:
+ case 2:
+ tm->tv_usec= ((int) ptr[4]) * 10000;
+ break;
+ case 3:
+ case 4:
+ tm->tv_usec= mi_sint2korr(ptr + 4) * 100;
+ break;
+ case 5:
+ case 6:
+ tm->tv_usec= mi_sint3korr(ptr + 4);
+ }
+}
+
+
+/**
+ Convert MySQL56 in-memory timestamp representation to on-disk representation.
+
+ @param tm The value to convert.
+ @param OUT ptr The pointer to store the value to.
+ @param dec Precision.
+*/
+void my_timestamp_to_binary(const struct timeval *tm, uchar *ptr, uint dec)
+{
+ DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS);
+ /* Stored value must have been previously properly rounded or truncated */
+ DBUG_ASSERT((tm->tv_usec %
+ (int) log_10_int[TIME_SECOND_PART_DIGITS - dec]) == 0);
+ mi_int4store(ptr, tm->tv_sec);
+ switch (dec)
+ {
+ case 0:
+ default:
+ break;
+ case 1:
+ case 2:
+ ptr[4]= (unsigned char) (char) (tm->tv_usec / 10000);
+ break;
+ case 3:
+ case 4:
+ mi_int2store(ptr + 4, tm->tv_usec / 100);
+ break;
+ /* Impossible second precision. Fall through */
+ case 5:
+ case 6:
+ mi_int3store(ptr + 4, tm->tv_usec);
+ }
+}
+
+/****************************************/
+
+
double TIME_to_double(const MYSQL_TIME *my_time)
{
double d= (double)TIME_to_ulonglong(my_time);
=== modified file 'sql/field.cc'
--- sql/field.cc 2013-06-06 19:32:29 +0000
+++ sql/field.cc 2013-06-19 04:51:38 +0000
@@ -87,6 +87,7 @@ const char field_separator=',';
#define FIELDTYPE_NUM (FIELDTYPE_TEAR_FROM + (255 - FIELDTYPE_TEAR_TO))
static inline int field_type2index (enum_field_types field_type)
{
+ field_type= real_type_to_type(field_type);
I don't like that MYSQL_TYPE_*2 types (which are, really, now only a
migration types, for mysql-5.6 data files) are leaking into the server.
I'd prefer if they'd stay in their corresponding Field objects
and the rest of the server wouldn't need to know they exist.
I tried to reduce the amount of MYSQL_TYPE_*2 appearance.
They now appear in:
field.h
field.cc
log_event.cc
rpl_utility.cc
sql_partition.cc
sql_table.cc
which I think is OK.
Also, I had to add them into two places:
item.cc: Item::cmp_type()
item_strfunc.cc: Item_func_dyncol_create::prepare_arguments()
to avoid the "enumeration value is not handled" warning.
I don't think that adding "default" is a good idea.
This should probably be fixed separately.
Perhaps, we need a separate enum consisting of real types,
like this:
enum enum_field_real_types {
MYSQL_REAL_TYPE_DATE,
MYSQL_REAL_TYPE_NEWDATE,
MYSQL_REAL_TYPE_TIME,
MYSQL_REAL_TYPE_TIME2
...
};
Then have enum_field_types defined using enum_field_real_types,
like this:
enum enum_field_types {
MYSQL_TYPE_DATE= MYSQL_REAL_TYPE_DATE,
MYSQL_TYPE_TIME= MYSQL_REAL_TYPE_TIME
...
// No codes like MYSQL_REAL_TYPE_NEWDATE or MYSQL_REAL_TYPE_TIME2 here
}
Then, all the functions in should use either enum_field_real_types
or enum_field_types, depending on what they actually need,
For example, the mentioned "value is not handled" should be gone,
because these functions need type (not real type!).
return (field_type < FIELDTYPE_TEAR_FROM ?
field_type :
((int)FIELDTYPE_TEAR_FROM) + (field_type - FIELDTYPE_TEAR_TO) - 1);
@@ -4690,6 +4767,16 @@ String *Field_timestamp::val_str(String
*to++= (char) ('0'+(char) (temp));
*to= 0;
val_buffer->set_charset(&my_charset_numeric);
+
+ if (uint dec= decimals())
eh? We never declare variables inside if(). A question of a consistent
coding style.
Fixed.
+ {
+ ulong sec_part= (ulong) sec_part_shift(ltime.second_part, dec);
+ char *buf= const_cast<char*>(val_buffer->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 val_buffer;
}
@@ -5092,7 +5198,18 @@ int Field_temporal::store(double nr)
}
-int Field_temporal::store(longlong nr, bool unsigned_val)
+int Field_temporal::store_decimal(const my_decimal *d)
+{
+ ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ double val;
+ /* TODO: use decimal2string? */
+ int err= warn_if_overflow(my_decimal2double(E_DEC_FATAL_ERROR &
+ ~E_DEC_OVERFLOW, d, &val));
decimal2string is slow, decimal2double is lossy.
Use my_decimal2seconds
Done.
+ return err | store(val);
+}
+
+
+int Field_temporal_with_date::store(longlong nr, bool unsigned_val)
{
int error;
MYSQL_TIME ltime;
@@ -5229,32 +5375,16 @@ longlong Field_time::val_int(void)
my_charset_bin
*/
-String *Field_time::val_str(String *val_buffer,
- String *val_ptr __attribute__((unused)))
+String *Field_time::val_str(String *str,
+ String *unused __attribute__((unused)))
{
ASSERT_COLUMN_MARKED_FOR_READ;
MYSQL_TIME ltime;
- long tmp=(long) sint3korr(ptr);
- ltime.neg= 0;
- if (tmp < 0)
- {
- 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);
- ltime.second= (uint) (tmp % 100);
- ltime.second_part= 0;
-
- val_buffer->alloc(MAX_DATE_STRING_REP_LENGTH);
- uint length= (uint) my_time_to_str(<ime,
- const_cast<char*>(val_buffer->ptr()), 0);
- val_buffer->length(length);
- val_buffer->set_charset(&my_charset_numeric);
-
- return val_buffer;
+ get_date(<ime, TIME_TIME_ONLY);
+ str->alloc(field_length + 1);
+ str->length(my_time_to_str(<ime, const_cast<char*>(str->ptr()), decimals()));
+ str->set_charset(&my_charset_numeric);
+ return str;
Well. I intentionally kept the old "optimized" version.
I'd expect a generic one to be slower.
May be it's ok, though...
It seems we agreed that the old version was not
really that much "optimized" to deserve so much
duplicate code :)
(I wrote about it in a separate letter and you did not argue).
}
@@ -5431,13 +5541,51 @@ void Field_time_hires::sql_type(String &
"time(%u)", dec));
}
-void Field_time_hires::make_field(Send_field *field)
+void Field_time_with_dec::make_field(Send_field *field)
{
Field::make_field(field);
field->decimals= dec;
}
/****************************************************************************
+** time type with fsp (MySQL-5.6 version)
+** In string context: HH:MM:SS.FFFFFF
+** In number context: HHMMSS.FFFFFF
+****************************************************************************/
+
+void Field_timef::sql_type(String &res) const
+{
+ if (dec == 0)
+ {
+ res.set_ascii(STRING_WITH_LEN("time"));
+ return;
+ }
+ const CHARSET_INFO *cs= res.charset();
+ res.length(cs->cset->snprintf(cs, (char*) res.ptr(), res.alloced_length(),
+ "time(%d)", dec));
+}
Why would your mysql-5.6 types need a separate sql_type() method?
It doesn't seem to be anything that couldn't go into the base class
Moved to the parent classes.
+
+int Field_timef::reset()
+{
+ my_time_packed_to_binary(0, ptr, dec);
+ return 0;
+}
+
+void Field_timef::store_TIME(MYSQL_TIME *ltime)
+{
+ my_time_trunc(ltime, decimals());
+ longlong tmp= TIME_to_longlong_time_packed(ltime);
+ my_time_packed_to_binary(tmp, ptr, dec);
+}
+
+bool Field_timef::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+{
+ longlong tmp= my_time_packed_from_binary(ptr, dec);
+ TIME_from_longlong_time_packed(ltime, tmp);
+ return false;
+}
+
+/****************************************************************************
** year type
** Save in a byte the year 0, 1901->2155
** Can handle 2 byte or 4 byte years!
@@ -9413,17 +9494,6 @@ bool Create_field::init(THD *thd, char *
DBUG_RETURN(TRUE);
}
- switch (fld_type) {
- case MYSQL_TYPE_DATE:
- case MYSQL_TYPE_NEWDATE:
- case MYSQL_TYPE_TIME:
- case MYSQL_TYPE_DATETIME:
- case MYSQL_TYPE_TIMESTAMP:
- charset= &my_charset_numeric;
- flags|= BINARY_FLAG;
- default: break;
- }
-
why?
Because Field_temporal does not need a charset any more,
as it is not a child of Field_str now.
DBUG_RETURN(FALSE); /* success */
}
=== modified file 'sql/field.h'
--- sql/field.h 2013-06-06 15:51:28 +0000
+++ sql/field.h 2013-06-19 09:46:34 +0000
@@ -428,6 +464,27 @@ class Field
virtual uint32 key_length() const { return pack_length(); }
virtual enum_field_types type() const =0;
virtual enum_field_types real_type() const { return type(); }
+ virtual enum_field_types binlog_type() const
+ {
+ /*
+ Binlog stores field->type() as type code by default.
+ This puts MYSQL_TYPE_STRING in case of CHAR, VARCHAR, SET and ENUM,
+ with extra data type details put into metadata.
+
+ We cannot store field->type() in case of temporal types with
+ fractional seconds: TIME(n), DATETIME(n) and TIMESTAMP(n),
+ because binlog records with MYSQL_TYPE_TIME, MYSQL_TYPE_DATETIME
+ type codes do not have metadata.
+ So for MySQL-5.6 temporal data types with fractional seconds we'll store
+ real_type() type codes instead, i.e.
+ MYSQL_TYPE_TIME2, MYSQL_TYPE_DATETIME2, MYSQL_TYPE_TIMESTAMP2,
+ and put precision into metatada.
+
+ Note: perhaps binlog should eventually be modified to store
+ real_type() instead of type() for all column types.
+ */
+ return type();
+ }
Eh, I don't like it. So, to replicate with RBR between tables with
TIME columns of different precision, one needs to create tables
in MySQL 5.6? That's very lame thing to say to users :(
I'd rather fix it to work for all temporal types, both 5.6 and ours.
Perhaps, indeed, store real_type() as you write above.
But in a separate changeset. And here let's just say that it doesn't
work at all, and we always put MYSQL_TYPE_TIME/etc in the binlog.
Fixed the comment.
inline int cmp(const uchar *str) { return cmp(ptr,str); }
virtual int cmp_max(const uchar *a, const uchar *b, uint max_len)
{ return cmp(a, b); }
@@ -661,6 +718,16 @@ class Field
{ return binary() ? &my_charset_bin : charset(); }
virtual CHARSET_INFO *sort_charset(void) const { return charset(); }
virtual bool has_charset(void) const { return FALSE; }
+ /*
+ match_collation_to_optimize_range() is to distinguish in
+ range optimizer (see opt_range.cc) between real string types:
+ CHAR, VARCHAR, TEXT
+ and the other string-alike types with result_type() == STRING_RESULT:
+ DATE, TIME, DATETIME, TIMESTAMP
+ We need it to decide whether to test if collation of the operation
+ matches collation of the field (needed only for real string types).
+ */
+ virtual bool match_collation_to_optimize_range() const { return false; }
Not needed. temporal types are not string-alike,
they have have cmp_type() == TIME_RESULT,
string types have STRING_RESULT.
It seems we agreed to try to do something around this in a separate
changeset.
virtual void set_charset(CHARSET_INFO *charset_arg) { }
virtual enum Derivation derivation(void) const
{ return DERIVATION_IMPLICIT; }
@@ -1345,7 +1407,67 @@ class Field_null :public Field_str {
};
-class Field_timestamp :public Field_str {
+class Field_temporal: public Field {
+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)
+ :Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg,
+ field_name_arg)
+ { flags|= BINARY_FLAG; }
+ Item_result result_type () const { return STRING_RESULT; }
+ uint32 max_display_length() { return field_length; }
+ bool str_needs_quotes() { return TRUE; }
+ enum Derivation derivation(void) const { return DERIVATION_NUMERIC; }
+ uint repertoire(void) const { return MY_REPERTOIRE_NUMERIC; }
+ CHARSET_INFO *charset(void) const { return &my_charset_numeric; }
+ const CHARSET_INFO *sort_charset(void) const { return &my_charset_bin; }
+ bool binary() const { return true; }
+ enum Item_result cmp_type () const { return TIME_RESULT; }
+ uint is_equal(Create_field *new_field);
+ bool eq_def(Field *field)
+ {
+ return (Field::eq_def(field) && decimals() == field->decimals());
+ }
+ int store_decimal(const my_decimal *);
+ my_decimal *val_decimal(my_decimal*);
+ void set_warnings(MYSQL_ERROR::enum_warning_level trunc_level,
+ const ErrConv *str, int was_cut, timestamp_type ts_type);
+ double pos_in_interval(Field *min, Field *max)
+ {
+ return pos_in_interval_val_str(min, max, 0);
Really? This would first convert a temporal value to a string,
and then use a quite complicated procedure of placing a string
in the interval. Wouldn't it be much cheaper to use
pos_in_interval_val_real() ?
Changed to pos_in_interval_val_real().
Note, mysql-test/r/statistics.result has changed slightly.
But I think it's Ok.
+ }
+};
+
+
+/**
+ Abstract class for:
+ - DATE
+ - DATETIME
+ - DATETIME(1..6)
+ - DATETIME(0..6) - MySQL56 version
+*/
+class Field_temporal_with_date: public Field_temporal {
+protected:
+ int store_TIME_with_warning(MYSQL_TIME *ltime, const ErrConv *str,
+ int was_cut, int have_smth_to_conv);
Eh? So you'll have *three* different store_TIME_with_warning() methods?
I didn't like my version, because I had *two*,
there should've been only one.
We decided to take a look into this later.
+ virtual void store_TIME(MYSQL_TIME *ltime) = 0;
+public:
+ Field_temporal_with_date(uchar *ptr_arg, uint32 len_arg,
+ uchar *null_ptr_arg, uchar null_bit_arg,
+ utype unireg_check_arg,
+ const char *field_name_arg)
+ :Field_temporal(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
+ unireg_check_arg, field_name_arg)
+ {}
+ int store(const char *to, uint length, CHARSET_INFO *charset);
+ int store(double nr);
+ int store(longlong nr, bool unsigned_val);
+ int store_time_dec(MYSQL_TIME *ltime, uint dec);
+};
+
+
+class Field_timestamp :public Field_temporal {
protected:
int store_TIME_with_warning(THD *, MYSQL_TIME *, const ErrConv *,
bool, bool);
=== modified file 'sql/opt_range.cc'
--- sql/opt_range.cc 2013-06-06 19:32:29 +0000
+++ sql/opt_range.cc 2013-06-18 10:35:35 +0000
@@ -8014,10 +8014,10 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND
*/
if (field->result_type() == STRING_RESULT &&
this and below should probably use cmp_type, not result_type
We agreed to try to do something around this in a separate changeset.
- ((Field_str*) field)->match_collation_to_optimize_range() &&
+ field->match_collation_to_optimize_range() &&
value->result_type() == STRING_RESULT &&
key_part->image_type == Field::itRAW &&
- ((Field_str*)field)->charset() != conf_func->compare_collation() &&
+ field->charset() != conf_func->compare_collation() &&
!(conf_func->compare_collation()->state & MY_CS_BINSORT &&
(type == Item_func::EQUAL_FUNC || type == Item_func::EQ_FUNC)))
goto end;
=== modified file 'sql/sql_time.h'
--- sql/sql_time.h 2012-08-31 12:15:52 +0000
+++ sql/sql_time.h 2013-06-18 10:35:36 +0000
@@ -110,4 +110,23 @@ extern DATE_TIME_FORMAT global_time_form
extern KNOWN_DATE_TIME_FORMAT known_date_time_formats[];
extern LEX_STRING interval_type_to_name[];
+/* Date/time rounding and truncation functions */
+inline long my_time_fraction_remainder(long nr, uint decimals)
+{
+ DBUG_ASSERT(decimals <= TIME_SECOND_PART_DIGITS);
+ return nr % (long) log_10_int[TIME_SECOND_PART_DIGITS - decimals];
+}
+inline void my_time_trunc(MYSQL_TIME *ltime, uint decimals)
+{
+ ltime->second_part-= my_time_fraction_remainder(ltime->second_part, decimals);
+}
good idea, but
1. put it in my_time.h instead of sec_part_truncate()
2. change item_timefunc.cc (and other files too) to use it
(this will remove all uses of sec_part_truncate())
Done.
+inline void my_datetime_trunc(MYSQL_TIME *ltime, uint decimals)
+{
+ return my_time_trunc(ltime, decimals);
+}
+inline void my_timeval_trunc(struct timeval *tv, uint decimals)
+{
+ tv->tv_usec-= my_time_fraction_remainder(tv->tv_usec, decimals);
+}
please move all these four functions to my_time.h
(although, I'd delete my_datetime_trunc() completely)
Done.
+
#endif /* SQL_TIME_INCLUDED */
Regards,
Sergei
=== modified file 'client/mysqlbinlog.cc'
--- client/mysqlbinlog.cc 2013-04-15 13:09:22 +0000
+++ client/mysqlbinlog.cc 2013-06-27 12:33:05 +0000
@@ -37,6 +37,7 @@
/* That one is necessary for defines of OPTION_NO_FOREIGN_KEY_CHECKS etc */
#include "sql_priv.h"
#include "log_event.h"
+#include "compat56.h"
#include "sql_common.h"
#include "my_dir.h"
#include <welcome_copyright_notice.h> // ORACLE_WELCOME_COPYRIGHT_NOTICE
@@ -2562,3 +2563,4 @@ void *sql_alloc(size_t size)
#include "sql_string.cc"
#include "sql_list.cc"
#include "rpl_filter.cc"
+#include "compat56.cc"
=== modified file 'include/my_time.h'
--- include/my_time.h 2013-05-24 15:09:59 +0000
+++ include/my_time.h 2013-06-27 11:24:23 +0000
@@ -111,6 +111,8 @@ longlong pack_time(MYSQL_TIME *my_time);
MYSQL_TIME *unpack_time(longlong packed, MYSQL_TIME *my_time);
int check_time_range(struct st_mysql_time *my_time, uint dec, int *warning);
+my_bool check_datetime_range(const MYSQL_TIME *ltime);
+
long calc_daynr(uint year,uint month,uint day);
uint calc_days_in_year(uint year);
@@ -163,6 +165,8 @@ int my_date_to_str(const MYSQL_TIME *l_t
int my_datetime_to_str(const MYSQL_TIME *l_time, char *to, uint digits);
int my_TIME_to_str(const MYSQL_TIME *l_time, char *to, uint digits);
+int my_timeval_to_str(const struct timeval *tm, char *to, uint dec);
+
static inline longlong sec_part_shift(longlong second_part, uint digits)
{
return second_part / (longlong)log_10_int[TIME_SECOND_PART_DIGITS - digits];
@@ -177,6 +181,22 @@ static inline ulong sec_part_truncate(ul
return second_part - second_part % (ulong)log_10_int[TIME_SECOND_PART_DIGITS - digits];
}
+/* Date/time rounding and truncation functions */
+static inline long my_time_fraction_remainder(long nr, uint decimals)
+{
+ DBUG_ASSERT(decimals <= TIME_SECOND_PART_DIGITS);
+ return nr % (long) log_10_int[TIME_SECOND_PART_DIGITS - decimals];
+}
+static inline void my_time_trunc(MYSQL_TIME *ltime, uint decimals)
+{
+ ltime->second_part-= my_time_fraction_remainder(ltime->second_part, decimals);
+}
+static inline void my_timeval_trunc(struct timeval *tv, uint decimals)
+{
+ tv->tv_usec-= my_time_fraction_remainder(tv->tv_usec, decimals);
+}
+
+
#define hrtime_to_my_time(X) ((my_time_t)hrtime_to_time(X))
/*
=== modified file 'include/mysql.h.pp'
--- include/mysql.h.pp 2013-05-24 15:09:59 +0000
+++ include/mysql.h.pp 2013-06-18 10:35:35 +0000
@@ -49,6 +49,9 @@ enum enum_field_types { MYSQL_TYPE_DECIM
MYSQL_TYPE_DATETIME, MYSQL_TYPE_YEAR,
MYSQL_TYPE_NEWDATE, MYSQL_TYPE_VARCHAR,
MYSQL_TYPE_BIT,
+ MYSQL_TYPE_TIMESTAMP2,
+ MYSQL_TYPE_DATETIME2,
+ MYSQL_TYPE_TIME2,
MYSQL_TYPE_NEWDECIMAL=246,
MYSQL_TYPE_ENUM=247,
MYSQL_TYPE_SET=248,
=== modified file 'include/mysql_com.h'
--- include/mysql_com.h 2013-06-06 19:32:29 +0000
+++ include/mysql_com.h 2013-06-27 10:54:59 +0000
@@ -400,6 +400,9 @@ enum enum_field_types { MYSQL_TYPE_DECIM
MYSQL_TYPE_DATETIME, MYSQL_TYPE_YEAR,
MYSQL_TYPE_NEWDATE, MYSQL_TYPE_VARCHAR,
MYSQL_TYPE_BIT,
+ MYSQL_TYPE_TIMESTAMP2, /* MySQL-5.6 TIMESTAMP */
+ MYSQL_TYPE_DATETIME2, /* MySQL-5.6 DATETIME */
+ MYSQL_TYPE_TIME2, /* MySQL-5.6 TIME */
MYSQL_TYPE_NEWDECIMAL=246,
MYSQL_TYPE_ENUM=247,
MYSQL_TYPE_SET=248,
=== modified file 'mysql-test/r/statistics.result'
--- mysql-test/r/statistics.result 2013-04-22 09:18:46 +0000
+++ mysql-test/r/statistics.result 2013-07-02 06:53:52 +0000
@@ -220,7 +220,7 @@ db_name table_name column_name min_value
test t1 a 0 49 0.0000 1.0000 4 SINGLE_PREC_HB 2E62A1D0
test t1 b vvvvvvvvvvvvv zzzzzzzzzzzzzzzzzz 0.2000 6.4000 4 SINGLE_PREC_HB 003FBFFF
test t1 c aaaa dddddddd 0.1250 7.0000 4 SINGLE_PREC_HB 0055AAFF
-test t1 d 1989-03-12 1999-07-23 0.1500 8.5000 4 SINGLE_PREC_HB 009393FF
+test t1 d 1989-03-12 1999-07-23 0.1500 8.5000 4 SINGLE_PREC_HB 001919FF
test t1 e 0.01 0.112 0.2250 6.2000 4 SINGLE_PREC_HB 000564E1
test t1 f 1 5 0.2000 6.4000 4 SINGLE_PREC_HB 3F7FBFBF
DELETE FROM mysql.column_stats;
@@ -238,7 +238,7 @@ db_name table_name column_name min_value
test t1 a 0 49 0.0000 1.0000 8 DOUBLE_PREC_HB 052F4363F4A1F9D0
test t1 b vvvvvvvvvvvvv zzzzzzzzzzzzzzzzzz 0.2000 6.4000 8 DOUBLE_PREC_HB 0000FF3FFFBFFFFF
test t1 c aaaa dddddddd 0.1250 7.0000 8 DOUBLE_PREC_HB 00005555AAAAFFFF
-test t1 d 1989-03-12 1999-07-23 0.1500 8.5000 8 DOUBLE_PREC_HB 000026942694FFFF
+test t1 d 1989-03-12 1999-07-23 0.1500 8.5000 8 DOUBLE_PREC_HB 0000031A031AFFFF
test t1 e 0.01 0.112 0.2250 6.2000 8 DOUBLE_PREC_HB 000005056464E1E1
test t1 f 1 5 0.2000 6.4000 8 DOUBLE_PREC_HB FF3FFF7FFFBFFFBF
DELETE FROM mysql.column_stats;
=== modified file 'mysql-test/r/strict.result'
--- mysql-test/r/strict.result 2012-04-07 13:58:46 +0000
+++ mysql-test/r/strict.result 2013-06-28 14:00:13 +0000
@@ -1135,7 +1135,7 @@ create table t1 (col1 date, col2 datetim
insert into t1 values (0,0,0);
ERROR 22007: Incorrect date value: '0' for column 'col1' at row 1
insert into t1 values (0.0,0.0,0.0);
-ERROR 22007: Incorrect date value: '0' for column 'col1' at row 1
+ERROR 22007: Incorrect date value: '0.0' for column 'col1' at row 1
insert into t1 (col1) values (convert('0000-00-00',date));
ERROR 22007: Incorrect datetime value: '0000-00-00'
insert into t1 (col1) values (cast('0000-00-00' as date));
=== added file 'mysql-test/r/type_temporal_mysql56.result'
--- mysql-test/r/type_temporal_mysql56.result 1970-01-01 00:00:00 +0000
+++ mysql-test/r/type_temporal_mysql56.result 2013-06-27 10:56:21 +0000
@@ -0,0 +1,89 @@
+SHOW CREATE TABLE mysql56time;
+Table Create Table
+mysql56time CREATE TABLE `mysql56time` (
+ `t0` time DEFAULT NULL,
+ `t1` time(1) DEFAULT NULL,
+ `t2` time(2) DEFAULT NULL,
+ `t3` time(3) DEFAULT NULL,
+ `t4` time(4) DEFAULT NULL,
+ `t5` time(5) DEFAULT NULL,
+ `t6` time(6) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+SELECT * FROM mysql56time;
+t0 838:59:59
+t1 838:59:59.0
+t2 838:59:59.00
+t3 838:59:59.000
+t4 838:59:59.0000
+t5 838:59:59.00000
+t6 838:59:59.000000
+t0 00:00:00
+t1 00:00:00.0
+t2 00:00:00.00
+t3 00:00:00.000
+t4 00:00:00.0000
+t5 00:00:00.00000
+t6 00:00:00.000000
+t0 -838:59:59
+t1 -838:59:59.0
+t2 -838:59:59.00
+t3 -838:59:59.000
+t4 -838:59:59.0000
+t5 -838:59:59.00000
+t6 -838:59:59.000000
+DROP TABLE mysql56time;
+SHOW CREATE TABLE mysql56datetime;
+Table Create Table
+mysql56datetime CREATE TABLE `mysql56datetime` (
+ `dt0` datetime DEFAULT NULL,
+ `dt1` datetime(1) DEFAULT NULL,
+ `dt2` datetime(2) DEFAULT NULL,
+ `dt3` datetime(3) DEFAULT NULL,
+ `dt4` datetime(4) DEFAULT NULL,
+ `dt5` datetime(5) DEFAULT NULL,
+ `dt6` datetime(6) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+SELECT * FROM mysql56datetime;
+dt0 0000-00-00 00:00:00
+dt1 0000-00-00 00:00:00.0
+dt2 0000-00-00 00:00:00.00
+dt3 0000-00-00 00:00:00.000
+dt4 0000-00-00 00:00:00.0000
+dt5 0000-00-00 00:00:00.00000
+dt6 0000-00-00 00:00:00.000000
+dt0 9999-12-31 23:59:59
+dt1 9999-12-31 23:59:59.9
+dt2 9999-12-31 23:59:59.99
+dt3 9999-12-31 23:59:59.999
+dt4 9999-12-31 23:59:59.9999
+dt5 9999-12-31 23:59:59.99999
+dt6 9999-12-31 23:59:59.999999
+DROP TABLE mysql56datetime;
+SET TIME_ZONE='+00:00';
+SHOW CREATE TABLE mysql56timestamp;
+Table Create Table
+mysql56timestamp CREATE TABLE `mysql56timestamp` (
+ `ts0` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ `ts1` timestamp(1) NOT NULL DEFAULT '0000-00-00 00:00:00.0',
+ `ts2` timestamp(2) NOT NULL DEFAULT '0000-00-00 00:00:00.00',
+ `ts3` timestamp(3) NOT NULL DEFAULT '0000-00-00 00:00:00.000',
+ `ts4` timestamp(4) NOT NULL DEFAULT '0000-00-00 00:00:00.0000',
+ `ts5` timestamp(5) NOT NULL DEFAULT '0000-00-00 00:00:00.00000',
+ `ts6` timestamp(6) NOT NULL DEFAULT '0000-00-00 00:00:00.000000'
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+SELECT * FROM mysql56timestamp;
+ts0 1970-01-01 00:00:01
+ts1 1970-01-01 00:00:01.0
+ts2 1970-01-01 00:00:01.00
+ts3 1970-01-01 00:00:01.000
+ts4 1970-01-01 00:00:01.0000
+ts5 1970-01-01 00:00:01.00000
+ts6 1970-01-01 00:00:01.000000
+ts0 2038-01-19 03:14:07
+ts1 2038-01-19 03:14:07.9
+ts2 2038-01-19 03:14:07.99
+ts3 2038-01-19 03:14:07.999
+ts4 2038-01-19 03:14:07.9999
+ts5 2038-01-19 03:14:07.99999
+ts6 2038-01-19 03:14:07.999999
+DROP TABLE mysql56timestamp;
=== added file 'mysql-test/std_data/mysql56datetime.MYD'
Binary files mysql-test/std_data/mysql56datetime.MYD 1970-01-01 00:00:00 +0000 and mysql-test/std_data/mysql56datetime.MYD 2013-06-19 07:53:28 +0000 differ
=== added file 'mysql-test/std_data/mysql56datetime.MYI'
Binary files mysql-test/std_data/mysql56datetime.MYI 1970-01-01 00:00:00 +0000 and mysql-test/std_data/mysql56datetime.MYI 2013-06-19 07:54:09 +0000 differ
=== added file 'mysql-test/std_data/mysql56datetime.frm'
Binary files mysql-test/std_data/mysql56datetime.frm 1970-01-01 00:00:00 +0000 and mysql-test/std_data/mysql56datetime.frm 2013-06-19 07:53:28 +0000 differ
=== added file 'mysql-test/std_data/mysql56time.MYD'
Binary files mysql-test/std_data/mysql56time.MYD 1970-01-01 00:00:00 +0000 and mysql-test/std_data/mysql56time.MYD 2013-06-19 07:53:28 +0000 differ
=== added file 'mysql-test/std_data/mysql56time.MYI'
Binary files mysql-test/std_data/mysql56time.MYI 1970-01-01 00:00:00 +0000 and mysql-test/std_data/mysql56time.MYI 2013-06-19 07:54:09 +0000 differ
=== added file 'mysql-test/std_data/mysql56time.frm'
Binary files mysql-test/std_data/mysql56time.frm 1970-01-01 00:00:00 +0000 and mysql-test/std_data/mysql56time.frm 2013-06-19 07:53:28 +0000 differ
=== added file 'mysql-test/std_data/mysql56timestamp.MYD'
Binary files mysql-test/std_data/mysql56timestamp.MYD 1970-01-01 00:00:00 +0000 and mysql-test/std_data/mysql56timestamp.MYD 2013-06-19 07:53:28 +0000 differ
=== added file 'mysql-test/std_data/mysql56timestamp.MYI'
Binary files mysql-test/std_data/mysql56timestamp.MYI 1970-01-01 00:00:00 +0000 and mysql-test/std_data/mysql56timestamp.MYI 2013-06-19 07:54:09 +0000 differ
=== added file 'mysql-test/std_data/mysql56timestamp.frm'
Binary files mysql-test/std_data/mysql56timestamp.frm 1970-01-01 00:00:00 +0000 and mysql-test/std_data/mysql56timestamp.frm 2013-06-19 07:53:28 +0000 differ
=== modified file 'mysql-test/suite/binlog/r/binlog_mysqlbinlog_row_innodb.result'
--- mysql-test/suite/binlog/r/binlog_mysqlbinlog_row_innodb.result 2013-04-15 08:55:27 +0000
+++ mysql-test/suite/binlog/r/binlog_mysqlbinlog_row_innodb.result 2013-06-18 10:35:35 +0000
@@ -2404,7 +2404,7 @@ BEGIN
### @28='1000:01:01' /* DATE meta=0 nullable=1 is_null=0 */
### @29=1000-01-01 00:00:00 /* DATETIME meta=0 nullable=1 is_null=0 */
### @30=75601 /* TIMESTAMP meta=0 nullable=0 is_null=0 */
-### @31='839:12:57' /* TIME meta=0 nullable=1 is_null=0 */
+### @31='-838:59:59' /* TIME meta=0 nullable=1 is_null=0 */
### @32=1901 /* YEAR meta=0 nullable=1 is_null=0 */
### @33='' /* STRING(1) meta=65025 nullable=1 is_null=0 */
### @34='' /* STRING(0) meta=65024 nullable=1 is_null=0 */
@@ -2766,7 +2766,7 @@ BEGIN
### @28='1000:01:01' /* DATE meta=0 nullable=1 is_null=0 */
### @29=1000-01-01 00:00:00 /* DATETIME meta=0 nullable=1 is_null=0 */
### @30=75601 /* TIMESTAMP meta=0 nullable=0 is_null=0 */
-### @31='839:12:57' /* TIME meta=0 nullable=1 is_null=0 */
+### @31='-838:59:59' /* TIME meta=0 nullable=1 is_null=0 */
### @32=1901 /* YEAR meta=0 nullable=1 is_null=0 */
### @33='' /* STRING(1) meta=65025 nullable=1 is_null=0 */
### @34='' /* STRING(0) meta=65024 nullable=1 is_null=0 */
@@ -3019,7 +3019,7 @@ BEGIN
### @28='1000:01:01' /* DATE meta=0 nullable=1 is_null=0 */
### @29=1000-01-01 00:00:00 /* DATETIME meta=0 nullable=1 is_null=0 */
### @30=75601 /* TIMESTAMP meta=0 nullable=0 is_null=0 */
-### @31='839:12:57' /* TIME meta=0 nullable=1 is_null=0 */
+### @31='-838:59:59' /* TIME meta=0 nullable=1 is_null=0 */
### @32=1901 /* YEAR meta=0 nullable=1 is_null=0 */
### @33='' /* STRING(1) meta=65025 nullable=1 is_null=0 */
### @34='' /* STRING(0) meta=65024 nullable=1 is_null=0 */
@@ -3551,7 +3551,7 @@ BEGIN
### @28='1000:01:01' /* DATE meta=0 nullable=1 is_null=0 */
### @29=1000-01-01 00:00:00 /* DATETIME meta=0 nullable=1 is_null=0 */
### @30=75601 /* TIMESTAMP meta=0 nullable=0 is_null=0 */
-### @31='839:12:57' /* TIME meta=0 nullable=1 is_null=0 */
+### @31='-838:59:59' /* TIME meta=0 nullable=1 is_null=0 */
### @32=1901 /* YEAR meta=0 nullable=1 is_null=0 */
### @33='' /* STRING(1) meta=65025 nullable=1 is_null=0 */
### @34='' /* STRING(0) meta=65024 nullable=1 is_null=0 */
=== modified file 'mysql-test/suite/binlog/r/binlog_mysqlbinlog_row_myisam.result'
--- mysql-test/suite/binlog/r/binlog_mysqlbinlog_row_myisam.result 2013-04-15 08:55:27 +0000
+++ mysql-test/suite/binlog/r/binlog_mysqlbinlog_row_myisam.result 2013-06-18 10:35:35 +0000
@@ -2404,7 +2404,7 @@ BEGIN
### @28='1000:01:01' /* DATE meta=0 nullable=1 is_null=0 */
### @29=1000-01-01 00:00:00 /* DATETIME meta=0 nullable=1 is_null=0 */
### @30=75601 /* TIMESTAMP meta=0 nullable=0 is_null=0 */
-### @31='839:12:57' /* TIME meta=0 nullable=1 is_null=0 */
+### @31='-838:59:59' /* TIME meta=0 nullable=1 is_null=0 */
### @32=1901 /* YEAR meta=0 nullable=1 is_null=0 */
### @33='' /* STRING(1) meta=65025 nullable=1 is_null=0 */
### @34='' /* STRING(0) meta=65024 nullable=1 is_null=0 */
@@ -2773,7 +2773,7 @@ BEGIN
### @28='1000:01:01' /* DATE meta=0 nullable=1 is_null=0 */
### @29=1000-01-01 00:00:00 /* DATETIME meta=0 nullable=1 is_null=0 */
### @30=75601 /* TIMESTAMP meta=0 nullable=0 is_null=0 */
-### @31='839:12:57' /* TIME meta=0 nullable=1 is_null=0 */
+### @31='-838:59:59' /* TIME meta=0 nullable=1 is_null=0 */
### @32=1901 /* YEAR meta=0 nullable=1 is_null=0 */
### @33='' /* STRING(1) meta=65025 nullable=1 is_null=0 */
### @34='' /* STRING(0) meta=65024 nullable=1 is_null=0 */
@@ -3028,7 +3028,7 @@ BEGIN
### @28='1000:01:01' /* DATE meta=0 nullable=1 is_null=0 */
### @29=1000-01-01 00:00:00 /* DATETIME meta=0 nullable=1 is_null=0 */
### @30=75601 /* TIMESTAMP meta=0 nullable=0 is_null=0 */
-### @31='839:12:57' /* TIME meta=0 nullable=1 is_null=0 */
+### @31='-838:59:59' /* TIME meta=0 nullable=1 is_null=0 */
### @32=1901 /* YEAR meta=0 nullable=1 is_null=0 */
### @33='' /* STRING(1) meta=65025 nullable=1 is_null=0 */
### @34='' /* STRING(0) meta=65024 nullable=1 is_null=0 */
@@ -3568,7 +3568,7 @@ BEGIN
### @28='1000:01:01' /* DATE meta=0 nullable=1 is_null=0 */
### @29=1000-01-01 00:00:00 /* DATETIME meta=0 nullable=1 is_null=0 */
### @30=75601 /* TIMESTAMP meta=0 nullable=0 is_null=0 */
-### @31='839:12:57' /* TIME meta=0 nullable=1 is_null=0 */
+### @31='-838:59:59' /* TIME meta=0 nullable=1 is_null=0 */
### @32=1901 /* YEAR meta=0 nullable=1 is_null=0 */
### @33='' /* STRING(1) meta=65025 nullable=1 is_null=0 */
### @34='' /* STRING(0) meta=65024 nullable=1 is_null=0 */
=== added file 'mysql-test/suite/rpl/r/rpl_temporal_mysql56.result'
--- mysql-test/suite/rpl/r/rpl_temporal_mysql56.result 1970-01-01 00:00:00 +0000
+++ mysql-test/suite/rpl/r/rpl_temporal_mysql56.result 2013-06-27 10:57:55 +0000
@@ -0,0 +1,84 @@
+include/master-slave.inc
+[connection master]
+SET TIME_ZONE='+00:00';
+SET TIME_ZONE='+00:00';
+INSERT INTO mysql56time VALUES ('01:01:01','01:01:01.1','01:01:01.11','01:01:01.111','01:01:01.1111','01:01:01.11111','01:01:01.111111');
+INSERT INTO mysql56datetime VALUES ('2001-01-01 01:01:01','2001-01-01 01:01:01.1','2001-01-01 01:01:01.11','2001-01-01 01:01:01.111','2001-01-01 01:01:01.1111','2001-01-01 01:01:01.11111','2001-01-01 01:01:01.111111');
+INSERT INTO mysql56timestamp VALUES ('2001-01-01 01:01:01','2001-01-01 01:01:01.1','2001-01-01 01:01:01.11','2001-01-01 01:01:01.111','2001-01-01 01:01:01.1111','2001-01-01 01:01:01.11111','2001-01-01 01:01:01.111111');
+SELECT * FROM mysql56time;
+t0 838:59:59
+t1 838:59:59.0
+t2 838:59:59.00
+t3 838:59:59.000
+t4 838:59:59.0000
+t5 838:59:59.00000
+t6 838:59:59.000000
+t0 00:00:00
+t1 00:00:00.0
+t2 00:00:00.00
+t3 00:00:00.000
+t4 00:00:00.0000
+t5 00:00:00.00000
+t6 00:00:00.000000
+t0 -838:59:59
+t1 -838:59:59.0
+t2 -838:59:59.00
+t3 -838:59:59.000
+t4 -838:59:59.0000
+t5 -838:59:59.00000
+t6 -838:59:59.000000
+t0 01:01:01
+t1 01:01:01.1
+t2 01:01:01.11
+t3 01:01:01.111
+t4 01:01:01.1111
+t5 01:01:01.11111
+t6 01:01:01.111111
+SELECT * FROM mysql56datetime;
+dt0 0000-00-00 00:00:00
+dt1 0000-00-00 00:00:00.0
+dt2 0000-00-00 00:00:00.00
+dt3 0000-00-00 00:00:00.000
+dt4 0000-00-00 00:00:00.0000
+dt5 0000-00-00 00:00:00.00000
+dt6 0000-00-00 00:00:00.000000
+dt0 9999-12-31 23:59:59
+dt1 9999-12-31 23:59:59.9
+dt2 9999-12-31 23:59:59.99
+dt3 9999-12-31 23:59:59.999
+dt4 9999-12-31 23:59:59.9999
+dt5 9999-12-31 23:59:59.99999
+dt6 9999-12-31 23:59:59.999999
+dt0 2001-01-01 01:01:01
+dt1 2001-01-01 01:01:01.1
+dt2 2001-01-01 01:01:01.11
+dt3 2001-01-01 01:01:01.111
+dt4 2001-01-01 01:01:01.1111
+dt5 2001-01-01 01:01:01.11111
+dt6 2001-01-01 01:01:01.111111
+SELECT * FROM mysql56timestamp;
+ts0 1970-01-01 00:00:01
+ts1 1970-01-01 00:00:01.0
+ts2 1970-01-01 00:00:01.00
+ts3 1970-01-01 00:00:01.000
+ts4 1970-01-01 00:00:01.0000
+ts5 1970-01-01 00:00:01.00000
+ts6 1970-01-01 00:00:01.000000
+ts0 2038-01-19 03:14:07
+ts1 2038-01-19 03:14:07.9
+ts2 2038-01-19 03:14:07.99
+ts3 2038-01-19 03:14:07.999
+ts4 2038-01-19 03:14:07.9999
+ts5 2038-01-19 03:14:07.99999
+ts6 2038-01-19 03:14:07.999999
+ts0 2001-01-01 01:01:01
+ts1 2001-01-01 01:01:01.1
+ts2 2001-01-01 01:01:01.11
+ts3 2001-01-01 01:01:01.111
+ts4 2001-01-01 01:01:01.1111
+ts5 2001-01-01 01:01:01.11111
+ts6 2001-01-01 01:01:01.111111
+DROP TABLE mysql56time;
+DROP TABLE mysql56datetime;
+DROP TABLE mysql56timestamp;
+include/rpl_end.inc
=== added file 'mysql-test/suite/rpl/t/rpl_temporal_mysql56.test'
--- mysql-test/suite/rpl/t/rpl_temporal_mysql56.test 1970-01-01 00:00:00 +0000
+++ mysql-test/suite/rpl/t/rpl_temporal_mysql56.test 2013-06-27 10:57:17 +0000
@@ -0,0 +1,48 @@
+--source include/master-slave.inc
+
+connection master;
+SET TIME_ZONE='+00:00';
+let $MYSQLD_MASTER_DATADIR= `select @@datadir`;
+
+connection slave;
+SET TIME_ZONE='+00:00';
+let $MYSQLD_SLAVE_DATADIR= `select @@datadir`;
+
+--copy_file std_data/mysql56time.frm $MYSQLD_MASTER_DATADIR/test/mysql56time.frm
+--copy_file std_data/mysql56time.MYD $MYSQLD_MASTER_DATADIR/test/mysql56time.MYD
+--copy_file std_data/mysql56time.MYI $MYSQLD_MASTER_DATADIR/test/mysql56time.MYI
+--copy_file std_data/mysql56time.frm $MYSQLD_SLAVE_DATADIR/test/mysql56time.frm
+--copy_file std_data/mysql56time.MYD $MYSQLD_SLAVE_DATADIR/test/mysql56time.MYD
+--copy_file std_data/mysql56time.MYI $MYSQLD_SLAVE_DATADIR/test/mysql56time.MYI
+
+--copy_file std_data/mysql56datetime.frm $MYSQLD_MASTER_DATADIR/test/mysql56datetime.frm
+--copy_file std_data/mysql56datetime.MYD $MYSQLD_MASTER_DATADIR/test/mysql56datetime.MYD
+--copy_file std_data/mysql56datetime.MYI $MYSQLD_MASTER_DATADIR/test/mysql56datetime.MYI
+--copy_file std_data/mysql56datetime.frm $MYSQLD_SLAVE_DATADIR/test/mysql56datetime.frm
+--copy_file std_data/mysql56datetime.MYD $MYSQLD_SLAVE_DATADIR/test/mysql56datetime.MYD
+--copy_file std_data/mysql56datetime.MYI $MYSQLD_SLAVE_DATADIR/test/mysql56datetime.MYI
+
+--copy_file std_data/mysql56timestamp.frm $MYSQLD_MASTER_DATADIR/test/mysql56timestamp.frm
+--copy_file std_data/mysql56timestamp.MYD $MYSQLD_MASTER_DATADIR/test/mysql56timestamp.MYD
+--copy_file std_data/mysql56timestamp.MYI $MYSQLD_MASTER_DATADIR/test/mysql56timestamp.MYI
+--copy_file std_data/mysql56timestamp.frm $MYSQLD_SLAVE_DATADIR/test/mysql56timestamp.frm
+--copy_file std_data/mysql56timestamp.MYD $MYSQLD_SLAVE_DATADIR/test/mysql56timestamp.MYD
+--copy_file std_data/mysql56timestamp.MYI $MYSQLD_SLAVE_DATADIR/test/mysql56timestamp.MYI
+
+connection master;
+INSERT INTO mysql56time VALUES ('01:01:01','01:01:01.1','01:01:01.11','01:01:01.111','01:01:01.1111','01:01:01.11111','01:01:01.111111');
+INSERT INTO mysql56datetime VALUES ('2001-01-01 01:01:01','2001-01-01 01:01:01.1','2001-01-01 01:01:01.11','2001-01-01 01:01:01.111','2001-01-01 01:01:01.1111','2001-01-01 01:01:01.11111','2001-01-01 01:01:01.111111');
+INSERT INTO mysql56timestamp VALUES ('2001-01-01 01:01:01','2001-01-01 01:01:01.1','2001-01-01 01:01:01.11','2001-01-01 01:01:01.111','2001-01-01 01:01:01.1111','2001-01-01 01:01:01.11111','2001-01-01 01:01:01.111111');
+sync_slave_with_master;
+
+connection slave;
+--query_vertical SELECT * FROM mysql56time
+--query_vertical SELECT * FROM mysql56datetime
+--query_vertical SELECT * FROM mysql56timestamp
+
+connection master;
+DROP TABLE mysql56time;
+DROP TABLE mysql56datetime;
+DROP TABLE mysql56timestamp;
+
+--source include/rpl_end.inc
=== added file 'mysql-test/t/type_temporal_mysql56.test'
--- mysql-test/t/type_temporal_mysql56.test 1970-01-01 00:00:00 +0000
+++ mysql-test/t/type_temporal_mysql56.test 2013-06-27 10:55:55 +0000
@@ -0,0 +1,23 @@
+
+let $MYSQLD_DATADIR= `select @@datadir`;
+--copy_file std_data/mysql56time.frm $MYSQLD_DATADIR/test/mysql56time.frm
+--copy_file std_data/mysql56time.MYD $MYSQLD_DATADIR/test/mysql56time.MYD
+--copy_file std_data/mysql56time.MYI $MYSQLD_DATADIR/test/mysql56time.MYI
+SHOW CREATE TABLE mysql56time;
+--query_vertical SELECT * FROM mysql56time
+DROP TABLE mysql56time;
+
+--copy_file std_data/mysql56datetime.frm $MYSQLD_DATADIR/test/mysql56datetime.frm
+--copy_file std_data/mysql56datetime.MYD $MYSQLD_DATADIR/test/mysql56datetime.MYD
+--copy_file std_data/mysql56datetime.MYI $MYSQLD_DATADIR/test/mysql56datetime.MYI
+SHOW CREATE TABLE mysql56datetime;
+--query_vertical SELECT * FROM mysql56datetime
+DROP TABLE mysql56datetime;
+
+--copy_file std_data/mysql56timestamp.frm $MYSQLD_DATADIR/test/mysql56timestamp.frm
+--copy_file std_data/mysql56timestamp.MYD $MYSQLD_DATADIR/test/mysql56timestamp.MYD
+--copy_file std_data/mysql56timestamp.MYI $MYSQLD_DATADIR/test/mysql56timestamp.MYI
+SET TIME_ZONE='+00:00';
+SHOW CREATE TABLE mysql56timestamp;
+--query_vertical SELECT * FROM mysql56timestamp
+DROP TABLE mysql56timestamp;
=== modified file 'sql-common/my_time.c'
--- sql-common/my_time.c 2013-04-07 12:00:16 +0000
+++ sql-common/my_time.c 2013-06-27 12:42:14 +0000
@@ -203,6 +203,29 @@ static uint skip_digits(const char **str
return s - start;
}
+
+/**
+ Check datetime, date, or normalized time (i.e. time without days) range.
+ @param ltime Datetime value.
+ @returns
+ @retval FALSE on success
+ @retval TRUE on error
+*/
+my_bool check_datetime_range(const MYSQL_TIME *ltime)
+{
+ /*
+ In case of MYSQL_TIMESTAMP_TIME hour value can be up to TIME_MAX_HOUR.
+ In case of MYSQL_TIMESTAMP_DATETIME it cannot be bigger than 23.
+ */
+ return
+ ltime->year > 9999 || ltime->month > 12 || ltime->day > 31 ||
+ ltime->minute > 59 || ltime->second > 59 ||
+ ltime->second_part > TIME_MAX_SECOND_PART ||
+ (ltime->hour >
+ (ltime->time_type == MYSQL_TIMESTAMP_TIME ? TIME_MAX_HOUR : 23));
+}
+
+
/*
Convert a timestamp string to a MYSQL_TIME value.
@@ -332,9 +355,14 @@ str_to_datetime(const char *str, uint le
uint second_part;
const char *start= ++str;
*was_cut= get_digits(&second_part, &number_of_fields, &str, end, 6);
- if (str - start < 6)
- second_part*= log_10_int[6 - (str - start)];
- l_time->second_part= second_part;
+ if (number_of_fields == 7)
+ {
+ if (str - start < 6)
+ second_part*= log_10_int[6 - (str - start)];
+ l_time->second_part= second_part;
+ }
+ else
+ l_time->second_part= 0;
if (skip_digits(&str, end))
*was_cut= 1;
}
@@ -1101,6 +1129,27 @@ int my_TIME_to_str(const MYSQL_TIME *l_t
}
+/**
+ Print a timestamp with an optional fractional part: XXXXX[.YYYYY]
+
+ @param tm The timestamp value to print.
+ @param OUT to The string pointer to print at.
+ @param dec Precision, in the range 0..6.
+ @return The length of the result string.
+*/
+int my_timeval_to_str(const struct timeval *tm, char *to, uint dec)
+{
+ char *pos= to + sprintf(to, "%d", (int) tm->tv_sec);
+ if (dec)
+ {
+ *pos++= '.';
+ pos= fmt_number((uint) sec_part_shift(tm->tv_usec, dec), pos, dec);
+ }
+ *pos= '\0';
+ return (int) (pos - to);
+}
+
+
/*
Convert datetime value specified as number to broken-down TIME
representation and form value of DATETIME type as side-effect.
=== modified file 'sql/CMakeLists.txt'
--- sql/CMakeLists.txt 2013-06-06 19:32:29 +0000
+++ sql/CMakeLists.txt 2013-06-27 12:13:26 +0000
@@ -37,7 +37,7 @@ IF(SSL_DEFINES)
ENDIF()
SET (SQL_SOURCE
- ../sql-common/client.c derror.cc des_key_file.cc
+ ../sql-common/client.c compat56.cc derror.cc des_key_file.cc
discover.cc ../libmysql/errmsg.c field.cc field_conv.cc
filesort_utils.cc
filesort.cc gstream.cc sha2.cc
=== added file 'sql/compat56.cc'
--- sql/compat56.cc 1970-01-01 00:00:00 +0000
+++ sql/compat56.cc 2013-06-27 12:42:32 +0000
@@ -0,0 +1,445 @@
+/*
+ Copyright (c) 2004, 2012, Oracle and/or its affiliates.
+ Copyright (c) 2013, MariaDB Foundation.
+
+ 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.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+
+#include "my_global.h"
+#include "compat56.h"
+#include "myisampack.h"
+#include "my_time.h"
+
+/*** MySQL56 TIME low-level memory and disk representation routines ***/
+
+/*
+ In-memory format:
+
+ 1 bit sign (Used for sign, when on disk)
+ 1 bit unused (Reserved for wider hour range, e.g. for intervals)
+ 10 bit hour (0-836)
+ 6 bit minute (0-59)
+ 6 bit second (0-59)
+ 24 bits microseconds (0-999999)
+
+ Total: 48 bits = 6 bytes
+ Suhhhhhh.hhhhmmmm.mmssssss.ffffffff.ffffffff.ffffffff
+*/
+
+
+/**
+ Convert time value to MySQL56 numeric packed representation.
+
+ @param ltime The value to convert.
+ @return Numeric packed representation.
+*/
+longlong TIME_to_longlong_time_packed(const MYSQL_TIME *ltime)
+{
+ /* If month is 0, we mix day with hours: "1 00:10:10" -> "24:00:10" */
+ long hms= (((ltime->month ? 0 : ltime->day * 24) + ltime->hour) << 12) |
+ (ltime->minute << 6) | ltime->second;
+ longlong tmp= MY_PACKED_TIME_MAKE(hms, ltime->second_part);
+ return ltime->neg ? -tmp : tmp;
+}
+
+
+
+/**
+ Convert MySQL56 time packed numeric representation to time.
+
+ @param OUT ltime The MYSQL_TIME variable to set.
+ @param tmp The packed numeric representation.
+*/
+void TIME_from_longlong_time_packed(MYSQL_TIME *ltime, longlong tmp)
+{
+ long hms;
+ if ((ltime->neg= (tmp < 0)))
+ tmp= -tmp;
+ hms= MY_PACKED_TIME_GET_INT_PART(tmp);
+ ltime->year= (uint) 0;
+ ltime->month= (uint) 0;
+ ltime->day= (uint) 0;
+ ltime->hour= (uint) (hms >> 12) % (1 << 10); /* 10 bits starting at 12th */
+ ltime->minute= (uint) (hms >> 6) % (1 << 6); /* 6 bits starting at 6th */
+ ltime->second= (uint) hms % (1 << 6); /* 6 bits starting at 0th */
+ ltime->second_part= MY_PACKED_TIME_GET_FRAC_PART(tmp);
+ ltime->time_type= MYSQL_TIMESTAMP_TIME;
+}
+
+
+/**
+ Calculate binary size of MySQL56 packed numeric time representation.
+
+ @param dec Precision.
+*/
+uint my_time_binary_length(uint dec)
+{
+ DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS);
+ return 3 + (dec + 1) / 2;
+}
+
+
+/*
+ On disk we convert from signed representation to unsigned
+ representation using TIMEF_OFS, so all values become binary comparable.
+*/
+#define TIMEF_OFS 0x800000000000LL
+#define TIMEF_INT_OFS 0x800000LL
+
+
+/**
+ Convert MySQL56 in-memory numeric time representation to on-disk representation
+
+ @param nr Value in packed numeric time format.
+ @param OUT ptr The buffer to put value at.
+ @param dec Precision.
+*/
+void my_time_packed_to_binary(longlong nr, uchar *ptr, uint dec)
+{
+ DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS);
+ /* Make sure the stored value was previously properly rounded or truncated */
+ DBUG_ASSERT((MY_PACKED_TIME_GET_FRAC_PART(nr) %
+ (int) log_10_int[TIME_SECOND_PART_DIGITS - dec]) == 0);
+
+ switch (dec)
+ {
+ case 0:
+ default:
+ mi_int3store(ptr, TIMEF_INT_OFS + MY_PACKED_TIME_GET_INT_PART(nr));
+ break;
+
+ case 1:
+ case 2:
+ mi_int3store(ptr, TIMEF_INT_OFS + MY_PACKED_TIME_GET_INT_PART(nr));
+ ptr[3]= (unsigned char) (char) (MY_PACKED_TIME_GET_FRAC_PART(nr) / 10000);
+ break;
+
+ case 4:
+ case 3:
+ mi_int3store(ptr, TIMEF_INT_OFS + MY_PACKED_TIME_GET_INT_PART(nr));
+ mi_int2store(ptr + 3, MY_PACKED_TIME_GET_FRAC_PART(nr) / 100);
+ break;
+
+ case 5:
+ case 6:
+ mi_int6store(ptr, nr + TIMEF_OFS);
+ break;
+ }
+}
+
+
+/**
+ Convert MySQL56 on-disk time representation to in-memory packed numeric
+ representation.
+
+ @param ptr The pointer to read the value at.
+ @param dec Precision.
+ @return Packed numeric time representation.
+*/
+longlong my_time_packed_from_binary(const uchar *ptr, uint dec)
+{
+ DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS);
+
+ switch (dec)
+ {
+ case 0:
+ default:
+ {
+ longlong intpart= mi_uint3korr(ptr) - TIMEF_INT_OFS;
+ return MY_PACKED_TIME_MAKE_INT(intpart);
+ }
+ case 1:
+ case 2:
+ {
+ longlong intpart= mi_uint3korr(ptr) - TIMEF_INT_OFS;
+ int frac= (uint) ptr[3];
+ if (intpart < 0 && frac)
+ {
+ /*
+ Negative values are stored with reverse fractional part order,
+ for binary sort compatibility.
+
+ Disk value intpart frac Time value Memory value
+ 800000.00 0 0 00:00:00.00 0000000000.000000
+ 7FFFFF.FF -1 255 -00:00:00.01 FFFFFFFFFF.FFD8F0
+ 7FFFFF.9D -1 99 -00:00:00.99 FFFFFFFFFF.F0E4D0
+ 7FFFFF.00 -1 0 -00:00:01.00 FFFFFFFFFF.000000
+ 7FFFFE.FF -1 255 -00:00:01.01 FFFFFFFFFE.FFD8F0
+ 7FFFFE.F6 -2 246 -00:00:01.10 FFFFFFFFFE.FE7960
+
+ Formula to convert fractional part from disk format
+ (now stored in "frac" variable) to absolute value: "0x100 - frac".
+ To reconstruct in-memory value, we shift
+ to the next integer value and then substruct fractional part.
+ */
+ intpart++; /* Shift to the next integer value */
+ frac-= 0x100; /* -(0x100 - frac) */
+ }
+ return MY_PACKED_TIME_MAKE(intpart, frac * 10000);
+ }
+
+ case 3:
+ case 4:
+ {
+ longlong intpart= mi_uint3korr(ptr) - TIMEF_INT_OFS;
+ int frac= mi_uint2korr(ptr + 3);
+ if (intpart < 0 && frac)
+ {
+ /*
+ Fix reverse fractional part order: "0x10000 - frac".
+ See comments for FSP=1 and FSP=2 above.
+ */
+ intpart++; /* Shift to the next integer value */
+ frac-= 0x10000; /* -(0x10000-frac) */
+ }
+ return MY_PACKED_TIME_MAKE(intpart, frac * 100);
+ }
+
+ case 5:
+ case 6:
+ return ((longlong) mi_uint6korr(ptr)) - TIMEF_OFS;
+ }
+}
+
+
+/*** MySQL56 DATETIME low-level memory and disk representation routines ***/
+
+/*
+ 1 bit sign (used when on disk)
+ 17 bits year*13+month (year 0-9999, month 0-12)
+ 5 bits day (0-31)
+ 5 bits hour (0-23)
+ 6 bits minute (0-59)
+ 6 bits second (0-59)
+ 24 bits microseconds (0-999999)
+
+ Total: 64 bits = 8 bytes
+
+ SYYYYYYY.YYYYYYYY.YYdddddh.hhhhmmmm.mmssssss.ffffffff.ffffffff.ffffffff
+*/
+
+/**
+ Convert datetime to MySQL56 packed numeric datetime representation.
+ @param ltime The value to convert.
+ @return Packed numeric representation of ltime.
+*/
+longlong TIME_to_longlong_datetime_packed(const MYSQL_TIME *ltime)
+{
+ longlong ymd= ((ltime->year * 13 + ltime->month) << 5) | ltime->day;
+ longlong hms= (ltime->hour << 12) | (ltime->minute << 6) | ltime->second;
+ longlong tmp= MY_PACKED_TIME_MAKE(((ymd << 17) | hms), ltime->second_part);
+ DBUG_ASSERT(!check_datetime_range(ltime)); /* Make sure no overflow */
+ return ltime->neg ? -tmp : tmp;
+}
+
+
+/**
+ Convert MySQL56 packed numeric datetime representation to MYSQL_TIME.
+ @param OUT ltime The datetime variable to convert to.
+ @param tmp The packed numeric datetime value.
+*/
+void TIME_from_longlong_datetime_packed(MYSQL_TIME *ltime, longlong tmp)
+{
+ longlong ymd, hms;
+ longlong ymdhms, ym;
+ if ((ltime->neg= (tmp < 0)))
+ tmp= -tmp;
+
+ ltime->second_part= MY_PACKED_TIME_GET_FRAC_PART(tmp);
+ ymdhms= MY_PACKED_TIME_GET_INT_PART(tmp);
+
+ ymd= ymdhms >> 17;
+ ym= ymd >> 5;
+ hms= ymdhms % (1 << 17);
+
+ ltime->day= ymd % (1 << 5);
+ ltime->month= ym % 13;
+ ltime->year= ym / 13;
+
+ ltime->second= hms % (1 << 6);
+ ltime->minute= (hms >> 6) % (1 << 6);
+ ltime->hour= (hms >> 12);
+
+ ltime->time_type= MYSQL_TIMESTAMP_DATETIME;
+}
+
+
+/**
+ Calculate binary size of MySQL56 packed datetime representation.
+ @param dec Precision.
+*/
+uint my_datetime_binary_length(uint dec)
+{
+ DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS);
+ return 5 + (dec + 1) / 2;
+}
+
+
+/*
+ On disk we store as unsigned number with DATETIMEF_INT_OFS offset,
+ for HA_KETYPE_BINARY compatibilty purposes.
+*/
+#define DATETIMEF_INT_OFS 0x8000000000LL
+
+
+/**
+ Convert MySQL56 on-disk datetime representation
+ to in-memory packed numeric representation.
+
+ @param ptr The pointer to read value at.
+ @param dec Precision.
+ @return In-memory packed numeric datetime representation.
+*/
+longlong my_datetime_packed_from_binary(const uchar *ptr, uint dec)
+{
+ longlong intpart= mi_uint5korr(ptr) - DATETIMEF_INT_OFS;
+ int frac;
+ DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS);
+ switch (dec)
+ {
+ case 0:
+ default:
+ return MY_PACKED_TIME_MAKE_INT(intpart);
+ case 1:
+ case 2:
+ frac= ((int) (signed char) ptr[5]) * 10000;
+ break;
+ case 3:
+ case 4:
+ frac= mi_sint2korr(ptr + 5) * 100;
+ break;
+ case 5:
+ case 6:
+ frac= mi_sint3korr(ptr + 5);
+ break;
+ }
+ return MY_PACKED_TIME_MAKE(intpart, frac);
+}
+
+
+/**
+ Store MySQL56 in-memory numeric packed datetime representation to disk.
+
+ @param nr In-memory numeric packed datetime representation.
+ @param OUT ptr The pointer to store at.
+ @param dec Precision, 1-6.
+*/
+void my_datetime_packed_to_binary(longlong nr, uchar *ptr, uint dec)
+{
+ DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS);
+ /* The value being stored must have been properly rounded or truncated */
+ DBUG_ASSERT((MY_PACKED_TIME_GET_FRAC_PART(nr) %
+ (int) log_10_int[TIME_SECOND_PART_DIGITS - dec]) == 0);
+
+ mi_int5store(ptr, MY_PACKED_TIME_GET_INT_PART(nr) + DATETIMEF_INT_OFS);
+ switch (dec)
+ {
+ case 0:
+ default:
+ break;
+ case 1:
+ case 2:
+ ptr[5]= (unsigned char) (char) (MY_PACKED_TIME_GET_FRAC_PART(nr) / 10000);
+ break;
+ case 3:
+ case 4:
+ mi_int2store(ptr + 5, MY_PACKED_TIME_GET_FRAC_PART(nr) / 100);
+ break;
+ case 5:
+ case 6:
+ mi_int3store(ptr + 5, MY_PACKED_TIME_GET_FRAC_PART(nr));
+ }
+}
+
+
+/*** MySQL56 TIMESTAMP low-level memory and disk representation routines ***/
+
+/**
+ Calculate on-disk size of a timestamp value.
+
+ @param dec Precision.
+*/
+uint my_timestamp_binary_length(uint dec)
+{
+ DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS);
+ return 4 + (dec + 1) / 2;
+}
+
+
+/**
+ Convert MySQL56 binary timestamp representation to in-memory representation.
+
+ @param OUT tm The variable to convert to.
+ @param ptr The pointer to read the value from.
+ @param dec Precision.
+*/
+void my_timestamp_from_binary(struct timeval *tm, const uchar *ptr, uint dec)
+{
+ DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS);
+ tm->tv_sec= mi_uint4korr(ptr);
+ switch (dec)
+ {
+ case 0:
+ default:
+ tm->tv_usec= 0;
+ break;
+ case 1:
+ case 2:
+ tm->tv_usec= ((int) ptr[4]) * 10000;
+ break;
+ case 3:
+ case 4:
+ tm->tv_usec= mi_sint2korr(ptr + 4) * 100;
+ break;
+ case 5:
+ case 6:
+ tm->tv_usec= mi_sint3korr(ptr + 4);
+ }
+}
+
+
+/**
+ Convert MySQL56 in-memory timestamp representation to on-disk representation.
+
+ @param tm The value to convert.
+ @param OUT ptr The pointer to store the value to.
+ @param dec Precision.
+*/
+void my_timestamp_to_binary(const struct timeval *tm, uchar *ptr, uint dec)
+{
+ DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS);
+ /* Stored value must have been previously properly rounded or truncated */
+ DBUG_ASSERT((tm->tv_usec %
+ (int) log_10_int[TIME_SECOND_PART_DIGITS - dec]) == 0);
+ mi_int4store(ptr, tm->tv_sec);
+ switch (dec)
+ {
+ case 0:
+ default:
+ break;
+ case 1:
+ case 2:
+ ptr[4]= (unsigned char) (char) (tm->tv_usec / 10000);
+ break;
+ case 3:
+ case 4:
+ mi_int2store(ptr + 4, tm->tv_usec / 100);
+ break;
+ /* Impossible second precision. Fall through */
+ case 5:
+ case 6:
+ mi_int3store(ptr + 4, tm->tv_usec);
+ }
+}
+
+/****************************************/
=== added file 'sql/compat56.h'
--- sql/compat56.h 1970-01-01 00:00:00 +0000
+++ sql/compat56.h 2013-06-27 12:41:04 +0000
@@ -0,0 +1,46 @@
+#ifndef COMPAT56_H_INCLUDED
+#define COMPAT56_H_INCLUDED
+/*
+ Copyright (c) 2004, 2012, Oracle and/or its affiliates.
+ Copyright (c) 2013 MariaDB Foundation.
+
+ 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.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+
+
+/** MySQL56 routines and macros **/
+#define MY_PACKED_TIME_GET_INT_PART(x) ((x) >> 24)
+#define MY_PACKED_TIME_GET_FRAC_PART(x) ((x) % (1LL << 24))
+#define MY_PACKED_TIME_MAKE(i, f) ((((longlong) (i)) << 24) + (f))
+#define MY_PACKED_TIME_MAKE_INT(i) ((((longlong) (i)) << 24))
+
+longlong TIME_to_longlong_datetime_packed(const MYSQL_TIME *);
+longlong TIME_to_longlong_time_packed(const MYSQL_TIME *);
+
+void TIME_from_longlong_datetime_packed(MYSQL_TIME *ltime, longlong nr);
+void TIME_from_longlong_time_packed(MYSQL_TIME *ltime, longlong nr);
+
+void my_datetime_packed_to_binary(longlong nr, uchar *ptr, uint dec);
+longlong my_datetime_packed_from_binary(const uchar *ptr, uint dec);
+uint my_datetime_binary_length(uint dec);
+
+void my_time_packed_to_binary(longlong nr, uchar *ptr, uint dec);
+longlong my_time_packed_from_binary(const uchar *ptr, uint dec);
+uint my_time_binary_length(uint dec);
+
+void my_timestamp_to_binary(const struct timeval *tm, uchar *ptr, uint dec);
+void my_timestamp_from_binary(struct timeval *tm, const uchar *ptr, uint dec);
+uint my_timestamp_binary_length(uint dec);
+/** End of MySQL routines and macros **/
+
+#endif /* COMPAT56_H_INCLUDED */
=== modified file 'sql/field.cc'
--- sql/field.cc 2013-06-06 19:32:29 +0000
+++ sql/field.cc 2013-07-01 06:01:51 +0000
@@ -87,6 +87,7 @@ const char field_separator=',';
#define FIELDTYPE_NUM (FIELDTYPE_TEAR_FROM + (255 - FIELDTYPE_TEAR_TO))
static inline int field_type2index (enum_field_types field_type)
{
+ field_type= real_type_to_type(field_type);
return (field_type < FIELDTYPE_TEAR_FROM ?
field_type :
((int)FIELDTYPE_TEAR_FROM) + (field_type - FIELDTYPE_TEAR_TO) - 1);
@@ -947,8 +948,10 @@ static enum_field_types field_types_merg
enum_field_types Field::field_type_merge(enum_field_types a,
enum_field_types b)
{
- DBUG_ASSERT(a < FIELDTYPE_TEAR_FROM || a > FIELDTYPE_TEAR_TO);
- DBUG_ASSERT(b < FIELDTYPE_TEAR_FROM || b > FIELDTYPE_TEAR_TO);
+ DBUG_ASSERT(real_type_to_type(a) < FIELDTYPE_TEAR_FROM ||
+ real_type_to_type(a) > FIELDTYPE_TEAR_TO);
+ DBUG_ASSERT(real_type_to_type(b) < FIELDTYPE_TEAR_FROM ||
+ real_type_to_type(b) > FIELDTYPE_TEAR_TO);
return field_types_merge_rules[field_type2index(a)]
[field_type2index(b)];
}
@@ -1042,8 +1045,8 @@ CPP_UNNAMED_NS_END
Item_result Field::result_merge_type(enum_field_types field_type)
{
- DBUG_ASSERT(field_type < FIELDTYPE_TEAR_FROM || field_type
- > FIELDTYPE_TEAR_TO);
+ DBUG_ASSERT(real_type_to_type(field_type) < FIELDTYPE_TEAR_FROM ||
+ real_type_to_type(field_type) > FIELDTYPE_TEAR_TO);
return field_types_result_type[field_type2index(field_type)];
}
@@ -1130,6 +1133,111 @@ void Field::make_sort_key(uchar *buff,ui
/**
+ @brief
+ Determine the relative position of the field value in a numeric interval
+
+ @details
+ The function returns a double number between 0.0 and 1.0 as the relative
+ position of the value of the this field in the numeric interval of [min,max].
+ If the value is not in the interval the the function returns 0.0 when
+ the value is less than min, and, 1.0 when the value is greater than max.
+
+ @param min value of the left end of the interval
+ @param max value of the right end of the interval
+
+ @return
+ relative position of the field value in the numeric interval [min,max]
+*/
+
+double Field::pos_in_interval_val_real(Field *min, Field *max)
+{
+ double n, d;
+ n= val_real() - min->val_real();
+ if (n < 0)
+ return 0.0;
+ d= max->val_real() - min->val_real();
+ if (d <= 0)
+ return 1.0;
+ return min(n/d, 1.0);
+}
+
+
+static
+inline ulonglong char_prefix_to_ulonglong(uchar *src)
+{
+ uint sz= sizeof(ulonglong);
+ for (uint i= 0; i < sz/2; i++)
+ {
+ uchar tmp= src[i];
+ src[i]= src[sz-1-i];
+ src[sz-1-i]= tmp;
+ }
+ return uint8korr(src);
+}
+
+
+/**
+ @brief
+ Determine the relative position of the field value in a string interval
+
+ @details
+ The function returns a double number between 0.0 and 1.0 as the relative
+ position of the value of the this field in the string interval of [min,max].
+ If the value is not in the interval the the function returns 0.0 when
+ the value is less than min, and, 1.0 when the value is greater than max.
+
+ @note
+ To calculate the relative position of the string value v in the interval
+ [min, max] the function first converts the beginning of these three
+ strings v, min, max into the strings that are used for byte comparison.
+ For each string not more sizeof(ulonglong) first bytes are taken
+ from the result of conversion. Then these bytes are interpreted as the
+ big-endian representation of an ulonglong integer. The values of these
+ integer numbers obtained for the strings v, min, max are used to calculate
+ the position of v in [min,max] in the same way is it's done for numeric
+ fields (see Field::pos_in_interval_val_real).
+
+ @todo
+ Improve the procedure for the case when min and max have the same
+ beginning
+
+ @param min value of the left end of the interval
+ @param max value of the right end of the interval
+
+ @return
+ relative position of the field value in the string interval [min,max]
+*/
+
+double Field::pos_in_interval_val_str(Field *min, Field *max, uint data_offset)
+{
+ uchar mp_prefix[sizeof(ulonglong)];
+ uchar minp_prefix[sizeof(ulonglong)];
+ uchar maxp_prefix[sizeof(ulonglong)];
+ ulonglong mp, minp, maxp;
+ my_strnxfrm(charset(), mp_prefix, sizeof(mp),
+ ptr + data_offset,
+ data_length());
+ my_strnxfrm(charset(), minp_prefix, sizeof(minp),
+ min->ptr + data_offset,
+ min->data_length());
+ my_strnxfrm(charset(), maxp_prefix, sizeof(maxp),
+ max->ptr + data_offset,
+ max->data_length());
+ mp= char_prefix_to_ulonglong(mp_prefix);
+ minp= char_prefix_to_ulonglong(minp_prefix);
+ maxp= char_prefix_to_ulonglong(maxp_prefix);
+ double n, d;
+ n= mp - minp;
+ if (n < 0)
+ return 0.0;
+ d= maxp - minp;
+ if (d <= 0)
+ return 1.0;
+ return min(n/d, 1.0);
+}
+
+
+/**
Numeric fields base class constructor.
*/
Field_num::Field_num(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
@@ -1275,36 +1383,6 @@ bool Field_num::get_int(CHARSET_INFO *cs
/**
- @brief
- Determine the relative position of the field value in a numeric interval
-
- @details
- The function returns a double number between 0.0 and 1.0 as the relative
- position of the value of the this field in the numeric interval of [min,max].
- If the value is not in the interval the the function returns 0.0 when
- the value is less than min, and, 1.0 when the value is greater than max.
-
- @param min value of the left end of the interval
- @param max value of the right end of the interval
-
- @return
- relative position of the field value in the numeric interval [min,max]
-*/
-
-double Field_num::pos_in_interval(Field *min, Field *max)
-{
- double n, d;
- n= val_real() - min->val_real();
- if (n < 0)
- return 0.0;
- d= max->val_real() - min->val_real();
- if (d <= 0)
- return 1.0;
- return min(n/d, 1.0);
-}
-
-
-/**
Process decimal library return codes and issue warnings for overflow and
truncation.
@@ -4485,13 +4563,12 @@ Field_timestamp::Field_timestamp(uchar *
uchar *null_ptr_arg, uchar null_bit_arg,
enum utype unireg_check_arg,
const char *field_name_arg,
- TABLE_SHARE *share,
- CHARSET_INFO *cs)
- :Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg, cs)
+ TABLE_SHARE *share)
+ :Field_temporal(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
+ unireg_check_arg, field_name_arg)
{
/* For 4.0 MYD and 4.0 InnoDB compatibility */
- flags|= UNSIGNED_FLAG | BINARY_FLAG;
+ flags|= UNSIGNED_FLAG;
if (unireg_check != NONE)
{
/*
@@ -4636,6 +4713,7 @@ String *Field_timestamp::val_str(String
{
MYSQL_TIME ltime;
uint32 temp, temp2;
+ uint dec;
char *to;
val_buffer->alloc(field_length+1);
@@ -4690,6 +4768,16 @@ String *Field_timestamp::val_str(String
*to++= (char) ('0'+(char) (temp));
*to= 0;
val_buffer->set_charset(&my_charset_numeric);
+
+ if ((dec= decimals()))
+ {
+ ulong sec_part= (ulong) sec_part_shift(ltime.second_part, dec);
+ char *buf= const_cast<char*>(val_buffer->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 val_buffer;
}
@@ -4743,7 +4831,14 @@ void Field_timestamp::sort_string(uchar
void Field_timestamp::sql_type(String &res) const
{
- res.set_ascii(STRING_WITH_LEN("timestamp"));
+ if (!decimals())
+ {
+ res.set_ascii(STRING_WITH_LEN("timestamp"));
+ return;
+ }
+ CHARSET_INFO *cs=res.charset();
+ res.length(cs->cset->snprintf(cs, (char*) res.ptr(), res.alloced_length(),
+ "timestamp(%u)", decimals()));
}
@@ -4783,13 +4878,6 @@ void Field_timestamp::set_explicit_defau
set_has_explicit_value();
}
-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));
-}
-
#ifdef NOT_USED
static void store_native(ulonglong num, uchar *to, uint bytes)
{
@@ -4883,7 +4971,7 @@ my_time_t Field_timestamp_hires::get_tim
return mi_uint4korr(ptr);
}
-double Field_timestamp_hires::val_real(void)
+double Field_timestamp_with_dec::val_real(void)
{
MYSQL_TIME ltime;
if (get_date(<ime, TIME_NO_ZERO_DATE))
@@ -4894,31 +4982,14 @@ double Field_timestamp_hires::val_real(v
ltime.minute * 1e2 + ltime.second + ltime.second_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;
-
- 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;
-}
-
-
-my_decimal *Field_timestamp_hires::val_decimal(my_decimal *d)
+my_decimal *Field_timestamp_with_dec::val_decimal(my_decimal *d)
{
MYSQL_TIME ltime;
get_date(<ime, 0);
return TIME_to_my_decimal(<ime, d);
}
-int Field_timestamp_hires::store_decimal(const my_decimal *d)
+int Field_timestamp::store_decimal(const my_decimal *d)
{
ulonglong nr;
ulong sec_part;
@@ -4941,7 +5012,7 @@ int Field_timestamp_hires::store_decimal
return store_TIME_with_warning(thd, <ime, &str, error, tmp != -1);
}
-int Field_timestamp_hires::set_time()
+int Field_timestamp_with_dec::set_time()
{
THD *thd= get_thd();
set_notnull();
@@ -4949,7 +5020,7 @@ int Field_timestamp_hires::set_time()
return 0;
}
-bool Field_timestamp_hires::send_binary(Protocol *protocol)
+bool Field_timestamp_with_dec::send_binary(Protocol *protocol)
{
MYSQL_TIME ltime;
Field_timestamp::get_date(<ime, 0);
@@ -4970,23 +5041,72 @@ int Field_timestamp_hires::cmp(const uch
}
-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)
+void Field_timestamp_with_dec::make_field(Send_field *field)
{
Field::make_field(field);
field->decimals= dec;
}
+
+/*************************************************************
+** MySQL-5.6 compatible TIMESTAMP(N)
+**************************************************************/
+
+void Field_timestampf::store_TIME(my_time_t timestamp, ulong sec_part)
+{
+ struct timeval tm;
+ tm.tv_sec= timestamp;
+ tm.tv_usec= sec_part;
+ my_timeval_trunc(&tm, dec);
+ my_timestamp_to_binary(&tm, ptr, dec);
+}
+
+
+my_time_t Field_timestampf::get_timestamp(ulong *sec_part) const
+{
+ struct timeval tm;
+ my_timestamp_from_binary(&tm, ptr, dec);
+ *sec_part= tm.tv_usec;
+ return tm.tv_sec;
+}
+
+
+/*************************************************************/
+uint Field_temporal::is_equal(Create_field *new_field)
+{
+ return new_field->sql_type == real_type() &&
+ new_field->length == max_display_length();
+}
+
+
+void Field_temporal::set_warnings(MYSQL_ERROR::enum_warning_level trunc_level,
+ const ErrConv *str, int was_cut,
+ timestamp_type ts_type)
+{
+ /*
+ 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, mysql_type_to_time_type(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, mysql_type_to_time_type(type()), 1);
+}
+
+
/*
Store string into a date/time field
@@ -4997,21 +5117,21 @@ void Field_timestamp_hires::make_field(S
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 ErrConv *str,
- int was_cut, int have_smth_to_conv)
+int Field_temporal_with_date::store_TIME_with_warning(MYSQL_TIME *ltime,
+ const ErrConv *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;
- if (was_cut == 0 &&
- have_smth_to_conv == 0 &&
- mysql_type_to_time_type(type()) != MYSQL_TIMESTAMP_TIME) // special case: zero date
+ if (was_cut == 0 && have_smth_to_conv == 0) // special case: zero date
+ {
was_cut= MYSQL_TIME_WARN_OUT_OF_RANGE;
- else
- if (!have_smth_to_conv)
+ }
+ else if (!have_smth_to_conv)
{
bzero(ltime, sizeof(*ltime));
was_cut= MYSQL_TIME_WARN_TRUNCATED;
@@ -5025,39 +5145,13 @@ int Field_temporal::store_TIME_with_warn
was_cut|= MYSQL_TIME_WARN_TRUNCATED;
ret= 3;
}
- else if (!(was_cut & MYSQL_TIME_WARN_TRUNCATED) &&
- mysql_type_to_time_type(type()) == MYSQL_TIMESTAMP_TIME &&
- (ltime->year || ltime->month))
- {
- ltime->year= ltime->month= ltime->day= 0;
- trunc_level= MYSQL_ERROR::WARN_LEVEL_NOTE;
- was_cut|= MYSQL_TIME_WARN_TRUNCATED;
- ret= 3;
- }
-
- /*
- error code logic:
- 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, mysql_type_to_time_type(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, mysql_type_to_time_type(type()), 1);
-
+ set_warnings(trunc_level, str, was_cut, mysql_type_to_time_type(type()));
store_TIME(ltime);
return was_cut ? ret : 0;
}
-int Field_temporal::store(const char *from,uint len,CHARSET_INFO *cs)
+int Field_temporal_with_date::store(const char *from, uint len, CHARSET_INFO *cs)
{
MYSQL_TIME ltime;
int error;
@@ -5075,7 +5169,7 @@ int Field_temporal::store(const char *fr
}
-int Field_temporal::store(double nr)
+int Field_temporal_with_date::store(double nr)
{
int error= 0;
MYSQL_TIME ltime;
@@ -5092,7 +5186,7 @@ int Field_temporal::store(double nr)
}
-int Field_temporal::store(longlong nr, bool unsigned_val)
+int Field_temporal_with_date::store(longlong nr, bool unsigned_val)
{
int error;
MYSQL_TIME ltime;
@@ -5110,7 +5204,7 @@ int Field_temporal::store(longlong nr, b
}
-int Field_temporal::store_time_dec(MYSQL_TIME *ltime, uint dec)
+int Field_temporal_with_date::store_time_dec(MYSQL_TIME *ltime, uint dec)
{
int error = 0, have_smth_to_conv= 1;
MYSQL_TIME l_time= *ltime;
@@ -5144,6 +5238,35 @@ my_decimal *Field_temporal::val_decimal(
** In number context: HHMMSS
** Stored as a 3 byte unsigned int
****************************************************************************/
+int Field_time::store_TIME_with_warning(MYSQL_TIME *ltime,
+ const ErrConv *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;
+
+ if (!have_smth_to_conv)
+ {
+ bzero(ltime, sizeof(*ltime));
+ was_cut= MYSQL_TIME_WARN_TRUNCATED;
+ ret= 1;
+ }
+ else if (!(was_cut & MYSQL_TIME_WARN_TRUNCATED) &&
+ (ltime->year || ltime->month))
+ {
+ ltime->year= ltime->month= ltime->day= 0;
+ trunc_level= MYSQL_ERROR::WARN_LEVEL_NOTE;
+ was_cut|= MYSQL_TIME_WARN_TRUNCATED;
+ ret= 3;
+ }
+ set_warnings(trunc_level, str, was_cut, MYSQL_TIMESTAMP_TIME);
+ store_TIME(ltime);
+ return was_cut ? ret : 0;
+}
+
void Field_time::store_TIME(MYSQL_TIME *ltime)
{
@@ -5229,32 +5352,16 @@ longlong Field_time::val_int(void)
my_charset_bin
*/
-String *Field_time::val_str(String *val_buffer,
- String *val_ptr __attribute__((unused)))
+String *Field_time::val_str(String *str,
+ String *unused __attribute__((unused)))
{
ASSERT_COLUMN_MARKED_FOR_READ;
MYSQL_TIME ltime;
- long tmp=(long) sint3korr(ptr);
- ltime.neg= 0;
- if (tmp < 0)
- {
- 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);
- ltime.second= (uint) (tmp % 100);
- ltime.second_part= 0;
-
- val_buffer->alloc(MAX_DATE_STRING_REP_LENGTH);
- uint length= (uint) my_time_to_str(<ime,
- const_cast<char*>(val_buffer->ptr()), 0);
- val_buffer->length(length);
- val_buffer->set_charset(&my_charset_numeric);
-
- return val_buffer;
+ get_date(<ime, TIME_TIME_ONLY);
+ str->alloc(field_length + 1);
+ str->length(my_time_to_str(<ime, const_cast<char*>(str->ptr()), decimals()));
+ str->set_charset(&my_charset_numeric);
+ return str;
}
@@ -5297,8 +5404,8 @@ bool Field_time::get_date(MYSQL_TIME *lt
bool Field_time::send_binary(Protocol *protocol)
{
MYSQL_TIME ltime;
- Field_time::get_date(<ime, TIME_TIME_ONLY);
- return protocol->store_time(<ime, 0);
+ get_date(<ime, TIME_TIME_ONLY);
+ return protocol->store_time(<ime, decimals());
}
@@ -5319,7 +5426,14 @@ void Field_time::sort_string(uchar *to,u
void Field_time::sql_type(String &res) const
{
- res.set_ascii(STRING_WITH_LEN("time"));
+ if (decimals() == 0)
+ {
+ res.set_ascii(STRING_WITH_LEN("time"));
+ return;
+ }
+ const CHARSET_INFO *cs= res.charset();
+ res.length(cs->cset->snprintf(cs, (char*) res.ptr(), res.alloced_length(),
+ "time(%d)", decimals()));
}
int Field_time_hires::reset()
@@ -5335,7 +5449,7 @@ void Field_time_hires::store_TIME(MYSQL_
store_bigendian(packed, ptr, Field_time_hires::pack_length());
}
-int Field_time_hires::store_decimal(const my_decimal *d)
+int Field_time::store_decimal(const my_decimal *d)
{
ulonglong nr;
ulong sec_part;
@@ -5354,35 +5468,23 @@ uint32 Field_time_hires::pack_length() c
return time_hires_bytes[dec];
}
-longlong Field_time_hires::val_int(void)
+longlong Field_time_with_dec::val_int(void)
{
ASSERT_COLUMN_MARKED_FOR_READ;
MYSQL_TIME ltime;
- Field_time_hires::get_date(<ime, TIME_TIME_ONLY);
+ get_date(<ime, TIME_TIME_ONLY);
longlong val= TIME_to_ulonglong_time(<ime);
return ltime.neg ? -val : val;
}
-double Field_time_hires::val_real(void)
+double Field_time_with_dec::val_real(void)
{
ASSERT_COLUMN_MARKED_FOR_READ;
MYSQL_TIME ltime;
- Field_time_hires::get_date(<ime, TIME_TIME_ONLY);
+ 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, ulonglong fuzzydate)
{
uint32 len= pack_length();
@@ -5402,14 +5504,6 @@ bool Field_time_hires::get_date(MYSQL_TI
}
-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());
@@ -5424,17 +5518,36 @@ void Field_time_hires::sort_string(uchar
to[0]^= 128;
}
-void Field_time_hires::sql_type(String &res) const
+void Field_time_with_dec::make_field(Send_field *field)
{
- CHARSET_INFO *cs=res.charset();
- res.length(cs->cset->snprintf(cs, (char*) res.ptr(), res.alloced_length(),
- "time(%u)", dec));
+ Field::make_field(field);
+ field->decimals= dec;
}
-void Field_time_hires::make_field(Send_field *field)
+/****************************************************************************
+** time type with fsp (MySQL-5.6 version)
+** In string context: HH:MM:SS.FFFFFF
+** In number context: HHMMSS.FFFFFF
+****************************************************************************/
+
+int Field_timef::reset()
{
- Field::make_field(field);
- field->decimals= dec;
+ my_time_packed_to_binary(0, ptr, dec);
+ return 0;
+}
+
+void Field_timef::store_TIME(MYSQL_TIME *ltime)
+{
+ my_time_trunc(ltime, decimals());
+ longlong tmp= TIME_to_longlong_time_packed(ltime);
+ my_time_packed_to_binary(tmp, ptr, dec);
+}
+
+bool Field_timef::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+{
+ longlong tmp= my_time_packed_from_binary(ptr, dec);
+ TIME_from_longlong_time_packed(ltime, tmp);
+ return false;
}
/****************************************************************************
@@ -5792,8 +5905,8 @@ bool Field_datetime::send_binary(Protoco
Field_datetime::get_date(&tm, TIME_FUZZY_DATE);
return protocol->store(&tm, 0);
}
-
-
+
+
double Field_datetime::val_real(void)
{
return (double) Field_datetime::val_int();
@@ -5901,7 +6014,14 @@ void Field_datetime::sort_string(uchar *
void Field_datetime::sql_type(String &res) const
{
- res.set_ascii(STRING_WITH_LEN("datetime"));
+ if (decimals() == 0)
+ {
+ res.set_ascii(STRING_WITH_LEN("datetime"));
+ return;
+ }
+ CHARSET_INFO *cs= res.charset();
+ res.length(cs->cset->snprintf(cs, (char*) res.ptr(), res.alloced_length(),
+ "datetime(%u)", decimals()));
}
@@ -5924,7 +6044,7 @@ void Field_datetime_hires::store_TIME(MY
store_bigendian(packed, ptr, Field_datetime_hires::pack_length());
}
-int Field_datetime_hires::store_decimal(const my_decimal *d)
+int Field_temporal_with_date::store_decimal(const my_decimal *d)
{
ulonglong nr;
ulong sec_part;
@@ -5949,38 +6069,38 @@ int Field_datetime_hires::store_decimal(
return store_TIME_with_warning(<ime, &str, error, tmp != -1);
}
-bool Field_datetime_hires::send_binary(Protocol *protocol)
+bool Field_datetime_with_dec::send_binary(Protocol *protocol)
{
MYSQL_TIME ltime;
- Field_datetime_hires::get_date(<ime, TIME_FUZZY_DATE);
+ get_date(<ime, TIME_FUZZY_DATE);
return protocol->store(<ime, dec);
}
-double Field_datetime_hires::val_real(void)
+double Field_datetime_with_dec::val_real(void)
{
MYSQL_TIME ltime;
- Field_datetime_hires::get_date(<ime, TIME_FUZZY_DATE);
+ get_date(<ime, TIME_FUZZY_DATE);
return TIME_to_double(<ime);
}
-longlong Field_datetime_hires::val_int(void)
+longlong Field_datetime_with_dec::val_int(void)
{
MYSQL_TIME ltime;
- Field_datetime_hires::get_date(<ime, TIME_FUZZY_DATE);
+ get_date(<ime, TIME_FUZZY_DATE);
return TIME_to_ulonglong_datetime(<ime);
}
-String *Field_datetime_hires::val_str(String *str,
- String *unused __attribute__((unused)))
+String *Field_datetime_with_dec::val_str(String *str,
+ String *unused __attribute__((unused)))
{
MYSQL_TIME ltime;
- Field_datetime_hires::get_date(<ime, TIME_FUZZY_DATE);
+ 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);
+ str->set_charset(&my_charset_numeric);
return str;
}
@@ -6007,27 +6127,42 @@ int Field_datetime_hires::cmp(const ucha
return a < b ? -1 : a > b ? 1 : 0;
}
-void Field_datetime_hires::sort_string(uchar *to,
- uint length __attribute__((unused)))
+void Field_datetime_with_dec::make_field(Send_field *field)
{
- DBUG_ASSERT(length == Field_datetime_hires::pack_length());
- memcpy(to, ptr, length);
+ Field::make_field(field);
+ field->decimals= dec;
}
-void Field_datetime_hires::sql_type(String &res) const
+/****************************************************************************
+** MySQL-5.6 compatible DATETIME(N)
+**
+****************************************************************************/
+int Field_datetimef::reset()
{
- CHARSET_INFO *cs=res.charset();
- res.length(cs->cset->snprintf(cs, (char*) res.ptr(), res.alloced_length(),
- "datetime(%u)", dec));
+ my_datetime_packed_to_binary(0, ptr, dec);
+ return 0;
}
-void Field_datetime_hires::make_field(Send_field *field)
+void Field_datetimef::store_TIME(MYSQL_TIME *ltime)
{
- Field::make_field(field);
- field->decimals= dec;
+ my_time_trunc(ltime, decimals());
+ longlong tmp= TIME_to_longlong_datetime_packed(ltime);
+ my_datetime_packed_to_binary(tmp, ptr, dec);
+}
+
+bool Field_datetimef::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+{
+ longlong tmp= my_datetime_packed_from_binary(ptr, dec);
+ TIME_from_longlong_datetime_packed(ltime, tmp);
+ if (!tmp)
+ return fuzzydate & TIME_NO_ZERO_DATE;
+ if (!ltime->month || !ltime->day)
+ return !(fuzzydate & TIME_FUZZY_DATE);
+ return false;
}
+
/****************************************************************************
** string type
** A string may be varchar or binary
@@ -6198,80 +6333,6 @@ int Field_str::store(double nr)
return store(buff, length, &my_charset_numeric);
}
-static
-inline ulonglong char_prefix_to_ulonglong(uchar *src)
-{
- uint sz= sizeof(ulonglong);
- for (uint i= 0; i < sz/2; i++)
- {
- uchar tmp= src[i];
- src[i]= src[sz-1-i];
- src[sz-1-i]= tmp;
- }
- return uint8korr(src);
-}
-
-/**
- @brief
- Determine the relative position of the field value in a string interval
-
- @details
- The function returns a double number between 0.0 and 1.0 as the relative
- position of the value of the this field in the string interval of [min,max].
- If the value is not in the interval the the function returns 0.0 when
- the value is less than min, and, 1.0 when the value is greater than max.
-
- @note
- To calculate the relative position of the string value v in the interval
- [min, max] the function first converts the beginning of these three
- strings v, min, max into the strings that are used for byte comparison.
- For each string not more sizeof(ulonglong) first bytes are taken
- from the result of conversion. Then these bytes are interpreted as the
- big-endian representation of an ulonglong integer. The values of these
- integer numbers obtained for the strings v, min, max are used to calculate
- the position of v in [min,max] in the same way is it's done for numeric
- fields (see Field_num::pos_in_interval).
-
- @todo
- Improve the procedure for the case when min and max have the same
- beginning
-
- @param min value of the left end of the interval
- @param max value of the right end of the interval
-
- @return
- relative position of the field value in the string interval [min,max]
-*/
-
-double Field_str::pos_in_interval(Field *min, Field *max)
-{
- uchar mp_prefix[sizeof(ulonglong)];
- uchar minp_prefix[sizeof(ulonglong)];
- uchar maxp_prefix[sizeof(ulonglong)];
- ulonglong mp, minp, maxp;
- my_strnxfrm(charset(), mp_prefix, sizeof(mp),
- ptr + length_size(),
- data_length());
- my_strnxfrm(charset(), minp_prefix, sizeof(minp),
- min->ptr + length_size(),
- min->data_length());
- my_strnxfrm(charset(), maxp_prefix, sizeof(maxp),
- max->ptr + length_size(),
- max->data_length());
- mp= char_prefix_to_ulonglong(mp_prefix);
- minp= char_prefix_to_ulonglong(minp_prefix);
- maxp= char_prefix_to_ulonglong(maxp_prefix);
- double n, d;
- n= mp - minp;
- if (n < 0)
- return 0.0;
- d= maxp - minp;
- if (d <= 0)
- return 1.0;
- return min(n/d, 1.0);
-}
-
-
uint Field::is_equal(Create_field *new_field)
{
return (new_field->sql_type == real_type());
@@ -8482,36 +8543,6 @@ my_decimal *Field_bit::val_decimal(my_de
}
-/**
- @brief
- Determine the relative position of the field value in a bit interval
-
- @details
- The function returns a double number between 0.0 and 1.0 as the relative
- position of the value of the this field in the bit interval of [min,max].
- If the value is not in the interval the the function returns 0.0 when
- the value is less than min, and, 1.0 when the value is greater than max.
-
- @param min value of the left end of the interval
- @param max value of the right end of the interval
-
- @return
- relative position of the field value in the bit interval [min,max]
-*/
-
-double Field_bit::pos_in_interval(Field *min, Field *max)
-{
- double n, d;
- n= val_real() - min->val_real();
- if (n < 0)
- return 0.0;
- d= max->val_real() - min->val_real();
- if (d <= 0)
- return 1.0;
- return min(n/d, 1.0);
-}
-
-
/*
Compare two bit fields using pointers within the record.
SYNOPSIS
@@ -9144,7 +9175,7 @@ bool Create_field::init(THD *thd, char *
it is NOT NULL, not an AUTO_INCREMENT field and not a TIMESTAMP.
*/
if (!fld_default_value && !(fld_type_modifier & AUTO_INCREMENT_FLAG) &&
- (fld_type_modifier & NOT_NULL_FLAG) && fld_type != MYSQL_TYPE_TIMESTAMP)
+ (fld_type_modifier & NOT_NULL_FLAG) && !is_timestamp_type(fld_type))
flags|= NO_DEFAULT_VALUE_FLAG;
if (fld_length != NULL)
@@ -9306,6 +9337,7 @@ bool Create_field::init(THD *thd, char *
}
break;
case MYSQL_TYPE_TIMESTAMP:
+ case MYSQL_TYPE_TIMESTAMP2:
if (length > MAX_DATETIME_PRECISION)
{
my_error(ER_TOO_BIG_PRECISION, MYF(0), length, fld_name,
@@ -9323,6 +9355,7 @@ bool Create_field::init(THD *thd, char *
length= MAX_DATE_WIDTH;
break;
case MYSQL_TYPE_TIME:
+ case MYSQL_TYPE_TIME2:
if (length > MAX_DATETIME_PRECISION)
{
my_error(ER_TOO_BIG_PRECISION, MYF(0), length, fld_name,
@@ -9332,6 +9365,7 @@ bool Create_field::init(THD *thd, char *
length+= MIN_TIME_WIDTH + (length ? 1 : 0);
break;
case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_DATETIME2:
if (length > MAX_DATETIME_PRECISION)
{
my_error(ER_TOO_BIG_PRECISION, MYF(0), length, fld_name,
@@ -9413,17 +9447,6 @@ bool Create_field::init(THD *thd, char *
DBUG_RETURN(TRUE);
}
- switch (fld_type) {
- case MYSQL_TYPE_DATE:
- case MYSQL_TYPE_NEWDATE:
- case MYSQL_TYPE_TIME:
- case MYSQL_TYPE_DATETIME:
- case MYSQL_TYPE_TIMESTAMP:
- charset= &my_charset_numeric;
- flags|= BINARY_FLAG;
- default: break;
- }
-
DBUG_RETURN(FALSE); /* success */
}
@@ -9462,10 +9485,16 @@ uint32 calc_pack_length(enum_field_types
case MYSQL_TYPE_TIME: return length > MIN_TIME_WIDTH
? time_hires_bytes[length - 1 - MIN_TIME_WIDTH]
: 3;
+ case MYSQL_TYPE_TIME2:
+ return length > MIN_TIME_WIDTH ?
+ my_time_binary_length(length - MIN_TIME_WIDTH - 1) : 3;
case MYSQL_TYPE_TIMESTAMP:
return length > MAX_DATETIME_WIDTH
? 4 + sec_part_bytes[length - 1 - MAX_DATETIME_WIDTH]
: 4;
+ case MYSQL_TYPE_TIMESTAMP2:
+ return length > MAX_DATETIME_WIDTH ?
+ my_timestamp_binary_length(length - MAX_DATETIME_WIDTH - 1) : 4;
case MYSQL_TYPE_DATE:
case MYSQL_TYPE_LONG : return 4;
case MYSQL_TYPE_FLOAT : return sizeof(float);
@@ -9474,6 +9503,9 @@ uint32 calc_pack_length(enum_field_types
return length > MAX_DATETIME_WIDTH
? datetime_hires_bytes[length - 1 - MAX_DATETIME_WIDTH]
: 8;
+ case MYSQL_TYPE_DATETIME2:
+ return length > MAX_DATETIME_WIDTH ?
+ my_datetime_binary_length(length - MAX_DATETIME_WIDTH - 1) : 5;
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;
@@ -9538,16 +9570,6 @@ Field *make_field(TABLE_SHARE *share, uc
null_bit= ((uchar) 1) << null_bit;
}
- switch (field_type) {
- case MYSQL_TYPE_DATE:
- case MYSQL_TYPE_NEWDATE:
- case MYSQL_TYPE_TIME:
- case MYSQL_TYPE_DATETIME:
- case MYSQL_TYPE_TIMESTAMP:
- field_charset= &my_charset_numeric;
- default: break;
- }
-
DBUG_PRINT("debug", ("field_type: %d, field_length: %u, interval: %p, pack_flag: %s%s%s%s%s",
field_type, field_length, interval,
FLAGSTR(pack_flag, FIELDFLAG_BINARY),
@@ -9661,30 +9683,51 @@ Field *make_field(TABLE_SHARE *share, uc
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);
+ field_name, share, dec);
+ }
+ case MYSQL_TYPE_TIMESTAMP2:
+ {
+ uint dec= field_length > MAX_DATETIME_WIDTH ?
+ field_length - MAX_DATETIME_WIDTH - 1: 0;
+ return new Field_timestampf(ptr, null_pos, null_bit, unireg_check,
+ field_name, share, dec);
}
case MYSQL_TYPE_YEAR:
return new Field_year(ptr,field_length,null_pos,null_bit,
unireg_check, field_name);
case MYSQL_TYPE_DATE:
return new Field_date(ptr,null_pos,null_bit,
- unireg_check, field_name, field_charset);
+ unireg_check, field_name);
case MYSQL_TYPE_NEWDATE:
return new Field_newdate(ptr,null_pos,null_bit,
- unireg_check, field_name, field_charset);
+ unireg_check, field_name);
case MYSQL_TYPE_TIME:
{
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);
+ field_name, dec);
+ }
+ case MYSQL_TYPE_TIME2:
+ {
+ uint dec= field_length > MIN_TIME_WIDTH ?
+ field_length - MIN_TIME_WIDTH - 1: 0;
+ return new Field_timef(ptr, null_pos, null_bit, unireg_check,
+ field_name, dec);
}
case MYSQL_TYPE_DATETIME:
{
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);
+ field_name, dec);
+ }
+ case MYSQL_TYPE_DATETIME2:
+ {
+ uint dec= field_length > MAX_DATETIME_WIDTH ?
+ field_length - MAX_DATETIME_WIDTH - 1: 0;
+ return new Field_datetimef(ptr, null_pos, null_bit, unireg_check,
+ field_name, dec);
}
case MYSQL_TYPE_NULL:
return new Field_null(ptr, field_length, unireg_check, field_name,
=== modified file 'sql/field.h'
--- sql/field.h 2013-06-06 15:51:28 +0000
+++ sql/field.h 2013-07-01 06:50:40 +0000
@@ -30,6 +30,7 @@
#include "sql_string.h" /* String */
#include "my_decimal.h" /* my_decimal */
#include "sql_error.h" /* MYSQL_ERROR */
+#include "compat56.h"
class Send_field;
class Protocol;
@@ -89,6 +90,42 @@ inline uint get_set_pack_length(int elem
return len > 4 ? 8 : len;
}
+
+/**
+ Recognizer for concrete data type (called real_type for some reason),
+ returning true if it is one of the TIMESTAMP types.
+*/
+inline bool is_timestamp_type(enum_field_types type)
+{
+ return type == MYSQL_TYPE_TIMESTAMP || type == MYSQL_TYPE_TIMESTAMP2;
+}
+
+
+/**
+ Convert temporal real types as retuned by field->real_type()
+ to field type as returned by field->type().
+
+ @param real_type Real type.
+ @retval Field type.
+*/
+inline enum_field_types real_type_to_type(enum_field_types real_type)
+{
+ switch (real_type)
+ {
+ case MYSQL_TYPE_TIME2:
+ return MYSQL_TYPE_TIME;
+ case MYSQL_TYPE_DATETIME2:
+ return MYSQL_TYPE_DATETIME;
+ case MYSQL_TYPE_TIMESTAMP2:
+ return MYSQL_TYPE_TIMESTAMP;
+ case MYSQL_TYPE_NEWDATE:
+ return MYSQL_TYPE_DATE;
+ /* Note: NEWDECIMAL is a type, not only a real_type */
+ default: return real_type;
+ }
+}
+
+
/*
Virtual_column_info is the class to contain additional
characteristics that is specific for a virtual/computed
@@ -428,6 +465,54 @@ class Field
virtual uint32 key_length() const { return pack_length(); }
virtual enum_field_types type() const =0;
virtual enum_field_types real_type() const { return type(); }
+ virtual enum_field_types binlog_type() const
+ {
+ /*
+ Binlog stores field->type() as type code by default. For example,
+ it puts MYSQL_TYPE_STRING in case of CHAR, VARCHAR, SET and ENUM,
+ with extra data type details put into metadata.
+
+ Binlog behaviour slightly differs between various MySQL and MariaDB
+ versions for the temporal data types TIME, DATETIME and TIMESTAMP.
+
+ MySQL prior to 5.6 uses MYSQL_TYPE_TIME, MYSQL_TYPE_DATETIME
+ and MYSQL_TYPE_TIMESTAMP type codes in binlog and stores no
+ additional metadata.
+
+ MariaDB-5.3 implements new versions for TIME, DATATIME, TIMESTAMP
+ with fractional second precision, but uses the old format for the
+ types TIME(0), DATETIME(0), TIMESTAMP(0), and it still stores
+ MYSQL_TYPE_TIME, MYSQL_TYPE_DATETIME and MYSQL_TYPE_TIMESTAMP in binlog,
+ with no additional metadata.
+ So row-based replication between temporal data types of
+ different precision is not possible in MariaDB.
+
+ MySQL-5.6 also implements a new version of TIME, DATETIME, TIMESTAMP
+ which support fractional second precision 0..6, and use the new
+ format even for the types TIME(0), DATETIME(0), TIMESTAMP(0).
+ For these new data types, MySQL-5.6 stores new type codes
+ MYSQL_TYPE_TIME2, MYSQL_TYPE_DATETIME2, MYSQL_TYPE_TIMESTAMP2 in binlog,
+ with fractional precision 0..6 put into metadata.
+ This makes it in theory possible to do row-based replication between
+ columns of different fractional precision (e.g. from TIME(1) on master
+ to TIME(6) on slave). However, it's not currently fully implemented yet.
+ MySQL-5.6 can only do row-based replication from the old types
+ TIME, DATETIME, TIMESTAMP (represented by MYSQL_TYPE_TIME,
+ MYSQL_TYPE_DATETIME and MYSQL_TYPE_TIMESTAMP type codes in binlog)
+ to the new corresponding types TIME(0), DATETIME(0), TIMESTAMP(0).
+
+ Note: MariaDB starting from the version 10.0 understands the new
+ MySQL-5.6 type codes MYSQL_TYPE_TIME2, MYSQL_TYPE_DATETIME2,
+ MYSQL_TYPE_TIMESTAMP2. When started over MySQL-5.6 tables both on
+ master and on slave, MariaDB-10.0 can also do row-based replication
+ from the old types TIME, DATETIME, TIMESTAMP to the new MySQL-5.6
+ types TIME(0), DATETIME(0), TIMESTAMP(0).
+
+ Note: perhaps binlog should eventually be modified to store
+ real_type() instead of type() for all column types.
+ */
+ return type();
+ }
inline int cmp(const uchar *str) { return cmp(ptr,str); }
virtual int cmp_max(const uchar *a, const uchar *b, uint max_len)
{ return cmp(a, b); }
@@ -661,6 +746,16 @@ class Field
{ return binary() ? &my_charset_bin : charset(); }
virtual CHARSET_INFO *sort_charset(void) const { return charset(); }
virtual bool has_charset(void) const { return FALSE; }
+ /*
+ match_collation_to_optimize_range() is to distinguish in
+ range optimizer (see opt_range.cc) between real string types:
+ CHAR, VARCHAR, TEXT
+ and the other string-alike types with result_type() == STRING_RESULT:
+ DATE, TIME, DATETIME, TIMESTAMP
+ We need it to decide whether to test if collation of the operation
+ matches collation of the field (needed only for real string types).
+ */
+ virtual bool match_collation_to_optimize_range() const { return false; }
virtual void set_charset(CHARSET_INFO *charset_arg) { }
virtual enum Derivation derivation(void) const
{ return DERIVATION_IMPLICIT; }
@@ -808,7 +903,8 @@ class Field
{
return (flags & (BINCMP_FLAG | BINARY_FLAG)) != 0;
}
-
+ double pos_in_interval_val_real(Field *min, Field *max);
+ double pos_in_interval_val_str(Field *min, Field *max, uint data_offset);
};
@@ -847,7 +943,10 @@ class Field_num :public Field {
bool get_int(CHARSET_INFO *cs, const char *from, uint len,
longlong *rnd, ulonglong unsigned_max,
longlong signed_min, longlong signed_max);
- double pos_in_interval(Field *min, Field *max);
+ double pos_in_interval(Field *min, Field *max)
+ {
+ return pos_in_interval_val_real(min, max);
+ }
};
@@ -860,23 +959,11 @@ class Field_str :public Field {
uchar null_bit_arg, utype unireg_check_arg,
const char *field_name_arg, CHARSET_INFO *charset);
Item_result result_type () const { return STRING_RESULT; }
- /*
- match_collation_to_optimize_range() is to distinguish in
- range optimizer (see opt_range.cc) between real string types:
- CHAR, VARCHAR, TEXT
- and the other string-alike types with result_type() == STRING_RESULT:
- DATE, TIME, DATETIME, TIMESTAMP
- We need it to decide whether to test if collation of the operation
- matches collation of the field (needed only for real string types).
- QQ: shouldn't DATE/TIME types have their own XXX_RESULT types eventually?
- */
- virtual bool match_collation_to_optimize_range() const=0;
uint decimals() const { return NOT_FIXED_DEC; }
int store(double nr);
int store(longlong nr, bool unsigned_val)=0;
int store_decimal(const my_decimal *);
int store(const char *to,uint length,CHARSET_INFO *cs)=0;
- uint size_of() const { return sizeof(*this); }
uint repertoire(void) const
{
return my_charset_repertoire(field_charset);
@@ -894,7 +981,10 @@ class Field_str :public Field {
uint is_equal(Create_field *new_field);
bool eq_cmp_as_binary() { return test(flags & BINARY_FLAG); }
virtual uint length_size() { return 0; }
- double pos_in_interval(Field *min, Field *max);
+ double pos_in_interval(Field *min, Field *max)
+ {
+ return pos_in_interval_val_str(min, max, length_size());
+ }
};
/* base class for Field_string, Field_varstring and Field_blob */
@@ -914,6 +1004,7 @@ class Field_longstr :public Field_str
int store_decimal(const my_decimal *d);
uint32 max_data_length() const;
+ bool match_collation_to_optimize_range() const { return true; }
};
/* base class for float and double and decimal (old one) */
@@ -1323,7 +1414,6 @@ class Field_null :public Field_str {
unireg_check_arg, field_name_arg, cs)
{}
enum_field_types type() const { return MYSQL_TYPE_NULL;}
- bool match_collation_to_optimize_range() const { return FALSE; }
int store(const char *to, uint length, CHARSET_INFO *cs)
{ null[0]=1; return 0; }
int store(double nr) { null[0]=1; return 0; }
@@ -1345,7 +1435,67 @@ class Field_null :public Field_str {
};
-class Field_timestamp :public Field_str {
+class Field_temporal: public Field {
+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)
+ :Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg,
+ field_name_arg)
+ { flags|= BINARY_FLAG; }
+ Item_result result_type () const { return STRING_RESULT; }
+ uint32 max_display_length() { return field_length; }
+ bool str_needs_quotes() { return TRUE; }
+ enum Derivation derivation(void) const { return DERIVATION_NUMERIC; }
+ uint repertoire(void) const { return MY_REPERTOIRE_NUMERIC; }
+ CHARSET_INFO *charset(void) const { return &my_charset_numeric; }
+ const CHARSET_INFO *sort_charset(void) const { return &my_charset_bin; }
+ bool binary() const { return true; }
+ enum Item_result cmp_type () const { return TIME_RESULT; }
+ uint is_equal(Create_field *new_field);
+ bool eq_def(Field *field)
+ {
+ return (Field::eq_def(field) && decimals() == field->decimals());
+ }
+ my_decimal *val_decimal(my_decimal*);
+ void set_warnings(MYSQL_ERROR::enum_warning_level trunc_level,
+ const ErrConv *str, int was_cut, timestamp_type ts_type);
+ double pos_in_interval(Field *min, Field *max)
+ {
+ return pos_in_interval_val_real(min, max);
+ }
+};
+
+
+/**
+ Abstract class for:
+ - DATE
+ - DATETIME
+ - DATETIME(1..6)
+ - DATETIME(0..6) - MySQL56 version
+*/
+class Field_temporal_with_date: public Field_temporal {
+protected:
+ int store_TIME_with_warning(MYSQL_TIME *ltime, const ErrConv *str,
+ int was_cut, int have_smth_to_conv);
+ virtual void store_TIME(MYSQL_TIME *ltime) = 0;
+public:
+ Field_temporal_with_date(uchar *ptr_arg, uint32 len_arg,
+ uchar *null_ptr_arg, uchar null_bit_arg,
+ utype unireg_check_arg,
+ const char *field_name_arg)
+ :Field_temporal(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
+ unireg_check_arg, field_name_arg)
+ {}
+ int store(const char *to, uint length, CHARSET_INFO *charset);
+ int store(double nr);
+ int store(longlong nr, bool unsigned_val);
+ int store_time_dec(MYSQL_TIME *ltime, uint dec);
+ int store_decimal(const my_decimal *);
+};
+
+
+class Field_timestamp :public Field_temporal {
protected:
int store_TIME_with_warning(THD *, MYSQL_TIME *, const ErrConv *,
bool, bool);
@@ -1353,21 +1503,14 @@ class Field_timestamp :public Field_str
Field_timestamp(uchar *ptr_arg, uint32 len_arg,
uchar *null_ptr_arg, uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
- TABLE_SHARE *share, CHARSET_INFO *cs);
- Field_timestamp(bool maybe_null_arg, const char *field_name_arg,
- CHARSET_INFO *cs);
+ TABLE_SHARE *share);
enum_field_types type() const { return MYSQL_TYPE_TIMESTAMP;}
- bool match_collation_to_optimize_range() const { return FALSE; }
enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONG_INT; }
- enum Item_result cmp_type () const { return TIME_RESULT; }
- enum Derivation derivation(void) const { return DERIVATION_NUMERIC; }
- uint repertoire(void) const { return MY_REPERTOIRE_NUMERIC; }
- CHARSET_INFO *charset(void) const { return &my_charset_numeric; }
- bool binary() const { return 1; }
int store(const char *to,uint length,CHARSET_INFO *charset);
int store(double nr);
int store(longlong nr, bool unsigned_val);
int store_time_dec(MYSQL_TIME *ltime, uint dec);
+ int store_decimal(const my_decimal *);
double val_real(void);
longlong val_int(void);
String *val_str(String*,String *);
@@ -1377,7 +1520,6 @@ class Field_timestamp :public Field_str
uint32 pack_length() const { return 4; }
void sql_type(String &str) const;
bool zero_pack() const { return 0; }
- uint decimals() const { return 0; }
virtual int set_time();
virtual void set_default()
{
@@ -1418,46 +1560,109 @@ class Field_timestamp :public Field_str
{
return unpack_int32(to, from, from_end);
}
+ uint size_of() const { return sizeof(*this); }
};
-class Field_timestamp_hires :public Field_timestamp {
+/**
+ Abstract class for:
+ - TIMESTAMP(1..6)
+ - TIMESTAMP(0..6) - MySQL56 version
+*/
+class Field_timestamp_with_dec :public Field_timestamp {
+protected:
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),
+ Field_timestamp_with_dec(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) :
+ Field_timestamp(ptr_arg,
+ MAX_DATETIME_WIDTH + dec_arg + test(dec_arg), null_ptr_arg,
+ null_bit_arg, unireg_check_arg, field_name_arg, share),
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 *);
- my_decimal* val_decimal(my_decimal*);
- 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, const uchar *from_end,
uint param_data)
{ return Field::unpack(to, from, from_end, param_data); }
+ void make_field(Send_field *field);
+ void sort_string(uchar *to, uint length)
+ {
+ DBUG_ASSERT(length == pack_length());
+ memcpy(to, ptr, length);
+ }
+ bool send_binary(Protocol *protocol);
+ double val_real(void);
+ my_decimal* val_decimal(my_decimal*);
+ int set_time();
+};
+
+
+class Field_timestamp_hires :public Field_timestamp_with_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) :
+ Field_timestamp_with_dec(ptr_arg, null_ptr_arg, null_bit_arg,
+ unireg_check_arg, field_name_arg, share, dec_arg)
+ {
+ DBUG_ASSERT(dec);
+ }
+ my_time_t get_timestamp(ulong *sec_part) const;
+ void store_TIME(my_time_t timestamp, ulong sec_part);
+ int cmp(const uchar *,const uchar *);
+ uint32 pack_length() const;
+ uint size_of() const { return sizeof(*this); }
+};
+
+
+/**
+ TIMESTAMP(0..6) - MySQL56 version
+*/
+class Field_timestampf :public Field_timestamp_with_dec {
+ int do_save_field_metadata(uchar *metadata_ptr)
+ {
+ *metadata_ptr= decimals();
+ return 1;
+ }
+public:
+ Field_timestampf(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) :
+ Field_timestamp_with_dec(ptr_arg, null_ptr_arg, null_bit_arg,
+ unireg_check_arg, field_name_arg, share, dec_arg)
+ {}
+ enum_field_types real_type() const { return MYSQL_TYPE_TIMESTAMP2; }
+ enum_field_types binlog_type() const { return MYSQL_TYPE_TIMESTAMP2; }
+ uint32 pack_length() const
+ {
+ return my_timestamp_binary_length(dec);
+ }
+ uint row_pack_length() { return pack_length(); }
+ uint pack_length_from_metadata(uint field_metadata)
+ {
+ DBUG_ENTER("Field_timestampf::pack_length_from_metadata");
+ uint tmp= my_timestamp_binary_length(field_metadata);
+ DBUG_RETURN(tmp);
+ }
+ int cmp(const uchar *a_ptr,const uchar *b_ptr)
+ {
+ return memcmp(a_ptr, b_ptr, pack_length());
+ }
+ void store_TIME(my_time_t timestamp, ulong sec_part);
+ my_time_t get_timestamp(ulong *sec_part) const;
uint size_of() const { return sizeof(*this); }
- bool eq_def(Field *field)
- { return Field_str::eq_def(field) && dec == field->decimals(); }
};
@@ -1484,56 +1689,24 @@ class Field_year :public Field_tiny {
};
-class Field_temporal: public Field_str {
-protected:
- int store_TIME_with_warning(MYSQL_TIME *ltime, const ErrConv *str,
- int was_cut, int have_smth_to_conv);
- virtual void store_TIME(MYSQL_TIME *ltime) = 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)
- { flags|= BINARY_FLAG; }
- enum Derivation derivation(void) const { return DERIVATION_NUMERIC; }
- uint repertoire(void) const { return MY_REPERTOIRE_NUMERIC; }
- CHARSET_INFO *charset(void) const { return &my_charset_numeric; }
- bool binary() const { return 1; }
- bool match_collation_to_optimize_range() const { return FALSE; }
- 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_dec(MYSQL_TIME *ltime, uint dec);
- my_decimal *val_decimal(my_decimal*);
- bool eq_def(Field *field)
- {
- return (Field_str::eq_def(field) && decimals() == field->decimals());
- }
-};
-
-class Field_date :public Field_temporal {
+class Field_date :public Field_temporal_with_date {
void store_TIME(MYSQL_TIME *ltime);
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_temporal(ptr_arg, MAX_DATE_WIDTH, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg, cs) {}
+ enum utype unireg_check_arg, const char *field_name_arg)
+ :Field_temporal_with_date(ptr_arg, MAX_DATE_WIDTH, null_ptr_arg, null_bit_arg,
+ unireg_check_arg, field_name_arg) {}
enum_field_types type() const { return MYSQL_TYPE_DATE;}
enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONG_INT; }
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 *);
- 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 zero_pack() const { return 1; }
uchar *pack(uchar* to, const uchar *from,
uint max_length __attribute__((unused)))
{
@@ -1544,23 +1717,22 @@ class Field_date :public Field_temporal
{
return unpack_int32(to, from, from_end);
}
+ uint size_of() const { return sizeof(*this); }
};
-class Field_newdate :public Field_temporal {
+class Field_newdate :public Field_temporal_with_date {
void store_TIME(MYSQL_TIME *ltime);
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_temporal(ptr_arg, MAX_DATE_WIDTH, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg, cs)
+ enum utype unireg_check_arg, const char *field_name_arg)
+ :Field_temporal_with_date(ptr_arg, MAX_DATE_WIDTH, null_ptr_arg, null_bit_arg,
+ unireg_check_arg, field_name_arg)
{}
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; }
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 *);
@@ -1569,19 +1741,22 @@ class Field_newdate :public Field_tempor
void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return 3; }
void sql_type(String &str) const;
- bool zero_pack() const { return 1; }
bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ uint size_of() const { return sizeof(*this); }
};
class Field_time :public Field_temporal {
- void store_TIME(MYSQL_TIME *ltime);
+protected:
+ virtual void store_TIME(MYSQL_TIME *ltime);
+ int store_TIME_with_warning(MYSQL_TIME *ltime, const ErrConv *str,
+ int was_cut, int have_smth_to_conv);
public:
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)
+ const char *field_name_arg)
:Field_temporal(ptr_arg, length_arg, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg, cs)
+ unireg_check_arg, field_name_arg)
{}
enum_field_types type() const { return MYSQL_TYPE_TIME;}
enum ha_base_keytype key_type() const { return HA_KEYTYPE_INT24; }
@@ -1589,7 +1764,7 @@ class Field_time :public Field_temporal
int store(const char *to,uint length,CHARSET_INFO *charset);
int store(double nr);
int store(longlong nr, bool unsigned_val);
- uint decimals() const { return 0; }
+ int store_decimal(const my_decimal *);
double val_real(void);
longlong val_int(void);
String *val_str(String*,String *);
@@ -1599,55 +1774,122 @@ class Field_time :public Field_temporal
void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return 3; }
void sql_type(String &str) const;
- bool zero_pack() const { return 1; }
+ uint size_of() const { return sizeof(*this); }
};
-class Field_time_hires :public Field_time {
+
+/**
+ Abstract class for:
+ - TIME(1..6)
+ - TIME(0..6) - MySQL56 version
+*/
+class Field_time_with_dec :public Field_time {
+protected:
uint dec;
+public:
+ Field_time_with_dec(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
+ enum utype unireg_check_arg, const char *field_name_arg,
+ uint dec_arg)
+ :Field_time(ptr_arg, MIN_TIME_WIDTH + dec_arg + test(dec_arg), null_ptr_arg,
+ null_bit_arg, unireg_check_arg, field_name_arg),
+ dec(dec_arg)
+ {
+ DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS);
+ }
+ uint decimals() const { return dec; }
+ enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; }
+ longlong val_int(void);
+ double val_real(void);
+ void make_field(Send_field *);
+};
+
+
+/**
+ TIME(1..6)
+*/
+class Field_time_hires :public Field_time_with_dec {
longlong zero_point;
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)
+ uint dec_arg)
+ :Field_time_with_dec(ptr_arg, null_ptr_arg,
+ null_bit_arg, unireg_check_arg, field_name_arg,
+ dec_arg)
{
DBUG_ASSERT(dec);
- DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS);
zero_point= sec_part_shift(
((TIME_MAX_VALUE_SECONDS+1LL)*TIME_SECOND_PART_FACTOR), dec);
}
- enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; }
- uint decimals() const { return dec; }
- int store_decimal(const my_decimal *d);
- longlong val_int(void);
- double val_real(void);
- String *val_str(String*,String *);
int reset(void);
bool get_date(MYSQL_TIME *ltime, ulonglong 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); }
};
-class Field_datetime :public Field_temporal {
+
+/**
+ TIME(0..6) - MySQL56 version
+*/
+class Field_timef :public Field_time_with_dec {
+ void store_TIME(MYSQL_TIME *ltime);
+ int do_save_field_metadata(uchar *metadata_ptr)
+ {
+ *metadata_ptr= decimals();
+ return 1;
+ }
+public:
+ Field_timef(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
+ enum utype unireg_check_arg, const char *field_name_arg,
+ uint dec_arg)
+ :Field_time_with_dec(ptr_arg, null_ptr_arg,
+ null_bit_arg, unireg_check_arg, field_name_arg,
+ dec_arg)
+ {
+ DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS);
+ }
+ enum_field_types real_type() const { return MYSQL_TYPE_TIME2; }
+ enum_field_types binlog_type() const { return MYSQL_TYPE_TIME2; }
+ uint32 pack_length() const
+ {
+ return my_time_binary_length(dec);
+ }
+ uint row_pack_length() { return pack_length(); }
+ uint pack_length_from_metadata(uint field_metadata)
+ {
+ DBUG_ENTER("Field_timef::pack_length_from_metadata");
+ uint tmp= my_time_binary_length(field_metadata);
+ DBUG_RETURN(tmp);
+ }
+ void sort_string(uchar *to, uint length)
+ {
+ DBUG_ASSERT(length == Field_timef::pack_length());
+ memcpy(to, ptr, length);
+ }
+ int cmp(const uchar *a_ptr, const uchar *b_ptr)
+ {
+ return memcmp(a_ptr, b_ptr, pack_length());
+ }
+ int reset();
+ bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ uint size_of() const { return sizeof(*this); }
+};
+
+
+class Field_datetime :public Field_temporal_with_date {
void store_TIME(MYSQL_TIME *ltime);
public:
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)
+ const char *field_name_arg)
+ :Field_temporal_with_date(ptr_arg, length_arg, null_ptr_arg, null_bit_arg,
+ unireg_check_arg, field_name_arg)
{}
enum_field_types type() const { return MYSQL_TYPE_DATETIME;}
enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONGLONG; }
- uint decimals() const { return 0; }
double val_real(void);
longlong val_int(void);
String *val_str(String*,String *);
@@ -1656,7 +1898,6 @@ class Field_datetime :public Field_tempo
void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return 8; }
void sql_type(String &str) const;
- bool zero_pack() const { return 1; }
bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
virtual int set_time();
virtual void set_default()
@@ -1690,85 +1931,149 @@ class Field_datetime :public Field_tempo
{
return unpack_int64(to, from, from_end);
}
+ uint size_of() const { return sizeof(*this); }
};
-class Field_datetime_hires :public Field_datetime {
- void store_TIME(MYSQL_TIME *ltime);
+/**
+ Abstract class for:
+ - DATETIME(1..6)
+ - DATETIME(0..6) - MySQL56 version
+*/
+class Field_datetime_with_dec :public Field_datetime {
+protected:
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,
+ Field_datetime_with_dec(uchar *ptr_arg, uchar *null_ptr_arg,
+ uchar null_bit_arg, enum utype unireg_check_arg,
+ const char *field_name_arg, uint dec_arg)
+ :Field_datetime(ptr_arg, MAX_DATETIME_WIDTH + dec_arg + test(dec_arg),
null_ptr_arg, null_bit_arg, unireg_check_arg,
- field_name_arg, cs), dec(dec_arg)
+ field_name_arg), 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; }
+ enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; }
void make_field(Send_field *field);
- int store_decimal(const my_decimal *d);
- 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, ulonglong 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, const uchar *from_end,
uint param_data)
{ return Field::unpack(to, from, from_end, param_data); }
+ void sort_string(uchar *to, uint length)
+ {
+ DBUG_ASSERT(length == pack_length());
+ memcpy(to, ptr, length);
+ }
+ double val_real(void);
+ longlong val_int(void);
+ String *val_str(String*,String *);
+};
+
+
+/**
+ DATETIME(1..6)
+*/
+class Field_datetime_hires :public Field_datetime_with_dec {
+ void store_TIME(MYSQL_TIME *ltime);
+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)
+ :Field_datetime_with_dec(ptr_arg, null_ptr_arg, null_bit_arg,
+ unireg_check_arg, field_name_arg, dec_arg)
+ {
+ DBUG_ASSERT(dec);
+ }
+ int cmp(const uchar *,const uchar *);
+ uint32 pack_length() const;
+ bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ uint size_of() const { return sizeof(*this); }
+};
+
+
+/**
+ DATETIME(0..6) - MySQL56 version
+*/
+class Field_datetimef :public Field_datetime_with_dec {
+ void store_TIME(MYSQL_TIME *ltime);
+ int do_save_field_metadata(uchar *metadata_ptr)
+ {
+ *metadata_ptr= decimals();
+ return 1;
+ }
+public:
+ Field_datetimef(uchar *ptr_arg, uchar *null_ptr_arg,
+ uchar null_bit_arg, enum utype unireg_check_arg,
+ const char *field_name_arg, uint dec_arg)
+ :Field_datetime_with_dec(ptr_arg, null_ptr_arg, null_bit_arg,
+ unireg_check_arg, field_name_arg, dec_arg)
+ {}
+ enum_field_types real_type() const { return MYSQL_TYPE_DATETIME2; }
+ enum_field_types binlog_type() const { return MYSQL_TYPE_DATETIME2; }
+ uint32 pack_length() const
+ {
+ return my_datetime_binary_length(dec);
+ }
+ uint row_pack_length() { return pack_length(); }
+ uint pack_length_from_metadata(uint field_metadata)
+ {
+ DBUG_ENTER("Field_datetimef::pack_length_from_metadata");
+ uint tmp= my_datetime_binary_length(field_metadata);
+ DBUG_RETURN(tmp);
+ }
+ int cmp(const uchar *a_ptr, const uchar *b_ptr)
+ {
+ return memcmp(a_ptr, b_ptr, pack_length());
+ }
+ int reset();
+ bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
uint size_of() const { return sizeof(*this); }
};
+
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)
+ TABLE_SHARE *share, uint dec)
{
if (dec==0)
return new Field_timestamp(ptr, MAX_DATETIME_WIDTH, null_ptr, null_bit,
- unireg_check, field_name, share, cs);
+ unireg_check, field_name, share);
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);
+ field_name, share, dec);
}
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)
+ uint dec)
{
if (dec == 0)
return new Field_time(ptr, MIN_TIME_WIDTH, null_ptr, null_bit,
- unireg_check, field_name, cs);
+ unireg_check, field_name);
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);
+ unireg_check, field_name, dec);
}
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)
+ const char *field_name, uint dec)
{
if (dec == 0)
return new Field_datetime(ptr, MAX_DATETIME_WIDTH, null_ptr, null_bit,
- unireg_check, field_name, cs);
+ unireg_check, field_name);
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);
+ unireg_check, field_name, dec);
}
class Field_string :public Field_longstr {
@@ -1795,7 +2100,6 @@ class Field_string :public Field_longstr
orig_table->s->frm_version < FRM_VER_TRUE_VARCHAR ?
MYSQL_TYPE_VAR_STRING : MYSQL_TYPE_STRING);
}
- bool match_collation_to_optimize_range() const { return TRUE; }
enum ha_base_keytype key_type() const
{ return binary() ? HA_KEYTYPE_BINARY : HA_KEYTYPE_TEXT; }
bool zero_pack() const { return 0; }
@@ -1876,7 +2180,6 @@ class Field_varstring :public Field_long
}
enum_field_types type() const { return MYSQL_TYPE_VARCHAR; }
- bool match_collation_to_optimize_range() const { return TRUE; }
enum ha_base_keytype key_type() const;
uint row_pack_length() { return field_length; }
bool zero_pack() const { return 0; }
@@ -1972,7 +2275,6 @@ class Field_blob :public Field_longstr {
:Field_longstr((uchar*) 0, 0, (uchar*) "", 0, NONE, "temp", system_charset_info),
packlength(packlength_arg) {}
enum_field_types type() const { return MYSQL_TYPE_BLOB;}
- bool match_collation_to_optimize_range() const { return TRUE; }
enum ha_base_keytype key_type() const
{ return binary() ? HA_KEYTYPE_VARBINARY2 : HA_KEYTYPE_VARTEXT2; }
int store(const char *to,uint length,CHARSET_INFO *charset);
@@ -2118,7 +2420,7 @@ class Field_geom :public Field_blob {
{ geom_type= geom_type_arg; }
enum ha_base_keytype key_type() const { return HA_KEYTYPE_VARBINARY2; }
enum_field_types type() const { return MYSQL_TYPE_GEOMETRY; }
- bool match_collation_to_optimize_range() const { return FALSE; }
+ bool match_collation_to_optimize_range() const { return false; }
void sql_type(String &str) const;
int store(const char *to, uint length, CHARSET_INFO *charset);
int store(double nr);
@@ -2156,7 +2458,6 @@ class Field_enum :public Field_str {
}
Field *new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type);
enum_field_types type() const { return MYSQL_TYPE_STRING; }
- bool match_collation_to_optimize_range() const { return FALSE; }
enum Item_result cmp_type () const { return INT_RESULT; }
enum ha_base_keytype key_type() const;
int store(const char *to,uint length,CHARSET_INFO *charset);
@@ -2309,7 +2610,10 @@ class Field_bit :public Field {
{
store(*((longlong *)val), TRUE);
}
- double pos_in_interval(Field *min, Field *max);
+ double pos_in_interval(Field *min, Field *max)
+ {
+ return pos_in_interval_val_real(min, max);
+ }
void get_image(uchar *buff, uint length, CHARSET_INFO *cs)
{ get_key_image(buff, length, itRAW); }
void set_image(const uchar *buff,uint length, CHARSET_INFO *cs)
=== modified file 'sql/item.cc'
--- sql/item.cc 2013-06-06 19:32:29 +0000
+++ sql/item.cc 2013-07-02 06:59:27 +0000
@@ -651,9 +651,12 @@ Item_result Item::cmp_type() const
case MYSQL_TYPE_GEOMETRY:
return STRING_RESULT;
case MYSQL_TYPE_TIMESTAMP:
+ case MYSQL_TYPE_TIMESTAMP2:
case MYSQL_TYPE_DATE:
case MYSQL_TYPE_TIME:
+ case MYSQL_TYPE_TIME2:
case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_DATETIME2:
case MYSQL_TYPE_NEWDATE:
return TIME_RESULT;
};
@@ -3218,11 +3221,7 @@ void Item_param::set_time(MYSQL_TIME *tm
value.time= *tm;
value.time.time_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.second_part > TIME_MAX_SECOND_PART)
+ if (check_datetime_range(&value.time))
{
ErrConvTime str(&value.time);
make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
@@ -5678,19 +5677,17 @@ Field *Item::tmp_table_field_from_field_
break;
case MYSQL_TYPE_NEWDATE:
case MYSQL_TYPE_DATE:
- field= new Field_newdate(0, null_ptr, 0, Field::NONE, name, &my_charset_bin);
+ field= new Field_newdate(0, null_ptr, 0, Field::NONE, name);
break;
case MYSQL_TYPE_TIME:
- field= new_Field_time(0, null_ptr, 0, Field::NONE, name,
- decimals, &my_charset_bin);
+ field= new_Field_time(0, null_ptr, 0, Field::NONE, name, decimals);
break;
case MYSQL_TYPE_TIMESTAMP:
field= new_Field_timestamp(0, null_ptr, 0,
- Field::NONE, name, 0, decimals, &my_charset_bin);
+ Field::NONE, name, 0, decimals);
break;
case MYSQL_TYPE_DATETIME:
- field= new_Field_datetime(0, null_ptr, 0, Field::NONE, name,
- decimals, &my_charset_bin);
+ field= new_Field_datetime(0, null_ptr, 0, Field::NONE, name, decimals);
break;
case MYSQL_TYPE_YEAR:
field= new Field_year((uchar*) 0, max_length, null_ptr, 0, Field::NONE,
=== modified file 'sql/item_strfunc.cc'
--- sql/item_strfunc.cc 2013-06-06 19:32:29 +0000
+++ sql/item_strfunc.cc 2013-07-02 05:52:21 +0000
@@ -3972,7 +3972,9 @@ bool Item_func_dyncol_create::prepare_ar
type= DYN_COL_NULL;
break;
case MYSQL_TYPE_TIMESTAMP:
+ case MYSQL_TYPE_TIMESTAMP2:
case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_DATETIME2:
type= DYN_COL_DATETIME;
break;
case MYSQL_TYPE_DATE:
@@ -3980,6 +3982,7 @@ bool Item_func_dyncol_create::prepare_ar
type= DYN_COL_DATE;
break;
case MYSQL_TYPE_TIME:
+ case MYSQL_TYPE_TIME2:
type= DYN_COL_TIME;
break;
case MYSQL_TYPE_VARCHAR:
=== modified file 'sql/item_sum.cc'
--- sql/item_sum.cc 2013-06-06 15:51:28 +0000
+++ sql/item_sum.cc 2013-06-18 10:35:35 +0000
@@ -1307,16 +1307,16 @@ Field *Item_sum_hybrid::create_tmp_field
switch (args[0]->field_type()) {
case MYSQL_TYPE_DATE:
field= new Field_newdate(0, maybe_null ? (uchar*)"" : 0, 0, Field::NONE,
- name, collation.collation);
+ name);
break;
case MYSQL_TYPE_TIME:
field= new_Field_time(0, maybe_null ? (uchar*)"" : 0, 0, Field::NONE,
- name, decimals, collation.collation);
+ name, decimals);
break;
case MYSQL_TYPE_TIMESTAMP:
case MYSQL_TYPE_DATETIME:
field= new_Field_datetime(0, maybe_null ? (uchar*)"" : 0, 0, Field::NONE,
- name, decimals, collation.collation);
+ name, decimals);
break;
default:
return Item_sum::create_tmp_field(group, table, convert_blob_length);
=== modified file 'sql/item_timefunc.cc'
--- sql/item_timefunc.cc 2013-04-07 12:00:16 +0000
+++ sql/item_timefunc.cc 2013-06-27 11:11:57 +0000
@@ -1574,7 +1574,7 @@ static void set_sec_part(ulong sec_part,
{
ltime->second_part= sec_part;
if (item->decimals < TIME_SECOND_PART_DIGITS)
- ltime->second_part= sec_part_truncate(ltime->second_part, item->decimals);
+ my_time_trunc(ltime, item->decimals);
}
}
@@ -2411,7 +2411,7 @@ bool Item_time_typecast::get_date(MYSQL_
if (get_arg0_time(ltime))
return 1;
if (decimals < TIME_SECOND_PART_DIGITS)
- ltime->second_part= sec_part_truncate(ltime->second_part, decimals);
+ my_time_trunc(ltime, decimals);
/*
MYSQL_TIMESTAMP_TIME value can have non-zero day part,
which we should not lose.
@@ -2450,8 +2450,7 @@ bool Item_datetime_typecast::get_date(MY
return 1;
if (decimals < TIME_SECOND_PART_DIGITS)
- ltime->second_part= sec_part_truncate(ltime->second_part, decimals);
-
+ my_time_trunc(ltime, decimals);
/*
ltime is valid MYSQL_TYPE_TIME (according to fuzzy_date).
=== modified file 'sql/log_event.cc'
--- sql/log_event.cc 2013-06-06 19:32:29 +0000
+++ sql/log_event.cc 2013-06-27 12:26:59 +0000
@@ -48,6 +48,7 @@
#include <my_dir.h>
#include "sql_show.h" // append_identifier
#include <strfunc.h>
+#include "compat56.h"
#endif /* MYSQL_CLIENT */
@@ -2128,6 +2129,17 @@ log_event_print_value(IO_CACHE *file, co
return 4;
}
+ case MYSQL_TYPE_TIMESTAMP2:
+ {
+ char buf[MAX_DATE_STRING_REP_LENGTH];
+ struct timeval tm;
+ my_timestamp_from_binary(&tm, ptr, meta);
+ int buflen= my_timeval_to_str(&tm, buf, meta);
+ my_b_write(file, buf, buflen);
+ my_snprintf(typestr, typestr_length, "TIMESTAMP(%d)", meta);
+ return my_timestamp_binary_length(meta);
+ }
+
case MYSQL_TYPE_DATETIME:
{
ulong d, t;
@@ -2142,15 +2154,41 @@ log_event_print_value(IO_CACHE *file, co
return 8;
}
+ case MYSQL_TYPE_DATETIME2:
+ {
+ char buf[MAX_DATE_STRING_REP_LENGTH];
+ MYSQL_TIME ltime;
+ longlong packed= my_datetime_packed_from_binary(ptr, meta);
+ TIME_from_longlong_datetime_packed(<ime, packed);
+ int buflen= my_datetime_to_str(<ime, buf, meta);
+ my_b_write_quoted(file, (uchar *) buf, buflen);
+ my_snprintf(typestr, typestr_length, "DATETIME(%d)", meta);
+ return my_datetime_binary_length(meta);
+ }
+
case MYSQL_TYPE_TIME:
{
- uint32 i32= uint3korr(ptr);
- my_b_printf(file, "'%02d:%02d:%02d'",
- i32 / 10000, (i32 % 10000) / 100, i32 % 100);
+ int32 tmp= sint3korr(ptr);
+ int32 i32= tmp >= 0 ? tmp : - tmp;
+ const char *sign= tmp < 0 ? "-" : "";
+ my_b_printf(file, "'%s%02d:%02d:%02d'",
+ sign, i32 / 10000, (i32 % 10000) / 100, i32 % 100, i32);
my_snprintf(typestr, typestr_length, "TIME");
return 3;
}
-
+
+ case MYSQL_TYPE_TIME2:
+ {
+ char buf[MAX_DATE_STRING_REP_LENGTH];
+ MYSQL_TIME ltime;
+ longlong packed= my_time_packed_from_binary(ptr, meta);
+ TIME_from_longlong_time_packed(<ime, packed);
+ int buflen= my_time_to_str(<ime, buf, meta);
+ my_b_write_quoted(file, (uchar *) buf, buflen);
+ my_snprintf(typestr, typestr_length, "TIME(%d)", meta);
+ return my_time_binary_length(meta);
+ }
+
case MYSQL_TYPE_NEWDATE:
{
uint32 tmp= uint3korr(ptr);
@@ -9860,7 +9898,7 @@ Table_map_log_event::Table_map_log_event
{
m_coltype= reinterpret_cast<uchar*>(m_memory);
for (unsigned int i= 0 ; i < m_table->s->fields ; ++i)
- m_coltype[i]= m_table->field[i]->type();
+ m_coltype[i]= m_table->field[i]->binlog_type();
}
/*
=== modified file 'sql/opt_range.cc'
--- sql/opt_range.cc 2013-06-06 19:32:29 +0000
+++ sql/opt_range.cc 2013-06-18 10:35:35 +0000
@@ -8014,10 +8014,10 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND
*/
if (field->result_type() == STRING_RESULT &&
- ((Field_str*) field)->match_collation_to_optimize_range() &&
+ field->match_collation_to_optimize_range() &&
value->result_type() == STRING_RESULT &&
key_part->image_type == Field::itRAW &&
- ((Field_str*)field)->charset() != conf_func->compare_collation() &&
+ field->charset() != conf_func->compare_collation() &&
!(conf_func->compare_collation()->state & MY_CS_BINSORT &&
(type == Item_func::EQUAL_FUNC || type == Item_func::EQ_FUNC)))
goto end;
@@ -12885,7 +12885,7 @@ check_group_min_max_predicates(Item *con
*/
((args[1]->result_type() == STRING_RESULT &&
image_type == Field::itRAW &&
- ((Field_str*) min_max_arg_item->field)->charset() !=
+ min_max_arg_item->field->charset() !=
pred->compare_collation())
||
/*
=== modified file 'sql/opt_table_elimination.cc'
--- sql/opt_table_elimination.cc 2012-02-17 11:19:38 +0000
+++ sql/opt_table_elimination.cc 2013-06-18 10:35:35 +0000
@@ -1482,7 +1482,7 @@ void check_equality(Dep_analysis_context
collation of the operation differ from the field collation.
*/
if (field->cmp_type() == STRING_RESULT &&
- ((Field_str*)field)->charset() != cond->compare_collation())
+ field->charset() != cond->compare_collation())
return;
}
}
=== modified file 'sql/protocol.cc'
--- sql/protocol.cc 2013-03-27 22:41:02 +0000
+++ sql/protocol.cc 2013-06-27 11:13:00 +0000
@@ -1427,7 +1427,7 @@ bool Protocol_binary::store(MYSQL_TIME *
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);
+ my_time_trunc(tm, decimals);
int4store(pos+7, tm->second_part);
if (tm->second_part)
length=11;
@@ -1469,7 +1469,7 @@ bool Protocol_binary::store_time(MYSQL_T
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);
+ my_time_trunc(tm, decimals);
int4store(pos+8, tm->second_part);
if (tm->second_part)
length=12;
=== modified file 'sql/rpl_utility.cc'
--- sql/rpl_utility.cc 2013-06-06 15:51:28 +0000
+++ sql/rpl_utility.cc 2013-06-19 05:07:00 +0000
@@ -109,12 +109,15 @@ max_display_length_for_field(enum_field_
case MYSQL_TYPE_DATE:
case MYSQL_TYPE_TIME:
+ case MYSQL_TYPE_TIME2:
return 3;
case MYSQL_TYPE_TIMESTAMP:
+ case MYSQL_TYPE_TIMESTAMP2:
return 4;
case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_DATETIME2:
return 8;
case MYSQL_TYPE_BIT:
@@ -262,12 +265,21 @@ uint32 table_def::calc_field_size(uint c
case MYSQL_TYPE_TIME:
length= 3;
break;
+ case MYSQL_TYPE_TIME2:
+ length= my_time_binary_length(m_field_metadata[col]);
+ break;
case MYSQL_TYPE_TIMESTAMP:
length= 4;
break;
+ case MYSQL_TYPE_TIMESTAMP2:
+ length= my_timestamp_binary_length(m_field_metadata[col]);
+ break;
case MYSQL_TYPE_DATETIME:
length= 8;
break;
+ case MYSQL_TYPE_DATETIME2:
+ length= my_datetime_binary_length(m_field_metadata[col]);
+ break;
case MYSQL_TYPE_BIT:
{
/*
@@ -376,6 +388,7 @@ void show_sql_type(enum_field_types type
break;
case MYSQL_TYPE_TIMESTAMP:
+ case MYSQL_TYPE_TIMESTAMP2:
str->set_ascii(STRING_WITH_LEN("timestamp"));
break;
@@ -393,10 +406,12 @@ void show_sql_type(enum_field_types type
break;
case MYSQL_TYPE_TIME:
+ case MYSQL_TYPE_TIME2:
str->set_ascii(STRING_WITH_LEN("time"));
break;
case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_DATETIME2:
str->set_ascii(STRING_WITH_LEN("datetime"));
break;
@@ -615,6 +630,23 @@ can_convert_field_to(Field *field,
else
DBUG_RETURN(false);
}
+ else if (metadata == 0 &&
+ ((field->real_type() == MYSQL_TYPE_TIMESTAMP2 &&
+ source_type == MYSQL_TYPE_TIMESTAMP) ||
+ (field->real_type() == MYSQL_TYPE_TIME2 &&
+ source_type == MYSQL_TYPE_TIME) ||
+ (field->real_type() == MYSQL_TYPE_DATETIME2 &&
+ source_type == MYSQL_TYPE_DATETIME)))
+ {
+ /*
+ TS-TODO: conversion from FSP1>FSP2.
+ Can do non-lossy conversion
+ from old TIME, TIMESTAMP, DATETIME
+ to MySQL56 TIME(0), TIMESTAMP(0), DATETIME(0).
+ */
+ *order_var= -1;
+ DBUG_RETURN(true);
+ }
else if (!slave_type_conversions_options)
DBUG_RETURN(false);
@@ -739,6 +771,9 @@ can_convert_field_to(Field *field,
case MYSQL_TYPE_NULL:
case MYSQL_TYPE_ENUM:
case MYSQL_TYPE_SET:
+ case MYSQL_TYPE_TIMESTAMP2:
+ case MYSQL_TYPE_DATETIME2:
+ case MYSQL_TYPE_TIME2:
DBUG_RETURN(false);
}
DBUG_RETURN(false); // To keep GCC happy
@@ -939,7 +974,7 @@ TABLE *table_def::create_conversion_tabl
DBUG_PRINT("debug", ("sql_type: %d, target_field: '%s', max_length: %d, decimals: %d,"
" maybe_null: %d, unsigned_flag: %d, pack_length: %u",
- type(col), target_table->field[col]->field_name,
+ binlog_type(col), target_table->field[col]->field_name,
max_length, decimals, TRUE, FALSE, pack_length));
field_def->init_for_tmp_table(type(col),
max_length,
@@ -993,7 +1028,7 @@ table_def::table_def(unsigned char *type
int index= 0;
for (unsigned int i= 0; i < m_size; i++)
{
- switch (m_type[i]) {
+ switch (binlog_type(i)) {
case MYSQL_TYPE_TINY_BLOB:
case MYSQL_TYPE_BLOB:
case MYSQL_TYPE_MEDIUM_BLOB:
@@ -1042,6 +1077,11 @@ table_def::table_def(unsigned char *type
m_field_metadata[i]= x;
break;
}
+ case MYSQL_TYPE_TIME2:
+ case MYSQL_TYPE_DATETIME2:
+ case MYSQL_TYPE_TIMESTAMP2:
+ m_field_metadata[i]= field_metadata[index++];
+ break;
default:
m_field_metadata[i]= 0;
break;
=== modified file 'sql/rpl_utility.h'
--- sql/rpl_utility.h 2013-05-07 11:05:09 +0000
+++ sql/rpl_utility.h 2013-06-18 10:35:35 +0000
@@ -65,6 +65,14 @@ class table_def
ulong size() const { return m_size; }
+ /**
+ Returns internal binlog type code for one field,
+ without translation to real types.
+ */
+ enum_field_types binlog_type(ulong index) const
+ {
+ return static_cast<enum_field_types>(m_type[index]);
+ }
/*
Return a representation of the type data for one field.
@@ -82,7 +90,7 @@ class table_def
either MYSQL_TYPE_STRING, MYSQL_TYPE_ENUM, or MYSQL_TYPE_SET, so
we might need to modify the type to get the real type.
*/
- enum_field_types source_type= static_cast<enum_field_types>(m_type[index]);
+ enum_field_types source_type= binlog_type(index);
uint16 source_metadata= m_field_metadata[index];
switch (source_type)
{
=== modified file 'sql/sql_partition.cc'
--- sql/sql_partition.cc 2013-06-06 15:51:28 +0000
+++ sql/sql_partition.cc 2013-07-02 06:19:23 +0000
@@ -1563,7 +1563,7 @@ bool field_is_partition_charset(Field *f
!(field->type() == MYSQL_TYPE_VARCHAR))
return FALSE;
{
- CHARSET_INFO *cs= ((Field_str*)field)->charset();
+ CHARSET_INFO *cs= field->charset();
if (!(field->type() == MYSQL_TYPE_STRING) ||
!(cs->state & MY_CS_BINSORT))
return TRUE;
@@ -1606,7 +1606,7 @@ bool check_part_func_fields(Field **ptr,
*/
if (field_is_partition_charset(field))
{
- CHARSET_INFO *cs= ((Field_str*)field)->charset();
+ CHARSET_INFO *cs= field->charset();
if (!ok_with_charsets ||
cs->mbmaxlen > 1 ||
cs->strxfrm_multiply > 1)
@@ -2090,6 +2090,8 @@ static int check_part_field(enum_field_t
case MYSQL_TYPE_DATE:
case MYSQL_TYPE_TIME:
case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_TIME2:
+ case MYSQL_TYPE_DATETIME2:
*result_type= STRING_RESULT;
*need_cs_check= TRUE;
return FALSE;
@@ -2102,6 +2104,7 @@ static int check_part_field(enum_field_t
case MYSQL_TYPE_NEWDECIMAL:
case MYSQL_TYPE_DECIMAL:
case MYSQL_TYPE_TIMESTAMP:
+ case MYSQL_TYPE_TIMESTAMP2:
case MYSQL_TYPE_NULL:
case MYSQL_TYPE_FLOAT:
case MYSQL_TYPE_DOUBLE:
@@ -2974,7 +2977,7 @@ static void copy_to_part_field_buffers(F
restore_ptr++;
if (!field->maybe_null() || !field->is_null())
{
- CHARSET_INFO *cs= ((Field_str*)field)->charset();
+ CHARSET_INFO *cs= field->charset();
uint max_len= field->pack_length();
uint data_len= field->data_length();
uchar *field_buf= *field_bufs;
=== modified file 'sql/sql_prepare.cc'
--- sql/sql_prepare.cc 2013-06-06 19:32:29 +0000
+++ sql/sql_prepare.cc 2013-06-27 11:16:36 +0000
@@ -4409,7 +4409,7 @@ bool Protocol_local::store(const char *s
bool Protocol_local::store(MYSQL_TIME *time, int decimals)
{
if (decimals != AUTO_SEC_PART_DIGITS)
- time->second_part= sec_part_truncate(time->second_part, decimals);
+ my_time_trunc(time, decimals);
return store_column(time, sizeof(MYSQL_TIME));
}
@@ -4427,7 +4427,7 @@ bool Protocol_local::store_date(MYSQL_TI
bool Protocol_local::store_time(MYSQL_TIME *time, int decimals)
{
if (decimals != AUTO_SEC_PART_DIGITS)
- time->second_part= sec_part_truncate(time->second_part, decimals);
+ my_time_trunc(time, decimals);
return store_column(time, sizeof(MYSQL_TIME));
}
=== modified file 'sql/sql_select.cc'
--- sql/sql_select.cc 2013-06-06 19:32:29 +0000
+++ sql/sql_select.cc 2013-06-18 10:35:35 +0000
@@ -4307,7 +4307,7 @@ add_key_field(JOIN *join,
{
if ((*value)->cmp_type() != STRING_RESULT)
return;
- if (((Field_str*)field)->charset() != cond->compare_collation())
+ if (field->charset() != cond->compare_collation())
return;
}
}
@@ -11857,7 +11857,7 @@ static bool check_simple_equality(Item *
if (field_item->cmp_type() == STRING_RESULT)
{
- CHARSET_INFO *cs= ((Field_str*) field_item->field)->charset();
+ CHARSET_INFO *cs= field_item->field->charset();
if (!item)
{
Item_func_eq *eq_item;
=== modified file 'sql/sql_table.cc'
--- sql/sql_table.cc 2013-06-06 19:32:29 +0000
+++ sql/sql_table.cc 2013-06-18 10:35:36 +0000
@@ -2790,6 +2790,8 @@ int prepare_create_field(Create_field *s
case MYSQL_TYPE_NEWDATE:
case MYSQL_TYPE_TIME:
case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_TIME2:
+ case MYSQL_TYPE_DATETIME2:
case MYSQL_TYPE_NULL:
sql_field->pack_flag=f_settype((uint) sql_field->sql_type);
break;
@@ -2808,6 +2810,7 @@ int prepare_create_field(Create_field *s
(sql_field->decimals << FIELDFLAG_DEC_SHIFT));
break;
case MYSQL_TYPE_TIMESTAMP:
+ case MYSQL_TYPE_TIMESTAMP2:
/* fall-through */
default:
sql_field->pack_flag=(FIELDFLAG_NUMBER |
@@ -2893,7 +2896,7 @@ void promote_first_timestamp_column(List
while ((column_definition= it++) != NULL)
{
- if (column_definition->sql_type == MYSQL_TYPE_TIMESTAMP || // TIMESTAMP
+ if (is_timestamp_type(column_definition->sql_type) || // TIMESTAMP
column_definition->unireg_check == Field::TIMESTAMP_OLD_FIELD) // Legacy
{
if ((column_definition->flags & NOT_NULL_FLAG) != 0 && // NOT NULL,
@@ -3854,7 +3857,7 @@ mysql_prepare_create_table(THD *thd, HA_
if (thd->variables.sql_mode & MODE_NO_ZERO_DATE &&
!sql_field->def &&
- sql_field->sql_type == MYSQL_TYPE_TIMESTAMP &&
+ is_timestamp_type(sql_field->sql_type) &&
(sql_field->flags & NOT_NULL_FLAG) &&
(type == Field::NONE || type == Field::TIMESTAMP_UN_FIELD))
{
@@ -5950,7 +5953,8 @@ mysql_prepare_alter_table(THD *thd, TABL
*/
if ((def->sql_type == MYSQL_TYPE_DATE ||
def->sql_type == MYSQL_TYPE_NEWDATE ||
- def->sql_type == MYSQL_TYPE_DATETIME) &&
+ def->sql_type == MYSQL_TYPE_DATETIME ||
+ def->sql_type == MYSQL_TYPE_DATETIME2) &&
!alter_info->datetime_field &&
!(~def->flags & (NO_DEFAULT_VALUE_FLAG | NOT_NULL_FLAG)) &&
thd->variables.sql_mode & MODE_NO_ZERO_DATE)
@@ -7582,6 +7586,7 @@ bool mysql_alter_table(THD *thd,char *ne
t_type= MYSQL_TIMESTAMP_DATE;
break;
case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_DATETIME2:
f_val= "0000-00-00 00:00:00";
t_type= MYSQL_TIMESTAMP_DATETIME;
break;
=== modified file 'sql/table.cc'
--- sql/table.cc 2013-06-06 19:32:29 +0000
+++ sql/table.cc 2013-06-18 10:35:36 +0000
@@ -3281,7 +3281,7 @@ bool get_field(MEM_ROOT *mem, Field *fie
}
if (!(to= strmake_root(mem, str.ptr(), length)))
length= 0; // Safety fix
- res->set(to, length, ((Field_str*)field)->charset());
+ res->set(to, length, field->charset());
return 0;
}
=== modified file 'storage/perfschema/pfs_engine_table.cc'
--- storage/perfschema/pfs_engine_table.cc 2013-06-06 19:32:29 +0000
+++ storage/perfschema/pfs_engine_table.cc 2013-06-18 10:35:36 +0000
@@ -514,7 +514,7 @@ void PFS_engine_table::set_field_enum(Fi
void PFS_engine_table::set_field_timestamp(Field *f, ulonglong value)
{
- DBUG_ASSERT(f->real_type() == MYSQL_TYPE_TIMESTAMP);
+ DBUG_ASSERT(is_timestamp_type(f->real_type()));
Field_timestamp *f2= (Field_timestamp*) f;
f2->store_TIME((long)(value / 1000000), (value % 1000000));
}
Follow ups
References