Kouhei Sutou
null+****@clear*****
Fri Mar 17 16:42:39 JST 2017
Kouhei Sutou 2017-03-17 16:42:39 +0900 (Fri, 17 Mar 2017) New Revision: 8b9853a097e6ea220dd7f2c459e272c881d6eb99 https://github.com/groonga/groonga/commit/8b9853a097e6ea220dd7f2c459e272c881d6eb99 Message: Extract bulk expr execution code for reuse Added files: lib/expr_executor.c lib/grn_expr_executor.h Modified files: lib/expr.c lib/sources.am Modified: lib/expr.c (+31 -602) =================================================================== --- lib/expr.c 2017-03-17 15:01:19 +0900 (a7236c1) +++ lib/expr.c 2017-03-17 16:42:39 +0900 (9d8161d) @@ -24,6 +24,7 @@ #include "grn_geo.h" #include "grn_expr.h" #include "grn_expr_code.h" +#include "grn_expr_executor.h" #include "grn_scanner.h" #include "grn_util.h" #include "grn_report.h" @@ -5264,10 +5265,18 @@ exec_result_to_score(grn_ctx *ctx, grn_obj *result, grn_obj *score_buffer) case GRN_VOID : return 0; case GRN_BULK : - if (grn_obj_cast(ctx, result, score_buffer, GRN_FALSE) != GRN_SUCCESS) { - return 1; + switch (result->header.domain) { + case GRN_DB_BOOL : + return GRN_BOOL_VALUE(result) ? 1 : 0; + case GRN_DB_INT32 : + return GRN_INT32_VALUE(result); + default : + GRN_BULK_REWIND(score_buffer); + if (grn_obj_cast(ctx, result, score_buffer, GRN_FALSE) != GRN_SUCCESS) { + return 1; + } + return GRN_INT32_VALUE(score_buffer); } - return GRN_INT32_VALUE(score_buffer); case GRN_UVECTOR : case GRN_PVECTOR : case GRN_VECTOR : @@ -5277,617 +5286,33 @@ exec_result_to_score(grn_ctx *ctx, grn_obj *result, grn_obj *score_buffer) } } -typedef union { - struct { - grn_obj *expr; - grn_obj *variable; - } common; - struct { - grn_obj *expr; - grn_obj *variable; - grn_obj score_buffer; - } general; - struct { - grn_obj *expr; - grn_obj *variable; - int32_t score; - } constant; - struct { - grn_obj *expr; - grn_obj *variable; - grn_obj *column; - grn_obj value_buffer; - grn_obj score_buffer; - } value; - struct { - grn_obj *expr; - grn_obj *variable; -#ifdef GRN_SUPPORT_REGEXP - OnigRegex regex; - grn_obj value_buffer; - grn_obj *normalizer; -#endif /* GRN_SUPPORT_REGEXP */ - } simple_regexp; - struct { - grn_obj *expr; - grn_obj *variable; - grn_obj value_buffer; - grn_obj constant_buffer; - int32_t score; - grn_bool (*exec)(grn_ctx *ctx, grn_obj *x, grn_obj *y); - } simple_condition; -} grn_table_select_sequential_data; - -typedef void (*grn_table_select_sequential_init_func)(grn_ctx *ctx, - grn_table_select_sequential_data *data); -typedef int32_t (*grn_table_select_sequential_exec_func)(grn_ctx *ctx, - grn_id id, - grn_table_select_sequential_data *data); -typedef void (*grn_table_select_sequential_fin_func)(grn_ctx *ctx, - grn_table_select_sequential_data *data); - -static void -grn_table_select_sequential_init_general(grn_ctx *ctx, - grn_table_select_sequential_data *data) -{ - GRN_INT32_INIT(&(data->general.score_buffer), 0); -} - -static int32_t -grn_table_select_sequential_exec_general(grn_ctx *ctx, - grn_id id, - grn_table_select_sequential_data *data) -{ - grn_obj *result; - GRN_RECORD_SET(ctx, data->general.variable, id); - result = grn_expr_exec(ctx, data->general.expr, 0); - if (ctx->rc) { - return -1; - } - return exec_result_to_score(ctx, result, &(data->general.score_buffer)); -} - -static void -grn_table_select_sequential_fin_general(grn_ctx *ctx, - grn_table_select_sequential_data *data) -{ - GRN_OBJ_FIN(ctx, &(data->general.score_buffer)); -} - -static grn_bool -grn_table_select_sequential_is_constant(grn_ctx *ctx, grn_obj *expr) -{ - grn_expr *e = (grn_expr *)expr; - grn_expr_code *target; - - if (e->codes_curr != 1) { - return GRN_FALSE; - } - - target = &(e->codes[0]); - - if (target->op != GRN_OP_PUSH) { - return GRN_FALSE; - } - if (!target->value) { - return GRN_FALSE; - } - - return GRN_TRUE; -} - -static void -grn_table_select_sequential_init_constant(grn_ctx *ctx, - grn_table_select_sequential_data *data) -{ - grn_obj *result; - grn_obj score_buffer; - - GRN_INT32_INIT(&score_buffer, 0); - result = grn_expr_exec(ctx, data->constant.expr, 0); - if (ctx->rc) { - data->constant.score = -1; - } else { - data->constant.score = exec_result_to_score(ctx, result, &score_buffer); - } - GRN_OBJ_FIN(ctx, &score_buffer); -} - -static int32_t -grn_table_select_sequential_exec_constant(grn_ctx *ctx, - grn_id id, - grn_table_select_sequential_data *data) -{ - return data->constant.score; -} - -static void -grn_table_select_sequential_fin_constant(grn_ctx *ctx, - grn_table_select_sequential_data *data) -{ -} - -static grn_bool -grn_table_select_sequential_is_value(grn_ctx *ctx, grn_obj *expr) -{ - grn_expr *e = (grn_expr *)expr; - grn_expr_code *target; - - if (e->codes_curr != 1) { - return GRN_FALSE; - } - - target = &(e->codes[0]); - - if (target->op != GRN_OP_GET_VALUE) { - return GRN_FALSE; - } - if (!target->value) { - return GRN_FALSE; - } - - return GRN_TRUE; -} - -static void -grn_table_select_sequential_init_value(grn_ctx *ctx, - grn_table_select_sequential_data *data) -{ - grn_expr *e = (grn_expr *)(data->value.expr); - - data->value.column = e->codes[0].value; - GRN_VOID_INIT(&(data->value.value_buffer)); - GRN_INT32_INIT(&(data->value.score_buffer), 0); -} - -static int32_t -grn_table_select_sequential_exec_value(grn_ctx *ctx, - grn_id id, - grn_table_select_sequential_data *data) -{ - grn_obj *value_buffer = &(data->value.value_buffer); - grn_obj *score_buffer = &(data->value.score_buffer); - int32_t score; - - GRN_BULK_REWIND(value_buffer); - grn_obj_get_value(ctx, data->value.column, id, value_buffer); - GRN_BULK_REWIND(score_buffer); - score = exec_result_to_score(ctx, value_buffer, score_buffer); - - return score; -} - -static void -grn_table_select_sequential_fin_value(grn_ctx *ctx, - grn_table_select_sequential_data *data) -{ - GRN_OBJ_FIN(ctx, &(data->value.score_buffer)); - GRN_OBJ_FIN(ctx, &(data->value.value_buffer)); -} - -#ifdef GRN_SUPPORT_REGEXP -static grn_bool -grn_table_select_sequential_is_simple_regexp(grn_ctx *ctx, grn_obj *expr) -{ - grn_expr *e = (grn_expr *)expr; - grn_expr_code *target; - grn_expr_code *pattern; - grn_expr_code *operator; - - if (e->codes_curr != 3) { - return GRN_FALSE; - } - - target = &(e->codes[0]); - pattern = &(e->codes[1]); - operator = &(e->codes[2]); - - if (operator->op != GRN_OP_REGEXP) { - return GRN_FALSE; - } - if (operator->nargs != 2) { - return GRN_FALSE; - } - - if (target->op != GRN_OP_GET_VALUE) { - return GRN_FALSE; - } - if (target->nargs != 1) { - return GRN_FALSE; - } - if (!target->value) { - return GRN_FALSE; - } - if (target->value->header.type != GRN_COLUMN_VAR_SIZE) { - return GRN_FALSE; - } - if ((target->value->header.flags & GRN_OBJ_COLUMN_TYPE_MASK) != - GRN_OBJ_COLUMN_SCALAR) { - return GRN_FALSE; - } - switch (grn_obj_get_range(ctx, target->value)) { - case GRN_DB_SHORT_TEXT : - case GRN_DB_TEXT : - case GRN_DB_LONG_TEXT : - break; - default : - return GRN_FALSE; - } - - if (pattern->op != GRN_OP_PUSH) { - return GRN_FALSE; - } - if (pattern->nargs != 1) { - return GRN_FALSE; - } - if (!pattern->value) { - return GRN_FALSE; - } - if (pattern->value->header.type != GRN_BULK) { - return GRN_FALSE; - } - switch (pattern->value->header.domain) { - case GRN_DB_SHORT_TEXT : - case GRN_DB_TEXT : - case GRN_DB_LONG_TEXT : - break; - default : - return GRN_FALSE; - } - - return GRN_TRUE; -} - -static void -grn_table_select_sequential_init_simple_regexp(grn_ctx *ctx, - grn_table_select_sequential_data *data) -{ - grn_expr *e = (grn_expr *)(data->simple_regexp.expr); - OnigEncoding onig_encoding; - int onig_result; - OnigErrorInfo onig_error_info; - grn_obj *pattern; - - if (ctx->encoding == GRN_ENC_NONE) { - data->simple_regexp.regex = NULL; - return; - } - - switch (ctx->encoding) { - case GRN_ENC_EUC_JP : - onig_encoding = ONIG_ENCODING_EUC_JP; - break; - case GRN_ENC_UTF8 : - onig_encoding = ONIG_ENCODING_UTF8; - break; - case GRN_ENC_SJIS : - onig_encoding = ONIG_ENCODING_CP932; - break; - case GRN_ENC_LATIN1 : - onig_encoding = ONIG_ENCODING_ISO_8859_1; - break; - case GRN_ENC_KOI8R : - onig_encoding = ONIG_ENCODING_KOI8_R; - break; - default : - data->simple_regexp.regex = NULL; - return; - } - - pattern = e->codes[1].value; - onig_result = onig_new(&(data->simple_regexp.regex), - GRN_TEXT_VALUE(pattern), - GRN_TEXT_VALUE(pattern) + GRN_TEXT_LEN(pattern), - ONIG_OPTION_ASCII_RANGE | - ONIG_OPTION_MULTILINE, - onig_encoding, - ONIG_SYNTAX_RUBY, - &onig_error_info); - if (onig_result != ONIG_NORMAL) { - char message[ONIG_MAX_ERROR_MESSAGE_LEN]; - onig_error_code_to_str(message, onig_result, onig_error_info); - ERR(GRN_INVALID_ARGUMENT, - "[table][select][sequential][regexp] " - "failed to create regular expression object: <%.*s>: %s", - (int)GRN_TEXT_LEN(pattern), GRN_TEXT_VALUE(pattern), - message); - return; - } - - GRN_VOID_INIT(&(data->simple_regexp.value_buffer)); - - data->simple_regexp.normalizer = - grn_ctx_get(ctx, GRN_NORMALIZER_AUTO_NAME, -1); -} - -static int32_t -grn_table_select_sequential_exec_simple_regexp(grn_ctx *ctx, - grn_id id, - grn_table_select_sequential_data *data) -{ - grn_expr *e = (grn_expr *)(data->simple_regexp.expr); - grn_obj *value_buffer = &(data->simple_regexp.value_buffer); - - if (ctx->rc) { - return -1; - } - - grn_obj_reinit_for(ctx, value_buffer, e->codes[0].value); - grn_obj_get_value(ctx, e->codes[0].value, id, value_buffer); - { - grn_obj *norm_target; - const char *norm_target_raw; - unsigned int norm_target_raw_length_in_bytes; - - norm_target = grn_string_open(ctx, - GRN_TEXT_VALUE(value_buffer), - GRN_TEXT_LEN(value_buffer), - data->simple_regexp.normalizer, - 0); - grn_string_get_normalized(ctx, norm_target, - &norm_target_raw, - &norm_target_raw_length_in_bytes, - NULL); - - { - OnigPosition position; - position = onig_search(data->simple_regexp.regex, - norm_target_raw, - norm_target_raw + norm_target_raw_length_in_bytes, - norm_target_raw, - norm_target_raw + norm_target_raw_length_in_bytes, - NULL, - ONIG_OPTION_NONE); - grn_obj_close(ctx, norm_target); - if (position == ONIG_MISMATCH) { - return -1; - } else { - return 1; - } - } - } -} - -static void -grn_table_select_sequential_fin_simple_regexp(grn_ctx *ctx, - grn_table_select_sequential_data *data) -{ - if (!data->simple_regexp.regex) { - return; - } - - onig_free(data->simple_regexp.regex); - GRN_OBJ_FIN(ctx, &(data->simple_regexp.value_buffer)); -} -#endif /* GRN_SUPPORT_REGEXP */ - -static grn_bool -grn_table_select_sequential_is_simple_condition(grn_ctx *ctx, grn_obj *expr) -{ - grn_expr *e = (grn_expr *)expr; - grn_expr_code *target; - grn_expr_code *constant; - grn_expr_code *operator; - - if (e->codes_curr != 3) { - return GRN_FALSE; - } - - target = &(e->codes[0]); - constant = &(e->codes[1]); - operator = &(e->codes[2]); - - switch (operator->op) { - case GRN_OP_EQUAL : - case GRN_OP_NOT_EQUAL : - case GRN_OP_LESS : - case GRN_OP_GREATER : - case GRN_OP_LESS_EQUAL : - case GRN_OP_GREATER_EQUAL : - break; - default : - return GRN_FALSE; - } - if (operator->nargs != 2) { - return GRN_FALSE; - } - - if (target->op != GRN_OP_GET_VALUE) { - return GRN_FALSE; - } - if (target->nargs != 1) { - return GRN_FALSE; - } - if (!target->value) { - return GRN_FALSE; - } - if ((target->value->header.flags & GRN_OBJ_COLUMN_TYPE_MASK) != - GRN_OBJ_COLUMN_SCALAR) { - return GRN_FALSE; - } - - if (constant->op != GRN_OP_PUSH) { - return GRN_FALSE; - } - if (constant->nargs != 1) { - return GRN_FALSE; - } - if (!constant->value) { - return GRN_FALSE; - } - if (constant->value->header.type != GRN_BULK) { - return GRN_FALSE; - } - - return GRN_TRUE; -} - -static void -grn_table_select_sequential_init_simple_condition( - grn_ctx *ctx, - grn_table_select_sequential_data *data) -{ - grn_expr *e = (grn_expr *)(data->simple_condition.expr); - grn_obj *target; - grn_obj *constant; - grn_operator op; - grn_obj *value_buffer; - grn_obj *constant_buffer; - grn_rc rc; - - target = e->codes[0].value; - constant = e->codes[1].value; - op = e->codes[2].op; - - data->simple_condition.score = 0; - - value_buffer = &(data->simple_condition.value_buffer); - GRN_VOID_INIT(value_buffer); - grn_obj_reinit_for(ctx, value_buffer, target); - - switch (op) { - case GRN_OP_EQUAL : - data->simple_condition.exec = grn_operator_exec_equal; - break; - case GRN_OP_NOT_EQUAL : - data->simple_condition.exec = grn_operator_exec_not_equal; - break; - case GRN_OP_LESS : - data->simple_condition.exec = grn_operator_exec_less; - break; - case GRN_OP_GREATER : - data->simple_condition.exec = grn_operator_exec_greater; - break; - case GRN_OP_LESS_EQUAL : - data->simple_condition.exec = grn_operator_exec_less_equal; - break; - case GRN_OP_GREATER_EQUAL : - data->simple_condition.exec = grn_operator_exec_greater_equal; - break; - default : - break; - } - - constant_buffer = &(data->simple_condition.constant_buffer); - GRN_VOID_INIT(constant_buffer); - grn_obj_reinit_for(ctx, constant_buffer, target); - rc = grn_obj_cast(ctx, constant, constant_buffer, GRN_FALSE); - if (rc != GRN_SUCCESS) { - grn_obj *type; - - type = grn_ctx_at(ctx, constant_buffer->header.domain); - if (grn_obj_is_table(ctx, type)) { - if (op == GRN_OP_NOT_EQUAL) { - data->simple_condition.score = 1; - } else { - data->simple_condition.score = -1; - } - } else { - int type_name_size; - char type_name[GRN_TABLE_MAX_KEY_SIZE]; - grn_obj inspected; - - type_name_size = grn_obj_name(ctx, type, type_name, - GRN_TABLE_MAX_KEY_SIZE); - GRN_TEXT_INIT(&inspected, 0); - grn_inspect(ctx, &inspected, constant); - ERR(rc, - "[table][select][sequential][condition] " - "failed to cast to <%.*s>: <%.*s>", - type_name_size, type_name, - (int)GRN_TEXT_LEN(&inspected), GRN_TEXT_VALUE(&inspected)); - } - return; - } -} - -static int32_t -grn_table_select_sequential_exec_simple_condition( - grn_ctx *ctx, - grn_id id, - grn_table_select_sequential_data *data) -{ - grn_expr *e = (grn_expr *)(data->simple_condition.expr); - grn_obj *target; - grn_obj *value_buffer = &(data->simple_condition.value_buffer); - grn_obj *constant_buffer = &(data->simple_condition.constant_buffer); - - if (ctx->rc) { - return -1; - } - - if (data->simple_condition.score != 0) { - return data->simple_condition.score; - } - - target = e->codes[0].value; - GRN_BULK_REWIND(value_buffer); - grn_obj_get_value(ctx, target, id, value_buffer); - - if (data->simple_condition.exec(ctx, value_buffer, constant_buffer)) { - return 1; - } else { - return -1; - } -} - -static void -grn_table_select_sequential_fin_simple_condition( - grn_ctx *ctx, - grn_table_select_sequential_data *data) -{ - GRN_OBJ_FIN(ctx, &(data->simple_condition.value_buffer)); - GRN_OBJ_FIN(ctx, &(data->simple_condition.constant_buffer)); -} - static void grn_table_select_sequential(grn_ctx *ctx, grn_obj *table, grn_obj *expr, grn_obj *v, grn_obj *res, grn_operator op) { + grn_obj *result; + grn_obj score_buffer; int32_t score; grn_id id, *idp; grn_table_cursor *tc; grn_hash_cursor *hc; grn_hash *s = (grn_hash *)res; - grn_table_select_sequential_data data; - grn_table_select_sequential_init_func init; - grn_table_select_sequential_exec_func exec; - grn_table_select_sequential_fin_func fin; - - data.common.expr = expr; - data.common.variable = v; - init = grn_table_select_sequential_init_general; - exec = grn_table_select_sequential_exec_general; - fin = grn_table_select_sequential_fin_general; - if (grn_table_select_sequential_is_constant(ctx, expr)) { - init = grn_table_select_sequential_init_constant; - exec = grn_table_select_sequential_exec_constant; - fin = grn_table_select_sequential_fin_constant; - } else if (grn_table_select_sequential_is_value(ctx, expr)) { - init = grn_table_select_sequential_init_value; - exec = grn_table_select_sequential_exec_value; - fin = grn_table_select_sequential_fin_value; -#ifdef GRN_SUPPORT_REGEXP - } else if (grn_table_select_sequential_is_simple_regexp(ctx, expr)) { - init = grn_table_select_sequential_init_simple_regexp; - exec = grn_table_select_sequential_exec_simple_regexp; - fin = grn_table_select_sequential_fin_simple_regexp; -#endif /* GRN_SUPPORT_REGEXP */ - } else if (grn_table_select_sequential_is_simple_condition(ctx, expr)) { - init = grn_table_select_sequential_init_simple_condition; - exec = grn_table_select_sequential_exec_simple_condition; - fin = grn_table_select_sequential_fin_simple_condition; - } - - init(ctx, &data); + grn_expr_executor *executor; + + executor = grn_expr_executor_open(ctx, expr); + if (!executor) { + return; + } + GRN_INT32_INIT(&score_buffer, 0); switch (op) { case GRN_OP_OR : if ((tc = grn_table_cursor_open(ctx, table, NULL, 0, NULL, 0, 0, -1, 0))) { while ((id = grn_table_cursor_next(ctx, tc))) { - score = exec(ctx, id, &data); + result = grn_expr_executor_exec(ctx, executor, id); if (ctx->rc) { break; } + score = exec_result_to_score(ctx, result, &score_buffer); if (score > 0) { grn_rset_recinfo *ri; if (grn_hash_add(ctx, s, &id, s->key_size, (void **)&ri, NULL)) { @@ -5902,10 +5327,11 @@ grn_table_select_sequential(grn_ctx *ctx, grn_obj *table, grn_obj *expr, if ((hc = grn_hash_cursor_open(ctx, s, NULL, 0, NULL, 0, 0, -1, 0))) { while (grn_hash_cursor_next(ctx, hc)) { grn_hash_cursor_get_key(ctx, hc, (void **) &idp); - score = exec(ctx, *idp, &data); + result = grn_expr_executor_exec(ctx, executor, *idp); if (ctx->rc) { break; } + score = exec_result_to_score(ctx, result, &score_buffer); if (score > 0) { grn_rset_recinfo *ri; grn_hash_cursor_get_value(ctx, hc, (void **) &ri); @@ -5921,10 +5347,11 @@ grn_table_select_sequential(grn_ctx *ctx, grn_obj *table, grn_obj *expr, if ((hc = grn_hash_cursor_open(ctx, s, NULL, 0, NULL, 0, 0, -1, 0))) { while (grn_hash_cursor_next(ctx, hc)) { grn_hash_cursor_get_key(ctx, hc, (void **) &idp); - score = exec(ctx, *idp, &data); + result = grn_expr_executor_exec(ctx, executor, *idp); if (ctx->rc) { break; } + score = exec_result_to_score(ctx, result, &score_buffer); if (score > 0) { grn_hash_cursor_delete(ctx, hc, NULL); } @@ -5936,10 +5363,11 @@ grn_table_select_sequential(grn_ctx *ctx, grn_obj *table, grn_obj *expr, if ((hc = grn_hash_cursor_open(ctx, s, NULL, 0, NULL, 0, 0, -1, 0))) { while (grn_hash_cursor_next(ctx, hc)) { grn_hash_cursor_get_key(ctx, hc, (void **) &idp); - score = exec(ctx, *idp, &data); + result = grn_expr_executor_exec(ctx, executor, *idp); if (ctx->rc) { break; } + score = exec_result_to_score(ctx, result, &score_buffer); if (score > 0) { grn_rset_recinfo *ri; grn_hash_cursor_get_value(ctx, hc, (void **) &ri); @@ -5952,7 +5380,8 @@ grn_table_select_sequential(grn_ctx *ctx, grn_obj *table, grn_obj *expr, default : break; } - fin(ctx, &data); + GRN_OBJ_FIN(ctx, &score_buffer); + grn_expr_executor_close(ctx, executor); } static inline void Added: lib/expr_executor.c (+688 -0) 100644 =================================================================== --- /dev/null +++ lib/expr_executor.c 2017-03-17 16:42:39 +0900 (c7de70b) @@ -0,0 +1,688 @@ +/* -*- c-basic-offset: 2 -*- */ +/* + Copyright(C) 2010-2017 Brazil + + 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 +*/ + +#include "grn.h" +#include "grn_expr_executor.h" + +#ifdef GRN_WITH_ONIGMO +# define GRN_SUPPORT_REGEXP +#endif + +#ifdef GRN_SUPPORT_REGEXP +# include "grn_normalizer.h" +# include <onigmo.h> +#endif + +typedef union { + struct { + grn_obj result_buffer; + } constant; + struct { + grn_obj *column; + grn_obj value_buffer; + } value; +#ifdef GRN_SUPPORT_REGEXP + struct { + grn_obj result_buffer; + OnigRegex regex; + grn_obj value_buffer; + grn_obj *normalizer; + } simple_regexp; +#endif /* GRN_SUPPORT_REGEXP */ + struct { + grn_bool need_exec; + grn_obj result_buffer; + grn_obj value_buffer; + grn_obj constant_buffer; + grn_bool (*exec)(grn_ctx *ctx, grn_obj *x, grn_obj *y); + } simple_condition; +} grn_expr_executor_data; + +typedef grn_obj *(*grn_expr_executor_exec_func)(grn_ctx *ctx, + grn_expr_executor *executor, + grn_id id); +typedef void (*grn_expr_executor_fin_func)(grn_ctx *ctx, + grn_expr_executor *executor); + +struct _grn_expr_executor { + grn_obj *expr; + grn_obj *variable; + grn_expr_executor_exec_func exec; + grn_expr_executor_fin_func fin; + grn_expr_executor_data data; +}; + +static void +grn_expr_executor_init_general(grn_ctx *ctx, + grn_expr_executor *executor) +{ +} + +static grn_obj * +grn_expr_executor_exec_general(grn_ctx *ctx, + grn_expr_executor *executor, + grn_id id) +{ + GRN_RECORD_SET(ctx, executor->variable, id); + return grn_expr_exec(ctx, executor->expr, 0); +} + +static void +grn_expr_executor_fin_general(grn_ctx *ctx, + grn_expr_executor *executor) +{ +} + +static grn_bool +grn_expr_executor_is_constant(grn_ctx *ctx, grn_obj *expr) +{ + grn_expr *e = (grn_expr *)expr; + grn_expr_code *target; + + if (e->codes_curr != 1) { + return GRN_FALSE; + } + + target = &(e->codes[0]); + + if (target->op != GRN_OP_PUSH) { + return GRN_FALSE; + } + if (!target->value) { + return GRN_FALSE; + } + + return GRN_TRUE; +} + +static void +grn_expr_executor_init_constant(grn_ctx *ctx, + grn_expr_executor *executor) +{ + grn_obj *result_buffer = &(executor->data.constant.result_buffer); + grn_obj *result; + + GRN_VOID_INIT(result_buffer); + result = grn_expr_exec(ctx, executor->expr, 0); + if (ctx->rc == GRN_SUCCESS) { + grn_obj_reinit(ctx, + result_buffer, + result->header.domain, + result->header.flags); + /* TODO: Support vector */ + grn_bulk_write(ctx, + result_buffer, + GRN_BULK_HEAD(result), + GRN_BULK_VSIZE(result)); + } +} + +static grn_obj * +grn_expr_executor_exec_constant(grn_ctx *ctx, + grn_expr_executor *executor, + grn_id id) +{ + return &(executor->data.constant.result_buffer); +} + +static void +grn_expr_executor_fin_constant(grn_ctx *ctx, + grn_expr_executor *executor) +{ + GRN_OBJ_FIN(ctx, &(executor->data.constant.result_buffer)); +} + +static grn_bool +grn_expr_executor_is_value(grn_ctx *ctx, grn_obj *expr) +{ + grn_expr *e = (grn_expr *)expr; + grn_expr_code *target; + + if (e->codes_curr != 1) { + return GRN_FALSE; + } + + target = &(e->codes[0]); + + if (target->op != GRN_OP_GET_VALUE) { + return GRN_FALSE; + } + if (!target->value) { + return GRN_FALSE; + } + + return GRN_TRUE; +} + +static void +grn_expr_executor_init_value(grn_ctx *ctx, + grn_expr_executor *executor) +{ + grn_expr *e = (grn_expr *)(executor->expr); + + executor->data.value.column = e->codes[0].value; + GRN_VOID_INIT(&(executor->data.value.value_buffer)); +} + +static grn_obj * +grn_expr_executor_exec_value(grn_ctx *ctx, + grn_expr_executor *executor, + grn_id id) +{ + grn_obj *value_buffer = &(executor->data.value.value_buffer); + + GRN_BULK_REWIND(value_buffer); + grn_obj_get_value(ctx, executor->data.value.column, id, value_buffer); + + return value_buffer; +} + +static void +grn_expr_executor_fin_value(grn_ctx *ctx, + grn_expr_executor *executor) +{ + GRN_OBJ_FIN(ctx, &(executor->data.value.value_buffer)); +} + +#ifdef GRN_SUPPORT_REGEXP +static grn_bool +grn_expr_executor_is_simple_regexp(grn_ctx *ctx, grn_obj *expr) +{ + grn_expr *e = (grn_expr *)expr; + grn_expr_code *target; + grn_expr_code *pattern; + grn_expr_code *operator; + + if (e->codes_curr != 3) { + return GRN_FALSE; + } + + target = &(e->codes[0]); + pattern = &(e->codes[1]); + operator = &(e->codes[2]); + + if (operator->op != GRN_OP_REGEXP) { + return GRN_FALSE; + } + if (operator->nargs != 2) { + return GRN_FALSE; + } + + if (target->op != GRN_OP_GET_VALUE) { + return GRN_FALSE; + } + if (target->nargs != 1) { + return GRN_FALSE; + } + if (!target->value) { + return GRN_FALSE; + } + if (target->value->header.type != GRN_COLUMN_VAR_SIZE) { + return GRN_FALSE; + } + if ((target->value->header.flags & GRN_OBJ_COLUMN_TYPE_MASK) != + GRN_OBJ_COLUMN_SCALAR) { + return GRN_FALSE; + } + switch (grn_obj_get_range(ctx, target->value)) { + case GRN_DB_SHORT_TEXT : + case GRN_DB_TEXT : + case GRN_DB_LONG_TEXT : + break; + default : + return GRN_FALSE; + } + + if (pattern->op != GRN_OP_PUSH) { + return GRN_FALSE; + } + if (pattern->nargs != 1) { + return GRN_FALSE; + } + if (!pattern->value) { + return GRN_FALSE; + } + if (pattern->value->header.type != GRN_BULK) { + return GRN_FALSE; + } + switch (pattern->value->header.domain) { + case GRN_DB_SHORT_TEXT : + case GRN_DB_TEXT : + case GRN_DB_LONG_TEXT : + break; + default : + return GRN_FALSE; + } + + return GRN_TRUE; +} + +static void +grn_expr_executor_init_simple_regexp(grn_ctx *ctx, + grn_expr_executor *executor) +{ + grn_expr *e = (grn_expr *)(executor->expr); + grn_obj *result_buffer = &(executor->data.simple_regexp.result_buffer); + OnigEncoding onig_encoding; + int onig_result; + OnigErrorInfo onig_error_info; + grn_obj *pattern; + + GRN_BOOL_INIT(result_buffer, 0); + GRN_BOOL_SET(ctx, result_buffer, GRN_FALSE); + + if (ctx->encoding == GRN_ENC_NONE) { + executor->data.simple_regexp.regex = NULL; + return; + } + + switch (ctx->encoding) { + case GRN_ENC_EUC_JP : + onig_encoding = ONIG_ENCODING_EUC_JP; + break; + case GRN_ENC_UTF8 : + onig_encoding = ONIG_ENCODING_UTF8; + break; + case GRN_ENC_SJIS : + onig_encoding = ONIG_ENCODING_CP932; + break; + case GRN_ENC_LATIN1 : + onig_encoding = ONIG_ENCODING_ISO_8859_1; + break; + case GRN_ENC_KOI8R : + onig_encoding = ONIG_ENCODING_KOI8_R; + break; + default : + executor->data.simple_regexp.regex = NULL; + return; + } + + pattern = e->codes[1].value; + onig_result = onig_new(&(executor->data.simple_regexp.regex), + GRN_TEXT_VALUE(pattern), + GRN_TEXT_VALUE(pattern) + GRN_TEXT_LEN(pattern), + ONIG_OPTION_ASCII_RANGE | + ONIG_OPTION_MULTILINE, + onig_encoding, + ONIG_SYNTAX_RUBY, + &onig_error_info); + if (onig_result != ONIG_NORMAL) { + char message[ONIG_MAX_ERROR_MESSAGE_LEN]; + onig_error_code_to_str(message, onig_result, onig_error_info); + ERR(GRN_INVALID_ARGUMENT, + "[expr-executor][regexp] " + "failed to create regular expression object: <%.*s>: %s", + (int)GRN_TEXT_LEN(pattern), GRN_TEXT_VALUE(pattern), + message); + return; + } + + GRN_VOID_INIT(&(executor->data.simple_regexp.value_buffer)); + + executor->data.simple_regexp.normalizer = + grn_ctx_get(ctx, GRN_NORMALIZER_AUTO_NAME, -1); +} + +static grn_obj * +grn_expr_executor_exec_simple_regexp(grn_ctx *ctx, + grn_expr_executor *executor, + grn_id id) +{ + grn_expr *e = (grn_expr *)(executor->expr); + OnigRegex regex = executor->data.simple_regexp.regex; + grn_obj *value_buffer = &(executor->data.simple_regexp.value_buffer); + grn_obj *result_buffer = &(executor->data.simple_regexp.result_buffer); + + if (ctx->rc) { + GRN_BOOL_SET(ctx, result_buffer, GRN_FALSE); + return result_buffer; + } + + if (!regex) { + return result_buffer; + } + + grn_obj_reinit_for(ctx, value_buffer, e->codes[0].value); + grn_obj_get_value(ctx, e->codes[0].value, id, value_buffer); + { + grn_obj *norm_target; + const char *norm_target_raw; + unsigned int norm_target_raw_length_in_bytes; + + norm_target = grn_string_open(ctx, + GRN_TEXT_VALUE(value_buffer), + GRN_TEXT_LEN(value_buffer), + executor->data.simple_regexp.normalizer, + 0); + grn_string_get_normalized(ctx, norm_target, + &norm_target_raw, + &norm_target_raw_length_in_bytes, + NULL); + + { + OnigPosition position; + position = onig_search(regex, + norm_target_raw, + norm_target_raw + norm_target_raw_length_in_bytes, + norm_target_raw, + norm_target_raw + norm_target_raw_length_in_bytes, + NULL, + ONIG_OPTION_NONE); + grn_obj_close(ctx, norm_target); + GRN_BOOL_SET(ctx, result_buffer, (position != ONIG_MISMATCH)); + return result_buffer; + } + } +} + +static void +grn_expr_executor_fin_simple_regexp(grn_ctx *ctx, + grn_expr_executor *executor) +{ + GRN_OBJ_FIN(ctx, &(executor->data.simple_regexp.result_buffer)); + + if (!executor->data.simple_regexp.regex) { + return; + } + + onig_free(executor->data.simple_regexp.regex); + GRN_OBJ_FIN(ctx, &(executor->data.simple_regexp.value_buffer)); +} +#endif /* GRN_SUPPORT_REGEXP */ + +static grn_bool +grn_expr_executor_is_simple_condition(grn_ctx *ctx, grn_obj *expr) +{ + grn_expr *e = (grn_expr *)expr; + grn_expr_code *target; + grn_expr_code *constant; + grn_expr_code *operator; + + if (e->codes_curr != 3) { + return GRN_FALSE; + } + + target = &(e->codes[0]); + constant = &(e->codes[1]); + operator = &(e->codes[2]); + + switch (operator->op) { + case GRN_OP_EQUAL : + case GRN_OP_NOT_EQUAL : + case GRN_OP_LESS : + case GRN_OP_GREATER : + case GRN_OP_LESS_EQUAL : + case GRN_OP_GREATER_EQUAL : + break; + default : + return GRN_FALSE; + } + if (operator->nargs != 2) { + return GRN_FALSE; + } + + if (target->op != GRN_OP_GET_VALUE) { + return GRN_FALSE; + } + if (target->nargs != 1) { + return GRN_FALSE; + } + if (!target->value) { + return GRN_FALSE; + } + if ((target->value->header.flags & GRN_OBJ_COLUMN_TYPE_MASK) != + GRN_OBJ_COLUMN_SCALAR) { + return GRN_FALSE; + } + + if (constant->op != GRN_OP_PUSH) { + return GRN_FALSE; + } + if (constant->nargs != 1) { + return GRN_FALSE; + } + if (!constant->value) { + return GRN_FALSE; + } + if (constant->value->header.type != GRN_BULK) { + return GRN_FALSE; + } + + return GRN_TRUE; +} + +static void +grn_expr_executor_init_simple_condition(grn_ctx *ctx, + grn_expr_executor *executor) +{ + grn_expr *e = (grn_expr *)(executor->expr); + grn_obj *target; + grn_obj *constant; + grn_operator op; + grn_obj *result_buffer; + grn_obj *value_buffer; + grn_obj *constant_buffer; + grn_rc rc; + + target = e->codes[0].value; + constant = e->codes[1].value; + op = e->codes[2].op; + + executor->data.simple_condition.need_exec = GRN_TRUE; + + result_buffer = &(executor->data.simple_condition.result_buffer); + GRN_BOOL_INIT(result_buffer, 0); + GRN_BOOL_SET(ctx, result_buffer, GRN_FALSE); + + value_buffer = &(executor->data.simple_condition.value_buffer); + GRN_VOID_INIT(value_buffer); + grn_obj_reinit_for(ctx, value_buffer, target); + + switch (op) { + case GRN_OP_EQUAL : + executor->data.simple_condition.exec = grn_operator_exec_equal; + break; + case GRN_OP_NOT_EQUAL : + executor->data.simple_condition.exec = grn_operator_exec_not_equal; + break; + case GRN_OP_LESS : + executor->data.simple_condition.exec = grn_operator_exec_less; + break; + case GRN_OP_GREATER : + executor->data.simple_condition.exec = grn_operator_exec_greater; + break; + case GRN_OP_LESS_EQUAL : + executor->data.simple_condition.exec = grn_operator_exec_less_equal; + break; + case GRN_OP_GREATER_EQUAL : + executor->data.simple_condition.exec = grn_operator_exec_greater_equal; + break; + default : + break; + } + + constant_buffer = &(executor->data.simple_condition.constant_buffer); + GRN_VOID_INIT(constant_buffer); + grn_obj_reinit_for(ctx, constant_buffer, target); + rc = grn_obj_cast(ctx, constant, constant_buffer, GRN_FALSE); + if (rc != GRN_SUCCESS) { + grn_obj *type; + + type = grn_ctx_at(ctx, constant_buffer->header.domain); + if (grn_obj_is_table(ctx, type)) { + GRN_BOOL_SET(ctx, result_buffer, (op == GRN_OP_NOT_EQUAL)); + executor->data.simple_condition.need_exec = GRN_FALSE; + } else { + int type_name_size; + char type_name[GRN_TABLE_MAX_KEY_SIZE]; + grn_obj inspected; + + type_name_size = grn_obj_name(ctx, type, type_name, + GRN_TABLE_MAX_KEY_SIZE); + GRN_TEXT_INIT(&inspected, 0); + grn_inspect(ctx, &inspected, constant); + ERR(rc, + "[expr-executor][condition] " + "failed to cast to <%.*s>: <%.*s>", + type_name_size, type_name, + (int)GRN_TEXT_LEN(&inspected), GRN_TEXT_VALUE(&inspected)); + } + } +} + +static grn_obj * +grn_expr_executor_exec_simple_condition(grn_ctx *ctx, + grn_expr_executor *executor, + grn_id id) +{ + grn_expr *e = (grn_expr *)(executor->expr); + grn_obj *target; + grn_obj *result_buffer = &(executor->data.simple_condition.result_buffer); + grn_obj *value_buffer = &(executor->data.simple_condition.value_buffer); + grn_obj *constant_buffer = &(executor->data.simple_condition.constant_buffer); + + if (ctx->rc) { + GRN_BOOL_SET(ctx, result_buffer, GRN_FALSE); + return result_buffer; + } + + if (!executor->data.simple_condition.need_exec) { + return result_buffer; + } + + target = e->codes[0].value; + GRN_BULK_REWIND(value_buffer); + grn_obj_get_value(ctx, target, id, value_buffer); + + if (executor->data.simple_condition.exec(ctx, value_buffer, constant_buffer)) { + GRN_BOOL_SET(ctx, result_buffer, GRN_TRUE); + } else { + GRN_BOOL_SET(ctx, result_buffer, GRN_FALSE); + } + return result_buffer; +} + +static void +grn_expr_executor_fin_simple_condition(grn_ctx *ctx, + grn_expr_executor *executor) +{ + GRN_OBJ_FIN(ctx, &(executor->data.simple_condition.result_buffer)); + GRN_OBJ_FIN(ctx, &(executor->data.simple_condition.value_buffer)); + GRN_OBJ_FIN(ctx, &(executor->data.simple_condition.constant_buffer)); +} + +grn_expr_executor * +grn_expr_executor_open(grn_ctx *ctx, grn_obj *expr) +{ + grn_obj *variable; + grn_expr_executor *executor; + + GRN_API_ENTER; + + if (!grn_obj_is_expr(ctx, expr)) { + grn_obj inspected; + GRN_TEXT_INIT(&inspected, 0); + grn_inspect(ctx, &inspected, expr); + ERR(ctx->rc, + "[expr-executor][open] invalid expression: %.*s", + (int)GRN_TEXT_LEN(&inspected), + GRN_TEXT_VALUE(&inspected)); + GRN_OBJ_FIN(ctx, &inspected); + GRN_API_RETURN(NULL); + } + + variable = grn_expr_get_var_by_offset(ctx, expr, 0); + if (!variable) { + grn_obj inspected; + GRN_TEXT_INIT(&inspected, 0); + grn_inspect(ctx, &inspected, expr); + ERR(ctx->rc, + "[expr-executor][open] expression has no variable: %.*s", + (int)GRN_TEXT_LEN(&inspected), + GRN_TEXT_VALUE(&inspected)); + GRN_OBJ_FIN(ctx, &inspected); + GRN_API_RETURN(NULL); + } + + executor = GRN_CALLOC(sizeof(grn_expr_executor)); + if (!executor) { + ERR(ctx->rc, + "[expr-executor][open] failed to allocate: %s", + ctx->errbuf); + GRN_API_RETURN(NULL); + } + + executor->expr = expr; + executor->variable = variable; + if (grn_expr_executor_is_constant(ctx, expr)) { + grn_expr_executor_init_constant(ctx, executor); + executor->exec = grn_expr_executor_exec_constant; + executor->fin = grn_expr_executor_fin_constant; + } else if (grn_expr_executor_is_value(ctx, expr)) { + grn_expr_executor_init_value(ctx, executor); + executor->exec = grn_expr_executor_exec_value; + executor->fin = grn_expr_executor_fin_value; +#ifdef GRN_SUPPORT_REGEXP + } else if (grn_expr_executor_is_simple_regexp(ctx, expr)) { + grn_expr_executor_init_simple_regexp(ctx, executor); + executor->exec = grn_expr_executor_exec_simple_regexp; + executor->fin = grn_expr_executor_fin_simple_regexp; +#endif /* GRN_SUPPORT_REGEXP */ + } else if (grn_expr_executor_is_simple_condition(ctx, expr)) { + grn_expr_executor_init_simple_condition(ctx, executor); + executor->exec = grn_expr_executor_exec_simple_condition; + executor->fin = grn_expr_executor_fin_simple_condition; + } else { + grn_expr_executor_init_general(ctx, executor); + executor->exec = grn_expr_executor_exec_general; + executor->fin = grn_expr_executor_fin_general; + } + + GRN_API_RETURN(executor); +} + +grn_obj * +grn_expr_executor_exec(grn_ctx *ctx, grn_expr_executor *executor, grn_id id) +{ + grn_obj *value; + + GRN_API_ENTER; + + if (!executor) { + GRN_API_RETURN(NULL); + } + + value = executor->exec(ctx, executor, id); + + GRN_API_RETURN(value); +} + +grn_rc +grn_expr_executor_close(grn_ctx *ctx, grn_expr_executor *executor) +{ + GRN_API_ENTER; + + if (!executor) { + GRN_API_RETURN(GRN_SUCCESS); + } + + executor->fin(ctx, executor); + GRN_FREE(executor); + + GRN_API_RETURN(GRN_SUCCESS); +} Added: lib/grn_expr_executor.h (+39 -0) 100644 =================================================================== --- /dev/null +++ lib/grn_expr_executor.h 2017-03-17 16:42:39 +0900 (df00134) @@ -0,0 +1,39 @@ +/* -*- c-basic-offset: 2 -*- */ +/* + Copyright(C) 2017 Brazil + + 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 +*/ + +#pragma once + +#include "grn_db.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _grn_expr_executor grn_expr_executor; + +grn_expr_executor *grn_expr_executor_open(grn_ctx *ctx, + grn_obj *expr); +grn_obj *grn_expr_executor_exec(grn_ctx *ctx, + grn_expr_executor *executor, + grn_id id); +grn_rc grn_expr_executor_close(grn_ctx *ctx, + grn_expr_executor *executor); + +#ifdef __cplusplus +} +#endif Modified: lib/sources.am (+2 -0) =================================================================== --- lib/sources.am 2017-03-17 15:01:19 +0900 (8c37853) +++ lib/sources.am 2017-03-17 16:42:39 +0900 (bd3710e) @@ -28,6 +28,8 @@ libgroonga_la_SOURCES = \ grn_expr.h \ expr_code.c \ grn_expr_code.h \ + expr_executor.c \ + grn_expr_executor.h \ geo.c \ grn_geo.h \ grn.h \ -------------- next part -------------- HTML����������������������������...Download