Kouhei Sutou
null+****@clear*****
Thu Jan 17 18:52:31 JST 2013
Kouhei Sutou 2013-01-17 18:52:31 +0900 (Thu, 17 Jan 2013) New Revision: b63aa4365b4004de18d5435274d43282485e13c3 https://github.com/groonga/groonga/commit/b63aa4365b4004de18d5435274d43282485e13c3 Merged 8061934: Merge pull request #51 from groonga/support-nested-index-range-search Log: Support nested index range search --filter 'column1.column2....columnN <= "1988-01-04 00:00:00"' is supported. Added files: test/command/suite/select/index/nested/by_column/range.expected test/command/suite/select/index/nested/by_column/range.test Modified files: lib/db.c lib/expr.c Modified: lib/db.c (+38 -14) =================================================================== --- lib/db.c 2013-01-17 16:28:00 +0900 (581eb6e) +++ lib/db.c 2013-01-17 18:52:31 +0900 (96c108a) @@ -7913,31 +7913,55 @@ grn_column_index_accessor_range(grn_ctx *ctx, grn_obj *obj, grn_operator op, grn_obj **ip = indexbuf; grn_accessor *a = (grn_accessor *)obj; - if (a->action == GRN_ACCESSOR_GET_KEY && - a->next && - a->next->action == GRN_ACCESSOR_GET_COLUMN_VALUE && - a->next->obj) { + while (a) { grn_hook *hooks; + grn_bool found = GRN_FALSE; + grn_hook_entry entry = -1; - obj = a->next->obj; - for (hooks = DB_OBJ(obj)->hooks[GRN_HOOK_SET]; hooks; hooks = hooks->next) { + switch (a->action) { + case GRN_ACCESSOR_GET_KEY : + entry = GRN_HOOK_INSERT; + break; + case GRN_ACCESSOR_GET_COLUMN_VALUE : + entry = GRN_HOOK_SET; + break; + default : + break; + } + + for (hooks = DB_OBJ(a->obj)->hooks[entry]; hooks; hooks = hooks->next) { default_set_value_hook_data *data = (void *)NEXT_ADDR(hooks); grn_obj *target = grn_ctx_at(ctx, data->target); + if (target->header.type != GRN_COLUMN_INDEX) { continue; } - if (section) { *section = (MULTI_COLUMN_INDEXP(target)) ? data->section : 0; } - { - grn_obj *tokenizer, *lexicon = grn_ctx_at(ctx, target->header.domain); + + found = GRN_TRUE; + if (!a->next) { + grn_obj *tokenizer; + grn_obj *lexicon; + + lexicon = grn_ctx_at(ctx, target->header.domain); if (!lexicon) { continue; } - if (lexicon->header.type != GRN_TABLE_PAT_KEY) { continue; } /* FIXME: GRN_TABLE_DAT_KEY should be supported */ + if (lexicon->header.type != GRN_TABLE_PAT_KEY) { continue; } + grn_table_get_info(ctx, lexicon, NULL, NULL, &tokenizer, NULL); if (tokenizer) { continue; } + + if (section) { + *section = (MULTI_COLUMN_INDEXP(target)) ? data->section : 0; + } + if (n < buf_size) { + *ip++ = target; + } + n++; } - if (n < buf_size) { - *ip++ = target; - } - n++; } + + if (!found) { + break; + } + a = a->next; } return n; Modified: lib/expr.c (+151 -3) =================================================================== --- lib/expr.c 2013-01-17 16:28:00 +0900 (26b547c) +++ lib/expr.c 2013-01-17 18:52:31 +0900 (f6fffe6) @@ -3796,7 +3796,11 @@ scan_info_build(grn_ctx *ctx, grn_obj *expr, int *n, } else if (GRN_ACCESSORP(*p)) { si->flags |= SCAN_ACCESSOR; if (grn_column_index(ctx, *p, c->op, &index, 1, &sid)) { - scan_info_put_index(ctx, si, index, sid, 1); + if (((grn_accessor *)(*p))->next) { + scan_info_put_index(ctx, si, *p, sid, 1); + } else { + scan_info_put_index(ctx, si, index, sid, 1); + } } } else { si->query = *p; @@ -3994,8 +3998,9 @@ grn_table_select_(grn_ctx *ctx, grn_obj *table, grn_obj *expr, grn_obj *v, } static inline grn_bool -grn_table_select_index_range(grn_ctx *ctx, grn_obj *table, grn_obj *index, - scan_info *si, grn_obj *res) +grn_table_select_index_range_column(grn_ctx *ctx, grn_obj *table, + grn_obj *index, + scan_info *si, grn_obj *res) { grn_bool processed = GRN_FALSE; grn_obj *index_table; @@ -4062,6 +4067,149 @@ grn_table_select_index_range(grn_ctx *ctx, grn_obj *table, grn_obj *index, } static inline grn_bool +grn_table_select_index_range_accessor(grn_ctx *ctx, grn_obj *table, + grn_obj *accessor_stack, + scan_info *si, grn_obj *res) +{ + int n_accessors; + grn_obj *current_res = NULL; + + n_accessors = GRN_BULK_VSIZE(accessor_stack) / sizeof(grn_obj *); + + { + grn_accessor *last_accessor; + grn_obj *target; + grn_obj *index; + grn_obj *range; + + last_accessor = (grn_accessor *)GRN_PTR_VALUE_AT(accessor_stack, + n_accessors - 1); + target = last_accessor->obj; + if (grn_column_index(ctx, target, si->op, &index, 1, NULL) == 0) { + return GRN_FALSE; + } + + range = grn_ctx_at(ctx, DB_OBJ(index)->range); + current_res = grn_table_create(ctx, NULL, 0, NULL, + GRN_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC, + range, + NULL); + grn_obj_unlink(ctx, range); + if (!current_res) { + return GRN_FALSE; + } + if (!grn_table_select_index_range_column(ctx, table, index, si, + current_res)) { + grn_obj_unlink(ctx, current_res); + return GRN_FALSE; + } + } + + { + int i; + + for (i = n_accessors - 1; i > 0; i--) { + grn_rc rc = GRN_SUCCESS; + grn_accessor *accessor; + grn_obj *index; + grn_obj *domain; + grn_obj *target; + grn_obj *next_res; + grn_operator next_op; + grn_id *next_record_id = NULL; + + accessor = (grn_accessor *)GRN_PTR_VALUE_AT(accessor_stack, i - 1); + target = accessor->obj; + if (grn_column_index(ctx, target, GRN_OP_EQUAL, &index, 1, NULL) == 0) { + grn_obj_unlink(ctx, current_res); + current_res = NULL; + break; + } + + if (i == 1) { + next_res = res; + next_op = si->logical_op; + } else { + grn_obj *range; + range = grn_ctx_at(ctx, DB_OBJ(index)->range); + next_res = grn_table_create(ctx, NULL, 0, NULL, + GRN_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC, + range, + NULL); + grn_obj_unlink(ctx, range); + if (!next_res) { + grn_obj_unlink(ctx, current_res); + current_res = NULL; + break; + } + next_op = GRN_OP_OR; + } + + domain = grn_ctx_at(ctx, index->header.domain); + GRN_HASH_EACH(ctx, (grn_hash *)current_res, id, &next_record_id, + NULL, NULL, { + if (domain->header.type == GRN_TABLE_NO_KEY) { + rc = grn_ii_sel(ctx, (grn_ii *)index, + (const char *)next_record_id, sizeof(grn_id), + (grn_hash *)next_res, next_op, NULL); + } else { + char key[GRN_TABLE_MAX_KEY_SIZE]; + int key_len; + key_len = grn_table_get_key(ctx, domain, *next_record_id, + key, GRN_TABLE_MAX_KEY_SIZE); + rc = grn_ii_sel(ctx, (grn_ii *)index, key, key_len, + (grn_hash *)next_res, next_op, NULL); + } + if (rc != GRN_SUCCESS) { + break; + } + }); + grn_obj_unlink(ctx, domain); + grn_obj_unlink(ctx, current_res); + + if (rc != GRN_SUCCESS) { + if (res != next_res) { + grn_obj_unlink(ctx, next_res); + } + current_res = NULL; + break; + } + current_res = next_res; + } + } + + return current_res == res; +} + +static inline grn_bool +grn_table_select_index_range(grn_ctx *ctx, grn_obj *table, grn_obj *index, + scan_info *si, grn_obj *res) +{ + if (si->flags & SCAN_ACCESSOR) { + grn_bool processed; + grn_accessor *accessor = (grn_accessor *)index; + grn_accessor *a; + grn_obj accessor_stack; + + if (index->header.type != GRN_ACCESSOR) { + return GRN_FALSE; + } + + GRN_PTR_INIT(&accessor_stack, GRN_OBJ_VECTOR, GRN_ID_NIL); + for (a = accessor; a; a = a->next) { + GRN_PTR_PUT(ctx, &accessor_stack, a); + } + processed = grn_table_select_index_range_accessor(ctx, table, + &accessor_stack, + si, res); + GRN_OBJ_FIN(ctx, &accessor_stack); + return processed; + } else { + return grn_table_select_index_range_column(ctx, table, index, si, res); + } +} + +static inline grn_bool grn_table_select_index(grn_ctx *ctx, grn_obj *table, scan_info *si, grn_obj *res) { Added: test/command/suite/select/index/nested/by_column/range.expected (+67 -0) 100644 =================================================================== --- /dev/null +++ test/command/suite/select/index/nested/by_column/range.expected 2013-01-17 18:52:31 +0900 (f6c15ca) @@ -0,0 +1,67 @@ +table_create Users TABLE_HASH_KEY ShortText +[[0,0.0,0.0],true] +column_create Users birthday COLUMN_SCALAR Time +[[0,0.0,0.0],true] +table_create Files TABLE_HASH_KEY ShortText +[[0,0.0,0.0],true] +column_create Files owner COLUMN_SCALAR Users +[[0,0.0,0.0],true] +column_create Users files_owner_index COLUMN_INDEX Files owner +[[0,0.0,0.0],true] +table_create Birthdays TABLE_PAT_KEY Time +[[0,0.0,0.0],true] +column_create Birthdays users_birthday COLUMN_INDEX Users birthday +[[0,0.0,0.0],true] +load --table Users +[ +{"_key": "Alice", "birthday": "1992-02-09 00:00:00"}, +{"_key": "Bob", "birthday": "1988-01-04 00:00:00"}, +{"_key": "Carlos", "birthday": "1982-12-29 00:00:00"} +] +[[0,0.0,0.0],3] +load --table Files +[ +{"_key": "/home/alice/.zshrc", "owner": "Alice"}, +{"_key": "/home/bob/.bashrc", "owner": "Bob"}, +{"_key": "/home/calros/public_html/index.html", "owner": "Carlos"} +] +[[0,0.0,0.0],3] +select Files --filter 'owner.birthday <= "1988-01-04 00:00:00"' --output_columns '_key, owner, owner.birthday' +[ + [ + 0, + 0.0, + 0.0 + ], + [ + [ + [ + 2 + ], + [ + [ + "_key", + "ShortText" + ], + [ + "owner", + "Users" + ], + [ + "owner.birthday", + "Time" + ] + ], + [ + "/home/calros/public_html/index.html", + "Carlos", + 409935600.0 + ], + [ + "/home/bob/.bashrc", + "Bob", + 568220400.0 + ] + ] + ] +] Added: test/command/suite/select/index/nested/by_column/range.test (+28 -0) 100644 =================================================================== --- /dev/null +++ test/command/suite/select/index/nested/by_column/range.test 2013-01-17 18:52:31 +0900 (5f87359) @@ -0,0 +1,28 @@ +table_create Users TABLE_HASH_KEY ShortText +column_create Users birthday COLUMN_SCALAR Time + +table_create Files TABLE_HASH_KEY ShortText +column_create Files owner COLUMN_SCALAR Users + +column_create Users files_owner_index COLUMN_INDEX Files owner + +table_create Birthdays TABLE_PAT_KEY Time +column_create Birthdays users_birthday COLUMN_INDEX Users birthday + +load --table Users +[ +{"_key": "Alice", "birthday": "1992-02-09 00:00:00"}, +{"_key": "Bob", "birthday": "1988-01-04 00:00:00"}, +{"_key": "Carlos", "birthday": "1982-12-29 00:00:00"} +] + +load --table Files +[ +{"_key": "/home/alice/.zshrc", "owner": "Alice"}, +{"_key": "/home/bob/.bashrc", "owner": "Bob"}, +{"_key": "/home/calros/public_html/index.html", "owner": "Carlos"} +] + +select Files \ + --filter 'owner.birthday <= "1988-01-04 00:00:00"' \ + --output_columns '_key, owner, owner.birthday' -------------- next part -------------- HTML����������������������������... Download