summaryrefslogtreecommitdiffstats
path: root/storage/mroonga/vendor/groonga/lib/expr_executor.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 18:07:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 18:07:14 +0000
commita175314c3e5827eb193872241446f2f8f5c9d33c (patch)
treecd3d60ca99ae00829c52a6ca79150a5b6e62528b /storage/mroonga/vendor/groonga/lib/expr_executor.c
parentInitial commit. (diff)
downloadmariadb-10.5-a175314c3e5827eb193872241446f2f8f5c9d33c.tar.xz
mariadb-10.5-a175314c3e5827eb193872241446f2f8f5c9d33c.zip
Adding upstream version 1:10.5.12.upstream/1%10.5.12upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'storage/mroonga/vendor/groonga/lib/expr_executor.c')
-rw-r--r--storage/mroonga/vendor/groonga/lib/expr_executor.c945
1 files changed, 945 insertions, 0 deletions
diff --git a/storage/mroonga/vendor/groonga/lib/expr_executor.c b/storage/mroonga/vendor/groonga/lib/expr_executor.c
new file mode 100644
index 00000000..bc78a650
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/expr_executor.c
@@ -0,0 +1,945 @@
+/* -*- 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-1335 USA
+*/
+
+#include "grn.h"
+#include "grn_ctx_impl.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_proc_ctx proc_ctx;
+ int n_args;
+ } proc;
+ struct {
+ grn_obj result_buffer;
+ grn_ra *ra;
+ grn_ra_cache ra_cache;
+ unsigned int ra_element_size;
+ grn_obj value_buffer;
+ grn_obj constant_buffer;
+ grn_operator_exec_func *exec;
+ } simple_condition_ra;
+ struct {
+ grn_bool need_exec;
+ grn_obj result_buffer;
+ grn_obj value_buffer;
+ grn_obj constant_buffer;
+ grn_operator_exec_func *exec;
+ } 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_proc(grn_ctx *ctx, grn_obj *expr)
+{
+ grn_expr *e = (grn_expr *)expr;
+ grn_obj *first;
+ grn_proc *proc;
+
+ if (e->codes_curr < 2) {
+ return GRN_FALSE;
+ }
+
+ first = e->codes[0].value;
+ if (!grn_obj_is_function_proc(ctx, first)) {
+ return GRN_FALSE;
+ }
+
+ proc = (grn_proc *)first;
+ if (!(proc->funcs[PROC_INIT] &&
+ proc->funcs[PROC_NEXT])) {
+ return GRN_FALSE;
+ }
+
+ if (e->codes[e->codes_curr - 1].op != GRN_OP_CALL) {
+ return GRN_FALSE;
+ }
+
+ return GRN_TRUE;
+}
+
+static void
+grn_expr_executor_init_proc(grn_ctx *ctx,
+ grn_expr_executor *executor)
+{
+ grn_proc_ctx *proc_ctx = &(executor->data.proc.proc_ctx);
+ grn_expr *expr;
+ grn_proc *proc;
+
+ expr = (grn_expr *)(executor->expr);
+ proc = (grn_proc *)(expr->codes[0].value);
+ proc_ctx->proc = proc;
+ proc_ctx->caller = executor->expr;
+ proc_ctx->phase = PROC_INIT;
+
+ executor->data.proc.n_args = expr->codes[expr->codes_curr - 1].nargs - 1;
+
+ proc->funcs[PROC_INIT](ctx, 0, NULL, &(proc_ctx->user_data));
+}
+
+static grn_obj *
+grn_expr_executor_exec_proc(grn_ctx *ctx,
+ grn_expr_executor *executor,
+ grn_id id)
+{
+ grn_proc_ctx *proc_ctx = &(executor->data.proc.proc_ctx);
+ int n_args = executor->data.proc.n_args;
+ grn_proc *proc;
+ grn_expr *expr;
+ grn_obj **args;
+ uint32_t values_curr;
+ uint32_t values_tail;
+ grn_obj *result;
+
+ proc = proc_ctx->proc;
+ proc_ctx->phase = PROC_NEXT;
+ GRN_RECORD_SET(ctx, executor->variable, id);
+
+ expr = (grn_expr *)(executor->expr);
+ values_curr = expr->values_curr;
+ values_tail = expr->values_tail;
+
+ expr->codes += 1;
+ expr->codes_curr -= 2;
+ grn_expr_exec(ctx, executor->expr, 0);
+ expr->codes_curr += 2;
+ expr->codes -= 1;
+
+ args = ctx->impl->stack + ctx->impl->stack_curr;
+ ctx->impl->stack_curr += n_args;
+ expr->values_curr = expr->values_tail;
+ result = proc->funcs[PROC_NEXT](ctx,
+ n_args,
+ args,
+ &(proc_ctx->user_data));
+ ctx->impl->stack_curr -= n_args;
+
+ expr->values_tail = values_tail;
+ expr->values_curr = values_curr;
+
+ return result;
+}
+
+static void
+grn_expr_executor_fin_proc(grn_ctx *ctx,
+ grn_expr_executor *executor)
+{
+ grn_proc_ctx *proc_ctx = &(executor->data.proc.proc_ctx);
+ grn_proc *proc;
+
+ proc = proc_ctx->proc;
+ proc_ctx->phase = PROC_FIN;
+ if (proc->funcs[PROC_FIN]) {
+ proc->funcs[PROC_FIN](ctx, 0, NULL, &(proc_ctx->user_data));
+ }
+}
+
+static grn_bool
+grn_expr_executor_is_simple_condition_ra(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->header.type != GRN_COLUMN_FIX_SIZE) {
+ 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;
+ }
+
+ {
+ grn_obj constant_buffer;
+ grn_rc rc;
+ GRN_VOID_INIT(&constant_buffer);
+ grn_obj_reinit_for(ctx, &constant_buffer, target->value);
+ rc = grn_obj_cast(ctx, constant->value, &constant_buffer, GRN_FALSE);
+ GRN_OBJ_FIN(ctx, &constant_buffer);
+ if (rc != GRN_SUCCESS) {
+ return GRN_FALSE;
+ }
+ }
+
+ return GRN_TRUE;
+}
+
+static void
+grn_expr_executor_init_simple_condition_ra(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;
+
+ target = e->codes[0].value;
+ constant = e->codes[1].value;
+ op = e->codes[2].op;
+
+ result_buffer = &(executor->data.simple_condition_ra.result_buffer);
+ GRN_BOOL_INIT(result_buffer, 0);
+ GRN_BOOL_SET(ctx, result_buffer, GRN_FALSE);
+
+ value_buffer = &(executor->data.simple_condition_ra.value_buffer);
+ GRN_VOID_INIT(value_buffer);
+ grn_obj_reinit_for(ctx, value_buffer, target);
+
+ executor->data.simple_condition_ra.ra = (grn_ra *)target;
+ GRN_RA_CACHE_INIT(executor->data.simple_condition_ra.ra,
+ &(executor->data.simple_condition_ra.ra_cache));
+ grn_ra_info(ctx,
+ executor->data.simple_condition_ra.ra,
+ &(executor->data.simple_condition_ra.ra_element_size));
+
+ executor->data.simple_condition_ra.exec = grn_operator_to_exec_func(op);
+
+ constant_buffer = &(executor->data.simple_condition_ra.constant_buffer);
+ GRN_VOID_INIT(constant_buffer);
+ grn_obj_reinit_for(ctx, constant_buffer, target);
+ grn_obj_cast(ctx, constant, constant_buffer, GRN_FALSE);
+}
+
+static grn_obj *
+grn_expr_executor_exec_simple_condition_ra(grn_ctx *ctx,
+ grn_expr_executor *executor,
+ grn_id id)
+{
+ grn_obj *result_buffer = &(executor->data.simple_condition_ra.result_buffer);
+ grn_obj *value_buffer = &(executor->data.simple_condition_ra.value_buffer);
+ grn_obj *constant_buffer =
+ &(executor->data.simple_condition_ra.constant_buffer);
+
+ if (ctx->rc) {
+ GRN_BOOL_SET(ctx, result_buffer, GRN_FALSE);
+ return result_buffer;
+ }
+
+ {
+ grn_ra *ra = executor->data.simple_condition_ra.ra;
+ grn_ra_cache *ra_cache = &(executor->data.simple_condition_ra.ra_cache);
+ unsigned int ra_element_size =
+ executor->data.simple_condition_ra.ra_element_size;
+ void *raw_value;
+ raw_value = grn_ra_ref_cache(ctx, ra, id, ra_cache);
+ GRN_BULK_REWIND(value_buffer);
+ grn_bulk_write(ctx, value_buffer, raw_value, ra_element_size);
+ }
+
+ if (executor->data.simple_condition_ra.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_ra(grn_ctx *ctx,
+ grn_expr_executor *executor)
+{
+ GRN_OBJ_FIN(ctx, &(executor->data.simple_condition_ra.result_buffer));
+ GRN_RA_CACHE_FIN(executor->data.simple_condition_ra.ra,
+ &(executor->data.simple_condition_ra.ra_cache));
+ GRN_OBJ_FIN(ctx, &(executor->data.simple_condition_ra.value_buffer));
+ GRN_OBJ_FIN(ctx, &(executor->data.simple_condition_ra.constant_buffer));
+}
+
+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 (!grn_obj_is_scalar_column(ctx, target->value)) {
+ 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);
+
+ executor->data.simple_condition.exec = grn_operator_to_exec_func(op);
+
+ 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_proc(ctx, expr)) {
+ grn_expr_executor_init_proc(ctx, executor);
+ executor->exec = grn_expr_executor_exec_proc;
+ executor->fin = grn_expr_executor_fin_proc;
+ } else if (grn_expr_executor_is_simple_condition_ra(ctx, expr)) {
+ grn_expr_executor_init_simple_condition_ra(ctx, executor);
+ executor->exec = grn_expr_executor_exec_simple_condition_ra;
+ executor->fin = grn_expr_executor_fin_simple_condition_ra;
+ } 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);
+}