Kouhei Sutou
null+****@clear*****
Mon May 21 20:51:06 JST 2018
Kouhei Sutou 2018-05-21 20:51:06 +0900 (Mon, 21 May 2018) New Revision: d4b6dfc1af7cfd57769476b1932875ed83a1a6a5 https://github.com/groonga/groonga/commit/d4b6dfc1af7cfd57769476b1932875ed83a1a6a5 Message: Move grn_expr_exec() core to grn_expr_executor Modified files: lib/expr.c lib/expr_executor.c lib/grn_db.h lib/grn_expr.h lib/grn_expr_code.h lib/output.c lib/proc/proc_in_records.c lib/scorer.c Modified: lib/expr.c (+38 -2404) =================================================================== --- lib/expr.c 2018-05-21 18:11:51 +0900 (37db7d84d) +++ lib/expr.c 2018-05-21 20:51:06 +0900 (19673c9f2) @@ -35,15 +35,6 @@ #include "grn_mrb.h" #include "mrb/mrb_expr.h" -#ifdef GRN_WITH_ONIGMO -# define GRN_SUPPORT_REGEXP -#endif - -#ifdef GRN_SUPPORT_REGEXP -# include "grn_normalizer.h" -# include <onigmo.h> -#endif - static double grn_table_select_enough_filtered_ratio = 0.0; static int grn_table_select_max_n_enough_filtered_records = 1000; static grn_bool grn_table_select_and_min_skip_enable = GRN_TRUE; @@ -531,6 +522,8 @@ grn_expr_open(grn_ctx *ctx, grn_obj_spec *spec, const uint8_t *p, const uint8_t expr->codes_curr = 0; expr->codes_size = size; expr->obj.header = spec->header; + expr->cache.codes = NULL; + expr->cache.codes_curr = 0; if (grn_expr_unpack(ctx, p, pe, (grn_obj *)expr) == pe) { goto exit; } else { @@ -634,6 +627,8 @@ grn_expr_create(grn_ctx *ctx, const char *name, unsigned int name_size) expr->values_size = size; expr->codes_curr = 0; expr->codes_size = size; + expr->cache.codes = NULL; + expr->cache.codes_curr = 0; GRN_DB_OBJ_SET_TYPE(expr, GRN_EXPR); expr->obj.header.domain = GRN_ID_NIL; expr->obj.range = GRN_ID_NIL; @@ -667,6 +662,9 @@ grn_expr_close(grn_ctx *ctx, grn_obj *expr) grn_hash_delete(ctx, ctx->impl->qe, &e->obj.header.domain, sizeof(grn_id), NULL); } */ + if (e->cache.codes) { + grn_expr_executor_fin(ctx, &(e->cache.executor)); + } grn_expr_clear_vars(ctx, expr); if (e->const_blks) { uint32_t nblks = e->nconsts + GRN_EXPR_CONST_BLK_SIZE - 1; @@ -805,8 +803,6 @@ grn_expr_get_var_by_offset(grn_ctx *ctx, grn_obj *expr, unsigned int offset) return res; } -#define EXPRVP(x) ((x)->header.impl_flags & GRN_OBJ_EXPRVALUE) - #define CONSTP(obj) ((obj) && ((obj)->header.impl_flags & GRN_OBJ_EXPRCONST)) #define PUSH_CODE(e,o,v,n,c) do {\ @@ -1481,39 +1477,6 @@ grn_expr_rewrite(grn_ctx *ctx, grn_obj *expr) GRN_API_RETURN(rewritten); } -#define WITH_SPSAVE(block) do {\ - ctx->impl->stack_curr = sp - ctx->impl->stack;\ - e->values_curr = vp - e->values;\ - block\ - vp = e->values + e->values_curr;\ - sp = ctx->impl->stack + ctx->impl->stack_curr;\ - s_ = ctx->impl->stack;\ - s0 = (sp > s_) ? sp[-1] : NULL;\ - s1 = (sp > s_ + 1) ? sp[-2] : NULL;\ -} while (0) - -#define GEO_RESOLUTION 3600000 -#define GEO_RADIOUS 6357303 -#define GEO_BES_C1 6334834 -#define GEO_BES_C2 6377397 -#define GEO_BES_C3 0.006674 -#define GEO_GRS_C1 6335439 -#define GEO_GRS_C2 6378137 -#define GEO_GRS_C3 0.006694 -#define GEO_INT2RAD(x) ((M_PI * x) / (GEO_RESOLUTION * 180)) - -#define VAR_SET_VALUE(ctx,var,value) do {\ - if (GRN_DB_OBJP(value)) {\ - (var)->header.type = GRN_PTR;\ - (var)->header.domain = DB_OBJ(value)->id;\ - GRN_PTR_SET(ctx, (var), (value));\ - } else {\ - (var)->header.type = (value)->header.type;\ - (var)->header.domain = (value)->header.domain;\ - GRN_TEXT_SET(ctx, (var), GRN_TEXT_VALUE(value), GRN_TEXT_LEN(value));\ - }\ -} while (0) - grn_rc grn_proc_call(grn_ctx *ctx, grn_obj *proc, int nargs, grn_obj *caller) { @@ -1563,1150 +1526,11 @@ grn_proc_call(grn_ctx *ctx, grn_obj *proc, int nargs, grn_obj *caller) GRN_API_RETURN(ctx->rc); } -#define PUSH1(v) do {\ - if (EXPRVP(v)) {\ - vp++;\ - if (vp - e->values > e->values_tail) { e->values_tail = vp - e->values; }\ - }\ - s1 = s0;\ - if (sp >= s_ + ctx->impl->stack_size) {\ - if (grn_ctx_expand_stack(ctx) != GRN_SUCCESS) {\ - goto exit;\ - }\ - sp += (ctx->impl->stack - s_);\ - s_ = ctx->impl->stack;\ - }\ - *sp++ = s0 = v;\ -} while (0) - -#define POP1(v) do {\ - if (EXPRVP(s0)) { vp--; }\ - v = s0;\ - s0 = s1;\ - sp--;\ - if (sp < s_) { ERR(GRN_INVALID_ARGUMENT, "stack underflow"); goto exit; }\ - s1 = (sp > s_ - 1) ? sp[-2] : NULL;\ -} while (0) - -#define ALLOC1(value) do {\ - s1 = s0;\ - if (sp >= s_ + ctx->impl->stack_size) {\ - if (grn_ctx_expand_stack(ctx) != GRN_SUCCESS) {\ - goto exit;\ - }\ - sp += (ctx->impl->stack - s_);\ - s_ = ctx->impl->stack;\ - }\ - *sp++ = s0 = value = vp++;\ - if (vp - e->values > e->values_tail) { e->values_tail = vp - e->values; }\ -} while (0) - -#define POP1ALLOC1(arg,value) do {\ - arg = s0;\ - if (EXPRVP(s0)) {\ - value = s0;\ - } else {\ - if (sp < s_ + 1) { ERR(GRN_INVALID_ARGUMENT, "stack underflow"); goto exit; }\ - sp[-1] = s0 = value = vp++;\ - if (vp - e->values > e->values_tail) { e->values_tail = vp - e->values; }\ - s0->header.impl_flags |= GRN_OBJ_EXPRVALUE;\ - }\ -} while (0) - -#define POP2ALLOC1(arg1,arg2,value) do {\ - if (EXPRVP(s0)) { vp--; }\ - if (EXPRVP(s1)) { vp--; }\ - arg2 = s0;\ - arg1 = s1;\ - sp--;\ - if (sp < s_ + 1) { ERR(GRN_INVALID_ARGUMENT, "stack underflow"); goto exit; }\ - s1 = (sp > s_ + 1) ? sp[-2] : NULL;\ - sp[-1] = s0 = value = vp++;\ - if (vp - e->values > e->values_tail) { e->values_tail = vp - e->values; }\ - s0->header.impl_flags |= GRN_OBJ_EXPRVALUE;\ -} while (0) - -#define INTEGER_ARITHMETIC_OPERATION_PLUS(x, y) ((x) + (y)) -#define FLOAT_ARITHMETIC_OPERATION_PLUS(x, y) ((double)(x) + (double)(y)) -#define INTEGER_ARITHMETIC_OPERATION_MINUS(x, y) ((x) - (y)) -#define FLOAT_ARITHMETIC_OPERATION_MINUS(x, y) ((double)(x) - (double)(y)) -#define INTEGER_ARITHMETIC_OPERATION_STAR(x, y) ((x) * (y)) -#define FLOAT_ARITHMETIC_OPERATION_STAR(x, y) ((double)(x) * (double)(y)) -#define INTEGER_ARITHMETIC_OPERATION_SLASH(x, y) ((x) / (y)) -#define FLOAT_ARITHMETIC_OPERATION_SLASH(x, y) ((double)(x) / (double)(y)) -#define INTEGER_ARITHMETIC_OPERATION_MOD(x, y) ((x) % (y)) -#define FLOAT_ARITHMETIC_OPERATION_MOD(x, y) (fmod((x), (y))) -#define INTEGER_ARITHMETIC_OPERATION_SHIFTL(x, y) ((x) << (y)) -#define FLOAT_ARITHMETIC_OPERATION_SHIFTL(x, y) \ - ((long long int)(x) << (long long int)(y)) -#define INTEGER_ARITHMETIC_OPERATION_SHIFTR(x, y) ((x) >> (y)) -#define FLOAT_ARITHMETIC_OPERATION_SHIFTR(x, y) \ - ((long long int)(x) >> (long long int)(y)) -#define INTEGER8_ARITHMETIC_OPERATION_SHIFTRR(x, y) \ - ((uint8_t)(x) >> (y)) -#define INTEGER16_ARITHMETIC_OPERATION_SHIFTRR(x, y) \ - ((uint16_t)(x) >> (y)) -#define INTEGER32_ARITHMETIC_OPERATION_SHIFTRR(x, y) \ - ((unsigned int)(x) >> (y)) -#define INTEGER64_ARITHMETIC_OPERATION_SHIFTRR(x, y) \ - ((long long unsigned int)(x) >> (y)) -#define FLOAT_ARITHMETIC_OPERATION_SHIFTRR(x, y) \ - ((long long unsigned int)(x) >> (long long unsigned int)(y)) - -#define INTEGER_ARITHMETIC_OPERATION_BITWISE_OR(x, y) ((x) | (y)) -#define FLOAT_ARITHMETIC_OPERATION_BITWISE_OR(x, y) \ - ((long long int)(x) | (long long int)(y)) -#define INTEGER_ARITHMETIC_OPERATION_BITWISE_XOR(x, y) ((x) ^ (y)) -#define FLOAT_ARITHMETIC_OPERATION_BITWISE_XOR(x, y) \ - ((long long int)(x) ^ (long long int)(y)) -#define INTEGER_ARITHMETIC_OPERATION_BITWISE_AND(x, y) ((x) & (y)) -#define FLOAT_ARITHMETIC_OPERATION_BITWISE_AND(x, y) \ - ((long long int)(x) & (long long int)(y)) - -#define INTEGER_UNARY_ARITHMETIC_OPERATION_MINUS(x) (-(x)) -#define FLOAT_UNARY_ARITHMETIC_OPERATION_MINUS(x) (-(x)) -#define INTEGER_UNARY_ARITHMETIC_OPERATION_BITWISE_NOT(x) (~(x)) -#define FLOAT_UNARY_ARITHMETIC_OPERATION_BITWISE_NOT(x) \ - (~((long long int)(x))) - -#define TEXT_ARITHMETIC_OPERATION(operator) do { \ - long long int x_; \ - long long int y_; \ - \ - res->header.domain = GRN_DB_INT64; \ - \ - GRN_INT64_SET(ctx, res, 0); \ - grn_obj_cast(ctx, x, res, GRN_FALSE); \ - x_ = GRN_INT64_VALUE(res); \ - \ - GRN_INT64_SET(ctx, res, 0); \ - grn_obj_cast(ctx, y, res, GRN_FALSE); \ - y_ = GRN_INT64_VALUE(res); \ - \ - GRN_INT64_SET(ctx, res, x_ operator y_); \ -} while (0) - -#define TEXT_UNARY_ARITHMETIC_OPERATION(unary_operator) do { \ - long long int x_; \ - \ - res->header.domain = GRN_DB_INT64; \ - \ - GRN_INT64_SET(ctx, res, 0); \ - grn_obj_cast(ctx, x, res, GRN_FALSE); \ - x_ = GRN_INT64_VALUE(res); \ - \ - GRN_INT64_SET(ctx, res, unary_operator x_); \ -} while (0) - -#define ARITHMETIC_OPERATION_NO_CHECK(y) do {} while (0) -#define ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y) do { \ - if ((long long int)y == 0) { \ - ERR(GRN_INVALID_ARGUMENT, "divisor should not be 0"); \ - goto exit; \ - } \ -} while (0) - - -#define NUMERIC_ARITHMETIC_OPERATION_DISPATCH(set, get, x_, y, res, \ - integer_operation, \ - float_operation, \ - right_expression_check, \ - invalid_type_error) do { \ - switch (y->header.domain) { \ - case GRN_DB_INT8 : \ - { \ - int8_t y_; \ - y_ = GRN_INT8_VALUE(y); \ - right_expression_check(y_); \ - set(ctx, res, integer_operation(x_, y_)); \ - } \ - break; \ - case GRN_DB_UINT8 : \ - { \ - uint8_t y_; \ - y_ = GRN_UINT8_VALUE(y); \ - right_expression_check(y_); \ - set(ctx, res, integer_operation(x_, y_)); \ - } \ - break; \ - case GRN_DB_INT16 : \ - { \ - int16_t y_; \ - y_ = GRN_INT16_VALUE(y); \ - right_expression_check(y_); \ - set(ctx, res, integer_operation(x_, y_)); \ - } \ - break; \ - case GRN_DB_UINT16 : \ - { \ - uint16_t y_; \ - y_ = GRN_UINT16_VALUE(y); \ - right_expression_check(y_); \ - set(ctx, res, integer_operation(x_, y_)); \ - } \ - break; \ - case GRN_DB_INT32 : \ - { \ - int y_; \ - y_ = GRN_INT32_VALUE(y); \ - right_expression_check(y_); \ - set(ctx, res, integer_operation(x_, y_)); \ - } \ - break; \ - case GRN_DB_UINT32 : \ - { \ - unsigned int y_; \ - y_ = GRN_UINT32_VALUE(y); \ - right_expression_check(y_); \ - set(ctx, res, integer_operation(x_, y_)); \ - } \ - break; \ - case GRN_DB_TIME : \ - { \ - long long int y_; \ - y_ = GRN_TIME_VALUE(y); \ - right_expression_check(y_); \ - set(ctx, res, integer_operation(x_, y_)); \ - } \ - break; \ - case GRN_DB_INT64 : \ - { \ - long long int y_; \ - y_ = GRN_INT64_VALUE(y); \ - right_expression_check(y_); \ - set(ctx, res, integer_operation(x_, y_)); \ - } \ - break; \ - case GRN_DB_UINT64 : \ - { \ - long long unsigned int y_; \ - y_ = GRN_UINT64_VALUE(y); \ - right_expression_check(y_); \ - set(ctx, res, integer_operation(x_, y_)); \ - } \ - break; \ - case GRN_DB_FLOAT : \ - { \ - double y_; \ - y_ = GRN_FLOAT_VALUE(y); \ - right_expression_check(y_); \ - res->header.domain = GRN_DB_FLOAT; \ - GRN_FLOAT_SET(ctx, res, float_operation(x_, y_)); \ - } \ - break; \ - case GRN_DB_SHORT_TEXT : \ - case GRN_DB_TEXT : \ - case GRN_DB_LONG_TEXT : \ - set(ctx, res, 0); \ - if (grn_obj_cast(ctx, y, res, GRN_FALSE)) { \ - ERR(GRN_INVALID_ARGUMENT, \ - "not a numerical format: <%.*s>", \ - (int)GRN_TEXT_LEN(y), GRN_TEXT_VALUE(y)); \ - goto exit; \ - } \ - set(ctx, res, integer_operation(x_, get(res))); \ - break; \ - default : \ - invalid_type_error; \ - break; \ - } \ -} while (0) - - -#define ARITHMETIC_OPERATION_DISPATCH(x, y, res, \ - integer8_operation, \ - integer16_operation, \ - integer32_operation, \ - integer64_operation, \ - float_operation, \ - left_expression_check, \ - right_expression_check, \ - text_operation, \ - invalid_type_error) do { \ - switch (x->header.domain) { \ - case GRN_DB_INT8 : \ - { \ - int8_t x_; \ - x_ = GRN_INT8_VALUE(x); \ - left_expression_check(x_); \ - NUMERIC_ARITHMETIC_OPERATION_DISPATCH(GRN_INT8_SET, \ - GRN_INT8_VALUE, \ - x_, y, res, \ - integer8_operation, \ - float_operation, \ - right_expression_check, \ - invalid_type_error); \ - } \ - break; \ - case GRN_DB_UINT8 : \ - { \ - uint8_t x_; \ - x_ = GRN_UINT8_VALUE(x); \ - left_expression_check(x_); \ - NUMERIC_ARITHMETIC_OPERATION_DISPATCH(GRN_UINT8_SET, \ - GRN_UINT8_VALUE, \ - x_, y, res, \ - integer8_operation, \ - float_operation, \ - right_expression_check, \ - invalid_type_error); \ - } \ - break; \ - case GRN_DB_INT16 : \ - { \ - int16_t x_; \ - x_ = GRN_INT16_VALUE(x); \ - left_expression_check(x_); \ - NUMERIC_ARITHMETIC_OPERATION_DISPATCH(GRN_INT16_SET, \ - GRN_INT16_VALUE, \ - x_, y, res, \ - integer16_operation, \ - float_operation, \ - right_expression_check, \ - invalid_type_error); \ - } \ - break; \ - case GRN_DB_UINT16 : \ - { \ - uint16_t x_; \ - x_ = GRN_UINT16_VALUE(x); \ - left_expression_check(x_); \ - NUMERIC_ARITHMETIC_OPERATION_DISPATCH(GRN_UINT16_SET, \ - GRN_UINT16_VALUE, \ - x_, y, res, \ - integer16_operation, \ - float_operation, \ - right_expression_check, \ - invalid_type_error); \ - } \ - break; \ - case GRN_DB_INT32 : \ - { \ - int x_; \ - x_ = GRN_INT32_VALUE(x); \ - left_expression_check(x_); \ - NUMERIC_ARITHMETIC_OPERATION_DISPATCH(GRN_INT32_SET, \ - GRN_INT32_VALUE, \ - x_, y, res, \ - integer32_operation, \ - float_operation, \ - right_expression_check, \ - invalid_type_error); \ - } \ - break; \ - case GRN_DB_UINT32 : \ - { \ - unsigned int x_; \ - x_ = GRN_UINT32_VALUE(x); \ - left_expression_check(x_); \ - NUMERIC_ARITHMETIC_OPERATION_DISPATCH(GRN_UINT32_SET, \ - GRN_UINT32_VALUE, \ - x_, y, res, \ - integer32_operation, \ - float_operation, \ - right_expression_check, \ - invalid_type_error); \ - } \ - break; \ - case GRN_DB_INT64 : \ - { \ - long long int x_; \ - x_ = GRN_INT64_VALUE(x); \ - left_expression_check(x_); \ - NUMERIC_ARITHMETIC_OPERATION_DISPATCH(GRN_INT64_SET, \ - GRN_INT64_VALUE, \ - x_, y, res, \ - integer64_operation, \ - float_operation, \ - right_expression_check, \ - invalid_type_error); \ - } \ - break; \ - case GRN_DB_TIME : \ - { \ - long long int x_; \ - x_ = GRN_TIME_VALUE(x); \ - left_expression_check(x_); \ - NUMERIC_ARITHMETIC_OPERATION_DISPATCH(GRN_TIME_SET, \ - GRN_TIME_VALUE, \ - x_, y, res, \ - integer64_operation, \ - float_operation, \ - right_expression_check, \ - invalid_type_error); \ - } \ - break; \ - case GRN_DB_UINT64 : \ - { \ - long long unsigned int x_; \ - x_ = GRN_UINT64_VALUE(x); \ - left_expression_check(x_); \ - NUMERIC_ARITHMETIC_OPERATION_DISPATCH(GRN_UINT64_SET, \ - GRN_UINT64_VALUE, \ - x_, y, res, \ - integer64_operation, \ - float_operation, \ - right_expression_check, \ - invalid_type_error); \ - } \ - break; \ - case GRN_DB_FLOAT : \ - { \ - double x_; \ - x_ = GRN_FLOAT_VALUE(x); \ - left_expression_check(x_); \ - NUMERIC_ARITHMETIC_OPERATION_DISPATCH(GRN_FLOAT_SET, \ - GRN_FLOAT_VALUE, \ - x_, y, res, \ - float_operation, \ - float_operation, \ - right_expression_check, \ - invalid_type_error); \ - } \ - break; \ - case GRN_DB_SHORT_TEXT : \ - case GRN_DB_TEXT : \ - case GRN_DB_LONG_TEXT : \ - text_operation; \ - break; \ - default: \ - invalid_type_error; \ - break; \ - } \ - code++; \ -} while (0) - -#define ARITHMETIC_BINARY_OPERATION_DISPATCH(operator, \ - integer8_operation, \ - integer16_operation, \ - integer32_operation, \ - integer64_operation, \ - float_operation, \ - left_expression_check, \ - right_expression_check, \ - text_operation, \ - invalid_type_error) do { \ - grn_obj *x = NULL; \ - grn_obj *y = NULL; \ - \ - POP2ALLOC1(x, y, res); \ - if (x->header.type == GRN_VECTOR || y->header.type == GRN_VECTOR) { \ - grn_obj inspected_x; \ - grn_obj inspected_y; \ - GRN_TEXT_INIT(&inspected_x, 0); \ - GRN_TEXT_INIT(&inspected_y, 0); \ - grn_inspect(ctx, &inspected_x, x); \ - grn_inspect(ctx, &inspected_y, y); \ - ERR(GRN_INVALID_ARGUMENT, \ - "<%s> doesn't support vector: <%.*s> %s <%.*s>", \ - operator, \ - (int)GRN_TEXT_LEN(&inspected_x), GRN_TEXT_VALUE(&inspected_x), \ - operator, \ - (int)GRN_TEXT_LEN(&inspected_y), GRN_TEXT_VALUE(&inspected_y)); \ - GRN_OBJ_FIN(ctx, &inspected_x); \ - GRN_OBJ_FIN(ctx, &inspected_y); \ - goto exit; \ - } \ - if (y != res) { \ - res->header.domain = x->header.domain; \ - } \ - ARITHMETIC_OPERATION_DISPATCH(x, y, res, \ - integer8_operation, \ - integer16_operation, \ - integer32_operation, \ - integer64_operation, \ - float_operation, \ - left_expression_check, \ - right_expression_check, \ - text_operation, \ - invalid_type_error); \ - if (y == res) { \ - res->header.domain = x->header.domain; \ - } \ -} while (0) - -#define SIGNED_INTEGER_DIVISION_OPERATION_SLASH(x, y) \ - ((y == -1) ? -(x) : (x) / (y)) -#define UNSIGNED_INTEGER_DIVISION_OPERATION_SLASH(x, y) ((x) / (y)) -#define FLOAT_DIVISION_OPERATION_SLASH(x, y) ((double)(x) / (double)(y)) -#define SIGNED_INTEGER_DIVISION_OPERATION_MOD(x, y) ((y == -1) ? 0 : (x) % (y)) -#define UNSIGNED_INTEGER_DIVISION_OPERATION_MOD(x, y) ((x) % (y)) -#define FLOAT_DIVISION_OPERATION_MOD(x, y) (fmod((x), (y))) - -#define DIVISION_OPERATION_DISPATCH_RIGHT(set, get, x_, y, res, \ - signed_integer_operation, \ - unsigned_integer_operation, \ - float_operation) do { \ - switch (y->header.domain) { \ - case GRN_DB_INT8 : \ - { \ - int y_; \ - y_ = GRN_INT8_VALUE(y); \ - ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_); \ - set(ctx, res, signed_integer_operation(x_, y_)); \ - } \ - break; \ - case GRN_DB_UINT8 : \ - { \ - int y_; \ - y_ = GRN_UINT8_VALUE(y); \ - ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_); \ - set(ctx, res, unsigned_integer_operation(x_, y_)); \ - } \ - break; \ - case GRN_DB_INT16 : \ - { \ - int y_; \ - y_ = GRN_INT16_VALUE(y); \ - ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_); \ - set(ctx, res, signed_integer_operation(x_, y_)); \ - } \ - break; \ - case GRN_DB_UINT16 : \ - { \ - int y_; \ - y_ = GRN_UINT16_VALUE(y); \ - ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_); \ - set(ctx, res, unsigned_integer_operation(x_, y_)); \ - } \ - break; \ - case GRN_DB_INT32 : \ - { \ - int y_; \ - y_ = GRN_INT32_VALUE(y); \ - ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_); \ - set(ctx, res, signed_integer_operation(x_, y_)); \ - } \ - break; \ - case GRN_DB_UINT32 : \ - { \ - unsigned int y_; \ - y_ = GRN_UINT32_VALUE(y); \ - ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_); \ - set(ctx, res, unsigned_integer_operation(x_, y_)); \ - } \ - break; \ - case GRN_DB_TIME : \ - { \ - long long int y_; \ - y_ = GRN_TIME_VALUE(y); \ - ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_); \ - set(ctx, res, signed_integer_operation(x_, y_)); \ - } \ - break; \ - case GRN_DB_INT64 : \ - { \ - long long int y_; \ - y_ = GRN_INT64_VALUE(y); \ - ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_); \ - set(ctx, res, signed_integer_operation(x_, y_)); \ - } \ - break; \ - case GRN_DB_UINT64 : \ - { \ - long long unsigned int y_; \ - y_ = GRN_UINT64_VALUE(y); \ - ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_); \ - set(ctx, res, unsigned_integer_operation(x_, y_)); \ - } \ - break; \ - case GRN_DB_FLOAT : \ - { \ - double y_; \ - y_ = GRN_FLOAT_VALUE(y); \ - ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_); \ - res->header.domain = GRN_DB_FLOAT; \ - GRN_FLOAT_SET(ctx, res, float_operation(x_, y_)); \ - } \ - break; \ - case GRN_DB_SHORT_TEXT : \ - case GRN_DB_TEXT : \ - case GRN_DB_LONG_TEXT : \ - set(ctx, res, 0); \ - if (grn_obj_cast(ctx, y, res, GRN_FALSE)) { \ - ERR(GRN_INVALID_ARGUMENT, \ - "not a numerical format: <%.*s>", \ - (int)GRN_TEXT_LEN(y), GRN_TEXT_VALUE(y)); \ - goto exit; \ - } \ - /* The following "+ 0" is needed to suppress warnings that say */ \ - /* comparison is always false due to limited range of data type */ \ - set(ctx, res, signed_integer_operation(x_, (get(res) + 0))); \ - break; \ - default : \ - break; \ - } \ -} while (0) - -#define DIVISION_OPERATION_DISPATCH_LEFT(x, y, res, \ - signed_integer_operation, \ - unsigned_integer_operation, \ - float_operation, \ - invalid_type_error) do { \ - switch (x->header.domain) { \ - case GRN_DB_INT8 : \ - { \ - int x_; \ - x_ = GRN_INT8_VALUE(x); \ - DIVISION_OPERATION_DISPATCH_RIGHT(GRN_INT8_SET, \ - GRN_INT8_VALUE, \ - x_, y, res, \ - signed_integer_operation, \ - unsigned_integer_operation, \ - float_operation); \ - } \ - break; \ - case GRN_DB_UINT8 : \ - { \ - int x_; \ - x_ = GRN_UINT8_VALUE(x); \ - DIVISION_OPERATION_DISPATCH_RIGHT(GRN_UINT8_SET, \ - (int)GRN_UINT8_VALUE, \ - x_, y, res, \ - signed_integer_operation, \ - unsigned_integer_operation, \ - float_operation); \ - } \ - break; \ - case GRN_DB_INT16 : \ - { \ - int x_; \ - x_ = GRN_INT16_VALUE(x); \ - DIVISION_OPERATION_DISPATCH_RIGHT(GRN_INT16_SET, \ - GRN_INT16_VALUE, \ - x_, y, res, \ - signed_integer_operation, \ - unsigned_integer_operation, \ - float_operation); \ - } \ - break; \ - case GRN_DB_UINT16 : \ - { \ - int x_; \ - x_ = GRN_UINT16_VALUE(x); \ - DIVISION_OPERATION_DISPATCH_RIGHT(GRN_UINT16_SET, \ - (int)GRN_UINT16_VALUE, \ - x_, y, res, \ - signed_integer_operation, \ - unsigned_integer_operation, \ - float_operation); \ - } \ - break; \ - case GRN_DB_INT32 : \ - { \ - int x_; \ - x_ = GRN_INT32_VALUE(x); \ - DIVISION_OPERATION_DISPATCH_RIGHT(GRN_INT32_SET, \ - GRN_INT32_VALUE, \ - x_, y, res, \ - signed_integer_operation, \ - unsigned_integer_operation, \ - float_operation); \ - } \ - break; \ - case GRN_DB_UINT32 : \ - { \ - unsigned int x_; \ - x_ = GRN_UINT32_VALUE(x); \ - DIVISION_OPERATION_DISPATCH_RIGHT(GRN_UINT32_SET, \ - GRN_UINT32_VALUE, \ - x_, y, res, \ - unsigned_integer_operation, \ - unsigned_integer_operation, \ - float_operation); \ - } \ - break; \ - case GRN_DB_INT64 : \ - { \ - long long int x_; \ - x_ = GRN_INT64_VALUE(x); \ - DIVISION_OPERATION_DISPATCH_RIGHT(GRN_INT64_SET, \ - GRN_INT64_VALUE, \ - x_, y, res, \ - signed_integer_operation, \ - unsigned_integer_operation, \ - float_operation); \ - } \ - break; \ - case GRN_DB_TIME : \ - { \ - long long int x_; \ - x_ = GRN_TIME_VALUE(x); \ - DIVISION_OPERATION_DISPATCH_RIGHT(GRN_TIME_SET, \ - GRN_TIME_VALUE, \ - x_, y, res, \ - signed_integer_operation, \ - unsigned_integer_operation, \ - float_operation); \ - } \ - break; \ - case GRN_DB_UINT64 : \ - { \ - long long unsigned int x_; \ - x_ = GRN_UINT64_VALUE(x); \ - DIVISION_OPERATION_DISPATCH_RIGHT(GRN_UINT64_SET, \ - GRN_UINT64_VALUE, \ - x_, y, res, \ - unsigned_integer_operation, \ - unsigned_integer_operation, \ - float_operation); \ - } \ - break; \ - case GRN_DB_FLOAT : \ - { \ - double x_; \ - x_ = GRN_FLOAT_VALUE(x); \ - DIVISION_OPERATION_DISPATCH_RIGHT(GRN_FLOAT_SET, \ - GRN_FLOAT_VALUE, \ - x_, y, res, \ - float_operation, \ - float_operation, \ - float_operation); \ - } \ - break; \ - case GRN_DB_SHORT_TEXT : \ - case GRN_DB_TEXT : \ - case GRN_DB_LONG_TEXT : \ - invalid_type_error; \ - break; \ - default: \ - break; \ - } \ - code++; \ -} while (0) - -#define DIVISION_OPERATION_DISPATCH(signed_integer_operation, \ - unsigned_integer_operation, \ - float_operation, \ - invalid_type_error) do { \ - grn_obj *x = NULL; \ - grn_obj *y = NULL; \ - \ - POP2ALLOC1(x, y, res); \ - if (y != res) { \ - res->header.domain = x->header.domain; \ - } \ - DIVISION_OPERATION_DISPATCH_LEFT(x, y, res, \ - signed_integer_operation, \ - unsigned_integer_operation, \ - float_operation, \ - invalid_type_error); \ - if (y == res) { \ - res->header.domain = x->header.domain; \ - } \ -} while (0) - -#define ARITHMETIC_UNARY_OPERATION_DISPATCH(integer_operation, \ - float_operation, \ - left_expression_check, \ - right_expression_check, \ - text_operation, \ - invalid_type_error) do { \ - grn_obj *x = NULL; \ - POP1ALLOC1(x, res); \ - res->header.domain = x->header.domain; \ - switch (x->header.domain) { \ - case GRN_DB_INT8 : \ - { \ - int8_t x_; \ - x_ = GRN_INT8_VALUE(x); \ - left_expression_check(x_); \ - GRN_INT8_SET(ctx, res, integer_operation(x_)); \ - } \ - break; \ - case GRN_DB_UINT8 : \ - { \ - int16_t x_; \ - x_ = GRN_UINT8_VALUE(x); \ - left_expression_check(x_); \ - GRN_INT16_SET(ctx, res, integer_operation(x_)); \ - res->header.domain = GRN_DB_INT16; \ - } \ - break; \ - case GRN_DB_INT16 : \ - { \ - int16_t x_; \ - x_ = GRN_INT16_VALUE(x); \ - left_expression_check(x_); \ - GRN_INT16_SET(ctx, res, integer_operation(x_)); \ - } \ - break; \ - case GRN_DB_UINT16 : \ - { \ - int x_; \ - x_ = GRN_UINT16_VALUE(x); \ - left_expression_check(x_); \ - GRN_INT32_SET(ctx, res, integer_operation(x_)); \ - res->header.domain = GRN_DB_INT32; \ - } \ - break; \ - case GRN_DB_INT32 : \ - { \ - int x_; \ - x_ = GRN_INT32_VALUE(x); \ - left_expression_check(x_); \ - GRN_INT32_SET(ctx, res, integer_operation(x_)); \ - } \ - break; \ - case GRN_DB_UINT32 : \ - { \ - long long int x_; \ - x_ = GRN_UINT32_VALUE(x); \ - left_expression_check(x_); \ - GRN_INT64_SET(ctx, res, integer_operation(x_)); \ - res->header.domain = GRN_DB_INT64; \ - } \ - break; \ - case GRN_DB_INT64 : \ - { \ - long long int x_; \ - x_ = GRN_INT64_VALUE(x); \ - left_expression_check(x_); \ - GRN_INT64_SET(ctx, res, integer_operation(x_)); \ - } \ - break; \ - case GRN_DB_TIME : \ - { \ - long long int x_; \ - x_ = GRN_TIME_VALUE(x); \ - left_expression_check(x_); \ - GRN_TIME_SET(ctx, res, integer_operation(x_)); \ - } \ - break; \ - case GRN_DB_UINT64 : \ - { \ - long long unsigned int x_; \ - x_ = GRN_UINT64_VALUE(x); \ - left_expression_check(x_); \ - if (x_ > (long long unsigned int)INT64_MAX) { \ - ERR(GRN_INVALID_ARGUMENT, \ - "too large UInt64 value to inverse sign: " \ - "<%" GRN_FMT_LLU ">", \ - x_); \ - goto exit; \ - } else { \ - long long int signed_x_; \ - signed_x_ = x_; \ - GRN_INT64_SET(ctx, res, integer_operation(signed_x_)); \ - res->header.domain = GRN_DB_INT64; \ - } \ - } \ - break; \ - case GRN_DB_FLOAT : \ - { \ - double x_; \ - x_ = GRN_FLOAT_VALUE(x); \ - left_expression_check(x_); \ - GRN_FLOAT_SET(ctx, res, float_operation(x_)); \ - } \ - break; \ - case GRN_DB_SHORT_TEXT : \ - case GRN_DB_TEXT : \ - case GRN_DB_LONG_TEXT : \ - text_operation; \ - break; \ - default: \ - invalid_type_error; \ - break; \ - } \ - code++; \ -} while (0) - -#define EXEC_OPERATE(operate_sentence, assign_sentence) \ - operate_sentence \ - assign_sentence - -#define EXEC_OPERATE_POST(operate_sentence, assign_sentence) \ - assign_sentence \ - operate_sentence - -#define UNARY_OPERATE_AND_ASSIGN_DISPATCH(exec_operate, delta, \ - set_flags) do { \ - grn_obj *var = NULL; \ - grn_obj *col = NULL; \ - grn_obj value; \ - grn_id rid; \ - \ - POP1ALLOC1(var, res); \ - if (var->header.type != GRN_PTR) { \ - ERR(GRN_INVALID_ARGUMENT, "invalid variable type: 0x%0x", \ - var->header.type); \ - goto exit; \ - } \ - if (GRN_BULK_VSIZE(var) != (sizeof(grn_obj *) + sizeof(grn_id))) { \ - ERR(GRN_INVALID_ARGUMENT, \ - "invalid variable size: " \ - "expected: %" GRN_FMT_SIZE \ - "actual: %" GRN_FMT_SIZE, \ - (sizeof(grn_obj *) + sizeof(grn_id)), GRN_BULK_VSIZE(var)); \ - goto exit; \ - } \ - col = GRN_PTR_VALUE(var); \ - rid = *(grn_id *)(GRN_BULK_HEAD(var) + sizeof(grn_obj *)); \ - res->header.type = GRN_VOID; \ - res->header.domain = DB_OBJ(col)->range; \ - switch (DB_OBJ(col)->range) { \ - case GRN_DB_INT32 : \ - GRN_INT32_INIT(&value, 0); \ - GRN_INT32_SET(ctx, &value, delta); \ - break; \ - case GRN_DB_UINT32 : \ - GRN_UINT32_INIT(&value, 0); \ - GRN_UINT32_SET(ctx, &value, delta); \ - break; \ - case GRN_DB_INT64 : \ - GRN_INT64_INIT(&value, 0); \ - GRN_INT64_SET(ctx, &value, delta); \ - break; \ - case GRN_DB_UINT64 : \ - GRN_UINT64_INIT(&value, 0); \ - GRN_UINT64_SET(ctx, &value, delta); \ - break; \ - case GRN_DB_FLOAT : \ - GRN_FLOAT_INIT(&value, 0); \ - GRN_FLOAT_SET(ctx, &value, delta); \ - break; \ - case GRN_DB_TIME : \ - GRN_TIME_INIT(&value, 0); \ - GRN_TIME_SET(ctx, &value, GRN_TIME_PACK(delta, 0)); \ - break; \ - default: \ - ERR(GRN_INVALID_ARGUMENT, \ - "invalid increment target type: %d " \ - "(FIXME: type name is needed)", DB_OBJ(col)->range); \ - goto exit; \ - break; \ - } \ - exec_operate(grn_obj_set_value(ctx, col, rid, &value, set_flags);, \ - grn_obj_get_value(ctx, col, rid, res);); \ - code++; \ -} while (0) - -#define ARITHMETIC_OPERATION_AND_ASSIGN_DISPATCH(integer8_operation, \ - integer16_operation, \ - integer32_operation, \ - integer64_operation, \ - float_operation, \ - left_expression_check, \ - right_expression_check,\ - text_operation) do { \ - grn_obj *value = NULL; \ - grn_obj *var = NULL; \ - grn_obj *res = NULL; \ - if (code->value) { \ - value = code->value; \ - POP1ALLOC1(var, res); \ - } else { \ - POP2ALLOC1(var, value, res); \ - } \ - if (var->header.type == GRN_PTR && \ - GRN_BULK_VSIZE(var) == (sizeof(grn_obj *) + sizeof(grn_id))) { \ - grn_obj *col = GRN_PTR_VALUE(var); \ - grn_id rid = *(grn_id *)(GRN_BULK_HEAD(var) + sizeof(grn_obj *)); \ - grn_obj variable_value, casted_value; \ - grn_id domain; \ - \ - value = GRN_OBJ_RESOLVE(ctx, value); \ - \ - domain = grn_obj_get_range(ctx, col); \ - GRN_OBJ_INIT(&variable_value, GRN_BULK, 0, domain); \ - grn_obj_get_value(ctx, col, rid, &variable_value); \ - \ - GRN_OBJ_INIT(&casted_value, GRN_BULK, 0, domain); \ - if (grn_obj_cast(ctx, value, &casted_value, GRN_FALSE)) { \ - ERR(GRN_INVALID_ARGUMENT, "invalid value: string"); \ - GRN_OBJ_FIN(ctx, &variable_value); \ - GRN_OBJ_FIN(ctx, &casted_value); \ - POP1(res); \ - goto exit; \ - } \ - grn_obj_reinit(ctx, res, domain, 0); \ - ARITHMETIC_OPERATION_DISPATCH((&variable_value), (&casted_value), \ - res, \ - integer8_operation, \ - integer16_operation, \ - integer32_operation, \ - integer64_operation, \ - float_operation, \ - left_expression_check, \ - right_expression_check, \ - text_operation,); \ - grn_obj_set_value(ctx, col, rid, res, GRN_OBJ_SET); \ - GRN_OBJ_FIN(ctx, (&variable_value)); \ - GRN_OBJ_FIN(ctx, (&casted_value)); \ - } else { \ - ERR(GRN_INVALID_ARGUMENT, "left hand expression isn't column."); \ - POP1(res); \ - } \ -} while (0) - -grn_inline static void -grn_expr_exec_get_member_vector(grn_ctx *ctx, - grn_obj *expr, - grn_obj *column_and_record_id, - grn_obj *index, - grn_obj *result) -{ - grn_obj *column; - grn_id record_id; - grn_obj values; - int i; - - column = GRN_PTR_VALUE(column_and_record_id); - record_id = *((grn_id *)(&(GRN_PTR_VALUE_AT(column_and_record_id, 1)))); - GRN_TEXT_INIT(&values, 0); - grn_obj_get_value(ctx, column, record_id, &values); - - i = GRN_UINT32_VALUE(index); - if (values.header.type == GRN_UVECTOR) { - int n_elements = 0; - grn_obj *range; - grn_id range_id = DB_OBJ(column)->range; - - grn_obj_reinit(ctx, result, range_id, 0); - range = grn_ctx_at(ctx, range_id); - if (range) { - switch (range->header.type) { - case GRN_TYPE : - n_elements = GRN_BULK_VSIZE(&values) / grn_type_size(ctx, range); - break; - case GRN_TABLE_HASH_KEY : - case GRN_TABLE_PAT_KEY : - case GRN_TABLE_DAT_KEY : - case GRN_TABLE_NO_KEY : - n_elements = GRN_BULK_VSIZE(&values) / sizeof(grn_id); - break; - } - } - if (n_elements > i) { -#define GET_UVECTOR_ELEMENT_AS(type) do { \ - GRN_ ## type ## _SET(ctx, \ - result, \ - GRN_ ## type ## _VALUE_AT(&values, i)); \ - } while (GRN_FALSE) - switch (values.header.domain) { - case GRN_DB_BOOL : - GET_UVECTOR_ELEMENT_AS(BOOL); - break; - case GRN_DB_INT8 : - GET_UVECTOR_ELEMENT_AS(INT8); - break; - case GRN_DB_UINT8 : - GET_UVECTOR_ELEMENT_AS(UINT8); - break; - case GRN_DB_INT16 : - GET_UVECTOR_ELEMENT_AS(INT16); - break; - case GRN_DB_UINT16 : - GET_UVECTOR_ELEMENT_AS(UINT16); - break; - case GRN_DB_INT32 : - GET_UVECTOR_ELEMENT_AS(INT32); - break; - case GRN_DB_UINT32 : - GET_UVECTOR_ELEMENT_AS(UINT32); - break; - case GRN_DB_INT64 : - GET_UVECTOR_ELEMENT_AS(INT64); - break; - case GRN_DB_UINT64 : - GET_UVECTOR_ELEMENT_AS(UINT64); - break; - case GRN_DB_FLOAT : - GET_UVECTOR_ELEMENT_AS(FLOAT); - break; - case GRN_DB_TIME : - GET_UVECTOR_ELEMENT_AS(TIME); - break; - default : - GET_UVECTOR_ELEMENT_AS(RECORD); - break; - } -#undef GET_UVECTOR_ELEMENT_AS - } - } else { - if (values.u.v.n_sections > i) { - const char *content; - unsigned int content_length; - grn_id domain; - - content_length = grn_vector_get_element(ctx, &values, i, - &content, NULL, &domain); - grn_obj_reinit(ctx, result, domain, 0); - grn_bulk_write(ctx, result, content, content_length); - } - } - - GRN_OBJ_FIN(ctx, &values); -} - -grn_inline static void -grn_expr_exec_get_member_table(grn_ctx *ctx, - grn_obj *expr, - grn_obj *table, - grn_obj *key, - grn_obj *result) -{ - grn_id id; - - if (table->header.domain == key->header.domain) { - id = grn_table_get(ctx, table, GRN_BULK_HEAD(key), GRN_BULK_VSIZE(key)); - } else { - grn_obj casted_key; - GRN_OBJ_INIT(&casted_key, GRN_BULK, 0, table->header.domain); - if (grn_obj_cast(ctx, key, &casted_key, GRN_FALSE) == GRN_SUCCESS) { - id = grn_table_get(ctx, table, - GRN_BULK_HEAD(&casted_key), - GRN_BULK_VSIZE(&casted_key)); - } else { - id = GRN_ID_NIL; - } - GRN_OBJ_FIN(ctx, &casted_key); - } - - grn_obj_reinit(ctx, result, DB_OBJ(table)->id, 0); - GRN_RECORD_SET(ctx, result, id); -} - -static grn_inline grn_bool -grn_expr_exec_is_simple_expr(grn_ctx *ctx, grn_obj *expr) -{ - grn_expr *e = (grn_expr *)expr; - - if (expr->header.type != GRN_EXPR) { - return GRN_FALSE; - } - - if (e->codes_curr != 1) { - return GRN_FALSE; - } - - switch (e->codes[0].op) { - case GRN_OP_PUSH : - return GRN_TRUE; - default : - return GRN_FALSE; - } -} - -static grn_inline grn_obj * -grn_expr_exec_simple(grn_ctx *ctx, grn_obj *expr) -{ - grn_expr *e = (grn_expr *)expr; - - return e->codes[0].value; -} - grn_obj * grn_expr_exec(grn_ctx *ctx, grn_obj *expr, int nargs) { - grn_obj *val = NULL; - uint32_t stack_curr = ctx->impl->stack_curr; + grn_obj *value = NULL; GRN_API_ENTER; - if (grn_expr_exec_is_simple_expr(ctx, expr)) { - val = grn_expr_exec_simple(ctx, expr); - GRN_API_RETURN(val); - } if (expr->header.type == GRN_PROC) { grn_proc *proc = (grn_proc *)expr; if (proc->type == GRN_PROC_COMMAND) { @@ -2714,1236 +1538,46 @@ grn_expr_exec(grn_ctx *ctx, grn_obj *expr, int nargs) input = grn_command_input_open(ctx, expr); grn_command_run(ctx, expr, input); grn_command_input_close(ctx, input); - GRN_API_RETURN(NULL); + value = NULL; } else { + uint32_t stack_curr = ctx->impl->stack_curr; grn_proc_call(ctx, expr, nargs, expr); + if (ctx->impl->stack_curr + nargs > stack_curr) { + value = grn_ctx_pop(ctx); + } + if (ctx->impl->stack_curr + nargs > stack_curr) { + /* + GRN_LOG(ctx, GRN_LOG_WARNING, "nargs=%d stack balance=%d", + nargs, stack_curr - ctx->impl->stack_curr); + */ + ctx->impl->stack_curr = stack_curr - nargs; + } } } else { grn_expr *e = (grn_expr *)expr; - register grn_obj **s_ = ctx->impl->stack; - register grn_obj *s0 = NULL; - register grn_obj *s1 = NULL; - register grn_obj **sp; - register grn_obj *vp = e->values; - grn_obj *res = NULL, *v0 = grn_expr_get_var_by_offset(ctx, expr, 0); - grn_expr_code *code = e->codes, *ce = &e->codes[e->codes_curr]; - sp = s_ + stack_curr; - while (code < ce) { - switch (code->op) { - case GRN_OP_NOP : - code++; - break; - case GRN_OP_PUSH : - PUSH1(code->value); - code++; - break; - case GRN_OP_POP : - { - grn_obj *obj = NULL; - POP1(obj); - code++; - } - break; - case GRN_OP_GET_REF : - { - grn_obj *col = NULL; - grn_obj *rec = NULL; - if (code->nargs == 1) { - rec = v0; - if (code->value) { - col = code->value; - ALLOC1(res); - } else { - POP1ALLOC1(col, res); - } - } else { - if (code->value) { - col = code->value; - POP1ALLOC1(rec, res); - } else { - POP2ALLOC1(rec, col, res); - } - } - if (col->header.type == GRN_BULK) { - grn_obj *table = grn_ctx_at(ctx, GRN_OBJ_GET_DOMAIN(rec)); - col = grn_obj_column(ctx, table, GRN_BULK_HEAD(col), GRN_BULK_VSIZE(col)); - if (col) { grn_expr_take_obj(ctx, (grn_obj *)e, col); } - } - if (col) { - res->header.type = GRN_PTR; - res->header.domain = GRN_ID_NIL; - GRN_PTR_SET(ctx, res, col); - GRN_UINT32_PUT(ctx, res, GRN_RECORD_VALUE(rec)); - } else { - ERR(GRN_INVALID_ARGUMENT, "col resolve failed"); - goto exit; - } - code++; - } - break; - case GRN_OP_CALL : - { - grn_obj *proc = NULL; - if (code->value) { - if (sp < s_ + code->nargs - 1) { - ERR(GRN_INVALID_ARGUMENT, "stack error"); - goto exit; - } - proc = code->value; - WITH_SPSAVE({ - grn_proc_call(ctx, proc, code->nargs - 1, expr); - }); - } else { - int offset = code->nargs; - if (sp < s_ + offset) { - ERR(GRN_INVALID_ARGUMENT, "stack error"); - goto exit; - } - proc = sp[-offset]; - if (grn_obj_is_window_function_proc(ctx, proc)) { - grn_obj inspected; - GRN_TEXT_INIT(&inspected, 0); - grn_inspect(ctx, &inspected, proc); - ERR(GRN_INVALID_ARGUMENT, - "window function can't be executed for each record: %.*s", - (int)GRN_TEXT_LEN(&inspected), - GRN_TEXT_VALUE(&inspected)); - GRN_OBJ_FIN(ctx, &inspected); - goto exit; - } else { - WITH_SPSAVE({ - grn_proc_call(ctx, proc, code->nargs - 1, expr); - }); - } - if (ctx->rc) { - goto exit; - } - POP1(res); - { - grn_obj *proc_; - POP1(proc_); - if (proc != proc_) { - GRN_LOG(ctx, GRN_LOG_WARNING, "stack may be corrupt"); - } - } - PUSH1(res); - } - } - code++; - break; - case GRN_OP_INTERN : - { - grn_obj *obj = NULL; - POP1(obj); - obj = GRN_OBJ_RESOLVE(ctx, obj); - res = grn_expr_get_var(ctx, expr, GRN_TEXT_VALUE(obj), GRN_TEXT_LEN(obj)); - if (!res) { res = grn_ctx_get(ctx, GRN_TEXT_VALUE(obj), GRN_TEXT_LEN(obj)); } - if (!res) { - ERR(GRN_INVALID_ARGUMENT, "intern failed"); - goto exit; - } - PUSH1(res); - } - code++; - break; - case GRN_OP_TABLE_CREATE : - { - grn_obj *value_type, *key_type, *flags, *name; - POP1(value_type); - value_type = GRN_OBJ_RESOLVE(ctx, value_type); - POP1(key_type); - key_type = GRN_OBJ_RESOLVE(ctx, key_type); - POP1(flags); - flags = GRN_OBJ_RESOLVE(ctx, flags); - POP1(name); - name = GRN_OBJ_RESOLVE(ctx, name); - res = grn_table_create(ctx, GRN_TEXT_VALUE(name), GRN_TEXT_LEN(name), - NULL, GRN_UINT32_VALUE(flags), - key_type, value_type); - PUSH1(res); - } - code++; - break; - case GRN_OP_EXPR_GET_VAR : - { - grn_obj *name = NULL; - grn_obj *expr = NULL; - POP1(name); - name = GRN_OBJ_RESOLVE(ctx, name); - POP1(expr); - expr = GRN_OBJ_RESOLVE(ctx, expr); - switch (name->header.domain) { - case GRN_DB_INT32 : - res = grn_expr_get_var_by_offset(ctx, expr, (unsigned int) GRN_INT32_VALUE(name)); - break; - case GRN_DB_UINT32 : - res = grn_expr_get_var_by_offset(ctx, expr, (unsigned int) GRN_UINT32_VALUE(name)); - break; - case GRN_DB_INT64 : - res = grn_expr_get_var_by_offset(ctx, expr, (unsigned int) GRN_INT64_VALUE(name)); - break; - case GRN_DB_UINT64 : - res = grn_expr_get_var_by_offset(ctx, expr, (unsigned int) GRN_UINT64_VALUE(name)); - break; - case GRN_DB_SHORT_TEXT : - case GRN_DB_TEXT : - case GRN_DB_LONG_TEXT : - res = grn_expr_get_var(ctx, expr, GRN_TEXT_VALUE(name), GRN_TEXT_LEN(name)); - break; - default : - ERR(GRN_INVALID_ARGUMENT, "invalid type"); - goto exit; - } - PUSH1(res); - } - code++; - break; - case GRN_OP_ASSIGN : - { - grn_obj *value = NULL; - grn_obj *var = NULL; - if (code->value) { - value = code->value; - } else { - POP1(value); - } - value = GRN_OBJ_RESOLVE(ctx, value); - POP1(var); - // var = GRN_OBJ_RESOLVE(ctx, var); - if (var->header.type == GRN_PTR && - GRN_BULK_VSIZE(var) == (sizeof(grn_obj *) + sizeof(grn_id))) { - grn_obj *col = GRN_PTR_VALUE(var); - grn_id rid = *(grn_id *)(GRN_BULK_HEAD(var) + sizeof(grn_obj *)); - grn_obj_set_value(ctx, col, rid, value, GRN_OBJ_SET); - } else { - VAR_SET_VALUE(ctx, var, value); - } - PUSH1(value); - } - code++; - break; - case GRN_OP_STAR_ASSIGN : - ARITHMETIC_OPERATION_AND_ASSIGN_DISPATCH( - INTEGER_ARITHMETIC_OPERATION_STAR, - INTEGER_ARITHMETIC_OPERATION_STAR, - INTEGER_ARITHMETIC_OPERATION_STAR, - INTEGER_ARITHMETIC_OPERATION_STAR, - FLOAT_ARITHMETIC_OPERATION_STAR, - ARITHMETIC_OPERATION_NO_CHECK, - ARITHMETIC_OPERATION_NO_CHECK, - { - ERR(GRN_INVALID_ARGUMENT, "variable *= \"string\" isn't supported"); - goto exit; - }); - break; - case GRN_OP_SLASH_ASSIGN : - ARITHMETIC_OPERATION_AND_ASSIGN_DISPATCH( - INTEGER_ARITHMETIC_OPERATION_SLASH, - INTEGER_ARITHMETIC_OPERATION_SLASH, - INTEGER_ARITHMETIC_OPERATION_SLASH, - INTEGER_ARITHMETIC_OPERATION_SLASH, - FLOAT_ARITHMETIC_OPERATION_SLASH, - ARITHMETIC_OPERATION_NO_CHECK, - ARITHMETIC_OPERATION_NO_CHECK, - { - ERR(GRN_INVALID_ARGUMENT, "variable /= \"string\" isn't supported"); - goto exit; - }); - break; - case GRN_OP_MOD_ASSIGN : - ARITHMETIC_OPERATION_AND_ASSIGN_DISPATCH( - INTEGER_ARITHMETIC_OPERATION_MOD, - INTEGER_ARITHMETIC_OPERATION_MOD, - INTEGER_ARITHMETIC_OPERATION_MOD, - INTEGER_ARITHMETIC_OPERATION_MOD, - FLOAT_ARITHMETIC_OPERATION_MOD, - ARITHMETIC_OPERATION_NO_CHECK, - ARITHMETIC_OPERATION_NO_CHECK, - { - ERR(GRN_INVALID_ARGUMENT, "variable %%= \"string\" isn't supported"); - goto exit; - }); - break; - case GRN_OP_PLUS_ASSIGN : - ARITHMETIC_OPERATION_AND_ASSIGN_DISPATCH( - INTEGER_ARITHMETIC_OPERATION_PLUS, - INTEGER_ARITHMETIC_OPERATION_PLUS, - INTEGER_ARITHMETIC_OPERATION_PLUS, - INTEGER_ARITHMETIC_OPERATION_PLUS, - FLOAT_ARITHMETIC_OPERATION_PLUS, - ARITHMETIC_OPERATION_NO_CHECK, - ARITHMETIC_OPERATION_NO_CHECK, - { - ERR(GRN_INVALID_ARGUMENT, "variable += \"string\" isn't supported"); - goto exit; - }); - break; - case GRN_OP_MINUS_ASSIGN : - ARITHMETIC_OPERATION_AND_ASSIGN_DISPATCH( - INTEGER_ARITHMETIC_OPERATION_MINUS, - INTEGER_ARITHMETIC_OPERATION_MINUS, - INTEGER_ARITHMETIC_OPERATION_MINUS, - INTEGER_ARITHMETIC_OPERATION_MINUS, - FLOAT_ARITHMETIC_OPERATION_MINUS, - ARITHMETIC_OPERATION_NO_CHECK, - ARITHMETIC_OPERATION_NO_CHECK, - { - ERR(GRN_INVALID_ARGUMENT, "variable -= \"string\" isn't supported"); - goto exit; - }); - break; - case GRN_OP_SHIFTL_ASSIGN : - ARITHMETIC_OPERATION_AND_ASSIGN_DISPATCH( - INTEGER_ARITHMETIC_OPERATION_SHIFTL, - INTEGER_ARITHMETIC_OPERATION_SHIFTL, - INTEGER_ARITHMETIC_OPERATION_SHIFTL, - INTEGER_ARITHMETIC_OPERATION_SHIFTL, - FLOAT_ARITHMETIC_OPERATION_SHIFTL, - ARITHMETIC_OPERATION_NO_CHECK, - ARITHMETIC_OPERATION_NO_CHECK, - { - ERR(GRN_INVALID_ARGUMENT, "variable <<= \"string\" isn't supported"); - goto exit; - }); - break; - case GRN_OP_SHIFTR_ASSIGN : - ARITHMETIC_OPERATION_AND_ASSIGN_DISPATCH( - INTEGER_ARITHMETIC_OPERATION_SHIFTR, - INTEGER_ARITHMETIC_OPERATION_SHIFTR, - INTEGER_ARITHMETIC_OPERATION_SHIFTR, - INTEGER_ARITHMETIC_OPERATION_SHIFTR, - FLOAT_ARITHMETIC_OPERATION_SHIFTR, - ARITHMETIC_OPERATION_NO_CHECK, - ARITHMETIC_OPERATION_NO_CHECK, - { - ERR(GRN_INVALID_ARGUMENT, "variable >>= \"string\" isn't supported"); - goto exit; - }); - break; - case GRN_OP_SHIFTRR_ASSIGN : - ARITHMETIC_OPERATION_AND_ASSIGN_DISPATCH( - INTEGER8_ARITHMETIC_OPERATION_SHIFTRR, - INTEGER16_ARITHMETIC_OPERATION_SHIFTRR, - INTEGER32_ARITHMETIC_OPERATION_SHIFTRR, - INTEGER64_ARITHMETIC_OPERATION_SHIFTRR, - FLOAT_ARITHMETIC_OPERATION_SHIFTRR, - ARITHMETIC_OPERATION_NO_CHECK, - ARITHMETIC_OPERATION_NO_CHECK, - { - ERR(GRN_INVALID_ARGUMENT, - "variable >>>= \"string\" isn't supported"); - goto exit; - }); - break; - case GRN_OP_AND_ASSIGN : - ARITHMETIC_OPERATION_AND_ASSIGN_DISPATCH( - INTEGER_ARITHMETIC_OPERATION_BITWISE_AND, - INTEGER_ARITHMETIC_OPERATION_BITWISE_AND, - INTEGER_ARITHMETIC_OPERATION_BITWISE_AND, - INTEGER_ARITHMETIC_OPERATION_BITWISE_AND, - FLOAT_ARITHMETIC_OPERATION_BITWISE_AND, - ARITHMETIC_OPERATION_NO_CHECK, - ARITHMETIC_OPERATION_NO_CHECK, - { - ERR(GRN_INVALID_ARGUMENT, "variable &= \"string\" isn't supported"); - goto exit; - }); - break; - case GRN_OP_OR_ASSIGN : - ARITHMETIC_OPERATION_AND_ASSIGN_DISPATCH( - INTEGER_ARITHMETIC_OPERATION_BITWISE_OR, - INTEGER_ARITHMETIC_OPERATION_BITWISE_OR, - INTEGER_ARITHMETIC_OPERATION_BITWISE_OR, - INTEGER_ARITHMETIC_OPERATION_BITWISE_OR, - FLOAT_ARITHMETIC_OPERATION_BITWISE_OR, - ARITHMETIC_OPERATION_NO_CHECK, - ARITHMETIC_OPERATION_NO_CHECK, - { - ERR(GRN_INVALID_ARGUMENT, "variable |= \"string\" isn't supported"); - goto exit; - }); - break; - case GRN_OP_XOR_ASSIGN : - ARITHMETIC_OPERATION_AND_ASSIGN_DISPATCH( - INTEGER_ARITHMETIC_OPERATION_BITWISE_XOR, - INTEGER_ARITHMETIC_OPERATION_BITWISE_XOR, - INTEGER_ARITHMETIC_OPERATION_BITWISE_XOR, - INTEGER_ARITHMETIC_OPERATION_BITWISE_XOR, - FLOAT_ARITHMETIC_OPERATION_BITWISE_XOR, - ARITHMETIC_OPERATION_NO_CHECK, - ARITHMETIC_OPERATION_NO_CHECK, - { - ERR(GRN_INVALID_ARGUMENT, "variable ^= \"string\" isn't supported"); - goto exit; - }); - break; - case GRN_OP_JUMP : - code += code->nargs + 1; - break; - case GRN_OP_CJUMP : - { - grn_obj *v = NULL; - POP1(v); - if (!grn_obj_is_true(ctx, v)) { - code += code->nargs; - } - } - code++; - break; - case GRN_OP_GET_VALUE : - { - grn_obj *col = NULL; - grn_obj *rec = NULL; - do { - if (code->nargs == 1) { - rec = v0; - if (code->value) { - col = code->value; - ALLOC1(res); - } else { - POP1ALLOC1(col, res); - } - } else { - if (code->value) { - col = code->value; - POP1ALLOC1(rec, res); - } else { - POP2ALLOC1(rec, col, res); - } - } - if (col->header.type == GRN_BULK) { - grn_obj *table = grn_ctx_at(ctx, GRN_OBJ_GET_DOMAIN(rec)); - col = grn_obj_column(ctx, table, GRN_BULK_HEAD(col), GRN_BULK_VSIZE(col)); - if (col) { grn_expr_take_obj(ctx, (grn_obj *)expr, col); } - } - if (!col) { - ERR(GRN_INVALID_ARGUMENT, "col resolve failed"); - goto exit; - } - grn_obj_reinit_for(ctx, res, col); - grn_obj_get_value(ctx, col, GRN_RECORD_VALUE(rec), res); - code++; - } while (code < ce && code->op == GRN_OP_GET_VALUE); - } - break; - case GRN_OP_OBJ_SEARCH : - { - grn_obj *op = NULL; - grn_obj *query = NULL; - grn_obj *index = NULL; - // todo : grn_search_optarg optarg; - POP1(op); - op = GRN_OBJ_RESOLVE(ctx, op); - POP1(res); - res = GRN_OBJ_RESOLVE(ctx, res); - POP1(query); - query = GRN_OBJ_RESOLVE(ctx, query); - POP1(index); - index = GRN_OBJ_RESOLVE(ctx, index); - grn_obj_search(ctx, index, query, res, - (grn_operator)GRN_UINT32_VALUE(op), NULL); - } - code++; - break; - case GRN_OP_TABLE_SELECT : - { - grn_obj *op = NULL; - grn_obj *res = NULL; - grn_obj *expr = NULL; - grn_obj *table = NULL; - POP1(op); - op = GRN_OBJ_RESOLVE(ctx, op); - POP1(res); - res = GRN_OBJ_RESOLVE(ctx, res); - POP1(expr); - expr = GRN_OBJ_RESOLVE(ctx, expr); - POP1(table); - table = GRN_OBJ_RESOLVE(ctx, table); - WITH_SPSAVE({ - grn_table_select(ctx, table, expr, res, (grn_operator)GRN_UINT32_VALUE(op)); - }); - PUSH1(res); - } - code++; - break; - case GRN_OP_TABLE_SORT : - { - grn_obj *keys_ = NULL; - grn_obj *res = NULL; - grn_obj *limit = NULL; - grn_obj *table = NULL; - POP1(keys_); - keys_ = GRN_OBJ_RESOLVE(ctx, keys_); - POP1(res); - res = GRN_OBJ_RESOLVE(ctx, res); - POP1(limit); - limit = GRN_OBJ_RESOLVE(ctx, limit); - POP1(table); - table = GRN_OBJ_RESOLVE(ctx, table); - { - grn_table_sort_key *keys; - const char *p = GRN_BULK_HEAD(keys_), *tokbuf[256]; - int n = grn_str_tok(p, GRN_BULK_VSIZE(keys_), ' ', tokbuf, 256, NULL); - if ((keys = GRN_MALLOCN(grn_table_sort_key, n))) { - int i, n_keys = 0; - for (i = 0; i < n; i++) { - uint32_t len = (uint32_t) (tokbuf[i] - p); - grn_obj *col = grn_obj_column(ctx, table, p, len); - if (col) { - keys[n_keys].key = col; - keys[n_keys].flags = GRN_TABLE_SORT_ASC; - keys[n_keys].offset = 0; - n_keys++; - } else { - if (p[0] == ':' && p[1] == 'd' && len == 2 && n_keys) { - keys[n_keys - 1].flags |= GRN_TABLE_SORT_DESC; - } - } - p = tokbuf[i] + 1; - } - WITH_SPSAVE({ - grn_table_sort(ctx, table, 0, GRN_INT32_VALUE(limit), res, keys, n_keys); - }); - for (i = 0; i < n_keys; i++) { - grn_obj_unlink(ctx, keys[i].key); - } - GRN_FREE(keys); - } - } - } - code++; - break; - case GRN_OP_TABLE_GROUP : - { - grn_obj *res = NULL; - grn_obj *keys_ = NULL; - grn_obj *table = NULL; - POP1(res); - res = GRN_OBJ_RESOLVE(ctx, res); - POP1(keys_); - keys_ = GRN_OBJ_RESOLVE(ctx, keys_); - POP1(table); - table = GRN_OBJ_RESOLVE(ctx, table); - { - grn_table_sort_key *keys; - grn_table_group_result results; - const char *p = GRN_BULK_HEAD(keys_), *tokbuf[256]; - int n = grn_str_tok(p, GRN_BULK_VSIZE(keys_), ' ', tokbuf, 256, NULL); - if ((keys = GRN_MALLOCN(grn_table_sort_key, n))) { - int i, n_keys = 0; - for (i = 0; i < n; i++) { - uint32_t len = (uint32_t) (tokbuf[i] - p); - grn_obj *col = grn_obj_column(ctx, table, p, len); - if (col) { - keys[n_keys].key = col; - keys[n_keys].flags = GRN_TABLE_SORT_ASC; - keys[n_keys].offset = 0; - n_keys++; - } else if (n_keys) { - if (p[0] == ':' && p[1] == 'd' && len == 2) { - keys[n_keys - 1].flags |= GRN_TABLE_SORT_DESC; - } else { - keys[n_keys - 1].offset = grn_atoi(p, p + len, NULL); - } - } - p = tokbuf[i] + 1; - } - /* todo : support multi-results */ - results.table = res; - results.key_begin = 0; - results.key_end = 0; - results.limit = 0; - results.flags = 0; - results.op = GRN_OP_OR; - WITH_SPSAVE({ - grn_table_group(ctx, table, keys, n_keys, &results, 1); - }); - for (i = 0; i < n_keys; i++) { - grn_obj_unlink(ctx, keys[i].key); - } - GRN_FREE(keys); - } - } - } - code++; - break; - case GRN_OP_JSON_PUT : - { - grn_obj_format format; - grn_obj *res = NULL; - grn_obj *str = NULL; - grn_obj *table = NULL; - POP1(res); - res = GRN_OBJ_RESOLVE(ctx, res); - POP1(str); - str = GRN_OBJ_RESOLVE(ctx, str); - POP1(table); - table = GRN_OBJ_RESOLVE(ctx, table); - GRN_OBJ_FORMAT_INIT(&format, grn_table_size(ctx, table), 0, -1, 0); - format.flags = 0; - grn_obj_columns(ctx, table, - GRN_TEXT_VALUE(str), GRN_TEXT_LEN(str), &format.columns); - grn_text_otoj(ctx, res, table, &format); - GRN_OBJ_FORMAT_FIN(ctx, &format); - } - code++; - break; - case GRN_OP_AND : - { - grn_obj *x = NULL; - grn_obj *y = NULL; - grn_obj *result = NULL; - POP2ALLOC1(x, y, res); - if (grn_obj_is_true(ctx, x)) { - if (grn_obj_is_true(ctx, y)) { - result = y; - } - } - if (result) { - if (res != result) { - grn_obj_reinit(ctx, res, result->header.domain, 0); - grn_obj_cast(ctx, result, res, GRN_FALSE); - } - } else { - grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0); - GRN_BOOL_SET(ctx, res, GRN_FALSE); - } - } - code++; - break; - case GRN_OP_OR : - { - grn_obj *x = NULL; - grn_obj *y = NULL; - grn_obj *result = NULL; - POP2ALLOC1(x, y, res); - if (grn_obj_is_true(ctx, x)) { - result = x; - } else { - if (grn_obj_is_true(ctx, y)) { - result = y; - } else { - result = NULL; - } - } - if (result) { - if (res != result) { - grn_obj_reinit(ctx, res, result->header.domain, 0); - grn_obj_cast(ctx, result, res, GRN_FALSE); - } - } else { - grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0); - GRN_BOOL_SET(ctx, res, GRN_FALSE); - } - } - code++; - break; - case GRN_OP_AND_NOT : - { - grn_obj *x = NULL; - grn_obj *y = NULL; - grn_bool is_true; - POP2ALLOC1(x, y, res); - if (!grn_obj_is_true(ctx, x) || grn_obj_is_true(ctx, y)) { - is_true = GRN_FALSE; - } else { - is_true = GRN_TRUE; - } - grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0); - GRN_BOOL_SET(ctx, res, is_true); - } - code++; - break; - case GRN_OP_ADJUST : - { - /* todo */ - } - code++; - break; - case GRN_OP_MATCH : - { - grn_obj *x = NULL; - grn_obj *y = NULL; - grn_bool matched; - POP1(y); - POP1(x); - WITH_SPSAVE({ - matched = grn_operator_exec_match(ctx, x, y); - }); - ALLOC1(res); - grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0); - GRN_BOOL_SET(ctx, res, matched); - } - code++; - break; - case GRN_OP_EQUAL : - { - grn_bool is_equal; - grn_obj *x = NULL; - grn_obj *y = NULL; - POP2ALLOC1(x, y, res); - is_equal = grn_operator_exec_equal(ctx, x, y); - grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0); - GRN_BOOL_SET(ctx, res, is_equal); - } - code++; - break; - case GRN_OP_NOT_EQUAL : - { - grn_bool is_not_equal; - grn_obj *x = NULL; - grn_obj *y = NULL; - POP2ALLOC1(x, y, res); - is_not_equal = grn_operator_exec_not_equal(ctx, x, y); - grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0); - GRN_BOOL_SET(ctx, res, is_not_equal); - } - code++; - break; - case GRN_OP_PREFIX : - { - grn_obj *x = NULL; - grn_obj *y = NULL; - grn_bool matched; - POP1(y); - POP1(x); - WITH_SPSAVE({ - matched = grn_operator_exec_prefix(ctx, x, y); - }); - ALLOC1(res); - grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0); - GRN_BOOL_SET(ctx, res, matched); - } - code++; - break; - case GRN_OP_SUFFIX : - { - grn_obj *x = NULL; - grn_obj *y = NULL; - grn_bool matched = GRN_FALSE; - POP2ALLOC1(x, y, res); - if (GRN_TEXT_LEN(x) >= GRN_TEXT_LEN(y) && - !memcmp(GRN_TEXT_VALUE(x) + GRN_TEXT_LEN(x) - GRN_TEXT_LEN(y), - GRN_TEXT_VALUE(y), GRN_TEXT_LEN(y))) { - matched = GRN_TRUE; - } - grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0); - GRN_BOOL_SET(ctx, res, matched); - } - code++; - break; - case GRN_OP_LESS : - { - grn_bool r; - grn_obj *x = NULL; - grn_obj *y = NULL; - POP2ALLOC1(x, y, res); - r = grn_operator_exec_less(ctx, x, y); - grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0); - GRN_BOOL_SET(ctx, res, r); - } - code++; - break; - case GRN_OP_GREATER : - { - grn_bool r; - grn_obj *x = NULL; - grn_obj *y = NULL; - POP2ALLOC1(x, y, res); - r = grn_operator_exec_greater(ctx, x, y); - grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0); - GRN_BOOL_SET(ctx, res, r); - } - code++; - break; - case GRN_OP_LESS_EQUAL : - { - grn_bool r; - grn_obj *x = NULL; - grn_obj *y = NULL; - POP2ALLOC1(x, y, res); - r = grn_operator_exec_less_equal(ctx, x, y); - grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0); - GRN_BOOL_SET(ctx, res, r); - } - code++; - break; - case GRN_OP_GREATER_EQUAL : - { - grn_bool r; - grn_obj *x = NULL; - grn_obj *y = NULL; - POP2ALLOC1(x, y, res); - r = grn_operator_exec_greater_equal(ctx, x, y); - grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0); - GRN_BOOL_SET(ctx, res, r); - } - code++; - break; - case GRN_OP_GEO_DISTANCE1 : - { - grn_obj *value = NULL; - double lng1, lat1, lng2, lat2, x, y, d; - POP1(value); - lng1 = GEO_INT2RAD(GRN_INT32_VALUE(value)); - POP1(value); - lat1 = GEO_INT2RAD(GRN_INT32_VALUE(value)); - POP1(value); - lng2 = GEO_INT2RAD(GRN_INT32_VALUE(value)); - POP1ALLOC1(value, res); - lat2 = GEO_INT2RAD(GRN_INT32_VALUE(value)); - x = (lng2 - lng1) * cos((lat1 + lat2) * 0.5); - y = (lat2 - lat1); - d = sqrt((x * x) + (y * y)) * GEO_RADIOUS; - res->header.type = GRN_BULK; - res->header.domain = GRN_DB_FLOAT; - GRN_FLOAT_SET(ctx, res, d); - } - code++; - break; - case GRN_OP_GEO_DISTANCE2 : - { - grn_obj *value = NULL; - double lng1, lat1, lng2, lat2, x, y, d; - POP1(value); - lng1 = GEO_INT2RAD(GRN_INT32_VALUE(value)); - POP1(value); - lat1 = GEO_INT2RAD(GRN_INT32_VALUE(value)); - POP1(value); - lng2 = GEO_INT2RAD(GRN_INT32_VALUE(value)); - POP1ALLOC1(value, res); - lat2 = GEO_INT2RAD(GRN_INT32_VALUE(value)); - x = sin(fabs(lng2 - lng1) * 0.5); - y = sin(fabs(lat2 - lat1) * 0.5); - d = asin(sqrt((y * y) + cos(lat1) * cos(lat2) * x * x)) * 2 * GEO_RADIOUS; - res->header.type = GRN_BULK; - res->header.domain = GRN_DB_FLOAT; - GRN_FLOAT_SET(ctx, res, d); - } - code++; - break; - case GRN_OP_GEO_DISTANCE3 : - { - grn_obj *value = NULL; - double lng1, lat1, lng2, lat2, p, q, m, n, x, y, d; - POP1(value); - lng1 = GEO_INT2RAD(GRN_INT32_VALUE(value)); - POP1(value); - lat1 = GEO_INT2RAD(GRN_INT32_VALUE(value)); - POP1(value); - lng2 = GEO_INT2RAD(GRN_INT32_VALUE(value)); - POP1ALLOC1(value, res); - lat2 = GEO_INT2RAD(GRN_INT32_VALUE(value)); - p = (lat1 + lat2) * 0.5; - q = (1 - GEO_BES_C3 * sin(p) * sin(p)); - m = GEO_BES_C1 / sqrt(q * q * q); - n = GEO_BES_C2 / sqrt(q); - x = n * cos(p) * fabs(lng1 - lng2); - y = m * fabs(lat1 - lat2); - d = sqrt((x * x) + (y * y)); - res->header.type = GRN_BULK; - res->header.domain = GRN_DB_FLOAT; - GRN_FLOAT_SET(ctx, res, d); - } - code++; - break; - case GRN_OP_GEO_DISTANCE4 : - { - grn_obj *value = NULL; - double lng1, lat1, lng2, lat2, p, q, m, n, x, y, d; - POP1(value); - lng1 = GEO_INT2RAD(GRN_INT32_VALUE(value)); - POP1(value); - lat1 = GEO_INT2RAD(GRN_INT32_VALUE(value)); - POP1(value); - lng2 = GEO_INT2RAD(GRN_INT32_VALUE(value)); - POP1ALLOC1(value, res); - lat2 = GEO_INT2RAD(GRN_INT32_VALUE(value)); - p = (lat1 + lat2) * 0.5; - q = (1 - GEO_GRS_C3 * sin(p) * sin(p)); - m = GEO_GRS_C1 / sqrt(q * q * q); - n = GEO_GRS_C2 / sqrt(q); - x = n * cos(p) * fabs(lng1 - lng2); - y = m * fabs(lat1 - lat2); - d = sqrt((x * x) + (y * y)); - res->header.type = GRN_BULK; - res->header.domain = GRN_DB_FLOAT; - GRN_FLOAT_SET(ctx, res, d); - } - code++; - break; - case GRN_OP_GEO_WITHINP5 : - { - int r; - grn_obj *value = NULL; - double lng0, lat0, lng1, lat1, x, y, d; - POP1(value); - lng0 = GEO_INT2RAD(GRN_INT32_VALUE(value)); - POP1(value); - lat0 = GEO_INT2RAD(GRN_INT32_VALUE(value)); - POP1(value); - lng1 = GEO_INT2RAD(GRN_INT32_VALUE(value)); - POP1(value); - lat1 = GEO_INT2RAD(GRN_INT32_VALUE(value)); - POP1ALLOC1(value, res); - x = (lng1 - lng0) * cos((lat0 + lat1) * 0.5); - y = (lat1 - lat0); - d = sqrt((x * x) + (y * y)) * GEO_RADIOUS; - switch (value->header.domain) { - case GRN_DB_INT32 : - r = d <= GRN_INT32_VALUE(value); - break; - case GRN_DB_FLOAT : - r = d <= GRN_FLOAT_VALUE(value); - break; - default : - r = 0; - break; - } - GRN_INT32_SET(ctx, res, r); - res->header.type = GRN_BULK; - res->header.domain = GRN_DB_INT32; - } - code++; - break; - case GRN_OP_GEO_WITHINP6 : - { - int r; - grn_obj *value = NULL; - double lng0, lat0, lng1, lat1, lng2, lat2, x, y, d; - POP1(value); - lng0 = GEO_INT2RAD(GRN_INT32_VALUE(value)); - POP1(value); - lat0 = GEO_INT2RAD(GRN_INT32_VALUE(value)); - POP1(value); - lng1 = GEO_INT2RAD(GRN_INT32_VALUE(value)); - POP1(value); - lat1 = GEO_INT2RAD(GRN_INT32_VALUE(value)); - POP1(value); - lng2 = GEO_INT2RAD(GRN_INT32_VALUE(value)); - POP1ALLOC1(value, res); - lat2 = GEO_INT2RAD(GRN_INT32_VALUE(value)); - x = (lng1 - lng0) * cos((lat0 + lat1) * 0.5); - y = (lat1 - lat0); - d = (x * x) + (y * y); - x = (lng2 - lng1) * cos((lat1 + lat2) * 0.5); - y = (lat2 - lat1); - r = d <= (x * x) + (y * y); - GRN_INT32_SET(ctx, res, r); - res->header.type = GRN_BULK; - res->header.domain = GRN_DB_INT32; - } - code++; - break; - case GRN_OP_GEO_WITHINP8 : - { - int r; - grn_obj *value = NULL; - int64_t ln0, la0, ln1, la1, ln2, la2, ln3, la3; - POP1(value); - ln0 = GRN_INT32_VALUE(value); - POP1(value); - la0 = GRN_INT32_VALUE(value); - POP1(value); - ln1 = GRN_INT32_VALUE(value); - POP1(value); - la1 = GRN_INT32_VALUE(value); - POP1(value); - ln2 = GRN_INT32_VALUE(value); - POP1(value); - la2 = GRN_INT32_VALUE(value); - POP1(value); - ln3 = GRN_INT32_VALUE(value); - POP1ALLOC1(value, res); - la3 = GRN_INT32_VALUE(value); - r = ((ln2 <= ln0) && (ln0 <= ln3) && (la2 <= la0) && (la0 <= la3)); - GRN_INT32_SET(ctx, res, r); - res->header.type = GRN_BULK; - res->header.domain = GRN_DB_INT32; - } - code++; - break; - case GRN_OP_PLUS : - ARITHMETIC_BINARY_OPERATION_DISPATCH( - "+", - INTEGER_ARITHMETIC_OPERATION_PLUS, - INTEGER_ARITHMETIC_OPERATION_PLUS, - INTEGER_ARITHMETIC_OPERATION_PLUS, - INTEGER_ARITHMETIC_OPERATION_PLUS, - FLOAT_ARITHMETIC_OPERATION_PLUS, - ARITHMETIC_OPERATION_NO_CHECK, - ARITHMETIC_OPERATION_NO_CHECK, - { - if (x == res) { - grn_obj_cast(ctx, y, res, GRN_FALSE); - } else if (y == res) { - grn_obj buffer; - GRN_TEXT_INIT(&buffer, 0); - grn_obj_cast(ctx, x, &buffer, GRN_FALSE); - grn_obj_cast(ctx, y, &buffer, GRN_FALSE); - GRN_BULK_REWIND(res); - grn_obj_cast(ctx, &buffer, res, GRN_FALSE); - GRN_OBJ_FIN(ctx, &buffer); - } else { - GRN_BULK_REWIND(res); - grn_obj_cast(ctx, x, res, GRN_FALSE); - grn_obj_cast(ctx, y, res, GRN_FALSE); - } - } - ,); - break; - case GRN_OP_MINUS : - if (code->nargs == 1) { - ARITHMETIC_UNARY_OPERATION_DISPATCH( - INTEGER_UNARY_ARITHMETIC_OPERATION_MINUS, - FLOAT_UNARY_ARITHMETIC_OPERATION_MINUS, - ARITHMETIC_OPERATION_NO_CHECK, - ARITHMETIC_OPERATION_NO_CHECK, - { - long long int x_; - - res->header.type = GRN_BULK; - res->header.domain = GRN_DB_INT64; - - GRN_INT64_SET(ctx, res, 0); - grn_obj_cast(ctx, x, res, GRN_FALSE); - x_ = GRN_INT64_VALUE(res); - - GRN_INT64_SET(ctx, res, -x_); - } - ,); - } else { - ARITHMETIC_BINARY_OPERATION_DISPATCH( - "-", - INTEGER_ARITHMETIC_OPERATION_MINUS, - INTEGER_ARITHMETIC_OPERATION_MINUS, - INTEGER_ARITHMETIC_OPERATION_MINUS, - INTEGER_ARITHMETIC_OPERATION_MINUS, - FLOAT_ARITHMETIC_OPERATION_MINUS, - ARITHMETIC_OPERATION_NO_CHECK, - ARITHMETIC_OPERATION_NO_CHECK, - { - ERR(GRN_INVALID_ARGUMENT, - "\"string\" - \"string\" " - "isn't supported"); - goto exit; - } - ,); - } - break; - case GRN_OP_STAR : - ARITHMETIC_BINARY_OPERATION_DISPATCH( - "*", - INTEGER_ARITHMETIC_OPERATION_STAR, - INTEGER_ARITHMETIC_OPERATION_STAR, - INTEGER_ARITHMETIC_OPERATION_STAR, - INTEGER_ARITHMETIC_OPERATION_STAR, - FLOAT_ARITHMETIC_OPERATION_STAR, - ARITHMETIC_OPERATION_NO_CHECK, - ARITHMETIC_OPERATION_NO_CHECK, - { - ERR(GRN_INVALID_ARGUMENT, - "\"string\" * \"string\" " - "isn't supported"); - goto exit; - } - ,); - break; - case GRN_OP_SLASH : - DIVISION_OPERATION_DISPATCH( - SIGNED_INTEGER_DIVISION_OPERATION_SLASH, - UNSIGNED_INTEGER_DIVISION_OPERATION_SLASH, - FLOAT_DIVISION_OPERATION_SLASH, - { - ERR(GRN_INVALID_ARGUMENT, - "\"string\" / \"string\" " - "isn't supported"); - goto exit; - }); - break; - case GRN_OP_MOD : - DIVISION_OPERATION_DISPATCH( - SIGNED_INTEGER_DIVISION_OPERATION_MOD, - UNSIGNED_INTEGER_DIVISION_OPERATION_MOD, - FLOAT_DIVISION_OPERATION_MOD, - { - ERR(GRN_INVALID_ARGUMENT, - "\"string\" %% \"string\" " - "isn't supported"); - goto exit; - }); - break; - case GRN_OP_BITWISE_NOT : - ARITHMETIC_UNARY_OPERATION_DISPATCH( - INTEGER_UNARY_ARITHMETIC_OPERATION_BITWISE_NOT, - FLOAT_UNARY_ARITHMETIC_OPERATION_BITWISE_NOT, - ARITHMETIC_OPERATION_NO_CHECK, - ARITHMETIC_OPERATION_NO_CHECK, - TEXT_UNARY_ARITHMETIC_OPERATION(~),); - break; - case GRN_OP_BITWISE_OR : - ARITHMETIC_BINARY_OPERATION_DISPATCH( - "|", - INTEGER_ARITHMETIC_OPERATION_BITWISE_OR, - INTEGER_ARITHMETIC_OPERATION_BITWISE_OR, - INTEGER_ARITHMETIC_OPERATION_BITWISE_OR, - INTEGER_ARITHMETIC_OPERATION_BITWISE_OR, - FLOAT_ARITHMETIC_OPERATION_BITWISE_OR, - ARITHMETIC_OPERATION_NO_CHECK, - ARITHMETIC_OPERATION_NO_CHECK, - TEXT_ARITHMETIC_OPERATION(|),); - break; - case GRN_OP_BITWISE_XOR : - ARITHMETIC_BINARY_OPERATION_DISPATCH( - "^", - INTEGER_ARITHMETIC_OPERATION_BITWISE_XOR, - INTEGER_ARITHMETIC_OPERATION_BITWISE_XOR, - INTEGER_ARITHMETIC_OPERATION_BITWISE_XOR, - INTEGER_ARITHMETIC_OPERATION_BITWISE_XOR, - FLOAT_ARITHMETIC_OPERATION_BITWISE_XOR, - ARITHMETIC_OPERATION_NO_CHECK, - ARITHMETIC_OPERATION_NO_CHECK, - TEXT_ARITHMETIC_OPERATION(^),); - break; - case GRN_OP_BITWISE_AND : - ARITHMETIC_BINARY_OPERATION_DISPATCH( - "&", - INTEGER_ARITHMETIC_OPERATION_BITWISE_AND, - INTEGER_ARITHMETIC_OPERATION_BITWISE_AND, - INTEGER_ARITHMETIC_OPERATION_BITWISE_AND, - INTEGER_ARITHMETIC_OPERATION_BITWISE_AND, - FLOAT_ARITHMETIC_OPERATION_BITWISE_AND, - ARITHMETIC_OPERATION_NO_CHECK, - ARITHMETIC_OPERATION_NO_CHECK, - TEXT_ARITHMETIC_OPERATION(&),); - break; - case GRN_OP_SHIFTL : - ARITHMETIC_BINARY_OPERATION_DISPATCH( - "<<", - INTEGER_ARITHMETIC_OPERATION_SHIFTL, - INTEGER_ARITHMETIC_OPERATION_SHIFTL, - INTEGER_ARITHMETIC_OPERATION_SHIFTL, - INTEGER_ARITHMETIC_OPERATION_SHIFTL, - FLOAT_ARITHMETIC_OPERATION_SHIFTL, - ARITHMETIC_OPERATION_NO_CHECK, - ARITHMETIC_OPERATION_NO_CHECK, - TEXT_ARITHMETIC_OPERATION(<<),); - break; - case GRN_OP_SHIFTR : - ARITHMETIC_BINARY_OPERATION_DISPATCH( - ">>", - INTEGER_ARITHMETIC_OPERATION_SHIFTR, - INTEGER_ARITHMETIC_OPERATION_SHIFTR, - INTEGER_ARITHMETIC_OPERATION_SHIFTR, - INTEGER_ARITHMETIC_OPERATION_SHIFTR, - FLOAT_ARITHMETIC_OPERATION_SHIFTR, - ARITHMETIC_OPERATION_NO_CHECK, - ARITHMETIC_OPERATION_NO_CHECK, - TEXT_ARITHMETIC_OPERATION(>>),); - break; - case GRN_OP_SHIFTRR : - ARITHMETIC_BINARY_OPERATION_DISPATCH( - ">>>", - INTEGER8_ARITHMETIC_OPERATION_SHIFTRR, - INTEGER16_ARITHMETIC_OPERATION_SHIFTRR, - INTEGER32_ARITHMETIC_OPERATION_SHIFTRR, - INTEGER64_ARITHMETIC_OPERATION_SHIFTRR, - FLOAT_ARITHMETIC_OPERATION_SHIFTRR, - ARITHMETIC_OPERATION_NO_CHECK, - ARITHMETIC_OPERATION_NO_CHECK, - { - long long unsigned int x_; - long long unsigned int y_; - - res->header.type = GRN_BULK; - res->header.domain = GRN_DB_INT64; - - GRN_INT64_SET(ctx, res, 0); - grn_obj_cast(ctx, x, res, GRN_FALSE); - x_ = GRN_INT64_VALUE(res); - - GRN_INT64_SET(ctx, res, 0); - grn_obj_cast(ctx, y, res, GRN_FALSE); - y_ = GRN_INT64_VALUE(res); - - GRN_INT64_SET(ctx, res, x_ >> y_); - } - ,); - break; - case GRN_OP_INCR : - UNARY_OPERATE_AND_ASSIGN_DISPATCH(EXEC_OPERATE, 1, GRN_OBJ_INCR); - break; - case GRN_OP_DECR : - UNARY_OPERATE_AND_ASSIGN_DISPATCH(EXEC_OPERATE, 1, GRN_OBJ_DECR); - break; - case GRN_OP_INCR_POST : - UNARY_OPERATE_AND_ASSIGN_DISPATCH(EXEC_OPERATE_POST, 1, GRN_OBJ_INCR); - break; - case GRN_OP_DECR_POST : - UNARY_OPERATE_AND_ASSIGN_DISPATCH(EXEC_OPERATE_POST, 1, GRN_OBJ_DECR); - break; - case GRN_OP_NOT : - { - grn_obj *value = NULL; - grn_bool value_boolean; - POP1ALLOC1(value, res); - GRN_OBJ_IS_TRUE(ctx, value, value_boolean); - grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0); - GRN_BOOL_SET(ctx, res, !value_boolean); - } - code++; - break; - case GRN_OP_GET_MEMBER : - { - grn_obj *receiver = NULL; - grn_obj *index_or_key = NULL; - POP2ALLOC1(receiver, index_or_key, res); - if (receiver->header.type == GRN_PTR) { - grn_obj *index = index_or_key; - grn_expr_exec_get_member_vector(ctx, expr, receiver, index, res); - } else { - grn_obj *key = index_or_key; - grn_expr_exec_get_member_table(ctx, expr, receiver, key, res); - } - code++; - } - break; - case GRN_OP_REGEXP : - { - grn_obj *target = NULL; - grn_obj *pattern = NULL; - grn_bool matched; - POP1(pattern); - POP1(target); - WITH_SPSAVE({ - matched = grn_operator_exec_regexp(ctx, target, pattern); - }); - ALLOC1(res); - grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0); - GRN_BOOL_SET(ctx, res, matched); - } - code++; - break; - default : - ERR(GRN_FUNCTION_NOT_IMPLEMENTED, "not implemented operator assigned"); + grn_expr_executor *executor = &(e->cache.executor); + grn_id id; + + if (e->codes != e->cache.codes || + e->codes_curr != e->cache.codes_curr) { + if (e->cache.codes) { + grn_expr_executor_fin(ctx, executor); + } + grn_expr_executor_init(ctx, executor, expr); + if (ctx->rc != GRN_SUCCESS) { + e->cache.codes = NULL; + e->cache.codes_curr = 0; goto exit; - break; } + e->cache.codes = e->codes; + e->cache.codes_curr = e->codes_curr; } - ctx->impl->stack_curr = sp - s_; - } - if (ctx->impl->stack_curr + nargs > stack_curr) { - val = grn_ctx_pop(ctx); + + id = GRN_RECORD_VALUE(executor->variable); + value = grn_expr_executor_exec(ctx, executor, id); } exit : - if (ctx->impl->stack_curr + nargs > stack_curr) { - /* - GRN_LOG(ctx, GRN_LOG_WARNING, "nargs=%d stack balance=%d", - nargs, stack_curr - ctx->impl->stack_curr); - */ - ctx->impl->stack_curr = stack_curr - nargs; - } - GRN_API_RETURN(val); + GRN_API_RETURN(value); } grn_obj * Modified: lib/expr_executor.c (+2376 -3) =================================================================== --- lib/expr_executor.c 2018-05-21 18:11:51 +0900 (145fc0669) +++ lib/expr_executor.c 2018-05-21 20:51:06 +0900 (7dda9d303) @@ -18,6 +18,8 @@ #include "grn.h" #include "grn_ctx_impl.h" +#include "grn_expr.h" +#include "grn_expr_code.h" #include "grn_expr_executor.h" #ifdef GRN_WITH_ONIGMO @@ -29,19 +31,2392 @@ # include <onigmo.h> #endif +#include <math.h> + static void grn_expr_executor_init_general(grn_ctx *ctx, grn_expr_executor *executor) { } +#define EXPRVP(x) ((x)->header.impl_flags & GRN_OBJ_EXPRVALUE) + +#define WITH_SPSAVE(block) do {\ + ctx->impl->stack_curr = sp - ctx->impl->stack;\ + e->values_curr = vp - e->values;\ + block\ + vp = e->values + e->values_curr;\ + sp = ctx->impl->stack + ctx->impl->stack_curr;\ + s_ = ctx->impl->stack;\ + s0 = (sp > s_) ? sp[-1] : NULL;\ + s1 = (sp > s_ + 1) ? sp[-2] : NULL;\ +} while (0) + +#define GEO_RESOLUTION 3600000 +#define GEO_RADIOUS 6357303 +#define GEO_BES_C1 6334834 +#define GEO_BES_C2 6377397 +#define GEO_BES_C3 0.006674 +#define GEO_GRS_C1 6335439 +#define GEO_GRS_C2 6378137 +#define GEO_GRS_C3 0.006694 +#define GEO_INT2RAD(x) ((M_PI * x) / (GEO_RESOLUTION * 180)) + +#define VAR_SET_VALUE(ctx,var,value) do {\ + if (GRN_DB_OBJP(value)) {\ + (var)->header.type = GRN_PTR;\ + (var)->header.domain = DB_OBJ(value)->id;\ + GRN_PTR_SET(ctx, (var), (value));\ + } else {\ + (var)->header.type = (value)->header.type;\ + (var)->header.domain = (value)->header.domain;\ + GRN_TEXT_SET(ctx, (var), GRN_TEXT_VALUE(value), GRN_TEXT_LEN(value));\ + }\ +} while (0) + +#define PUSH1(v) do {\ + if (EXPRVP(v)) {\ + vp++;\ + if (vp - e->values > e->values_tail) { e->values_tail = vp - e->values; }\ + }\ + s1 = s0;\ + if (sp >= s_ + ctx->impl->stack_size) {\ + if (grn_ctx_expand_stack(ctx) != GRN_SUCCESS) {\ + goto exit;\ + }\ + sp += (ctx->impl->stack - s_);\ + s_ = ctx->impl->stack;\ + }\ + *sp++ = s0 = v;\ +} while (0) + +#define POP1(v) do {\ + if (EXPRVP(s0)) { vp--; }\ + v = s0;\ + s0 = s1;\ + sp--;\ + if (sp < s_) { ERR(GRN_INVALID_ARGUMENT, "stack underflow"); goto exit; }\ + s1 = (sp > s_ - 1) ? sp[-2] : NULL;\ +} while (0) + +#define ALLOC1(value) do {\ + s1 = s0;\ + if (sp >= s_ + ctx->impl->stack_size) {\ + if (grn_ctx_expand_stack(ctx) != GRN_SUCCESS) {\ + goto exit;\ + }\ + sp += (ctx->impl->stack - s_);\ + s_ = ctx->impl->stack;\ + }\ + *sp++ = s0 = value = vp++;\ + if (vp - e->values > e->values_tail) { e->values_tail = vp - e->values; }\ +} while (0) + +#define POP1ALLOC1(arg,value) do {\ + arg = s0;\ + if (EXPRVP(s0)) {\ + value = s0;\ + } else {\ + if (sp < s_ + 1) { ERR(GRN_INVALID_ARGUMENT, "stack underflow"); goto exit; }\ + sp[-1] = s0 = value = vp++;\ + if (vp - e->values > e->values_tail) { e->values_tail = vp - e->values; }\ + s0->header.impl_flags |= GRN_OBJ_EXPRVALUE;\ + }\ +} while (0) + +#define POP2ALLOC1(arg1,arg2,value) do {\ + if (EXPRVP(s0)) { vp--; }\ + if (EXPRVP(s1)) { vp--; }\ + arg2 = s0;\ + arg1 = s1;\ + sp--;\ + if (sp < s_ + 1) { ERR(GRN_INVALID_ARGUMENT, "stack underflow"); goto exit; }\ + s1 = (sp > s_ + 1) ? sp[-2] : NULL;\ + sp[-1] = s0 = value = vp++;\ + if (vp - e->values > e->values_tail) { e->values_tail = vp - e->values; }\ + s0->header.impl_flags |= GRN_OBJ_EXPRVALUE;\ +} while (0) + +#define INTEGER_ARITHMETIC_OPERATION_PLUS(x, y) ((x) + (y)) +#define FLOAT_ARITHMETIC_OPERATION_PLUS(x, y) ((double)(x) + (double)(y)) +#define INTEGER_ARITHMETIC_OPERATION_MINUS(x, y) ((x) - (y)) +#define FLOAT_ARITHMETIC_OPERATION_MINUS(x, y) ((double)(x) - (double)(y)) +#define INTEGER_ARITHMETIC_OPERATION_STAR(x, y) ((x) * (y)) +#define FLOAT_ARITHMETIC_OPERATION_STAR(x, y) ((double)(x) * (double)(y)) +#define INTEGER_ARITHMETIC_OPERATION_SLASH(x, y) ((x) / (y)) +#define FLOAT_ARITHMETIC_OPERATION_SLASH(x, y) ((double)(x) / (double)(y)) +#define INTEGER_ARITHMETIC_OPERATION_MOD(x, y) ((x) % (y)) +#define FLOAT_ARITHMETIC_OPERATION_MOD(x, y) (fmod((x), (y))) +#define INTEGER_ARITHMETIC_OPERATION_SHIFTL(x, y) ((x) << (y)) +#define FLOAT_ARITHMETIC_OPERATION_SHIFTL(x, y) \ + ((long long int)(x) << (long long int)(y)) +#define INTEGER_ARITHMETIC_OPERATION_SHIFTR(x, y) ((x) >> (y)) +#define FLOAT_ARITHMETIC_OPERATION_SHIFTR(x, y) \ + ((long long int)(x) >> (long long int)(y)) +#define INTEGER8_ARITHMETIC_OPERATION_SHIFTRR(x, y) \ + ((uint8_t)(x) >> (y)) +#define INTEGER16_ARITHMETIC_OPERATION_SHIFTRR(x, y) \ + ((uint16_t)(x) >> (y)) +#define INTEGER32_ARITHMETIC_OPERATION_SHIFTRR(x, y) \ + ((unsigned int)(x) >> (y)) +#define INTEGER64_ARITHMETIC_OPERATION_SHIFTRR(x, y) \ + ((long long unsigned int)(x) >> (y)) +#define FLOAT_ARITHMETIC_OPERATION_SHIFTRR(x, y) \ + ((long long unsigned int)(x) >> (long long unsigned int)(y)) + +#define INTEGER_ARITHMETIC_OPERATION_BITWISE_OR(x, y) ((x) | (y)) +#define FLOAT_ARITHMETIC_OPERATION_BITWISE_OR(x, y) \ + ((long long int)(x) | (long long int)(y)) +#define INTEGER_ARITHMETIC_OPERATION_BITWISE_XOR(x, y) ((x) ^ (y)) +#define FLOAT_ARITHMETIC_OPERATION_BITWISE_XOR(x, y) \ + ((long long int)(x) ^ (long long int)(y)) +#define INTEGER_ARITHMETIC_OPERATION_BITWISE_AND(x, y) ((x) & (y)) +#define FLOAT_ARITHMETIC_OPERATION_BITWISE_AND(x, y) \ + ((long long int)(x) & (long long int)(y)) + +#define INTEGER_UNARY_ARITHMETIC_OPERATION_MINUS(x) (-(x)) +#define FLOAT_UNARY_ARITHMETIC_OPERATION_MINUS(x) (-(x)) +#define INTEGER_UNARY_ARITHMETIC_OPERATION_BITWISE_NOT(x) (~(x)) +#define FLOAT_UNARY_ARITHMETIC_OPERATION_BITWISE_NOT(x) \ + (~((long long int)(x))) + +#define TEXT_ARITHMETIC_OPERATION(operator) do { \ + long long int x_; \ + long long int y_; \ + \ + res->header.domain = GRN_DB_INT64; \ + \ + GRN_INT64_SET(ctx, res, 0); \ + grn_obj_cast(ctx, x, res, GRN_FALSE); \ + x_ = GRN_INT64_VALUE(res); \ + \ + GRN_INT64_SET(ctx, res, 0); \ + grn_obj_cast(ctx, y, res, GRN_FALSE); \ + y_ = GRN_INT64_VALUE(res); \ + \ + GRN_INT64_SET(ctx, res, x_ operator y_); \ +} while (0) + +#define TEXT_UNARY_ARITHMETIC_OPERATION(unary_operator) do { \ + long long int x_; \ + \ + res->header.domain = GRN_DB_INT64; \ + \ + GRN_INT64_SET(ctx, res, 0); \ + grn_obj_cast(ctx, x, res, GRN_FALSE); \ + x_ = GRN_INT64_VALUE(res); \ + \ + GRN_INT64_SET(ctx, res, unary_operator x_); \ +} while (0) + +#define ARITHMETIC_OPERATION_NO_CHECK(y) do {} while (0) +#define ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y) do { \ + if ((long long int)y == 0) { \ + ERR(GRN_INVALID_ARGUMENT, "divisor should not be 0"); \ + goto exit; \ + } \ +} while (0) + + +#define NUMERIC_ARITHMETIC_OPERATION_DISPATCH(set, get, x_, y, res, \ + integer_operation, \ + float_operation, \ + right_expression_check, \ + invalid_type_error) do { \ + switch (y->header.domain) { \ + case GRN_DB_INT8 : \ + { \ + int8_t y_; \ + y_ = GRN_INT8_VALUE(y); \ + right_expression_check(y_); \ + set(ctx, res, integer_operation(x_, y_)); \ + } \ + break; \ + case GRN_DB_UINT8 : \ + { \ + uint8_t y_; \ + y_ = GRN_UINT8_VALUE(y); \ + right_expression_check(y_); \ + set(ctx, res, integer_operation(x_, y_)); \ + } \ + break; \ + case GRN_DB_INT16 : \ + { \ + int16_t y_; \ + y_ = GRN_INT16_VALUE(y); \ + right_expression_check(y_); \ + set(ctx, res, integer_operation(x_, y_)); \ + } \ + break; \ + case GRN_DB_UINT16 : \ + { \ + uint16_t y_; \ + y_ = GRN_UINT16_VALUE(y); \ + right_expression_check(y_); \ + set(ctx, res, integer_operation(x_, y_)); \ + } \ + break; \ + case GRN_DB_INT32 : \ + { \ + int y_; \ + y_ = GRN_INT32_VALUE(y); \ + right_expression_check(y_); \ + set(ctx, res, integer_operation(x_, y_)); \ + } \ + break; \ + case GRN_DB_UINT32 : \ + { \ + unsigned int y_; \ + y_ = GRN_UINT32_VALUE(y); \ + right_expression_check(y_); \ + set(ctx, res, integer_operation(x_, y_)); \ + } \ + break; \ + case GRN_DB_TIME : \ + { \ + long long int y_; \ + y_ = GRN_TIME_VALUE(y); \ + right_expression_check(y_); \ + set(ctx, res, integer_operation(x_, y_)); \ + } \ + break; \ + case GRN_DB_INT64 : \ + { \ + long long int y_; \ + y_ = GRN_INT64_VALUE(y); \ + right_expression_check(y_); \ + set(ctx, res, integer_operation(x_, y_)); \ + } \ + break; \ + case GRN_DB_UINT64 : \ + { \ + long long unsigned int y_; \ + y_ = GRN_UINT64_VALUE(y); \ + right_expression_check(y_); \ + set(ctx, res, integer_operation(x_, y_)); \ + } \ + break; \ + case GRN_DB_FLOAT : \ + { \ + double y_; \ + y_ = GRN_FLOAT_VALUE(y); \ + right_expression_check(y_); \ + res->header.domain = GRN_DB_FLOAT; \ + GRN_FLOAT_SET(ctx, res, float_operation(x_, y_)); \ + } \ + break; \ + case GRN_DB_SHORT_TEXT : \ + case GRN_DB_TEXT : \ + case GRN_DB_LONG_TEXT : \ + set(ctx, res, 0); \ + if (grn_obj_cast(ctx, y, res, GRN_FALSE)) { \ + ERR(GRN_INVALID_ARGUMENT, \ + "not a numerical format: <%.*s>", \ + (int)GRN_TEXT_LEN(y), GRN_TEXT_VALUE(y)); \ + goto exit; \ + } \ + set(ctx, res, integer_operation(x_, get(res))); \ + break; \ + default : \ + invalid_type_error; \ + break; \ + } \ +} while (0) + + +#define ARITHMETIC_OPERATION_DISPATCH(x, y, res, \ + integer8_operation, \ + integer16_operation, \ + integer32_operation, \ + integer64_operation, \ + float_operation, \ + left_expression_check, \ + right_expression_check, \ + text_operation, \ + invalid_type_error) do { \ + switch (x->header.domain) { \ + case GRN_DB_INT8 : \ + { \ + int8_t x_; \ + x_ = GRN_INT8_VALUE(x); \ + left_expression_check(x_); \ + NUMERIC_ARITHMETIC_OPERATION_DISPATCH(GRN_INT8_SET, \ + GRN_INT8_VALUE, \ + x_, y, res, \ + integer8_operation, \ + float_operation, \ + right_expression_check, \ + invalid_type_error); \ + } \ + break; \ + case GRN_DB_UINT8 : \ + { \ + uint8_t x_; \ + x_ = GRN_UINT8_VALUE(x); \ + left_expression_check(x_); \ + NUMERIC_ARITHMETIC_OPERATION_DISPATCH(GRN_UINT8_SET, \ + GRN_UINT8_VALUE, \ + x_, y, res, \ + integer8_operation, \ + float_operation, \ + right_expression_check, \ + invalid_type_error); \ + } \ + break; \ + case GRN_DB_INT16 : \ + { \ + int16_t x_; \ + x_ = GRN_INT16_VALUE(x); \ + left_expression_check(x_); \ + NUMERIC_ARITHMETIC_OPERATION_DISPATCH(GRN_INT16_SET, \ + GRN_INT16_VALUE, \ + x_, y, res, \ + integer16_operation, \ + float_operation, \ + right_expression_check, \ + invalid_type_error); \ + } \ + break; \ + case GRN_DB_UINT16 : \ + { \ + uint16_t x_; \ + x_ = GRN_UINT16_VALUE(x); \ + left_expression_check(x_); \ + NUMERIC_ARITHMETIC_OPERATION_DISPATCH(GRN_UINT16_SET, \ + GRN_UINT16_VALUE, \ + x_, y, res, \ + integer16_operation, \ + float_operation, \ + right_expression_check, \ + invalid_type_error); \ + } \ + break; \ + case GRN_DB_INT32 : \ + { \ + int x_; \ + x_ = GRN_INT32_VALUE(x); \ + left_expression_check(x_); \ + NUMERIC_ARITHMETIC_OPERATION_DISPATCH(GRN_INT32_SET, \ + GRN_INT32_VALUE, \ + x_, y, res, \ + integer32_operation, \ + float_operation, \ + right_expression_check, \ + invalid_type_error); \ + } \ + break; \ + case GRN_DB_UINT32 : \ + { \ + unsigned int x_; \ + x_ = GRN_UINT32_VALUE(x); \ + left_expression_check(x_); \ + NUMERIC_ARITHMETIC_OPERATION_DISPATCH(GRN_UINT32_SET, \ + GRN_UINT32_VALUE, \ + x_, y, res, \ + integer32_operation, \ + float_operation, \ + right_expression_check, \ + invalid_type_error); \ + } \ + break; \ + case GRN_DB_INT64 : \ + { \ + long long int x_; \ + x_ = GRN_INT64_VALUE(x); \ + left_expression_check(x_); \ + NUMERIC_ARITHMETIC_OPERATION_DISPATCH(GRN_INT64_SET, \ + GRN_INT64_VALUE, \ + x_, y, res, \ + integer64_operation, \ + float_operation, \ + right_expression_check, \ + invalid_type_error); \ + } \ + break; \ + case GRN_DB_TIME : \ + { \ + long long int x_; \ + x_ = GRN_TIME_VALUE(x); \ + left_expression_check(x_); \ + NUMERIC_ARITHMETIC_OPERATION_DISPATCH(GRN_TIME_SET, \ + GRN_TIME_VALUE, \ + x_, y, res, \ + integer64_operation, \ + float_operation, \ + right_expression_check, \ + invalid_type_error); \ + } \ + break; \ + case GRN_DB_UINT64 : \ + { \ + long long unsigned int x_; \ + x_ = GRN_UINT64_VALUE(x); \ + left_expression_check(x_); \ + NUMERIC_ARITHMETIC_OPERATION_DISPATCH(GRN_UINT64_SET, \ + GRN_UINT64_VALUE, \ + x_, y, res, \ + integer64_operation, \ + float_operation, \ + right_expression_check, \ + invalid_type_error); \ + } \ + break; \ + case GRN_DB_FLOAT : \ + { \ + double x_; \ + x_ = GRN_FLOAT_VALUE(x); \ + left_expression_check(x_); \ + NUMERIC_ARITHMETIC_OPERATION_DISPATCH(GRN_FLOAT_SET, \ + GRN_FLOAT_VALUE, \ + x_, y, res, \ + float_operation, \ + float_operation, \ + right_expression_check, \ + invalid_type_error); \ + } \ + break; \ + case GRN_DB_SHORT_TEXT : \ + case GRN_DB_TEXT : \ + case GRN_DB_LONG_TEXT : \ + text_operation; \ + break; \ + default: \ + invalid_type_error; \ + break; \ + } \ + code++; \ +} while (0) + +#define ARITHMETIC_BINARY_OPERATION_DISPATCH(operator, \ + integer8_operation, \ + integer16_operation, \ + integer32_operation, \ + integer64_operation, \ + float_operation, \ + left_expression_check, \ + right_expression_check, \ + text_operation, \ + invalid_type_error) do { \ + grn_obj *x = NULL; \ + grn_obj *y = NULL; \ + \ + POP2ALLOC1(x, y, res); \ + if (x->header.type == GRN_VECTOR || y->header.type == GRN_VECTOR) { \ + grn_obj inspected_x; \ + grn_obj inspected_y; \ + GRN_TEXT_INIT(&inspected_x, 0); \ + GRN_TEXT_INIT(&inspected_y, 0); \ + grn_inspect(ctx, &inspected_x, x); \ + grn_inspect(ctx, &inspected_y, y); \ + ERR(GRN_INVALID_ARGUMENT, \ + "<%s> doesn't support vector: <%.*s> %s <%.*s>", \ + operator, \ + (int)GRN_TEXT_LEN(&inspected_x), GRN_TEXT_VALUE(&inspected_x), \ + operator, \ + (int)GRN_TEXT_LEN(&inspected_y), GRN_TEXT_VALUE(&inspected_y)); \ + GRN_OBJ_FIN(ctx, &inspected_x); \ + GRN_OBJ_FIN(ctx, &inspected_y); \ + goto exit; \ + } \ + if (y != res) { \ + res->header.domain = x->header.domain; \ + } \ + ARITHMETIC_OPERATION_DISPATCH(x, y, res, \ + integer8_operation, \ + integer16_operation, \ + integer32_operation, \ + integer64_operation, \ + float_operation, \ + left_expression_check, \ + right_expression_check, \ + text_operation, \ + invalid_type_error); \ + if (y == res) { \ + res->header.domain = x->header.domain; \ + } \ +} while (0) + +#define SIGNED_INTEGER_DIVISION_OPERATION_SLASH(x, y) \ + ((y == -1) ? -(x) : (x) / (y)) +#define UNSIGNED_INTEGER_DIVISION_OPERATION_SLASH(x, y) ((x) / (y)) +#define FLOAT_DIVISION_OPERATION_SLASH(x, y) ((double)(x) / (double)(y)) +#define SIGNED_INTEGER_DIVISION_OPERATION_MOD(x, y) ((y == -1) ? 0 : (x) % (y)) +#define UNSIGNED_INTEGER_DIVISION_OPERATION_MOD(x, y) ((x) % (y)) +#define FLOAT_DIVISION_OPERATION_MOD(x, y) (fmod((x), (y))) + +#define DIVISION_OPERATION_DISPATCH_RIGHT(set, get, x_, y, res, \ + signed_integer_operation, \ + unsigned_integer_operation, \ + float_operation) do { \ + switch (y->header.domain) { \ + case GRN_DB_INT8 : \ + { \ + int y_; \ + y_ = GRN_INT8_VALUE(y); \ + ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_); \ + set(ctx, res, signed_integer_operation(x_, y_)); \ + } \ + break; \ + case GRN_DB_UINT8 : \ + { \ + int y_; \ + y_ = GRN_UINT8_VALUE(y); \ + ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_); \ + set(ctx, res, unsigned_integer_operation(x_, y_)); \ + } \ + break; \ + case GRN_DB_INT16 : \ + { \ + int y_; \ + y_ = GRN_INT16_VALUE(y); \ + ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_); \ + set(ctx, res, signed_integer_operation(x_, y_)); \ + } \ + break; \ + case GRN_DB_UINT16 : \ + { \ + int y_; \ + y_ = GRN_UINT16_VALUE(y); \ + ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_); \ + set(ctx, res, unsigned_integer_operation(x_, y_)); \ + } \ + break; \ + case GRN_DB_INT32 : \ + { \ + int y_; \ + y_ = GRN_INT32_VALUE(y); \ + ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_); \ + set(ctx, res, signed_integer_operation(x_, y_)); \ + } \ + break; \ + case GRN_DB_UINT32 : \ + { \ + unsigned int y_; \ + y_ = GRN_UINT32_VALUE(y); \ + ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_); \ + set(ctx, res, unsigned_integer_operation(x_, y_)); \ + } \ + break; \ + case GRN_DB_TIME : \ + { \ + long long int y_; \ + y_ = GRN_TIME_VALUE(y); \ + ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_); \ + set(ctx, res, signed_integer_operation(x_, y_)); \ + } \ + break; \ + case GRN_DB_INT64 : \ + { \ + long long int y_; \ + y_ = GRN_INT64_VALUE(y); \ + ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_); \ + set(ctx, res, signed_integer_operation(x_, y_)); \ + } \ + break; \ + case GRN_DB_UINT64 : \ + { \ + long long unsigned int y_; \ + y_ = GRN_UINT64_VALUE(y); \ + ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_); \ + set(ctx, res, unsigned_integer_operation(x_, y_)); \ + } \ + break; \ + case GRN_DB_FLOAT : \ + { \ + double y_; \ + y_ = GRN_FLOAT_VALUE(y); \ + ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_); \ + res->header.domain = GRN_DB_FLOAT; \ + GRN_FLOAT_SET(ctx, res, float_operation(x_, y_)); \ + } \ + break; \ + case GRN_DB_SHORT_TEXT : \ + case GRN_DB_TEXT : \ + case GRN_DB_LONG_TEXT : \ + set(ctx, res, 0); \ + if (grn_obj_cast(ctx, y, res, GRN_FALSE)) { \ + ERR(GRN_INVALID_ARGUMENT, \ + "not a numerical format: <%.*s>", \ + (int)GRN_TEXT_LEN(y), GRN_TEXT_VALUE(y)); \ + goto exit; \ + } \ + /* The following "+ 0" is needed to suppress warnings that say */ \ + /* comparison is always false due to limited range of data type */ \ + set(ctx, res, signed_integer_operation(x_, (get(res) + 0))); \ + break; \ + default : \ + break; \ + } \ +} while (0) + +#define DIVISION_OPERATION_DISPATCH_LEFT(x, y, res, \ + signed_integer_operation, \ + unsigned_integer_operation, \ + float_operation, \ + invalid_type_error) do { \ + switch (x->header.domain) { \ + case GRN_DB_INT8 : \ + { \ + int x_; \ + x_ = GRN_INT8_VALUE(x); \ + DIVISION_OPERATION_DISPATCH_RIGHT(GRN_INT8_SET, \ + GRN_INT8_VALUE, \ + x_, y, res, \ + signed_integer_operation, \ + unsigned_integer_operation, \ + float_operation); \ + } \ + break; \ + case GRN_DB_UINT8 : \ + { \ + int x_; \ + x_ = GRN_UINT8_VALUE(x); \ + DIVISION_OPERATION_DISPATCH_RIGHT(GRN_UINT8_SET, \ + (int)GRN_UINT8_VALUE, \ + x_, y, res, \ + signed_integer_operation, \ + unsigned_integer_operation, \ + float_operation); \ + } \ + break; \ + case GRN_DB_INT16 : \ + { \ + int x_; \ + x_ = GRN_INT16_VALUE(x); \ + DIVISION_OPERATION_DISPATCH_RIGHT(GRN_INT16_SET, \ + GRN_INT16_VALUE, \ + x_, y, res, \ + signed_integer_operation, \ + unsigned_integer_operation, \ + float_operation); \ + } \ + break; \ + case GRN_DB_UINT16 : \ + { \ + int x_; \ + x_ = GRN_UINT16_VALUE(x); \ + DIVISION_OPERATION_DISPATCH_RIGHT(GRN_UINT16_SET, \ + (int)GRN_UINT16_VALUE, \ + x_, y, res, \ + signed_integer_operation, \ + unsigned_integer_operation, \ + float_operation); \ + } \ + break; \ + case GRN_DB_INT32 : \ + { \ + int x_; \ + x_ = GRN_INT32_VALUE(x); \ + DIVISION_OPERATION_DISPATCH_RIGHT(GRN_INT32_SET, \ + GRN_INT32_VALUE, \ + x_, y, res, \ + signed_integer_operation, \ + unsigned_integer_operation, \ + float_operation); \ + } \ + break; \ + case GRN_DB_UINT32 : \ + { \ + unsigned int x_; \ + x_ = GRN_UINT32_VALUE(x); \ + DIVISION_OPERATION_DISPATCH_RIGHT(GRN_UINT32_SET, \ + GRN_UINT32_VALUE, \ + x_, y, res, \ + unsigned_integer_operation, \ + unsigned_integer_operation, \ + float_operation); \ + } \ + break; \ + case GRN_DB_INT64 : \ + { \ + long long int x_; \ + x_ = GRN_INT64_VALUE(x); \ + DIVISION_OPERATION_DISPATCH_RIGHT(GRN_INT64_SET, \ + GRN_INT64_VALUE, \ + x_, y, res, \ + signed_integer_operation, \ + unsigned_integer_operation, \ + float_operation); \ + } \ + break; \ + case GRN_DB_TIME : \ + { \ + long long int x_; \ + x_ = GRN_TIME_VALUE(x); \ + DIVISION_OPERATION_DISPATCH_RIGHT(GRN_TIME_SET, \ + GRN_TIME_VALUE, \ + x_, y, res, \ + signed_integer_operation, \ + unsigned_integer_operation, \ + float_operation); \ + } \ + break; \ + case GRN_DB_UINT64 : \ + { \ + long long unsigned int x_; \ + x_ = GRN_UINT64_VALUE(x); \ + DIVISION_OPERATION_DISPATCH_RIGHT(GRN_UINT64_SET, \ + GRN_UINT64_VALUE, \ + x_, y, res, \ + unsigned_integer_operation, \ + unsigned_integer_operation, \ + float_operation); \ + } \ + break; \ + case GRN_DB_FLOAT : \ + { \ + double x_; \ + x_ = GRN_FLOAT_VALUE(x); \ + DIVISION_OPERATION_DISPATCH_RIGHT(GRN_FLOAT_SET, \ + GRN_FLOAT_VALUE, \ + x_, y, res, \ + float_operation, \ + float_operation, \ + float_operation); \ + } \ + break; \ + case GRN_DB_SHORT_TEXT : \ + case GRN_DB_TEXT : \ + case GRN_DB_LONG_TEXT : \ + invalid_type_error; \ + break; \ + default: \ + break; \ + } \ + code++; \ +} while (0) + +#define DIVISION_OPERATION_DISPATCH(signed_integer_operation, \ + unsigned_integer_operation, \ + float_operation, \ + invalid_type_error) do { \ + grn_obj *x = NULL; \ + grn_obj *y = NULL; \ + \ + POP2ALLOC1(x, y, res); \ + if (y != res) { \ + res->header.domain = x->header.domain; \ + } \ + DIVISION_OPERATION_DISPATCH_LEFT(x, y, res, \ + signed_integer_operation, \ + unsigned_integer_operation, \ + float_operation, \ + invalid_type_error); \ + if (y == res) { \ + res->header.domain = x->header.domain; \ + } \ +} while (0) + +#define ARITHMETIC_UNARY_OPERATION_DISPATCH(integer_operation, \ + float_operation, \ + left_expression_check, \ + right_expression_check, \ + text_operation, \ + invalid_type_error) do { \ + grn_obj *x = NULL; \ + POP1ALLOC1(x, res); \ + res->header.domain = x->header.domain; \ + switch (x->header.domain) { \ + case GRN_DB_INT8 : \ + { \ + int8_t x_; \ + x_ = GRN_INT8_VALUE(x); \ + left_expression_check(x_); \ + GRN_INT8_SET(ctx, res, integer_operation(x_)); \ + } \ + break; \ + case GRN_DB_UINT8 : \ + { \ + int16_t x_; \ + x_ = GRN_UINT8_VALUE(x); \ + left_expression_check(x_); \ + GRN_INT16_SET(ctx, res, integer_operation(x_)); \ + res->header.domain = GRN_DB_INT16; \ + } \ + break; \ + case GRN_DB_INT16 : \ + { \ + int16_t x_; \ + x_ = GRN_INT16_VALUE(x); \ + left_expression_check(x_); \ + GRN_INT16_SET(ctx, res, integer_operation(x_)); \ + } \ + break; \ + case GRN_DB_UINT16 : \ + { \ + int x_; \ + x_ = GRN_UINT16_VALUE(x); \ + left_expression_check(x_); \ + GRN_INT32_SET(ctx, res, integer_operation(x_)); \ + res->header.domain = GRN_DB_INT32; \ + } \ + break; \ + case GRN_DB_INT32 : \ + { \ + int x_; \ + x_ = GRN_INT32_VALUE(x); \ + left_expression_check(x_); \ + GRN_INT32_SET(ctx, res, integer_operation(x_)); \ + } \ + break; \ + case GRN_DB_UINT32 : \ + { \ + long long int x_; \ + x_ = GRN_UINT32_VALUE(x); \ + left_expression_check(x_); \ + GRN_INT64_SET(ctx, res, integer_operation(x_)); \ + res->header.domain = GRN_DB_INT64; \ + } \ + break; \ + case GRN_DB_INT64 : \ + { \ + long long int x_; \ + x_ = GRN_INT64_VALUE(x); \ + left_expression_check(x_); \ + GRN_INT64_SET(ctx, res, integer_operation(x_)); \ + } \ + break; \ + case GRN_DB_TIME : \ + { \ + long long int x_; \ + x_ = GRN_TIME_VALUE(x); \ + left_expression_check(x_); \ + GRN_TIME_SET(ctx, res, integer_operation(x_)); \ + } \ + break; \ + case GRN_DB_UINT64 : \ + { \ + long long unsigned int x_; \ + x_ = GRN_UINT64_VALUE(x); \ + left_expression_check(x_); \ + if (x_ > (long long unsigned int)INT64_MAX) { \ + ERR(GRN_INVALID_ARGUMENT, \ + "too large UInt64 value to inverse sign: " \ + "<%" GRN_FMT_LLU ">", \ + x_); \ + goto exit; \ + } else { \ + long long int signed_x_; \ + signed_x_ = x_; \ + GRN_INT64_SET(ctx, res, integer_operation(signed_x_)); \ + res->header.domain = GRN_DB_INT64; \ + } \ + } \ + break; \ + case GRN_DB_FLOAT : \ + { \ + double x_; \ + x_ = GRN_FLOAT_VALUE(x); \ + left_expression_check(x_); \ + GRN_FLOAT_SET(ctx, res, float_operation(x_)); \ + } \ + break; \ + case GRN_DB_SHORT_TEXT : \ + case GRN_DB_TEXT : \ + case GRN_DB_LONG_TEXT : \ + text_operation; \ + break; \ + default: \ + invalid_type_error; \ + break; \ + } \ + code++; \ +} while (0) + +#define EXEC_OPERATE(operate_sentence, assign_sentence) \ + operate_sentence \ + assign_sentence + +#define EXEC_OPERATE_POST(operate_sentence, assign_sentence) \ + assign_sentence \ + operate_sentence + +#define UNARY_OPERATE_AND_ASSIGN_DISPATCH(exec_operate, delta, \ + set_flags) do { \ + grn_obj *var = NULL; \ + grn_obj *col = NULL; \ + grn_obj value; \ + grn_id rid; \ + \ + POP1ALLOC1(var, res); \ + if (var->header.type != GRN_PTR) { \ + ERR(GRN_INVALID_ARGUMENT, "invalid variable type: 0x%0x", \ + var->header.type); \ + goto exit; \ + } \ + if (GRN_BULK_VSIZE(var) != (sizeof(grn_obj *) + sizeof(grn_id))) { \ + ERR(GRN_INVALID_ARGUMENT, \ + "invalid variable size: " \ + "expected: %" GRN_FMT_SIZE \ + "actual: %" GRN_FMT_SIZE, \ + (sizeof(grn_obj *) + sizeof(grn_id)), GRN_BULK_VSIZE(var)); \ + goto exit; \ + } \ + col = GRN_PTR_VALUE(var); \ + rid = *(grn_id *)(GRN_BULK_HEAD(var) + sizeof(grn_obj *)); \ + res->header.type = GRN_VOID; \ + res->header.domain = DB_OBJ(col)->range; \ + switch (DB_OBJ(col)->range) { \ + case GRN_DB_INT32 : \ + GRN_INT32_INIT(&value, 0); \ + GRN_INT32_SET(ctx, &value, delta); \ + break; \ + case GRN_DB_UINT32 : \ + GRN_UINT32_INIT(&value, 0); \ + GRN_UINT32_SET(ctx, &value, delta); \ + break; \ + case GRN_DB_INT64 : \ + GRN_INT64_INIT(&value, 0); \ + GRN_INT64_SET(ctx, &value, delta); \ + break; \ + case GRN_DB_UINT64 : \ + GRN_UINT64_INIT(&value, 0); \ + GRN_UINT64_SET(ctx, &value, delta); \ + break; \ + case GRN_DB_FLOAT : \ + GRN_FLOAT_INIT(&value, 0); \ + GRN_FLOAT_SET(ctx, &value, delta); \ + break; \ + case GRN_DB_TIME : \ + GRN_TIME_INIT(&value, 0); \ + GRN_TIME_SET(ctx, &value, GRN_TIME_PACK(delta, 0)); \ + break; \ + default: \ + ERR(GRN_INVALID_ARGUMENT, \ + "invalid increment target type: %d " \ + "(FIXME: type name is needed)", DB_OBJ(col)->range); \ + goto exit; \ + break; \ + } \ + exec_operate(grn_obj_set_value(ctx, col, rid, &value, set_flags);, \ + grn_obj_get_value(ctx, col, rid, res);); \ + code++; \ +} while (0) + +#define ARITHMETIC_OPERATION_AND_ASSIGN_DISPATCH(integer8_operation, \ + integer16_operation, \ + integer32_operation, \ + integer64_operation, \ + float_operation, \ + left_expression_check, \ + right_expression_check,\ + text_operation) do { \ + grn_obj *value = NULL; \ + grn_obj *var = NULL; \ + grn_obj *res = NULL; \ + if (code->value) { \ + value = code->value; \ + POP1ALLOC1(var, res); \ + } else { \ + POP2ALLOC1(var, value, res); \ + } \ + if (var->header.type == GRN_PTR && \ + GRN_BULK_VSIZE(var) == (sizeof(grn_obj *) + sizeof(grn_id))) { \ + grn_obj *col = GRN_PTR_VALUE(var); \ + grn_id rid = *(grn_id *)(GRN_BULK_HEAD(var) + sizeof(grn_obj *)); \ + grn_obj variable_value, casted_value; \ + grn_id domain; \ + \ + value = GRN_OBJ_RESOLVE(ctx, value); \ + \ + domain = grn_obj_get_range(ctx, col); \ + GRN_OBJ_INIT(&variable_value, GRN_BULK, 0, domain); \ + grn_obj_get_value(ctx, col, rid, &variable_value); \ + \ + GRN_OBJ_INIT(&casted_value, GRN_BULK, 0, domain); \ + if (grn_obj_cast(ctx, value, &casted_value, GRN_FALSE)) { \ + ERR(GRN_INVALID_ARGUMENT, "invalid value: string"); \ + GRN_OBJ_FIN(ctx, &variable_value); \ + GRN_OBJ_FIN(ctx, &casted_value); \ + POP1(res); \ + goto exit; \ + } \ + grn_obj_reinit(ctx, res, domain, 0); \ + ARITHMETIC_OPERATION_DISPATCH((&variable_value), (&casted_value), \ + res, \ + integer8_operation, \ + integer16_operation, \ + integer32_operation, \ + integer64_operation, \ + float_operation, \ + left_expression_check, \ + right_expression_check, \ + text_operation,); \ + grn_obj_set_value(ctx, col, rid, res, GRN_OBJ_SET); \ + GRN_OBJ_FIN(ctx, (&variable_value)); \ + GRN_OBJ_FIN(ctx, (&casted_value)); \ + } else { \ + ERR(GRN_INVALID_ARGUMENT, "left hand expression isn't column."); \ + POP1(res); \ + } \ +} while (0) + +grn_inline static void +grn_expr_exec_get_member_vector(grn_ctx *ctx, + grn_obj *expr, + grn_obj *column_and_record_id, + grn_obj *index, + grn_obj *result) +{ + grn_obj *column; + grn_id record_id; + grn_obj values; + int i; + + column = GRN_PTR_VALUE(column_and_record_id); + record_id = *((grn_id *)(&(GRN_PTR_VALUE_AT(column_and_record_id, 1)))); + GRN_TEXT_INIT(&values, 0); + grn_obj_get_value(ctx, column, record_id, &values); + + i = GRN_UINT32_VALUE(index); + if (values.header.type == GRN_UVECTOR) { + int n_elements = 0; + grn_obj *range; + grn_id range_id = DB_OBJ(column)->range; + + grn_obj_reinit(ctx, result, range_id, 0); + range = grn_ctx_at(ctx, range_id); + if (range) { + switch (range->header.type) { + case GRN_TYPE : + n_elements = GRN_BULK_VSIZE(&values) / grn_type_size(ctx, range); + break; + case GRN_TABLE_HASH_KEY : + case GRN_TABLE_PAT_KEY : + case GRN_TABLE_DAT_KEY : + case GRN_TABLE_NO_KEY : + n_elements = GRN_BULK_VSIZE(&values) / sizeof(grn_id); + break; + } + } + if (n_elements > i) { +#define GET_UVECTOR_ELEMENT_AS(type) do { \ + GRN_ ## type ## _SET(ctx, \ + result, \ + GRN_ ## type ## _VALUE_AT(&values, i)); \ + } while (GRN_FALSE) + switch (values.header.domain) { + case GRN_DB_BOOL : + GET_UVECTOR_ELEMENT_AS(BOOL); + break; + case GRN_DB_INT8 : + GET_UVECTOR_ELEMENT_AS(INT8); + break; + case GRN_DB_UINT8 : + GET_UVECTOR_ELEMENT_AS(UINT8); + break; + case GRN_DB_INT16 : + GET_UVECTOR_ELEMENT_AS(INT16); + break; + case GRN_DB_UINT16 : + GET_UVECTOR_ELEMENT_AS(UINT16); + break; + case GRN_DB_INT32 : + GET_UVECTOR_ELEMENT_AS(INT32); + break; + case GRN_DB_UINT32 : + GET_UVECTOR_ELEMENT_AS(UINT32); + break; + case GRN_DB_INT64 : + GET_UVECTOR_ELEMENT_AS(INT64); + break; + case GRN_DB_UINT64 : + GET_UVECTOR_ELEMENT_AS(UINT64); + break; + case GRN_DB_FLOAT : + GET_UVECTOR_ELEMENT_AS(FLOAT); + break; + case GRN_DB_TIME : + GET_UVECTOR_ELEMENT_AS(TIME); + break; + default : + GET_UVECTOR_ELEMENT_AS(RECORD); + break; + } +#undef GET_UVECTOR_ELEMENT_AS + } + } else { + if (values.u.v.n_sections > i) { + const char *content; + unsigned int content_length; + grn_id domain; + + content_length = grn_vector_get_element(ctx, &values, i, + &content, NULL, &domain); + grn_obj_reinit(ctx, result, domain, 0); + grn_bulk_write(ctx, result, content, content_length); + } + } + + GRN_OBJ_FIN(ctx, &values); +} + +grn_inline static void +grn_expr_exec_get_member_table(grn_ctx *ctx, + grn_obj *expr, + grn_obj *table, + grn_obj *key, + grn_obj *result) +{ + grn_id id; + + if (table->header.domain == key->header.domain) { + id = grn_table_get(ctx, table, GRN_BULK_HEAD(key), GRN_BULK_VSIZE(key)); + } else { + grn_obj casted_key; + GRN_OBJ_INIT(&casted_key, GRN_BULK, 0, table->header.domain); + if (grn_obj_cast(ctx, key, &casted_key, GRN_FALSE) == GRN_SUCCESS) { + id = grn_table_get(ctx, table, + GRN_BULK_HEAD(&casted_key), + GRN_BULK_VSIZE(&casted_key)); + } else { + id = GRN_ID_NIL; + } + GRN_OBJ_FIN(ctx, &casted_key); + } + + grn_obj_reinit(ctx, result, DB_OBJ(table)->id, 0); + GRN_RECORD_SET(ctx, result, id); +} + +static grn_obj * +expr_exec(grn_ctx *ctx, grn_obj *expr) +{ + grn_obj *val = NULL; + uint32_t stack_curr = ctx->impl->stack_curr; + grn_expr *e = (grn_expr *)expr; + register grn_obj **s_ = ctx->impl->stack; + register grn_obj *s0 = NULL; + register grn_obj *s1 = NULL; + register grn_obj **sp; + register grn_obj *vp = e->values; + grn_obj *res = NULL, *v0 = grn_expr_get_var_by_offset(ctx, expr, 0); + grn_expr_code *code = e->codes, *ce = &e->codes[e->codes_curr]; + sp = s_ + stack_curr; + while (code < ce) { + switch (code->op) { + case GRN_OP_NOP : + code++; + break; + case GRN_OP_PUSH : + PUSH1(code->value); + code++; + break; + case GRN_OP_POP : + { + grn_obj *obj = NULL; + POP1(obj); + code++; + } + break; + case GRN_OP_GET_REF : + { + grn_obj *col = NULL; + grn_obj *rec = NULL; + if (code->nargs == 1) { + rec = v0; + if (code->value) { + col = code->value; + ALLOC1(res); + } else { + POP1ALLOC1(col, res); + } + } else { + if (code->value) { + col = code->value; + POP1ALLOC1(rec, res); + } else { + POP2ALLOC1(rec, col, res); + } + } + if (col->header.type == GRN_BULK) { + grn_obj *table = grn_ctx_at(ctx, GRN_OBJ_GET_DOMAIN(rec)); + col = grn_obj_column(ctx, table, GRN_BULK_HEAD(col), GRN_BULK_VSIZE(col)); + if (col) { grn_expr_take_obj(ctx, (grn_obj *)e, col); } + } + if (col) { + res->header.type = GRN_PTR; + res->header.domain = GRN_ID_NIL; + GRN_PTR_SET(ctx, res, col); + GRN_UINT32_PUT(ctx, res, GRN_RECORD_VALUE(rec)); + } else { + ERR(GRN_INVALID_ARGUMENT, "col resolve failed"); + goto exit; + } + code++; + } + break; + case GRN_OP_CALL : + { + grn_obj *proc = NULL; + if (code->value) { + if (sp < s_ + code->nargs - 1) { + ERR(GRN_INVALID_ARGUMENT, "stack error"); + goto exit; + } + proc = code->value; + WITH_SPSAVE({ + grn_proc_call(ctx, proc, code->nargs - 1, expr); + }); + } else { + int offset = code->nargs; + if (sp < s_ + offset) { + ERR(GRN_INVALID_ARGUMENT, "stack error"); + goto exit; + } + proc = sp[-offset]; + if (grn_obj_is_window_function_proc(ctx, proc)) { + grn_obj inspected; + GRN_TEXT_INIT(&inspected, 0); + grn_inspect(ctx, &inspected, proc); + ERR(GRN_INVALID_ARGUMENT, + "window function can't be executed for each record: %.*s", + (int)GRN_TEXT_LEN(&inspected), + GRN_TEXT_VALUE(&inspected)); + GRN_OBJ_FIN(ctx, &inspected); + goto exit; + } else { + WITH_SPSAVE({ + grn_proc_call(ctx, proc, code->nargs - 1, expr); + }); + } + if (ctx->rc) { + goto exit; + } + POP1(res); + { + grn_obj *proc_; + POP1(proc_); + if (proc != proc_) { + GRN_LOG(ctx, GRN_LOG_WARNING, "stack may be corrupt"); + } + } + PUSH1(res); + } + } + code++; + break; + case GRN_OP_INTERN : + { + grn_obj *obj = NULL; + POP1(obj); + obj = GRN_OBJ_RESOLVE(ctx, obj); + res = grn_expr_get_var(ctx, expr, GRN_TEXT_VALUE(obj), GRN_TEXT_LEN(obj)); + if (!res) { res = grn_ctx_get(ctx, GRN_TEXT_VALUE(obj), GRN_TEXT_LEN(obj)); } + if (!res) { + ERR(GRN_INVALID_ARGUMENT, "intern failed"); + goto exit; + } + PUSH1(res); + } + code++; + break; + case GRN_OP_TABLE_CREATE : + { + grn_obj *value_type, *key_type, *flags, *name; + POP1(value_type); + value_type = GRN_OBJ_RESOLVE(ctx, value_type); + POP1(key_type); + key_type = GRN_OBJ_RESOLVE(ctx, key_type); + POP1(flags); + flags = GRN_OBJ_RESOLVE(ctx, flags); + POP1(name); + name = GRN_OBJ_RESOLVE(ctx, name); + res = grn_table_create(ctx, GRN_TEXT_VALUE(name), GRN_TEXT_LEN(name), + NULL, GRN_UINT32_VALUE(flags), + key_type, value_type); + PUSH1(res); + } + code++; + break; + case GRN_OP_EXPR_GET_VAR : + { + grn_obj *name = NULL; + grn_obj *expr = NULL; + POP1(name); + name = GRN_OBJ_RESOLVE(ctx, name); + POP1(expr); + expr = GRN_OBJ_RESOLVE(ctx, expr); + switch (name->header.domain) { + case GRN_DB_INT32 : + res = grn_expr_get_var_by_offset(ctx, expr, (unsigned int) GRN_INT32_VALUE(name)); + break; + case GRN_DB_UINT32 : + res = grn_expr_get_var_by_offset(ctx, expr, (unsigned int) GRN_UINT32_VALUE(name)); + break; + case GRN_DB_INT64 : + res = grn_expr_get_var_by_offset(ctx, expr, (unsigned int) GRN_INT64_VALUE(name)); + break; + case GRN_DB_UINT64 : + res = grn_expr_get_var_by_offset(ctx, expr, (unsigned int) GRN_UINT64_VALUE(name)); + break; + case GRN_DB_SHORT_TEXT : + case GRN_DB_TEXT : + case GRN_DB_LONG_TEXT : + res = grn_expr_get_var(ctx, expr, GRN_TEXT_VALUE(name), GRN_TEXT_LEN(name)); + break; + default : + ERR(GRN_INVALID_ARGUMENT, "invalid type"); + goto exit; + } + PUSH1(res); + } + code++; + break; + case GRN_OP_ASSIGN : + { + grn_obj *value = NULL; + grn_obj *var = NULL; + if (code->value) { + value = code->value; + } else { + POP1(value); + } + value = GRN_OBJ_RESOLVE(ctx, value); + POP1(var); + // var = GRN_OBJ_RESOLVE(ctx, var); + if (var->header.type == GRN_PTR && + GRN_BULK_VSIZE(var) == (sizeof(grn_obj *) + sizeof(grn_id))) { + grn_obj *col = GRN_PTR_VALUE(var); + grn_id rid = *(grn_id *)(GRN_BULK_HEAD(var) + sizeof(grn_obj *)); + grn_obj_set_value(ctx, col, rid, value, GRN_OBJ_SET); + } else { + VAR_SET_VALUE(ctx, var, value); + } + PUSH1(value); + } + code++; + break; + case GRN_OP_STAR_ASSIGN : + ARITHMETIC_OPERATION_AND_ASSIGN_DISPATCH( + INTEGER_ARITHMETIC_OPERATION_STAR, + INTEGER_ARITHMETIC_OPERATION_STAR, + INTEGER_ARITHMETIC_OPERATION_STAR, + INTEGER_ARITHMETIC_OPERATION_STAR, + FLOAT_ARITHMETIC_OPERATION_STAR, + ARITHMETIC_OPERATION_NO_CHECK, + ARITHMETIC_OPERATION_NO_CHECK, + { + ERR(GRN_INVALID_ARGUMENT, "variable *= \"string\" isn't supported"); + goto exit; + }); + break; + case GRN_OP_SLASH_ASSIGN : + ARITHMETIC_OPERATION_AND_ASSIGN_DISPATCH( + INTEGER_ARITHMETIC_OPERATION_SLASH, + INTEGER_ARITHMETIC_OPERATION_SLASH, + INTEGER_ARITHMETIC_OPERATION_SLASH, + INTEGER_ARITHMETIC_OPERATION_SLASH, + FLOAT_ARITHMETIC_OPERATION_SLASH, + ARITHMETIC_OPERATION_NO_CHECK, + ARITHMETIC_OPERATION_NO_CHECK, + { + ERR(GRN_INVALID_ARGUMENT, "variable /= \"string\" isn't supported"); + goto exit; + }); + break; + case GRN_OP_MOD_ASSIGN : + ARITHMETIC_OPERATION_AND_ASSIGN_DISPATCH( + INTEGER_ARITHMETIC_OPERATION_MOD, + INTEGER_ARITHMETIC_OPERATION_MOD, + INTEGER_ARITHMETIC_OPERATION_MOD, + INTEGER_ARITHMETIC_OPERATION_MOD, + FLOAT_ARITHMETIC_OPERATION_MOD, + ARITHMETIC_OPERATION_NO_CHECK, + ARITHMETIC_OPERATION_NO_CHECK, + { + ERR(GRN_INVALID_ARGUMENT, "variable %%= \"string\" isn't supported"); + goto exit; + }); + break; + case GRN_OP_PLUS_ASSIGN : + ARITHMETIC_OPERATION_AND_ASSIGN_DISPATCH( + INTEGER_ARITHMETIC_OPERATION_PLUS, + INTEGER_ARITHMETIC_OPERATION_PLUS, + INTEGER_ARITHMETIC_OPERATION_PLUS, + INTEGER_ARITHMETIC_OPERATION_PLUS, + FLOAT_ARITHMETIC_OPERATION_PLUS, + ARITHMETIC_OPERATION_NO_CHECK, + ARITHMETIC_OPERATION_NO_CHECK, + { + ERR(GRN_INVALID_ARGUMENT, "variable += \"string\" isn't supported"); + goto exit; + }); + break; + case GRN_OP_MINUS_ASSIGN : + ARITHMETIC_OPERATION_AND_ASSIGN_DISPATCH( + INTEGER_ARITHMETIC_OPERATION_MINUS, + INTEGER_ARITHMETIC_OPERATION_MINUS, + INTEGER_ARITHMETIC_OPERATION_MINUS, + INTEGER_ARITHMETIC_OPERATION_MINUS, + FLOAT_ARITHMETIC_OPERATION_MINUS, + ARITHMETIC_OPERATION_NO_CHECK, + ARITHMETIC_OPERATION_NO_CHECK, + { + ERR(GRN_INVALID_ARGUMENT, "variable -= \"string\" isn't supported"); + goto exit; + }); + break; + case GRN_OP_SHIFTL_ASSIGN : + ARITHMETIC_OPERATION_AND_ASSIGN_DISPATCH( + INTEGER_ARITHMETIC_OPERATION_SHIFTL, + INTEGER_ARITHMETIC_OPERATION_SHIFTL, + INTEGER_ARITHMETIC_OPERATION_SHIFTL, + INTEGER_ARITHMETIC_OPERATION_SHIFTL, + FLOAT_ARITHMETIC_OPERATION_SHIFTL, + ARITHMETIC_OPERATION_NO_CHECK, + ARITHMETIC_OPERATION_NO_CHECK, + { + ERR(GRN_INVALID_ARGUMENT, "variable <<= \"string\" isn't supported"); + goto exit; + }); + break; + case GRN_OP_SHIFTR_ASSIGN : + ARITHMETIC_OPERATION_AND_ASSIGN_DISPATCH( + INTEGER_ARITHMETIC_OPERATION_SHIFTR, + INTEGER_ARITHMETIC_OPERATION_SHIFTR, + INTEGER_ARITHMETIC_OPERATION_SHIFTR, + INTEGER_ARITHMETIC_OPERATION_SHIFTR, + FLOAT_ARITHMETIC_OPERATION_SHIFTR, + ARITHMETIC_OPERATION_NO_CHECK, + ARITHMETIC_OPERATION_NO_CHECK, + { + ERR(GRN_INVALID_ARGUMENT, "variable >>= \"string\" isn't supported"); + goto exit; + }); + break; + case GRN_OP_SHIFTRR_ASSIGN : + ARITHMETIC_OPERATION_AND_ASSIGN_DISPATCH( + INTEGER8_ARITHMETIC_OPERATION_SHIFTRR, + INTEGER16_ARITHMETIC_OPERATION_SHIFTRR, + INTEGER32_ARITHMETIC_OPERATION_SHIFTRR, + INTEGER64_ARITHMETIC_OPERATION_SHIFTRR, + FLOAT_ARITHMETIC_OPERATION_SHIFTRR, + ARITHMETIC_OPERATION_NO_CHECK, + ARITHMETIC_OPERATION_NO_CHECK, + { + ERR(GRN_INVALID_ARGUMENT, + "variable >>>= \"string\" isn't supported"); + goto exit; + }); + break; + case GRN_OP_AND_ASSIGN : + ARITHMETIC_OPERATION_AND_ASSIGN_DISPATCH( + INTEGER_ARITHMETIC_OPERATION_BITWISE_AND, + INTEGER_ARITHMETIC_OPERATION_BITWISE_AND, + INTEGER_ARITHMETIC_OPERATION_BITWISE_AND, + INTEGER_ARITHMETIC_OPERATION_BITWISE_AND, + FLOAT_ARITHMETIC_OPERATION_BITWISE_AND, + ARITHMETIC_OPERATION_NO_CHECK, + ARITHMETIC_OPERATION_NO_CHECK, + { + ERR(GRN_INVALID_ARGUMENT, "variable &= \"string\" isn't supported"); + goto exit; + }); + break; + case GRN_OP_OR_ASSIGN : + ARITHMETIC_OPERATION_AND_ASSIGN_DISPATCH( + INTEGER_ARITHMETIC_OPERATION_BITWISE_OR, + INTEGER_ARITHMETIC_OPERATION_BITWISE_OR, + INTEGER_ARITHMETIC_OPERATION_BITWISE_OR, + INTEGER_ARITHMETIC_OPERATION_BITWISE_OR, + FLOAT_ARITHMETIC_OPERATION_BITWISE_OR, + ARITHMETIC_OPERATION_NO_CHECK, + ARITHMETIC_OPERATION_NO_CHECK, + { + ERR(GRN_INVALID_ARGUMENT, "variable |= \"string\" isn't supported"); + goto exit; + }); + break; + case GRN_OP_XOR_ASSIGN : + ARITHMETIC_OPERATION_AND_ASSIGN_DISPATCH( + INTEGER_ARITHMETIC_OPERATION_BITWISE_XOR, + INTEGER_ARITHMETIC_OPERATION_BITWISE_XOR, + INTEGER_ARITHMETIC_OPERATION_BITWISE_XOR, + INTEGER_ARITHMETIC_OPERATION_BITWISE_XOR, + FLOAT_ARITHMETIC_OPERATION_BITWISE_XOR, + ARITHMETIC_OPERATION_NO_CHECK, + ARITHMETIC_OPERATION_NO_CHECK, + { + ERR(GRN_INVALID_ARGUMENT, "variable ^= \"string\" isn't supported"); + goto exit; + }); + break; + case GRN_OP_JUMP : + code += code->nargs + 1; + break; + case GRN_OP_CJUMP : + { + grn_obj *v = NULL; + POP1(v); + if (!grn_obj_is_true(ctx, v)) { + code += code->nargs; + } + } + code++; + break; + case GRN_OP_GET_VALUE : + { + grn_obj *col = NULL; + grn_obj *rec = NULL; + do { + if (code->nargs == 1) { + rec = v0; + if (code->value) { + col = code->value; + ALLOC1(res); + } else { + POP1ALLOC1(col, res); + } + } else { + if (code->value) { + col = code->value; + POP1ALLOC1(rec, res); + } else { + POP2ALLOC1(rec, col, res); + } + } + if (col->header.type == GRN_BULK) { + grn_obj *table = grn_ctx_at(ctx, GRN_OBJ_GET_DOMAIN(rec)); + col = grn_obj_column(ctx, table, GRN_BULK_HEAD(col), GRN_BULK_VSIZE(col)); + if (col) { grn_expr_take_obj(ctx, (grn_obj *)expr, col); } + } + if (!col) { + ERR(GRN_INVALID_ARGUMENT, "col resolve failed"); + goto exit; + } + grn_obj_reinit_for(ctx, res, col); + grn_obj_get_value(ctx, col, GRN_RECORD_VALUE(rec), res); + code++; + } while (code < ce && code->op == GRN_OP_GET_VALUE); + } + break; + case GRN_OP_OBJ_SEARCH : + { + grn_obj *op = NULL; + grn_obj *query = NULL; + grn_obj *index = NULL; + // todo : grn_search_optarg optarg; + POP1(op); + op = GRN_OBJ_RESOLVE(ctx, op); + POP1(res); + res = GRN_OBJ_RESOLVE(ctx, res); + POP1(query); + query = GRN_OBJ_RESOLVE(ctx, query); + POP1(index); + index = GRN_OBJ_RESOLVE(ctx, index); + grn_obj_search(ctx, index, query, res, + (grn_operator)GRN_UINT32_VALUE(op), NULL); + } + code++; + break; + case GRN_OP_TABLE_SELECT : + { + grn_obj *op = NULL; + grn_obj *res = NULL; + grn_obj *expr = NULL; + grn_obj *table = NULL; + POP1(op); + op = GRN_OBJ_RESOLVE(ctx, op); + POP1(res); + res = GRN_OBJ_RESOLVE(ctx, res); + POP1(expr); + expr = GRN_OBJ_RESOLVE(ctx, expr); + POP1(table); + table = GRN_OBJ_RESOLVE(ctx, table); + WITH_SPSAVE({ + grn_table_select(ctx, table, expr, res, (grn_operator)GRN_UINT32_VALUE(op)); + }); + PUSH1(res); + } + code++; + break; + case GRN_OP_TABLE_SORT : + { + grn_obj *keys_ = NULL; + grn_obj *res = NULL; + grn_obj *limit = NULL; + grn_obj *table = NULL; + POP1(keys_); + keys_ = GRN_OBJ_RESOLVE(ctx, keys_); + POP1(res); + res = GRN_OBJ_RESOLVE(ctx, res); + POP1(limit); + limit = GRN_OBJ_RESOLVE(ctx, limit); + POP1(table); + table = GRN_OBJ_RESOLVE(ctx, table); + { + grn_table_sort_key *keys; + const char *p = GRN_BULK_HEAD(keys_), *tokbuf[256]; + int n = grn_str_tok(p, GRN_BULK_VSIZE(keys_), ' ', tokbuf, 256, NULL); + if ((keys = GRN_MALLOCN(grn_table_sort_key, n))) { + int i, n_keys = 0; + for (i = 0; i < n; i++) { + uint32_t len = (uint32_t) (tokbuf[i] - p); + grn_obj *col = grn_obj_column(ctx, table, p, len); + if (col) { + keys[n_keys].key = col; + keys[n_keys].flags = GRN_TABLE_SORT_ASC; + keys[n_keys].offset = 0; + n_keys++; + } else { + if (p[0] == ':' && p[1] == 'd' && len == 2 && n_keys) { + keys[n_keys - 1].flags |= GRN_TABLE_SORT_DESC; + } + } + p = tokbuf[i] + 1; + } + WITH_SPSAVE({ + grn_table_sort(ctx, table, 0, GRN_INT32_VALUE(limit), res, keys, n_keys); + }); + for (i = 0; i < n_keys; i++) { + grn_obj_unlink(ctx, keys[i].key); + } + GRN_FREE(keys); + } + } + } + code++; + break; + case GRN_OP_TABLE_GROUP : + { + grn_obj *res = NULL; + grn_obj *keys_ = NULL; + grn_obj *table = NULL; + POP1(res); + res = GRN_OBJ_RESOLVE(ctx, res); + POP1(keys_); + keys_ = GRN_OBJ_RESOLVE(ctx, keys_); + POP1(table); + table = GRN_OBJ_RESOLVE(ctx, table); + { + grn_table_sort_key *keys; + grn_table_group_result results; + const char *p = GRN_BULK_HEAD(keys_), *tokbuf[256]; + int n = grn_str_tok(p, GRN_BULK_VSIZE(keys_), ' ', tokbuf, 256, NULL); + if ((keys = GRN_MALLOCN(grn_table_sort_key, n))) { + int i, n_keys = 0; + for (i = 0; i < n; i++) { + uint32_t len = (uint32_t) (tokbuf[i] - p); + grn_obj *col = grn_obj_column(ctx, table, p, len); + if (col) { + keys[n_keys].key = col; + keys[n_keys].flags = GRN_TABLE_SORT_ASC; + keys[n_keys].offset = 0; + n_keys++; + } else if (n_keys) { + if (p[0] == ':' && p[1] == 'd' && len == 2) { + keys[n_keys - 1].flags |= GRN_TABLE_SORT_DESC; + } else { + keys[n_keys - 1].offset = grn_atoi(p, p + len, NULL); + } + } + p = tokbuf[i] + 1; + } + /* todo : support multi-results */ + results.table = res; + results.key_begin = 0; + results.key_end = 0; + results.limit = 0; + results.flags = 0; + results.op = GRN_OP_OR; + WITH_SPSAVE({ + grn_table_group(ctx, table, keys, n_keys, &results, 1); + }); + for (i = 0; i < n_keys; i++) { + grn_obj_unlink(ctx, keys[i].key); + } + GRN_FREE(keys); + } + } + } + code++; + break; + case GRN_OP_JSON_PUT : + { + grn_obj_format format; + grn_obj *res = NULL; + grn_obj *str = NULL; + grn_obj *table = NULL; + POP1(res); + res = GRN_OBJ_RESOLVE(ctx, res); + POP1(str); + str = GRN_OBJ_RESOLVE(ctx, str); + POP1(table); + table = GRN_OBJ_RESOLVE(ctx, table); + GRN_OBJ_FORMAT_INIT(&format, grn_table_size(ctx, table), 0, -1, 0); + format.flags = 0; + grn_obj_columns(ctx, table, + GRN_TEXT_VALUE(str), GRN_TEXT_LEN(str), &format.columns); + grn_text_otoj(ctx, res, table, &format); + GRN_OBJ_FORMAT_FIN(ctx, &format); + } + code++; + break; + case GRN_OP_AND : + { + grn_obj *x = NULL; + grn_obj *y = NULL; + grn_obj *result = NULL; + POP2ALLOC1(x, y, res); + if (grn_obj_is_true(ctx, x)) { + if (grn_obj_is_true(ctx, y)) { + result = y; + } + } + if (result) { + if (res != result) { + grn_obj_reinit(ctx, res, result->header.domain, 0); + grn_obj_cast(ctx, result, res, GRN_FALSE); + } + } else { + grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0); + GRN_BOOL_SET(ctx, res, GRN_FALSE); + } + } + code++; + break; + case GRN_OP_OR : + { + grn_obj *x = NULL; + grn_obj *y = NULL; + grn_obj *result = NULL; + POP2ALLOC1(x, y, res); + if (grn_obj_is_true(ctx, x)) { + result = x; + } else { + if (grn_obj_is_true(ctx, y)) { + result = y; + } else { + result = NULL; + } + } + if (result) { + if (res != result) { + grn_obj_reinit(ctx, res, result->header.domain, 0); + grn_obj_cast(ctx, result, res, GRN_FALSE); + } + } else { + grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0); + GRN_BOOL_SET(ctx, res, GRN_FALSE); + } + } + code++; + break; + case GRN_OP_AND_NOT : + { + grn_obj *x = NULL; + grn_obj *y = NULL; + grn_bool is_true; + POP2ALLOC1(x, y, res); + if (!grn_obj_is_true(ctx, x) || grn_obj_is_true(ctx, y)) { + is_true = GRN_FALSE; + } else { + is_true = GRN_TRUE; + } + grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0); + GRN_BOOL_SET(ctx, res, is_true); + } + code++; + break; + case GRN_OP_ADJUST : + { + /* todo */ + } + code++; + break; + case GRN_OP_MATCH : + { + grn_obj *x = NULL; + grn_obj *y = NULL; + grn_bool matched; + POP1(y); + POP1(x); + WITH_SPSAVE({ + matched = grn_operator_exec_match(ctx, x, y); + }); + ALLOC1(res); + grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0); + GRN_BOOL_SET(ctx, res, matched); + } + code++; + break; + case GRN_OP_EQUAL : + { + grn_bool is_equal; + grn_obj *x = NULL; + grn_obj *y = NULL; + POP2ALLOC1(x, y, res); + is_equal = grn_operator_exec_equal(ctx, x, y); + grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0); + GRN_BOOL_SET(ctx, res, is_equal); + } + code++; + break; + case GRN_OP_NOT_EQUAL : + { + grn_bool is_not_equal; + grn_obj *x = NULL; + grn_obj *y = NULL; + POP2ALLOC1(x, y, res); + is_not_equal = grn_operator_exec_not_equal(ctx, x, y); + grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0); + GRN_BOOL_SET(ctx, res, is_not_equal); + } + code++; + break; + case GRN_OP_PREFIX : + { + grn_obj *x = NULL; + grn_obj *y = NULL; + grn_bool matched; + POP1(y); + POP1(x); + WITH_SPSAVE({ + matched = grn_operator_exec_prefix(ctx, x, y); + }); + ALLOC1(res); + grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0); + GRN_BOOL_SET(ctx, res, matched); + } + code++; + break; + case GRN_OP_SUFFIX : + { + grn_obj *x = NULL; + grn_obj *y = NULL; + grn_bool matched = GRN_FALSE; + POP2ALLOC1(x, y, res); + if (GRN_TEXT_LEN(x) >= GRN_TEXT_LEN(y) && + !memcmp(GRN_TEXT_VALUE(x) + GRN_TEXT_LEN(x) - GRN_TEXT_LEN(y), + GRN_TEXT_VALUE(y), GRN_TEXT_LEN(y))) { + matched = GRN_TRUE; + } + grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0); + GRN_BOOL_SET(ctx, res, matched); + } + code++; + break; + case GRN_OP_LESS : + { + grn_bool r; + grn_obj *x = NULL; + grn_obj *y = NULL; + POP2ALLOC1(x, y, res); + r = grn_operator_exec_less(ctx, x, y); + grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0); + GRN_BOOL_SET(ctx, res, r); + } + code++; + break; + case GRN_OP_GREATER : + { + grn_bool r; + grn_obj *x = NULL; + grn_obj *y = NULL; + POP2ALLOC1(x, y, res); + r = grn_operator_exec_greater(ctx, x, y); + grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0); + GRN_BOOL_SET(ctx, res, r); + } + code++; + break; + case GRN_OP_LESS_EQUAL : + { + grn_bool r; + grn_obj *x = NULL; + grn_obj *y = NULL; + POP2ALLOC1(x, y, res); + r = grn_operator_exec_less_equal(ctx, x, y); + grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0); + GRN_BOOL_SET(ctx, res, r); + } + code++; + break; + case GRN_OP_GREATER_EQUAL : + { + grn_bool r; + grn_obj *x = NULL; + grn_obj *y = NULL; + POP2ALLOC1(x, y, res); + r = grn_operator_exec_greater_equal(ctx, x, y); + grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0); + GRN_BOOL_SET(ctx, res, r); + } + code++; + break; + case GRN_OP_GEO_DISTANCE1 : + { + grn_obj *value = NULL; + double lng1, lat1, lng2, lat2, x, y, d; + POP1(value); + lng1 = GEO_INT2RAD(GRN_INT32_VALUE(value)); + POP1(value); + lat1 = GEO_INT2RAD(GRN_INT32_VALUE(value)); + POP1(value); + lng2 = GEO_INT2RAD(GRN_INT32_VALUE(value)); + POP1ALLOC1(value, res); + lat2 = GEO_INT2RAD(GRN_INT32_VALUE(value)); + x = (lng2 - lng1) * cos((lat1 + lat2) * 0.5); + y = (lat2 - lat1); + d = sqrt((x * x) + (y * y)) * GEO_RADIOUS; + res->header.type = GRN_BULK; + res->header.domain = GRN_DB_FLOAT; + GRN_FLOAT_SET(ctx, res, d); + } + code++; + break; + case GRN_OP_GEO_DISTANCE2 : + { + grn_obj *value = NULL; + double lng1, lat1, lng2, lat2, x, y, d; + POP1(value); + lng1 = GEO_INT2RAD(GRN_INT32_VALUE(value)); + POP1(value); + lat1 = GEO_INT2RAD(GRN_INT32_VALUE(value)); + POP1(value); + lng2 = GEO_INT2RAD(GRN_INT32_VALUE(value)); + POP1ALLOC1(value, res); + lat2 = GEO_INT2RAD(GRN_INT32_VALUE(value)); + x = sin(fabs(lng2 - lng1) * 0.5); + y = sin(fabs(lat2 - lat1) * 0.5); + d = asin(sqrt((y * y) + cos(lat1) * cos(lat2) * x * x)) * 2 * GEO_RADIOUS; + res->header.type = GRN_BULK; + res->header.domain = GRN_DB_FLOAT; + GRN_FLOAT_SET(ctx, res, d); + } + code++; + break; + case GRN_OP_GEO_DISTANCE3 : + { + grn_obj *value = NULL; + double lng1, lat1, lng2, lat2, p, q, m, n, x, y, d; + POP1(value); + lng1 = GEO_INT2RAD(GRN_INT32_VALUE(value)); + POP1(value); + lat1 = GEO_INT2RAD(GRN_INT32_VALUE(value)); + POP1(value); + lng2 = GEO_INT2RAD(GRN_INT32_VALUE(value)); + POP1ALLOC1(value, res); + lat2 = GEO_INT2RAD(GRN_INT32_VALUE(value)); + p = (lat1 + lat2) * 0.5; + q = (1 - GEO_BES_C3 * sin(p) * sin(p)); + m = GEO_BES_C1 / sqrt(q * q * q); + n = GEO_BES_C2 / sqrt(q); + x = n * cos(p) * fabs(lng1 - lng2); + y = m * fabs(lat1 - lat2); + d = sqrt((x * x) + (y * y)); + res->header.type = GRN_BULK; + res->header.domain = GRN_DB_FLOAT; + GRN_FLOAT_SET(ctx, res, d); + } + code++; + break; + case GRN_OP_GEO_DISTANCE4 : + { + grn_obj *value = NULL; + double lng1, lat1, lng2, lat2, p, q, m, n, x, y, d; + POP1(value); + lng1 = GEO_INT2RAD(GRN_INT32_VALUE(value)); + POP1(value); + lat1 = GEO_INT2RAD(GRN_INT32_VALUE(value)); + POP1(value); + lng2 = GEO_INT2RAD(GRN_INT32_VALUE(value)); + POP1ALLOC1(value, res); + lat2 = GEO_INT2RAD(GRN_INT32_VALUE(value)); + p = (lat1 + lat2) * 0.5; + q = (1 - GEO_GRS_C3 * sin(p) * sin(p)); + m = GEO_GRS_C1 / sqrt(q * q * q); + n = GEO_GRS_C2 / sqrt(q); + x = n * cos(p) * fabs(lng1 - lng2); + y = m * fabs(lat1 - lat2); + d = sqrt((x * x) + (y * y)); + res->header.type = GRN_BULK; + res->header.domain = GRN_DB_FLOAT; + GRN_FLOAT_SET(ctx, res, d); + } + code++; + break; + case GRN_OP_GEO_WITHINP5 : + { + int r; + grn_obj *value = NULL; + double lng0, lat0, lng1, lat1, x, y, d; + POP1(value); + lng0 = GEO_INT2RAD(GRN_INT32_VALUE(value)); + POP1(value); + lat0 = GEO_INT2RAD(GRN_INT32_VALUE(value)); + POP1(value); + lng1 = GEO_INT2RAD(GRN_INT32_VALUE(value)); + POP1(value); + lat1 = GEO_INT2RAD(GRN_INT32_VALUE(value)); + POP1ALLOC1(value, res); + x = (lng1 - lng0) * cos((lat0 + lat1) * 0.5); + y = (lat1 - lat0); + d = sqrt((x * x) + (y * y)) * GEO_RADIOUS; + switch (value->header.domain) { + case GRN_DB_INT32 : + r = d <= GRN_INT32_VALUE(value); + break; + case GRN_DB_FLOAT : + r = d <= GRN_FLOAT_VALUE(value); + break; + default : + r = 0; + break; + } + GRN_INT32_SET(ctx, res, r); + res->header.type = GRN_BULK; + res->header.domain = GRN_DB_INT32; + } + code++; + break; + case GRN_OP_GEO_WITHINP6 : + { + int r; + grn_obj *value = NULL; + double lng0, lat0, lng1, lat1, lng2, lat2, x, y, d; + POP1(value); + lng0 = GEO_INT2RAD(GRN_INT32_VALUE(value)); + POP1(value); + lat0 = GEO_INT2RAD(GRN_INT32_VALUE(value)); + POP1(value); + lng1 = GEO_INT2RAD(GRN_INT32_VALUE(value)); + POP1(value); + lat1 = GEO_INT2RAD(GRN_INT32_VALUE(value)); + POP1(value); + lng2 = GEO_INT2RAD(GRN_INT32_VALUE(value)); + POP1ALLOC1(value, res); + lat2 = GEO_INT2RAD(GRN_INT32_VALUE(value)); + x = (lng1 - lng0) * cos((lat0 + lat1) * 0.5); + y = (lat1 - lat0); + d = (x * x) + (y * y); + x = (lng2 - lng1) * cos((lat1 + lat2) * 0.5); + y = (lat2 - lat1); + r = d <= (x * x) + (y * y); + GRN_INT32_SET(ctx, res, r); + res->header.type = GRN_BULK; + res->header.domain = GRN_DB_INT32; + } + code++; + break; + case GRN_OP_GEO_WITHINP8 : + { + int r; + grn_obj *value = NULL; + int64_t ln0, la0, ln1, la1, ln2, la2, ln3, la3; + POP1(value); + ln0 = GRN_INT32_VALUE(value); + POP1(value); + la0 = GRN_INT32_VALUE(value); + POP1(value); + ln1 = GRN_INT32_VALUE(value); + POP1(value); + la1 = GRN_INT32_VALUE(value); + POP1(value); + ln2 = GRN_INT32_VALUE(value); + POP1(value); + la2 = GRN_INT32_VALUE(value); + POP1(value); + ln3 = GRN_INT32_VALUE(value); + POP1ALLOC1(value, res); + la3 = GRN_INT32_VALUE(value); + r = ((ln2 <= ln0) && (ln0 <= ln3) && (la2 <= la0) && (la0 <= la3)); + GRN_INT32_SET(ctx, res, r); + res->header.type = GRN_BULK; + res->header.domain = GRN_DB_INT32; + } + code++; + break; + case GRN_OP_PLUS : + ARITHMETIC_BINARY_OPERATION_DISPATCH( + "+", + INTEGER_ARITHMETIC_OPERATION_PLUS, + INTEGER_ARITHMETIC_OPERATION_PLUS, + INTEGER_ARITHMETIC_OPERATION_PLUS, + INTEGER_ARITHMETIC_OPERATION_PLUS, + FLOAT_ARITHMETIC_OPERATION_PLUS, + ARITHMETIC_OPERATION_NO_CHECK, + ARITHMETIC_OPERATION_NO_CHECK, + { + if (x == res) { + grn_obj_cast(ctx, y, res, GRN_FALSE); + } else if (y == res) { + grn_obj buffer; + GRN_TEXT_INIT(&buffer, 0); + grn_obj_cast(ctx, x, &buffer, GRN_FALSE); + grn_obj_cast(ctx, y, &buffer, GRN_FALSE); + GRN_BULK_REWIND(res); + grn_obj_cast(ctx, &buffer, res, GRN_FALSE); + GRN_OBJ_FIN(ctx, &buffer); + } else { + GRN_BULK_REWIND(res); + grn_obj_cast(ctx, x, res, GRN_FALSE); + grn_obj_cast(ctx, y, res, GRN_FALSE); + } + } + ,); + break; + case GRN_OP_MINUS : + if (code->nargs == 1) { + ARITHMETIC_UNARY_OPERATION_DISPATCH( + INTEGER_UNARY_ARITHMETIC_OPERATION_MINUS, + FLOAT_UNARY_ARITHMETIC_OPERATION_MINUS, + ARITHMETIC_OPERATION_NO_CHECK, + ARITHMETIC_OPERATION_NO_CHECK, + { + long long int x_; + + res->header.type = GRN_BULK; + res->header.domain = GRN_DB_INT64; + + GRN_INT64_SET(ctx, res, 0); + grn_obj_cast(ctx, x, res, GRN_FALSE); + x_ = GRN_INT64_VALUE(res); + + GRN_INT64_SET(ctx, res, -x_); + } + ,); + } else { + ARITHMETIC_BINARY_OPERATION_DISPATCH( + "-", + INTEGER_ARITHMETIC_OPERATION_MINUS, + INTEGER_ARITHMETIC_OPERATION_MINUS, + INTEGER_ARITHMETIC_OPERATION_MINUS, + INTEGER_ARITHMETIC_OPERATION_MINUS, + FLOAT_ARITHMETIC_OPERATION_MINUS, + ARITHMETIC_OPERATION_NO_CHECK, + ARITHMETIC_OPERATION_NO_CHECK, + { + ERR(GRN_INVALID_ARGUMENT, + "\"string\" - \"string\" " + "isn't supported"); + goto exit; + } + ,); + } + break; + case GRN_OP_STAR : + ARITHMETIC_BINARY_OPERATION_DISPATCH( + "*", + INTEGER_ARITHMETIC_OPERATION_STAR, + INTEGER_ARITHMETIC_OPERATION_STAR, + INTEGER_ARITHMETIC_OPERATION_STAR, + INTEGER_ARITHMETIC_OPERATION_STAR, + FLOAT_ARITHMETIC_OPERATION_STAR, + ARITHMETIC_OPERATION_NO_CHECK, + ARITHMETIC_OPERATION_NO_CHECK, + { + ERR(GRN_INVALID_ARGUMENT, + "\"string\" * \"string\" " + "isn't supported"); + goto exit; + } + ,); + break; + case GRN_OP_SLASH : + DIVISION_OPERATION_DISPATCH( + SIGNED_INTEGER_DIVISION_OPERATION_SLASH, + UNSIGNED_INTEGER_DIVISION_OPERATION_SLASH, + FLOAT_DIVISION_OPERATION_SLASH, + { + ERR(GRN_INVALID_ARGUMENT, + "\"string\" / \"string\" " + "isn't supported"); + goto exit; + }); + break; + case GRN_OP_MOD : + DIVISION_OPERATION_DISPATCH( + SIGNED_INTEGER_DIVISION_OPERATION_MOD, + UNSIGNED_INTEGER_DIVISION_OPERATION_MOD, + FLOAT_DIVISION_OPERATION_MOD, + { + ERR(GRN_INVALID_ARGUMENT, + "\"string\" %% \"string\" " + "isn't supported"); + goto exit; + }); + break; + case GRN_OP_BITWISE_NOT : + ARITHMETIC_UNARY_OPERATION_DISPATCH( + INTEGER_UNARY_ARITHMETIC_OPERATION_BITWISE_NOT, + FLOAT_UNARY_ARITHMETIC_OPERATION_BITWISE_NOT, + ARITHMETIC_OPERATION_NO_CHECK, + ARITHMETIC_OPERATION_NO_CHECK, + TEXT_UNARY_ARITHMETIC_OPERATION(~),); + break; + case GRN_OP_BITWISE_OR : + ARITHMETIC_BINARY_OPERATION_DISPATCH( + "|", + INTEGER_ARITHMETIC_OPERATION_BITWISE_OR, + INTEGER_ARITHMETIC_OPERATION_BITWISE_OR, + INTEGER_ARITHMETIC_OPERATION_BITWISE_OR, + INTEGER_ARITHMETIC_OPERATION_BITWISE_OR, + FLOAT_ARITHMETIC_OPERATION_BITWISE_OR, + ARITHMETIC_OPERATION_NO_CHECK, + ARITHMETIC_OPERATION_NO_CHECK, + TEXT_ARITHMETIC_OPERATION(|),); + break; + case GRN_OP_BITWISE_XOR : + ARITHMETIC_BINARY_OPERATION_DISPATCH( + "^", + INTEGER_ARITHMETIC_OPERATION_BITWISE_XOR, + INTEGER_ARITHMETIC_OPERATION_BITWISE_XOR, + INTEGER_ARITHMETIC_OPERATION_BITWISE_XOR, + INTEGER_ARITHMETIC_OPERATION_BITWISE_XOR, + FLOAT_ARITHMETIC_OPERATION_BITWISE_XOR, + ARITHMETIC_OPERATION_NO_CHECK, + ARITHMETIC_OPERATION_NO_CHECK, + TEXT_ARITHMETIC_OPERATION(^),); + break; + case GRN_OP_BITWISE_AND : + ARITHMETIC_BINARY_OPERATION_DISPATCH( + "&", + INTEGER_ARITHMETIC_OPERATION_BITWISE_AND, + INTEGER_ARITHMETIC_OPERATION_BITWISE_AND, + INTEGER_ARITHMETIC_OPERATION_BITWISE_AND, + INTEGER_ARITHMETIC_OPERATION_BITWISE_AND, + FLOAT_ARITHMETIC_OPERATION_BITWISE_AND, + ARITHMETIC_OPERATION_NO_CHECK, + ARITHMETIC_OPERATION_NO_CHECK, + TEXT_ARITHMETIC_OPERATION(&),); + break; + case GRN_OP_SHIFTL : + ARITHMETIC_BINARY_OPERATION_DISPATCH( + "<<", + INTEGER_ARITHMETIC_OPERATION_SHIFTL, + INTEGER_ARITHMETIC_OPERATION_SHIFTL, + INTEGER_ARITHMETIC_OPERATION_SHIFTL, + INTEGER_ARITHMETIC_OPERATION_SHIFTL, + FLOAT_ARITHMETIC_OPERATION_SHIFTL, + ARITHMETIC_OPERATION_NO_CHECK, + ARITHMETIC_OPERATION_NO_CHECK, + TEXT_ARITHMETIC_OPERATION(<<),); + break; + case GRN_OP_SHIFTR : + ARITHMETIC_BINARY_OPERATION_DISPATCH( + ">>", + INTEGER_ARITHMETIC_OPERATION_SHIFTR, + INTEGER_ARITHMETIC_OPERATION_SHIFTR, + INTEGER_ARITHMETIC_OPERATION_SHIFTR, + INTEGER_ARITHMETIC_OPERATION_SHIFTR, + FLOAT_ARITHMETIC_OPERATION_SHIFTR, + ARITHMETIC_OPERATION_NO_CHECK, + ARITHMETIC_OPERATION_NO_CHECK, + TEXT_ARITHMETIC_OPERATION(>>),); + break; + case GRN_OP_SHIFTRR : + ARITHMETIC_BINARY_OPERATION_DISPATCH( + ">>>", + INTEGER8_ARITHMETIC_OPERATION_SHIFTRR, + INTEGER16_ARITHMETIC_OPERATION_SHIFTRR, + INTEGER32_ARITHMETIC_OPERATION_SHIFTRR, + INTEGER64_ARITHMETIC_OPERATION_SHIFTRR, + FLOAT_ARITHMETIC_OPERATION_SHIFTRR, + ARITHMETIC_OPERATION_NO_CHECK, + ARITHMETIC_OPERATION_NO_CHECK, + { + long long unsigned int x_; + long long unsigned int y_; + + res->header.type = GRN_BULK; + res->header.domain = GRN_DB_INT64; + + GRN_INT64_SET(ctx, res, 0); + grn_obj_cast(ctx, x, res, GRN_FALSE); + x_ = GRN_INT64_VALUE(res); + + GRN_INT64_SET(ctx, res, 0); + grn_obj_cast(ctx, y, res, GRN_FALSE); + y_ = GRN_INT64_VALUE(res); + + GRN_INT64_SET(ctx, res, x_ >> y_); + } + ,); + break; + case GRN_OP_INCR : + UNARY_OPERATE_AND_ASSIGN_DISPATCH(EXEC_OPERATE, 1, GRN_OBJ_INCR); + break; + case GRN_OP_DECR : + UNARY_OPERATE_AND_ASSIGN_DISPATCH(EXEC_OPERATE, 1, GRN_OBJ_DECR); + break; + case GRN_OP_INCR_POST : + UNARY_OPERATE_AND_ASSIGN_DISPATCH(EXEC_OPERATE_POST, 1, GRN_OBJ_INCR); + break; + case GRN_OP_DECR_POST : + UNARY_OPERATE_AND_ASSIGN_DISPATCH(EXEC_OPERATE_POST, 1, GRN_OBJ_DECR); + break; + case GRN_OP_NOT : + { + grn_obj *value = NULL; + grn_bool value_boolean; + POP1ALLOC1(value, res); + GRN_OBJ_IS_TRUE(ctx, value, value_boolean); + grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0); + GRN_BOOL_SET(ctx, res, !value_boolean); + } + code++; + break; + case GRN_OP_GET_MEMBER : + { + grn_obj *receiver = NULL; + grn_obj *index_or_key = NULL; + POP2ALLOC1(receiver, index_or_key, res); + if (receiver->header.type == GRN_PTR) { + grn_obj *index = index_or_key; + grn_expr_exec_get_member_vector(ctx, expr, receiver, index, res); + } else { + grn_obj *key = index_or_key; + grn_expr_exec_get_member_table(ctx, expr, receiver, key, res); + } + code++; + } + break; + case GRN_OP_REGEXP : + { + grn_obj *target = NULL; + grn_obj *pattern = NULL; + grn_bool matched; + POP1(pattern); + POP1(target); + WITH_SPSAVE({ + matched = grn_operator_exec_regexp(ctx, target, pattern); + }); + ALLOC1(res); + grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0); + GRN_BOOL_SET(ctx, res, matched); + } + code++; + break; + default : + ERR(GRN_FUNCTION_NOT_IMPLEMENTED, "not implemented operator assigned"); + goto exit; + break; + } + } + ctx->impl->stack_curr = sp - s_; + if (ctx->impl->stack_curr > stack_curr) { + val = grn_ctx_pop(ctx); + } +exit : + if (ctx->impl->stack_curr > stack_curr) { + /* + GRN_LOG(ctx, GRN_LOG_WARNING, "stack balance=%d", + stack_curr - ctx->impl->stack_curr); + */ + ctx->impl->stack_curr = stack_curr; + } + return val; +} + 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); + return expr_exec(ctx, executor->expr); } static void @@ -415,8 +2790,6 @@ grn_expr_executor_is_proc(grn_ctx *ctx, return GRN_TRUE; } -grn_rc grn_ctx_expand_stack(grn_ctx *ctx); - static grn_obj * grn_expr_executor_exec_proc(grn_ctx *ctx, grn_expr_executor *executor, Modified: lib/grn_db.h (+0 -36) =================================================================== --- lib/grn_db.h 2018-05-21 18:11:51 +0900 (891f9922e) +++ lib/grn_db.h 2018-05-21 20:51:06 +0900 (263cba455) @@ -387,42 +387,6 @@ grn_rc grn_db_init_builtin_types(grn_ctx *ctx); typedef struct _grn_expr grn_expr; -#define GRN_EXPR_CODE_RELATIONAL_EXPRESSION (0x01) - -typedef struct { - grn_obj *value; - int32_t nargs; - grn_operator op; - uint8_t flags; - int32_t modify; -} grn_expr_code; - -#define GRN_EXPR_CONST_BLK_SIZE GRN_STACK_SIZE - -struct _grn_expr { - grn_db_obj obj; - grn_obj name_buf; - grn_expr_var *vars; - uint32_t nvars; - /* -- compatible with grn_proc -- */ - - uint16_t cacheable; - uint16_t taintable; - grn_obj **const_blks; - grn_obj *values; - grn_expr_code *codes; - uint32_t nconsts; - uint32_t values_curr; - uint32_t values_tail; - uint32_t values_size; - uint32_t codes_curr; - uint32_t codes_size; - - grn_obj objs; - grn_obj dfi; - grn_expr_code *code0; -}; - grn_rc grn_expr_parser_close(grn_ctx *ctx); /** Modified: lib/grn_expr.h (+36 -0) =================================================================== --- lib/grn_expr.h 2018-05-21 18:11:51 +0900 (1aa1fcd39) +++ lib/grn_expr.h 2018-05-21 20:51:06 +0900 (d0fefc4ce) @@ -19,11 +19,45 @@ #pragma once #include "grn_db.h" +#include "grn_expr_code.h" +#include "grn_expr_executor.h" #ifdef __cplusplus extern "C" { #endif +#define GRN_EXPR_CONST_BLK_SIZE GRN_STACK_SIZE + +struct _grn_expr { + grn_db_obj obj; + grn_obj name_buf; + grn_expr_var *vars; + uint32_t nvars; + /* -- compatible with grn_proc -- */ + + uint16_t cacheable; + uint16_t taintable; + grn_obj **const_blks; + grn_obj *values; + grn_expr_code *codes; + uint32_t nconsts; + uint32_t values_curr; + uint32_t values_tail; + uint32_t values_size; + uint32_t codes_curr; + uint32_t codes_size; + + grn_obj objs; + grn_obj dfi; + grn_expr_code *code0; + + struct { + grn_expr_code *codes; + uint32_t codes_curr; + grn_expr_executor executor; + } cache; +}; + #define SCAN_ACCESSOR (0x01) #define SCAN_PUSH (0x02) #define SCAN_POP (0x04) @@ -83,6 +117,8 @@ void grn_p_expr_code(grn_ctx *ctx, grn_expr_code *code); grn_obj *grn_expr_alloc_const(grn_ctx *ctx, grn_obj *expr); +grn_rc grn_ctx_expand_stack(grn_ctx *ctx); + grn_bool grn_expr_is_simple_function_call(grn_ctx *ctx, grn_obj *expr); grn_obj *grn_expr_simple_function_call_get_function(grn_ctx *ctx, grn_obj *expr); grn_rc grn_expr_simple_function_call_get_arguments(grn_ctx *ctx, Modified: lib/grn_expr_code.h (+11 -1) =================================================================== --- lib/grn_expr_code.h 2018-05-21 18:11:51 +0900 (f33c532ee) +++ lib/grn_expr_code.h 2018-05-21 20:51:06 +0900 (424b7433c) @@ -1,6 +1,6 @@ /* -*- c-basic-offset: 2 -*- */ /* - Copyright(C) 2015-2016 Brazil + Copyright(C) 2015-2018 Brazil This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -24,6 +24,16 @@ extern "C" { #endif +#define GRN_EXPR_CODE_RELATIONAL_EXPRESSION (0x01) + +typedef struct { + grn_obj *value; + int32_t nargs; + grn_operator op; + uint8_t flags; + int32_t modify; +} grn_expr_code; + unsigned int grn_expr_code_n_used_codes(grn_ctx *ctx, grn_expr_code *start, grn_expr_code *target); Modified: lib/output.c (+3 -2) =================================================================== --- lib/output.c 2018-05-21 18:11:51 +0900 (a8972cd07) +++ lib/output.c 2018-05-21 20:51:06 +0900 (f4b020df7) @@ -1,5 +1,6 @@ /* -*- c-basic-offset: 2 -*- */ -/* Copyright(C) 2009-2015 Brazil +/* + Copyright(C) 2009-2018 Brazil This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -20,7 +21,7 @@ #include <string.h> #include "grn_str.h" #include "grn_db.h" -#include "grn_expr_code.h" +#include "grn_expr.h" #include "grn_util.h" #include "grn_output.h" Modified: lib/proc/proc_in_records.c (+2 -1) =================================================================== --- lib/proc/proc_in_records.c 2018-05-21 18:11:51 +0900 (ca85678e7) +++ lib/proc/proc_in_records.c 2018-05-21 20:51:06 +0900 (cea9bdd7c) @@ -1,6 +1,6 @@ /* -*- c-basic-offset: 2 -*- */ /* - Copyright(C) 2017 Brazil + Copyright(C) 2017-2018 Brazil This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -18,6 +18,7 @@ #include "../grn_proc.h" #include "../grn_db.h" +#include "../grn_expr.h" #include "../grn_store.h" #include <groonga/plugin.h> Modified: lib/scorer.c (+2 -1) =================================================================== --- lib/scorer.c 2018-05-21 18:11:51 +0900 (f1c110ddd) +++ lib/scorer.c 2018-05-21 20:51:06 +0900 (919a97257) @@ -1,6 +1,6 @@ /* -*- c-basic-offset: 2 -*- */ /* - Copyright(C) 2015 Brazil + Copyright(C) 2015-2018 Brazil This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -20,6 +20,7 @@ #include "grn.h" #include "grn_db.h" +#include "grn_expr.h" #include "grn_scorer.h" #include <groonga/scorer.h>