diff --git a/ext/groonga/rb-grn-context.c b/ext/groonga/rb-grn-context.c index 41e71ff9..a6991ae5 100644 --- a/ext/groonga/rb-grn-context.c +++ b/ext/groonga/rb-grn-context.c @@ -2,7 +2,7 @@ /* Copyright (C) 2010-2021 Sutou Kouhei Copyright (C) 2016 Masafumi Yokoyama - Copyright (C) 2019 Horimoto Yasuhiro + Copyright (C) 2019-2022 Horimoto Yasuhiro This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -326,6 +326,26 @@ rb_grn_context_ensure (VALUE *context) return SELF(*context); } +/* + * If context has already implemented database, it returns +true+, + * otherwise it returns +false+. + * + * @return [Boolean] `true` if context has already implemented database. + * `false` if context does not implement database. + */ +VALUE +rb_grn_context_implement_db (grn_ctx *context) +{ + grn_obj *database; + + database = grn_ctx_db(context); + if (database) { + return Qtrue; + } else { + return Qfalse; + } +} + VALUE rb_grn_context_rb_string_new (grn_ctx *context, const char *string, long length) { diff --git a/ext/groonga/rb-grn-patricia-trie.c b/ext/groonga/rb-grn-patricia-trie.c index 15021bf6..c8435417 100644 --- a/ext/groonga/rb-grn-patricia-trie.c +++ b/ext/groonga/rb-grn-patricia-trie.c @@ -166,10 +166,12 @@ rb_grn_patricia_trie_s_create (int argc, VALUE *argv, VALUE klass) grn_obj *key_type = NULL, *value_type = NULL, *table; const char *name = NULL, *path = NULL; unsigned name_size = 0; + unsigned int key_size = 0; + unsigned int value_size = 0; grn_table_flags flags = GRN_OBJ_TABLE_PAT_KEY; VALUE rb_table; VALUE options, rb_context, rb_name, rb_path, rb_persistent; - VALUE rb_key_normalize, rb_key_with_sis, rb_key_type; + VALUE rb_key_normalize, rb_key_with_sis, rb_key_type, rb_key_size, rb_key_var_size; VALUE rb_value_type; VALUE rb_default_tokenizer; VALUE rb_token_filters; @@ -186,6 +188,8 @@ rb_grn_patricia_trie_s_create (int argc, VALUE *argv, VALUE klass) "key_normalize", &rb_key_normalize, "key_with_sis", &rb_key_with_sis, "key_type", &rb_key_type, + "key_size", &rb_key_size, + "key_var_size", &rb_key_var_size, "value_type", &rb_value_type, "default_tokenizer", &rb_default_tokenizer, "token_filters", &rb_token_filters, @@ -227,8 +231,17 @@ rb_grn_patricia_trie_s_create (int argc, VALUE *argv, VALUE klass) if (RVAL2CBOOL(rb_sub_records)) flags |= GRN_OBJ_WITH_SUBREC; - table = grn_table_create(context, name, name_size, path, - flags, key_type, value_type); + if (rb_grn_context_implement_db(context)) { + table = grn_table_create(context, name, name_size, path, + flags, key_type, value_type); + } else { + if (RVAL2CBOOL(rb_key_var_size)) + flags |= GRN_OBJ_KEY_VAR_SIZE; + if (!NIL_P(rb_key_size)) + key_size = NUM2UINT(rb_key_size); + value_size = 0; + table = (grn_obj *)grn_pat_create(context, path, key_size, value_size, flags); + } if (!table) rb_grn_context_check(context, rb_ary_new_from_values(argc, argv)); rb_table = GRNOBJECT2RVAL(klass, context, table, GRN_TRUE); diff --git a/ext/groonga/rb-grn-table.c b/ext/groonga/rb-grn-table.c index 0b6cb196..58a2074b 100644 --- a/ext/groonga/rb-grn-table.c +++ b/ext/groonga/rb-grn-table.c @@ -298,6 +298,7 @@ rb_grn_table_define_column (int argc, VALUE *argv, VALUE self) unsigned name_size = 0; grn_column_flags flags = 0; VALUE rb_name, rb_value_type; + VALUE rb_value_size, rb_value_var_size; VALUE options, rb_path, rb_persistent, rb_compress, rb_type, rb_with_weight; VALUE rb_weight_float32; VALUE rb_missing_mode; @@ -319,6 +320,8 @@ rb_grn_table_define_column (int argc, VALUE *argv, VALUE self) "path", &rb_path, "persistent", &rb_persistent, "type", &rb_type, + "value_size", &rb_value_size, + "value_var_size", &rb_value_var_size, "with_weight", &rb_with_weight, "compress", &rb_compress, "weight_float32", &rb_weight_float32, @@ -420,8 +423,58 @@ rb_grn_table_define_column (int argc, VALUE *argv, VALUE self) rb_grn_inspect(rb_invalid_mode)); } - column = grn_column_create(context, table, name, name_size, - path, flags, value_type); + if (rb_grn_context_implement_db(context)) { + column = grn_column_create(context, table, name, name_size, + path, flags, value_type); + } else { + char fullname[GRN_TABLE_MAX_KEY_SIZE]; + unsigned int fullname_size; + int table_name_len = strlen(fullname); + if (name_size + 1 + table_name_len > GRN_TABLE_MAX_KEY_SIZE) { + rb_raise(rb_eArgError, + "[column][create] too long column name: required name_size(%d) < %d" + ": <%.*s>.<%.*s>", + name_size, GRN_TABLE_MAX_KEY_SIZE - 1 - table_name_len, + table_name_len, fullname, name_size, name); + } +// fullname[table_name_len] = '.'; +// grn_memcpy(fullname + table_name_len + 1, name, name_size); +// fullname_size = table_name_len + 1 + name_size; +// grn_ctx *target_ctx = context; +// grn_id id = GRN_ID_NIL; +// id = grn_pat_add(target_ctx, +// target_ctx->impl->temporary_columns, +// fullname, fullname_size, +// NULL, +// &added); +// id |= GRN_OBJ_TMP_OBJECT | GRN_OBJ_TMP_COLUMN; + + if (RVAL2CBOOL(rb_value_var_size)) + flags |= GRN_OBJ_KEY_VAR_SIZE; + int64_t value_size = 0; + if (!NIL_P(rb_value_size)) + value_size = NUM2INT(rb_value_size); + + grn_obj *res; + switch (flags & GRN_OBJ_COLUMN_TYPE_MASK) { + case GRN_OBJ_COLUMN_SCALAR : + if ((flags & GRN_OBJ_KEY_VAR_SIZE) || value_size > sizeof(int64_t)) { + res = (grn_obj *)grn_ja_create(context, path, value_size, flags); + } else { + res = (grn_obj *)grn_ra_create(context, path, value_size, flags); + } + break; + case GRN_OBJ_COLUMN_VECTOR : + res = (grn_obj *)grn_ja_create(context, path, value_size * 30/*todo*/, flags); + //todo : zlib support + break; + case GRN_OBJ_COLUMN_INDEX : + res = (grn_obj *)grn_ii_create(context, path, table, flags); //todo : ii layout support + break; + } + column = res; + } + if (context->rc) { VALUE rb_related_object; rb_related_object = diff --git a/ext/groonga/rb-grn.h b/ext/groonga/rb-grn.h index 77985175..8dc3dcbc 100644 --- a/ext/groonga/rb-grn.h +++ b/ext/groonga/rb-grn.h @@ -393,6 +393,7 @@ void rb_grn_context_reset_floating_objects(RbGrnContext *rb_grn_contex void rb_grn_context_mark_grn_id (grn_ctx *context, grn_id id); grn_ctx *rb_grn_context_ensure (VALUE *context); +VALUE rb_grn_context_implement_db (grn_ctx *context); VALUE rb_grn_context_get_default (void); VALUE rb_grn_context_to_exception (grn_ctx *context, VALUE related_object); diff --git a/test/test-patricia-trie-no-db.rb b/test/test-patricia-trie-no-db.rb new file mode 100644 index 00000000..dce940f4 --- /dev/null +++ b/test/test-patricia-trie-no-db.rb @@ -0,0 +1,109 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2022 Horimoto Yasuhiro +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License version 2.1 as published by the Free Software Foundation. +# +# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +class PatriciaTrieTestNoDB < Test::Unit::TestCase + include GroongaTestUtils + include ERB::Util + + + def test_support_key? + assert_predicate(Groonga::PatriciaTrie.create(key_size: 4096, + key_var_size: true), + :support_key?) + end + + def test_add + users = Groonga::PatriciaTrie.create(key_size: 4096, key_var_size: true) + users.define_column("address", value_size: 4096, value_var_size: true) + me = users.add("me", :address => "me@example.com") + assert_equal("me@example.com", me[:address]) + end + + def test_key? + users = Groonga::PatriciaTrie.create(key_size: 4096, key_var_size: true) + assert_false(users.key?("morita")) + users.add("morita") + assert_true(users.key?("morita")) + end + + def test_has_key? + users = Groonga::PatriciaTrie.create(key_size: 4096, key_var_size: true) + assert_false(users.has_key?("morita")) + users.add("morita") + assert_true(users.has_key?("morita")) + end + + def test_scan + Groonga::Context.default_options = {:encoding => "utf-8"} + words = Groonga::PatriciaTrie.create(key_size: 4096, key_var_size: true) + words.add("リンク") + arupaka = words.add("アルパカ") + words.add("アルパカ(生物)") + adventure_of_link = words.add('リンクの冒険') + words.add('冒険') + gaxtu = words.add('ガッ') + muteki = words.add('MUTEKI') + assert_equal([[muteki, "MUTEKI", 0, 6], + [adventure_of_link, "リンクの冒険", 7, 18], + [arupaka, "アルパカ", 42, 12], + [gaxtu, "ガッ", 55, 6]], + words.scan('MUTEKI リンクの冒険 ミリバール アルパカ ガッ')) + end + + def test_added? + users = Groonga::PatriciaTrie.create(key_size: 4096, key_var_size: true) + bob = users.add("bob") + assert_predicate(bob, :added?) + bob_again = users.add("bob") + assert_not_predicate(bob_again, :added?) + end + + def test_rename + users = Groonga::PatriciaTrie.create(key_size: 4096, key_var_size: true) + name = users.define_column("name", value_size: 4096, value_var_size: true) + address = users.define_column("address", value_size: 4096, value_var_size: true) + + users.rename("People") + assert_equal(["People", "People.name", "People.address"], + [users.name, name.name, address.name]) + end + + def test_each + users = Groonga::PatriciaTrie.create(key_size: 4096, key_var_size: true) + users.add("Alice") + users.add("Bob") + users.add("Carl") + + user_names = [] + users.each do |user| + user_names << user.key + end + assert_equal(["Alice", "Bob", "Carl"], user_names) + end + + def test_truncate + users = Groonga::PatriciaTrie.create(key_size: 4096, key_var_size: true) + users.add("Alice") + users.add("Bob") + users.add("Carl") + assert_equal(3, users.size) + assert_nothing_raised do + users.truncate + end + assert_equal(0, users.size) + end +end