null+****@clear*****
null+****@clear*****
2012年 2月 4日 (土) 23:29:07 JST
Kouhei Sutou 2012-02-04 23:29:07 +0900 (Sat, 04 Feb 2012) New Revision: bb89e3def6587f27b3130637c674aba8dd4e681b Log: [storage] support time with fractional seconds. Added files: test/sql/suite/mroonga_storage/r/column_time_fractional_seconds.result test/sql/suite/mroonga_storage/t/column_time_fractional_seconds.test Modified files: ha_mroonga.cc ha_mroonga.h Modified: ha_mroonga.cc (+126 -34) =================================================================== --- ha_mroonga.cc 2012-02-04 21:47:00 +0900 (4770807) +++ ha_mroonga.cc 2012-02-04 23:29:07 +0900 (2c2dc23) @@ -983,7 +983,8 @@ static grn_builtin_type mrn_grn_type_from_field(grn_ctx *ctx, Field *field, break; #endif #ifdef MRN_HAVE_MYSQL_TYPE_TIME2 - case MYSQL_TYPE_TIME2: // TIME; 3bytes + case MYSQL_TYPE_TIME2: // TIME(FSP); 3 + (FSP + 1) / 2 bytes + // 0 <= FSP <= 6; 3-6bytes type = GRN_DB_TIME; // 8bytes break; #endif @@ -1253,6 +1254,52 @@ static uchar *mrn_multiple_column_key_encode(KEY *key_info, return buffer; } +static long long int mrn_mysql_time_to_grn_time(MYSQL_TIME *mysql_time) +{ + MRN_DBUG_ENTER_FUNCTION(); + int sec = 0, usec = 0; + switch (mysql_time->time_type) { + case MYSQL_TIMESTAMP_DATE: + { + struct tm date; + memset(&date, 0, sizeof(struct tm)); + date.tm_year = mysql_time->year - 1900; + date.tm_mon = mysql_time->month - 1; + date.tm_mday = mysql_time->day; + sec = mktime(&date) + mrn_utc_diff_in_seconds; + } + break; + case MYSQL_TIMESTAMP_DATETIME: + { + struct tm datetime; + memset(&datetime, 0, sizeof(struct tm)); + datetime.tm_year = mysql_time->year - 1900; + datetime.tm_mon = mysql_time->month - 1; + datetime.tm_mday = mysql_time->day; + datetime.tm_hour = mysql_time->hour; + datetime.tm_min = mysql_time->minute; + datetime.tm_sec = mysql_time->second; + sec = mktime(&datetime) + mrn_utc_diff_in_seconds; + } + break; + case MYSQL_TIMESTAMP_TIME: + sec = + mysql_time->hour * 60 * 60 + + mysql_time->minute * 60 + + mysql_time->second; + break; + default: + sec = 0; + break; + } + if (mysql_time->neg) { + sec = -sec; + } + usec = mysql_time->second_part; + long long int grn_time = GRN_TIME_PACK(sec, usec); + DBUG_RETURN(grn_time); +} + static uint mrn_alter_table_flags(uint flags) { uint ret_flags = 0; ret_flags |= @@ -7148,7 +7195,7 @@ int ha_mroonga::generic_store_bulk_time(Field *field, grn_obj *buf) { MRN_DBUG_ENTER_METHOD(); int error = 0; - long long value = field->val_int(); + long long int value = field->val_int(); grn_obj_reinit(ctx, buf, GRN_DB_INT32, 0); GRN_INT32_SET(ctx, buf, value); DBUG_RETURN(error); @@ -7161,16 +7208,7 @@ int ha_mroonga::generic_store_bulk_datetime(Field *field, grn_obj *buf) Field_datetime *datetime_field = (Field_datetime *)field; MYSQL_TIME mysql_time; datetime_field->get_time(&mysql_time); - struct tm date; - memset(&date, 0, sizeof(struct tm)); - date.tm_year = mysql_time.year - 1900; - date.tm_mon = mysql_time.month - 1; - date.tm_mday = mysql_time.day; - date.tm_hour = mysql_time.hour; - date.tm_min = mysql_time.minute; - date.tm_sec = mysql_time.second; - int32 seconds = mktime(&date) + mrn_utc_diff_in_seconds; - long long int time = GRN_TIME_PACK(seconds, mysql_time.second_part); + long long int time = mrn_mysql_time_to_grn_time(&mysql_time); grn_obj_reinit(ctx, buf, GRN_DB_TIME, 0); GRN_TIME_SET(ctx, buf, time); DBUG_RETURN(error); @@ -7184,16 +7222,21 @@ int ha_mroonga::generic_store_bulk_datetime2(Field *field, grn_obj *buf) Field_datetimef *datetimef_field = (Field_datetimef *)field; MYSQL_TIME mysql_time; datetimef_field->get_time(&mysql_time); - struct tm date; - memset(&date, 0, sizeof(struct tm)); - date.tm_year = mysql_time.year - 1900; - date.tm_mon = mysql_time.month - 1; - date.tm_mday = mysql_time.day; - date.tm_hour = mysql_time.hour; - date.tm_min = mysql_time.minute; - date.tm_sec = mysql_time.second; - int32 seconds = mktime(&date) + mrn_utc_diff_in_seconds; - long long int time = GRN_TIME_PACK(seconds, mysql_time.second_part); + long long int time = mrn_mysql_time_to_grn_time(&mysql_time); + grn_obj_reinit(ctx, buf, GRN_DB_TIME, 0); + GRN_TIME_SET(ctx, buf, time); + DBUG_RETURN(error); +} +#endif + +#ifdef MRN_HAVE_MYSQL_TYPE_TIME2 +int ha_mroonga::generic_store_bulk_time2(Field *field, grn_obj *buf) +{ + MRN_DBUG_ENTER_METHOD(); + int error = 0; + MYSQL_TIME mysql_time; + field->get_time(&mysql_time); + long long int time = mrn_mysql_time_to_grn_time(&mysql_time); grn_obj_reinit(ctx, buf, GRN_DB_TIME, 0); GRN_TIME_SET(ctx, buf, time); DBUG_RETURN(error); @@ -7207,13 +7250,7 @@ int ha_mroonga::generic_store_bulk_new_date(Field *field, grn_obj *buf) Field_newdate *newdate_field = (Field_newdate *)field; MYSQL_TIME mysql_date; newdate_field->get_time(&mysql_date); - struct tm date; - memset(&date, 0, sizeof(struct tm)); - date.tm_year = mysql_date.year - 1900; - date.tm_mon = mysql_date.month - 1; - date.tm_mday = mysql_date.day; - int32 seconds = mktime(&date) + mrn_utc_diff_in_seconds; - long long int time = GRN_TIME_PACK(seconds, 0); + long long int time = mrn_mysql_time_to_grn_time(&mysql_date); grn_obj_reinit(ctx, buf, GRN_DB_TIME, 0); GRN_TIME_SET(ctx, buf, time); DBUG_RETURN(error); @@ -7318,7 +7355,7 @@ int ha_mroonga::generic_store_bulk(Field *field, grn_obj *buf) #endif #ifdef MRN_HAVE_MYSQL_TYPE_TIME2 case MYSQL_TYPE_TIME2: - error = generic_store_bulk_time(field, buf); + error = generic_store_bulk_time2(field, buf); break; #endif case MYSQL_TYPE_NEWDECIMAL: @@ -7518,7 +7555,7 @@ void ha_mroonga::storage_store_field_datetime2(Field *field, uint value_length) { long long int time = *((long long int *)value); - int32 sec, usec; + int sec, usec; GRN_TIME_UNPACK(time, sec, usec); struct tm date; time_t sec_t = sec; @@ -7537,6 +7574,30 @@ void ha_mroonga::storage_store_field_datetime2(Field *field, } #endif +#ifdef MRN_HAVE_MYSQL_TYPE_TIME2 +void ha_mroonga::storage_store_field_time2(Field *field, + const char *value, + uint value_length) +{ + MYSQL_TIME mysql_time; + memset(&mysql_time, 0, sizeof(MYSQL_TIME)); + + long long int time = *((long long int *)value); + if (time < 0) { + mysql_time.neg = true; + time = -time; + } + int sec, usec; + GRN_TIME_UNPACK(time, sec, usec); + mysql_time.time_type = MYSQL_TIMESTAMP_TIME; + mysql_time.hour = sec / (60 * 60); + mysql_time.minute = sec / 60 % 60; + mysql_time.second = sec % 60; + mysql_time.second_part = usec; + field->store_time(&mysql_time); +} +#endif + void ha_mroonga::storage_store_field_blob(Field *field, const char *value, uint value_length) @@ -7632,7 +7693,7 @@ void ha_mroonga::storage_store_field(Field *field, #endif #ifdef MRN_HAVE_MYSQL_TYPE_TIME2 case MYSQL_TYPE_TIME2: - storage_store_field_time(field, value, value_length); + storage_store_field_time2(field, value, value_length); break; #endif case MYSQL_TYPE_NEWDECIMAL: @@ -7745,12 +7806,38 @@ void ha_mroonga::storage_store_fields_by_index(uchar *buf) DBUG_VOID_RETURN; } +#ifdef MRN_HAVE_MYSQL_TYPE_TIME2 +int ha_mroonga::storage_encode_key_time2(Field *field, const uchar *key, + uchar *buf, uint *size) +{ + MRN_DBUG_ENTER_METHOD(); + int error = 0; + + Field_timef *time2_field = (Field_timef *)field; + long long int packed_time = + my_time_packed_from_binary(key, time2_field->decimals()); + MYSQL_TIME mysql_time; + TIME_from_longlong_time_packed(&mysql_time, packed_time); + int sec, usec; + sec = mysql_time.hour * 60 * 60 + mysql_time.minute * 60 + mysql_time.second; + if (mysql_time.neg) { + sec = -sec; + } + usec = mysql_time.second_part; + long long int time = GRN_TIME_PACK(sec, usec); + memcpy(buf, &time, 8); + *size = 8; + + DBUG_RETURN(error); +} +#endif + int ha_mroonga::storage_encode_key(Field *field, const uchar *key, uchar *buf, uint *size) { MRN_DBUG_ENTER_METHOD(); int error; - char *ptr = (char *)key; + const uchar *ptr = key; error = mrn_change_encoding(ctx, field->charset()); if (error) @@ -7861,12 +7948,17 @@ int ha_mroonga::storage_encode_key(Field *field, const uchar *key, *size = 8; break; } +#ifdef MRN_HAVE_MYSQL_TYPE_TIME2 + case MYSQL_TYPE_TIME2: + storage_encode_key_time2(field, ptr, buf, size); + break; +#endif case MYSQL_TYPE_STRING: case MYSQL_TYPE_VARCHAR: case MYSQL_TYPE_BLOB: { ptr += HA_KEY_BLOB_LENGTH; - const char *val = ptr; + const char *val = (const char *)ptr; int len = strlen(val); memcpy(buf, val, len); *size = len; Modified: ha_mroonga.h (+11 -0) =================================================================== --- ha_mroonga.h 2012-02-04 21:47:00 +0900 (1b78e81) +++ ha_mroonga.h 2012-02-04 23:29:07 +0900 (e25e149) @@ -432,6 +432,9 @@ private: #ifdef MRN_HAVE_MYSQL_TYPE_DATETIME2 int generic_store_bulk_datetime2(Field *field, grn_obj *buf); #endif +#ifdef MRN_HAVE_MYSQL_TYPE_TIME2 + int generic_store_bulk_time2(Field *field, grn_obj *buf); +#endif int generic_store_bulk_new_decimal(Field *field, grn_obj *buf); int generic_store_bulk_blob(Field *field, grn_obj *buf); int generic_store_bulk_geometry(Field *field, grn_obj *buf); @@ -457,6 +460,10 @@ private: void storage_store_field_datetime2(Field *field, const char *value, uint value_length); #endif +#ifdef MRN_HAVE_MYSQL_TYPE_TIME2 + void storage_store_field_time2(Field *field, + const char *value, uint value_length); +#endif void storage_store_field_blob(Field *field, const char *value, uint value_length); void storage_store_field_geometry(Field *field, @@ -465,6 +472,10 @@ private: void storage_store_fields(uchar *buf, grn_id record_id); void storage_store_fields_by_index(uchar *buf); +#ifdef MRN_HAVE_MYSQL_TYPE_TIME2 + int storage_encode_key_time2(Field *field, const uchar *key, + uchar *buf, uint *size); +#endif int storage_encode_key(Field *field, const uchar *key, uchar *buf, uint *size); void set_pk_bitmap(); Added: test/sql/suite/mroonga_storage/r/column_time_fractional_seconds.result (+40 -0) 100644 =================================================================== --- /dev/null +++ test/sql/suite/mroonga_storage/r/column_time_fractional_seconds.result 2012-02-04 23:29:07 +0900 (87613ae) @@ -0,0 +1,40 @@ +DROP TABLE IF EXISTS running_records; +CREATE TABLE running_records ( +id INT PRIMARY KEY AUTO_INCREMENT, +title TEXT, +average TIME(6), +max TIME(6), +KEY (average) +) DEFAULT CHARSET UTF8; +SHOW CREATE TABLE running_records; +Table Create Table +running_records CREATE TABLE `running_records` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `title` text, + `average` time(6) DEFAULT NULL, + `max` time(6) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `average` (`average`) +) ENGINE=mroonga DEFAULT CHARSET=utf8 +INSERT INTO running_records (title, average, max) +VALUES ("normal condition", "01:00:00.000001", "01:05:00.000001"); +INSERT INTO running_records (title, average, max) +VALUES ("bad condition", "12:23:34.123456", "838:59:58.999999"); +INSERT INTO running_records (title, average, max) +VALUES ("record failure", "-838:59:59.000000", "-838:59:59.000000"); +SELECT * FROM running_records; +id title average max +1 normal condition 01:00:00.000001 01:05:00.000001 +2 bad condition 12:23:34.123456 838:59:58.999999 +3 record failure -838:59:59.000000 -838:59:59.000000 +SELECT * FROM running_records +WHERE average BETWEEN "00:59:59.999999" AND "100:10:10.101010"; +id title average max +1 normal condition 01:00:00.000001 01:05:00.000001 +2 bad condition 12:23:34.123456 838:59:58.999999 +SELECT * FROM running_records +WHERE average BETWEEN "-838:59:59.000000" AND "01:00:00.000001"; +id title average max +3 record failure -838:59:59.000000 -838:59:59.000000 +1 normal condition 01:00:00.000001 01:05:00.000001 +DROP TABLE running_records; Added: test/sql/suite/mroonga_storage/t/column_time_fractional_seconds.test (+50 -0) 100644 =================================================================== --- /dev/null +++ test/sql/suite/mroonga_storage/t/column_time_fractional_seconds.test 2012-02-04 23:29:07 +0900 (4652b17) @@ -0,0 +1,50 @@ +# Copyright(C) 2012 Kouhei Sutou <kou****@clear*****> +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +--source include/have_mroonga.inc +--source include/have_fractional_seconds.inc + +--disable_warnings +DROP TABLE IF EXISTS running_records; +--enable_warnings + +CREATE TABLE running_records ( + id INT PRIMARY KEY AUTO_INCREMENT, + title TEXT, + average TIME(6), + max TIME(6), + KEY (average) +) DEFAULT CHARSET UTF8; +SHOW CREATE TABLE running_records; + +INSERT INTO running_records (title, average, max) + VALUES ("normal condition", "01:00:00.000001", "01:05:00.000001"); +INSERT INTO running_records (title, average, max) + VALUES ("bad condition", "12:23:34.123456", "838:59:58.999999"); +INSERT INTO running_records (title, average, max) + VALUES ("record failure", "-838:59:59.000000", "-838:59:59.000000"); + +SELECT * FROM running_records; + +SELECT * FROM running_records + WHERE average BETWEEN "00:59:59.999999" AND "100:10:10.101010"; + +SELECT * FROM running_records + WHERE average BETWEEN "-838:59:59.000000" AND "01:00:00.000001"; + +DROP TABLE running_records; + +--source include/have_mroonga_deinit.inc