void test_is_key_accessor(gconstpointer data) { const gchar *name; grn_obj *table; grn_obj *object; assert_send_command("table_create Names TABLE_HASH_KEY ShortText"); assert_send_command("table_create Users TABLE_HASH_KEY ShortText"); assert_send_command("column_create Users name COLUMN_SCALAR Names"); table = grn_ctx_get(context, "Users", -1); name = gcut_data_get_string(data, "name"); object = grn_obj_column(context, table, name, strlen(name)); if (gcut_data_get_string(data, "expected")) { cut_assert_true(grn_obj_is_key_accessor(context, object)); } else { cut_assert_false(grn_obj_is_key_accessor(context, object)); } }
static mrb_value indexable_index_ids(mrb_state *mrb, mrb_value self) { grn_ctx *ctx = (grn_ctx *)mrb->ud; grn_obj *object; grn_hook_entry entry; int i; int n_indexes; mrb_value mrb_index_ids; grn_obj hook_data; object = DATA_PTR(self); if (grn_obj_is_key_accessor(ctx, object)) { object = grn_ctx_at(ctx, object->header.domain); } if (grn_obj_is_table(ctx, object)) { entry = GRN_HOOK_INSERT; } else if (grn_obj_is_column(ctx, object)) { entry = GRN_HOOK_SET; } else { return mrb_ary_new(mrb); } n_indexes = grn_obj_get_nhooks(ctx, object, entry); mrb_index_ids = mrb_ary_new_capa(mrb, n_indexes); GRN_TEXT_INIT(&hook_data, 0); for (i = 0; i < n_indexes; i++) { GRN_BULK_REWIND(&hook_data); grn_obj_get_hook(ctx, object, entry, i, &hook_data); if (GRN_BULK_VSIZE(&hook_data) == sizeof(grn_obj_default_set_value_hook_data)) { grn_obj_default_set_value_hook_data *data; data = (grn_obj_default_set_value_hook_data *)GRN_TEXT_VALUE(&hook_data); mrb_ary_push(mrb, mrb_index_ids, mrb_fixnum_value(data->target)); } } return mrb_index_ids; }
static grn_rc selector_fuzzy_search(grn_ctx *ctx, grn_obj *table, grn_obj *index, int nargs, grn_obj **args, grn_obj *res, grn_operator op) { grn_rc rc = GRN_SUCCESS; grn_obj *target = NULL; grn_obj *obj; grn_obj *query; uint32_t max_distance = 1; uint32_t prefix_length = 0; uint32_t prefix_match_size = 0; uint32_t max_expansion = 0; int flags = 0; grn_bool use_sequential_search = GRN_FALSE; if ((nargs - 1) < 2) { GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT, "fuzzy_search(): wrong number of arguments (%d ...)", nargs - 1); rc = ctx->rc; goto exit; } obj = args[1]; query = args[2]; if (nargs == 4) { grn_obj *options = args[3]; grn_hash_cursor *cursor; void *key; grn_obj *value; int key_size; if (options->header.type != GRN_TABLE_HASH_KEY) { GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT, "fuzzy_search(): " "3rd argument must be object literal: <%.*s>", (int)GRN_TEXT_LEN(options), GRN_TEXT_VALUE(options)); goto exit; } cursor = grn_hash_cursor_open(ctx, (grn_hash *)options, NULL, 0, NULL, 0, 0, -1, 0); if (!cursor) { GRN_PLUGIN_ERROR(ctx, GRN_NO_MEMORY_AVAILABLE, "fuzzy_search(): couldn't open cursor"); goto exit; } while (grn_hash_cursor_next(ctx, cursor) != GRN_ID_NIL) { grn_hash_cursor_get_key_value(ctx, cursor, &key, &key_size, (void **)&value); if (key_size == 12 && !memcmp(key, "max_distance", 12)) { max_distance = GRN_UINT32_VALUE(value); } else if (key_size == 13 && !memcmp(key, "prefix_length", 13)) { prefix_length = GRN_UINT32_VALUE(value); } else if (key_size == 13 && !memcmp(key, "max_expansion", 13)) { max_expansion = GRN_UINT32_VALUE(value); } else if (key_size == 18 && !memcmp(key, "with_transposition", 18)) { if (GRN_BOOL_VALUE(value)) { flags |= GRN_TABLE_FUZZY_SEARCH_WITH_TRANSPOSITION; } } else { GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT, "invalid option name: <%.*s>", key_size, (char *)key); grn_hash_cursor_close(ctx, cursor); goto exit; } } grn_hash_cursor_close(ctx, cursor); } if (index) { target = index; } else { if (obj->header.type == GRN_COLUMN_INDEX) { target = obj; } else { grn_column_index(ctx, obj, GRN_OP_FUZZY, &target, 1, NULL); } } if (target) { grn_obj *lexicon; use_sequential_search = GRN_TRUE; lexicon = grn_ctx_at(ctx, target->header.domain); if (lexicon) { if (lexicon->header.type == GRN_TABLE_PAT_KEY) { use_sequential_search = GRN_FALSE; } grn_obj_unlink(ctx, lexicon); } } else { if (grn_obj_is_key_accessor(ctx, obj) && table->header.type == GRN_TABLE_PAT_KEY) { target = table; } else { use_sequential_search = GRN_TRUE; } } if (prefix_length) { const char *s = GRN_TEXT_VALUE(query); const char *e = GRN_BULK_CURR(query); const char *p; unsigned int cl = 0; unsigned int length = 0; for (p = s; p < e && (cl = grn_charlen(ctx, p, e)); p += cl) { length++; if (length > prefix_length) { break; } } prefix_match_size = p - s; } if (use_sequential_search) { rc = sequential_fuzzy_search(ctx, table, obj, query, max_distance, prefix_match_size, max_expansion, flags, res, op); goto exit; } if (!target) { grn_obj inspected; GRN_TEXT_INIT(&inspected, 0); grn_inspect(ctx, &inspected, target); GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT, "fuzzy_search(): " "column must be COLUMN_INDEX or TABLE_PAT_KEY: <%.*s>", (int)GRN_TEXT_LEN(&inspected), GRN_TEXT_VALUE(&inspected)); rc = ctx->rc; GRN_OBJ_FIN(ctx, &inspected); } else { grn_search_optarg options = {0}; options.mode = GRN_OP_FUZZY; options.fuzzy.prefix_match_size = prefix_match_size; options.fuzzy.max_distance = max_distance; options.fuzzy.max_expansion = max_expansion; options.fuzzy.flags = flags; grn_obj_search(ctx, target, query, res, op, &options); } exit : return rc; }