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