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