[Groonga-mysql-commit] mroonga/mroonga [master] [storage] support negative number for multipul column index.

Back to archive index

null+****@clear***** null+****@clear*****
2011年 9月 23日 (金) 20:27:03 JST


Kouhei Sutou	2011-09-23 11:27:03 +0000 (Fri, 23 Sep 2011)

  New Revision: d6c89043d80adaffcff82aa616f210b4bdae619d

  Log:
    [storage] support negative number for multipul column index.
    
    refs #455

  Added files:
    test/sql/groonga_storage/r/multiple_column_index_int.result
    test/sql/groonga_storage/t/multiple_column_index_int.test
  Modified files:
    configure.ac
    ha_mroonga.cc
    ha_mroonga.h

  Modified: configure.ac (+1 -0)
===================================================================
--- configure.ac    2011-09-23 08:15:17 +0000 (c2b80ad)
+++ configure.ac    2011-09-23 11:27:03 +0000 (5bb3718)
@@ -2,6 +2,7 @@ AC_INIT([groonga-storage-engine], [1.0], [ikdtt****@gmail*****])
 AC_CONFIG_HEADERS([config.h])
 AM_INIT_AUTOMAKE([-Wall -Werror foreign])
 
+AC_C_BIGENDIAN
 AC_PROG_CC
 AC_PROG_CXX
 AC_PROG_CPP

  Modified: ha_mroonga.cc (+192 -27)
===================================================================
--- ha_mroonga.cc    2011-09-23 08:15:17 +0000 (c33099f)
+++ ha_mroonga.cc    2011-09-23 11:27:03 +0000 (e901e9b)
@@ -561,8 +561,143 @@ static int mrn_set_buf(grn_ctx *ctx, Field *field, grn_obj *buf, int *size)
   return error;
 }
 
+#ifdef WORDS_BIGENDIAN
+#define mrn_byte_order_host_to_network(buf, key, size)  \
+{                                                       \
+  uint32_t size_ = (uint32_t)(size);                    \
+  uint8_t *buf_ = (uint8_t *)(buf);                     \
+  uint8_t *key_ = (uint8_t *)(key);                     \
+  while (size_--) { *buf_++ = *key_++; }                \
+}
+#else /* WORDS_BIGENDIAN */
+#define mrn_byte_order_host_to_network(buf, key, size)  \
+{                                                       \
+  uint32_t size_ = (uint32_t)(size);                    \
+  uint8_t *buf_ = (uint8_t *)(buf);                     \
+  uint8_t *key_ = (uint8_t *)(key) + size_;             \
+  while (size_--) { *buf_++ = *(--key_); }              \
+}
+#endif /* WORDS_BIGENDIAN */
+
+static uchar *mrn_multiple_column_key_encode(KEY *key_info,
+                                             const uchar *key, uint key_length,
+                                             uchar *buffer, uint *encoded_length)
+{
+  const uchar *current_key = key;
+  const uchar *key_end = key + key_length;
+  uchar *current_buffer = buffer;
+
+  int n_key_parts = key_info->key_parts;
+  *encoded_length = 0;
+  for (int i = 0; i < n_key_parts && current_key < key_end; i++) {
+    KEY_PART_INFO key_part = key_info->key_part[i];
+    Field *field = key_part.field;
+
+    if (field->null_bit) {
+      current_key += 1;
+    }
+
+    enum {
+      TYPE_LONG_LONG_NUMBER,
+      TYPE_NUMBER,
+      TYPE_FLOAT,
+      TYPE_BYTE_SEQUENCE
+    } data_type;
+    uint32 data_size;
+    long long int long_long_value;
+    double float_value;
+    switch (field->type()) {
+    case MYSQL_TYPE_BIT:
+    case MYSQL_TYPE_ENUM:
+    case MYSQL_TYPE_SET:
+    case MYSQL_TYPE_TINY:
+      data_type = TYPE_NUMBER;
+      data_size = 1;
+      break;
+    case MYSQL_TYPE_SHORT:
+      data_type = TYPE_NUMBER;
+      data_size = 2;
+      break;
+    case MYSQL_TYPE_INT24:
+      data_type = TYPE_NUMBER;
+      data_size = 3;
+      break;
+    case MYSQL_TYPE_LONG:
+      data_type = TYPE_NUMBER;
+      data_size = 4;
+      break;
+    case MYSQL_TYPE_LONGLONG:
+      data_type = TYPE_NUMBER;
+      data_size = 8;
+      break;
+    case MYSQL_TYPE_FLOAT:
+      data_type = TYPE_FLOAT;
+      data_size = 8;
+      float4get(float_value, current_key);
+      break;
+    case MYSQL_TYPE_DOUBLE:
+      data_type = TYPE_FLOAT;
+      data_size = 8;
+      float8get(float_value, current_key);
+      break;
+    case MYSQL_TYPE_TIME:
+    case MYSQL_TYPE_YEAR:
+    case MYSQL_TYPE_DATE:
+    case MYSQL_TYPE_DATETIME:
+      data_type = TYPE_LONG_LONG_NUMBER;
+      long_long_value = (long long int)sint8korr(current_key);
+      data_size = 8;
+      break;
+    case MYSQL_TYPE_STRING:
+    case MYSQL_TYPE_VARCHAR:
+    case MYSQL_TYPE_BLOB:
+      data_type = TYPE_BYTE_SEQUENCE;
+      data_size = key_part.length;
+      break;
+    default:
+      data_type = TYPE_BYTE_SEQUENCE;
+      data_size = key_part.length;
+      break;
+    }
+
+    switch (data_type) {
+    case TYPE_LONG_LONG_NUMBER:
+      mrn_byte_order_host_to_network(current_buffer, &long_long_value,
+                                     data_size);
+      *((uint8_t *)(current_buffer)) ^= 0x80;
+      break;
+    case TYPE_NUMBER:
+      mrn_byte_order_host_to_network(current_buffer, current_key, data_size);
+      {
+        Field_num *number_field = (Field_num *)field;
+        if (!number_field->unsigned_flag) {
+          *((uint8_t *)(current_buffer)) ^= 0x80;
+        }
+      }
+      break;
+    case TYPE_FLOAT:
+      {
+        long_long_value = (long long int)(float_value);
+        long_long_value ^= ((long_long_value >> 63) | (1LL << 63));
+        mrn_byte_order_host_to_network(current_buffer, &long_long_value,
+                                       data_size);
+      }
+      break;
+    case TYPE_BYTE_SEQUENCE:
+      memcpy(current_buffer, current_key, data_size);
+      break;
+    }
+
+    current_key += data_size;
+    current_buffer += data_size;
+    *encoded_length += data_size;
+  }
+
+  return buffer;
+}
+
 static int mrn_set_key_buf(grn_ctx *ctx, Field *field,
-                           const uchar *key, char *buf, uint *size)
+                           const uchar *key, uchar *buf, uint *size)
 {
   char *ptr = (char*) key;
 
@@ -576,8 +711,7 @@ static int mrn_set_key_buf(grn_ctx *ctx, Field *field,
   case MYSQL_TYPE_SET:
   case MYSQL_TYPE_TINY:
     {
-      char val = *ptr;
-      buf[0] = val;
+      memcpy(buf, ptr, 1);
       *size = 1;
       break;
     }
@@ -1872,8 +2006,8 @@ int ha_mroonga::wrapper_open_indexes(const char *name)
     // for HA_KEY_ALG_FULLTEXT keys.
     grn_index_tables = (grn_obj **)malloc(sizeof(grn_obj *) * n_keys);
     grn_index_columns = (grn_obj **)malloc(sizeof(grn_obj *) * n_keys);
-    key_min = (char **)malloc(sizeof(char *) * n_keys);
-    key_max = (char **)malloc(sizeof(char *) * n_keys);
+    key_min = (uchar **)malloc(sizeof(uchar *) * n_keys);
+    key_max = (uchar **)malloc(sizeof(uchar *) * n_keys);
   } else {
     grn_index_tables = grn_index_columns = NULL;
     key_min = key_max = NULL;
@@ -1889,8 +2023,8 @@ int ha_mroonga::wrapper_open_indexes(const char *name)
       continue;
     }
 
-    key_min[i] = (char *)malloc(MRN_MAX_KEY_SIZE);
-    key_max[i] = (char *)malloc(MRN_MAX_KEY_SIZE);
+    key_min[i] = (uchar *)malloc(MRN_MAX_KEY_SIZE);
+    key_max[i] = (uchar *)malloc(MRN_MAX_KEY_SIZE);
 
     if (i == n_primary_keys) {
       grn_index_tables[i] = grn_index_columns[i] = NULL;
@@ -2052,8 +2186,8 @@ int ha_mroonga::storage_open_indexes(const char *name)
   if (n_keys > 0) {
     grn_index_tables = (grn_obj **)malloc(sizeof(grn_obj *) * n_keys);
     grn_index_columns = (grn_obj **)malloc(sizeof(grn_obj *) * n_keys);
-    key_min = (char **)malloc(sizeof(char *) * n_keys);
-    key_max = (char **)malloc(sizeof(char *) * n_keys);
+    key_min = (uchar **)malloc(sizeof(uchar *) * n_keys);
+    key_max = (uchar **)malloc(sizeof(uchar *) * n_keys);
   } else {
     grn_index_tables = grn_index_columns = NULL;
     key_min = key_max = NULL;
@@ -2063,8 +2197,8 @@ int ha_mroonga::storage_open_indexes(const char *name)
   mrn_table_name_gen(name, table_name);
   int i = 0;
   for (i = 0; i < n_keys; i++) {
-    key_min[i] = (char *)malloc(MRN_MAX_KEY_SIZE);
-    key_max[i] = (char *)malloc(MRN_MAX_KEY_SIZE);
+    key_min[i] = (uchar *)malloc(MRN_MAX_KEY_SIZE);
+    key_max[i] = (uchar *)malloc(MRN_MAX_KEY_SIZE);
 
     if (i == pkey_nr) {
       grn_index_tables[i] = grn_index_columns[i] = NULL;
@@ -3089,8 +3223,9 @@ int ha_mroonga::storage_write_row_index(uchar *buf, grn_id record_id)
   my_bitmap_map *tmp_map = dbug_tmp_use_all_columns(table, table->read_set);
 #endif
 
-  grn_obj key;
+  grn_obj key, encoded_key;
   GRN_TEXT_INIT(&key, 0);
+  GRN_TEXT_INIT(&encoded_key, 0);
 
   uint i;
   uint n_keys = table->s->keys;
@@ -3109,9 +3244,18 @@ int ha_mroonga::storage_write_row_index(uchar *buf, grn_id record_id)
              buf,
              &key_info,
              key_info.key_length);
+    GRN_BULK_REWIND(&encoded_key);
+    grn_bulk_space(ctx, &encoded_key, key_info.key_length);
+    uint encoded_key_length;
+    mrn_multiple_column_key_encode(&key_info,
+                                   (uchar *)(GRN_TEXT_VALUE(&key)),
+                                   key_info.key_length,
+                                   (uchar *)(GRN_TEXT_VALUE(&encoded_key)),
+                                   &encoded_key_length);
 
     grn_rc rc;
-    rc = grn_column_index_update(ctx, index_column, record_id, 0, NULL, &key);
+    rc = grn_column_index_update(ctx, index_column, record_id, 0, NULL,
+                                 &encoded_key);
     if (rc) {
       error = ER_ERROR_ON_WRITE;
       my_message(error, ctx->errbuf, MYF(0));
@@ -3123,6 +3267,7 @@ err:
 #ifndef DBUG_OFF
   dbug_tmp_restore_column_map(table->read_set, tmp_map);
 #endif
+  grn_obj_unlink(ctx, &encoded_key);
   grn_obj_unlink(ctx, &key);
 
   DBUG_RETURN(error);
@@ -3505,16 +3650,25 @@ ha_rows ha_mroonga::storage_records_in_range(uint key_nr, key_range *range_min,
         range_min->length == range_max->length &&
         memcmp(range_min->key, range_max->key, range_min->length) == 0) {
       flags |= GRN_CURSOR_PREFIX;
-      val_min = range_min->key;
-      size_min = range_min->length;
+      val_min = mrn_multiple_column_key_encode(&key_info,
+                                               range_min->key,
+                                               range_min->length,
+                                               key_min[key_nr],
+                                               &size_min);
     } else {
       if (range_min) {
-        val_min = range_min->key;
-        size_min = range_min->length;
+        val_min = mrn_multiple_column_key_encode(&key_info,
+                                                 range_min->key,
+                                                 range_min->length,
+                                                 key_min[key_nr],
+                                                 &size_min);
       }
       if (range_max) {
-        val_max = range_max->key;
-        size_max = range_max->length;
+        val_max = mrn_multiple_column_key_encode(&key_info,
+                                                 range_max->key,
+                                                 range_max->length,
+                                                 key_max[key_nr],
+                                                 &size_max);
       }
     }
   } else {
@@ -3723,8 +3877,10 @@ int ha_mroonga::storage_index_read_map(uchar *buf, const uchar *key,
   bool is_multiple_column_index = key_info.key_parts > 1;
   if (is_multiple_column_index) {
     flags |= GRN_CURSOR_PREFIX;
-    val_min = key;
-    size_min = calculate_key_len(table, active_index, key, keypart_map);
+    uint key_length = calculate_key_len(table, active_index, key, keypart_map);
+    val_min = mrn_multiple_column_key_encode(&key_info,
+                                             key, key_length,
+                                             key_min[active_index], &size_min);
   } else {
     KEY_PART_INFO key_part = key_info.key_part[0];
     Field *field = key_part.field;
@@ -4302,16 +4458,25 @@ int ha_mroonga::storage_read_range_first(const key_range *start_key,
         start_key->length == end_key->length &&
         memcmp(start_key->key, end_key->key, start_key->length) == 0) {
       flags |= GRN_CURSOR_PREFIX;
-      val_min = start_key->key;
-      size_min = start_key->length;
+      val_min = mrn_multiple_column_key_encode(&key_info,
+                                               start_key->key,
+                                               start_key->length,
+                                               key_min[active_index],
+                                               &size_min);
     } else {
       if (start_key) {
-        val_min = start_key->key;
-        size_min = start_key->length;
+        val_min = mrn_multiple_column_key_encode(&key_info,
+                                                 start_key->key,
+                                                 start_key->length,
+                                                 key_min[active_index],
+                                                 &size_min);
       }
       if (end_key) {
-        val_max = end_key->key;
-        size_max = end_key->length;
+        val_max = mrn_multiple_column_key_encode(&key_info,
+                                                 end_key->key,
+                                                 end_key->length,
+                                                 key_max[active_index],
+                                                 &size_max);
       }
     }
   } else {

  Modified: ha_mroonga.h (+2 -2)
===================================================================
--- ha_mroonga.h    2011-09-23 08:15:17 +0000 (eb3cb5d)
+++ ha_mroonga.h    2011-09-23 11:27:03 +0000 (af30d2a)
@@ -137,8 +137,8 @@ private:
   st_mrn_ft_info mrn_ft_info;
   grn_obj *matched_record_keys;
 
-  char **key_min;
-  char **key_max;
+  uchar **key_min;
+  uchar **key_max;
   int *key_min_len;
   int *key_max_len;
   uint dup_key;

  Added: test/sql/groonga_storage/r/multiple_column_index_int.result (+40 -0) 100644
===================================================================
--- /dev/null
+++ test/sql/groonga_storage/r/multiple_column_index_int.result    2011-09-23 11:27:03 +0000 (ce7bec5)
@@ -0,0 +1,40 @@
+drop table if exists listing;
+set names utf8;
+create table scores (
+id int primary key auto_increment not null,
+name char(30) not null,
+score int not null,
+index property (name, score)
+) default charset utf8;
+show create table scores;
+Table	Create Table
+scores	CREATE TABLE `scores` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `name` char(30) NOT NULL,
+  `score` int(11) NOT NULL,
+  PRIMARY KEY (`id`),
+  KEY `property` (`name`,`score`)
+) ENGINE=groonga DEFAULT CHARSET=utf8
+insert into scores (name, score) values("Taro Yamada", 29);
+insert into scores (name, score) values("Taro Yamada", -12);
+insert into scores (name, score) values("Jiro Yamada", 27);
+insert into scores (name, score) values("Taro Yamada", 10);
+select * from scores;
+id	name	score
+1	Taro Yamada	29
+2	Taro Yamada	-12
+3	Jiro Yamada	27
+4	Taro Yamada	10
+select * from scores where name = "Taro Yamada";
+id	name	score
+2	Taro Yamada	-12
+4	Taro Yamada	10
+1	Taro Yamada	29
+select * from scores where name = "Taro Yamada" and score = 29;
+id	name	score
+1	Taro Yamada	29
+select * from scores where name = "Taro Yamada" and (score >= -12 and score < 29);
+id	name	score
+2	Taro Yamada	-12
+4	Taro Yamada	10
+drop table scores;

  Added: test/sql/groonga_storage/t/multiple_column_index_int.test (+41 -0) 100644
===================================================================
--- /dev/null
+++ test/sql/groonga_storage/t/multiple_column_index_int.test    2011-09-23 11:27:03 +0000 (6615fff)
@@ -0,0 +1,41 @@
+# Copyright(C) 2011 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 suite/groonga_include/groonga_init.inc
+
+--disable_warnings
+drop table if exists listing;
+--enable_warnings
+
+set names utf8;
+create table scores (
+  id int primary key auto_increment not null,
+  name char(30) not null,
+  score int not null,
+  index property (name, score)
+) default charset utf8;
+show create table scores;
+insert into scores (name, score) values("Taro Yamada", 29);
+insert into scores (name, score) values("Taro Yamada", -12);
+insert into scores (name, score) values("Jiro Yamada", 27);
+insert into scores (name, score) values("Taro Yamada", 10);
+select * from scores;
+select * from scores where name = "Taro Yamada";
+select * from scores where name = "Taro Yamada" and score = 29;
+select * from scores where name = "Taro Yamada" and (score >= -12 and score < 29);
+drop table scores;
+
+--source suite/groonga_include/groonga_deinit.inc




Groonga-mysql-commit メーリングリストの案内
Back to archive index