[Groonga-mysql-commit] mroonga/mroonga [master] [storage] support time with fractional seconds.

Zurück zum Archiv-Index

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




Groonga-mysql-commit メーリングリストの案内
Zurück zum Archiv-Index