From a175314c3e5827eb193872241446f2f8f5c9d33c Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 4 May 2024 20:07:14 +0200 Subject: Adding upstream version 1:10.5.12. Signed-off-by: Daniel Baumann --- .../mroonga/vendor/groonga/lib/ts/ts_expr_node.c | 5325 ++++++++++++++++++++ 1 file changed, 5325 insertions(+) create mode 100644 storage/mroonga/vendor/groonga/lib/ts/ts_expr_node.c (limited to 'storage/mroonga/vendor/groonga/lib/ts/ts_expr_node.c') diff --git a/storage/mroonga/vendor/groonga/lib/ts/ts_expr_node.c b/storage/mroonga/vendor/groonga/lib/ts/ts_expr_node.c new file mode 100644 index 00000000..4ae90003 --- /dev/null +++ b/storage/mroonga/vendor/groonga/lib/ts/ts_expr_node.c @@ -0,0 +1,5325 @@ +/* -*- c-basic-offset: 2 -*- */ +/* + Copyright(C) 2015-2016 Brazil + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License version 2.1 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA +*/ + +#include "ts_expr_node.h" + +#include +#include + +#include "../grn_ctx.h" +#include "../grn_dat.h" +#include "../grn_db.h" +#include "../grn_geo.h" +#include "../grn_hash.h" +#include "../grn_pat.h" +#include "../grn_store.h" + +#include "ts_log.h" +#include "ts_str.h" +#include "ts_util.h" + +/*------------------------------------------------------------- + * Built-in data kinds. + */ + +/* grn_ts_bool_is_valid() returns whether a value is valid or not. */ +inline static grn_ts_bool +grn_ts_bool_is_valid(grn_ts_bool value) +{ + return GRN_TRUE; +} + +/* grn_ts_int_is_valid() returns whether a value is valid or not. */ +inline static grn_ts_bool +grn_ts_int_is_valid(grn_ts_int value) +{ + return GRN_TRUE; +} + +/* grn_ts_float_is_valid() returns whether a value is valid or not. */ +inline static grn_ts_bool +grn_ts_float_is_valid(grn_ts_float value) +{ + return isfinite(value); +} + +/* grn_ts_time_is_valid() returns whether a value is valid or not. */ +inline static grn_ts_bool +grn_ts_time_is_valid(grn_ts_time value) +{ + return GRN_TRUE; +} + +/* grn_ts_text_is_valid() returns whether a value is valid or not. */ +inline static grn_ts_bool +grn_ts_text_is_valid(grn_ts_text value) +{ + return value.ptr || !value.size; +} + +/* grn_ts_geo_is_valid() returns whether a value is valid or not. */ +inline static grn_ts_bool +grn_ts_geo_is_valid(grn_ts_geo value) +{ + return ((value.latitude >= GRN_GEO_MIN_LATITUDE) && + (value.latitude <= GRN_GEO_MAX_LATITUDE)) && + ((value.longitude >= GRN_GEO_MIN_LONGITUDE) && + (value.longitude <= GRN_GEO_MAX_LONGITUDE)); +} + +#define GRN_TS_VECTOR_IS_VALID(type)\ + if (value.size) {\ + size_t i;\ + if (!value.ptr) {\ + return GRN_FALSE;\ + }\ + for (i = 0; i < value.size; i++) {\ + if (!grn_ts_ ## type ## _is_valid(value.ptr[i])) {\ + return GRN_FALSE;\ + }\ + }\ + }\ + return GRN_TRUE; +/* grn_ts_bool_vector_is_valid() returns whether a value is valid or not. */ +inline static grn_ts_bool +grn_ts_bool_vector_is_valid(grn_ts_bool_vector value) +{ + GRN_TS_VECTOR_IS_VALID(bool) +} + +/* grn_ts_int_vector_is_valid() returns whether a value is valid or not. */ +inline static grn_ts_bool +grn_ts_int_vector_is_valid(grn_ts_int_vector value) +{ + GRN_TS_VECTOR_IS_VALID(int) +} + +/* grn_ts_float_vector_is_valid() returns whether a value is valid or not. */ +inline static grn_ts_bool +grn_ts_float_vector_is_valid(grn_ts_float_vector value) +{ + GRN_TS_VECTOR_IS_VALID(float) +} + +/* grn_ts_time_vector_is_valid() returns whether a value is valid or not. */ +inline static grn_ts_bool +grn_ts_time_vector_is_valid(grn_ts_time_vector value) +{ + GRN_TS_VECTOR_IS_VALID(time) +} + +/* grn_ts_text_vector_is_valid() returns whether a value is valid or not. */ +inline static grn_ts_bool +grn_ts_text_vector_is_valid(grn_ts_text_vector value) +{ + GRN_TS_VECTOR_IS_VALID(text) +} + +/* grn_ts_geo_vector_is_valid() returns whether a value is valid or not. */ +inline static grn_ts_bool +grn_ts_geo_vector_is_valid(grn_ts_geo_vector value) +{ + GRN_TS_VECTOR_IS_VALID(geo) +} +#undef GRN_TS_VECTOR_IS_VALID + +/* grn_ts_bool_zero() returns a zero. */ +inline static grn_ts_bool +grn_ts_bool_zero(void) +{ + return GRN_FALSE; +} + +/* grn_ts_int_zero() returns a zero. */ +inline static grn_ts_int +grn_ts_int_zero(void) +{ + return 0; +} + +/* grn_ts_float_zero() returns a zero. */ +inline static grn_ts_float +grn_ts_float_zero(void) +{ + return 0.0; +} + +/* grn_ts_time_zero() returns a zero. */ +inline static grn_ts_time +grn_ts_time_zero(void) +{ + return 0; +} + +/* grn_ts_text_zero() returns a zero. */ +inline static grn_ts_text +grn_ts_text_zero(void) +{ + return (grn_ts_text){ NULL, 0 }; +} + +/* grn_ts_geo_zero() returns a zero. */ +inline static grn_ts_geo +grn_ts_geo_zero(void) +{ + return (grn_ts_geo){ 0, 0 }; +} + +/* grn_ts_ref_zero() returns a zero. */ +inline static grn_ts_ref +grn_ts_ref_zero(void) +{ + return (grn_ts_ref){ 0, 0.0 }; +} + +/* grn_ts_data_type_to_kind() returns a kind associated with a type. */ +static grn_ts_data_kind +grn_ts_data_type_to_kind(grn_ts_data_type type) +{ + switch (type) { + case GRN_DB_VOID: { + return GRN_TS_VOID; + } + case GRN_DB_BOOL: { + return GRN_TS_BOOL; + } + case GRN_DB_INT8: + case GRN_DB_INT16: + case GRN_DB_INT32: + case GRN_DB_INT64: + case GRN_DB_UINT8: + case GRN_DB_UINT16: + case GRN_DB_UINT32: + case GRN_DB_UINT64: { + return GRN_TS_INT; + } + case GRN_DB_FLOAT: { + return GRN_TS_FLOAT; + } + case GRN_DB_TIME: { + return GRN_TS_TIME; + } + case GRN_DB_SHORT_TEXT: + case GRN_DB_TEXT: + case GRN_DB_LONG_TEXT: { + return GRN_TS_TEXT; + } + case GRN_DB_TOKYO_GEO_POINT: + case GRN_DB_WGS84_GEO_POINT: { + return GRN_TS_GEO; + } + default: { + return GRN_TS_REF; + } + } +} + +/* grn_ts_data_kind_to_type() returns a type associated with a kind. */ +static grn_ts_data_type +grn_ts_data_kind_to_type(grn_ts_data_kind kind) +{ + switch (kind & ~GRN_TS_VECTOR_FLAG) { + case GRN_TS_BOOL: { + return GRN_DB_BOOL; + } + case GRN_TS_INT: { + return GRN_DB_INT64; + } + case GRN_TS_FLOAT: { + return GRN_DB_FLOAT; + } + case GRN_TS_TIME: { + return GRN_DB_TIME; + } + case GRN_TS_TEXT: { + return GRN_DB_TEXT; + } + case GRN_TS_GEO: { + /* GRN_DB_TOKYO_GEO_POINT or GRN_DB_WGS84_GEO_POINT. */ + return GRN_DB_VOID; + } + case GRN_TS_REF: { + /* + * grn_ts_data_kind does not have enough information to get a correct + * table ID. + */ + return GRN_DB_VOID; + } + default: { + return GRN_DB_VOID; + } + } +} + +/*------------------------------------------------------------- + * Operators. + */ + +/* grn_ts_op_logical_not_bool() returns !arg. */ +inline static grn_ts_bool +grn_ts_op_logical_not_bool(grn_ts_bool arg) +{ + return !arg; +} + +/* grn_ts_op_bitwise_not_bool() returns ~arg. */ +inline static grn_ts_bool +grn_ts_op_bitwise_not_bool(grn_ts_bool arg) +{ + return !arg; +} + +/* grn_ts_op_bitwise_not_int() returns ~arg. */ +inline static grn_ts_int +grn_ts_op_bitwise_not_int(grn_ts_int arg) +{ + return ~arg; +} + +/* grn_ts_op_positive_int() returns +arg. */ +inline static grn_ts_int +grn_ts_op_positive_int(grn_ts_int arg) +{ + return arg; +} + +/* grn_ts_op_positive_float() returns +arg. */ +inline static grn_ts_float +grn_ts_op_positive_float(grn_ts_float arg) +{ + return arg; +} + +/* grn_ts_op_negative_int() returns -arg. */ +inline static grn_ts_int +grn_ts_op_negative_int(grn_ts_int arg) +{ + return -arg; +} + +/* grn_ts_op_negative_float() returns -arg. */ +inline static grn_ts_float +grn_ts_op_negative_float(grn_ts_float arg) +{ + return -arg; +} + +/* grn_ts_op_float() returns (Float)arg. */ +static grn_rc +grn_ts_op_float(grn_ctx *ctx, grn_ts_int arg, grn_ts_float *out) +{ + *out = (grn_ts_float)arg; + return GRN_SUCCESS; +} + +/* grn_ts_op_time() returns (Time)arg. */ +static grn_rc +grn_ts_op_time(grn_ctx *ctx, grn_ts_text arg, grn_ts_time *out) +{ + grn_timeval value; + grn_rc rc = grn_str2timeval(arg.ptr, arg.size, &value); + if (rc != GRN_SUCCESS) { + GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "grn_str2timeval failed"); + } + *out = (grn_ts_time)((value.tv_sec * 1000000) + (value.tv_nsec / 1000)); + return GRN_SUCCESS; +} + +/* grn_ts_op_bitwise_and_bool() returns lhs & rhs. */ +inline static grn_ts_bool +grn_ts_op_bitwise_and_bool(grn_ts_bool lhs, grn_ts_bool rhs) +{ + return lhs & rhs; +} + +/* grn_ts_op_bitwise_and_int() returns lhs & rhs. */ +inline static grn_ts_int +grn_ts_op_bitwise_and_int(grn_ts_int lhs, grn_ts_int rhs) +{ + return lhs & rhs; +} + +/* grn_ts_op_bitwise_or_bool() returns lhs | rhs. */ +inline static grn_ts_bool +grn_ts_op_bitwise_or_bool(grn_ts_bool lhs, grn_ts_bool rhs) +{ + return lhs | rhs; +} + +/* grn_ts_op_bitwise_or_int() returns lhs | rhs. */ +inline static grn_ts_int +grn_ts_op_bitwise_or_int(grn_ts_int lhs, grn_ts_int rhs) +{ + return lhs | rhs; +} + +/* grn_ts_op_bitwise_xor_bool() returns lhs ^ rhs. */ +inline static grn_ts_bool +grn_ts_op_bitwise_xor_bool(grn_ts_bool lhs, grn_ts_bool rhs) +{ + return lhs ^ rhs; +} + +/* grn_ts_op_bitwise_xor_int() returns lhs ^ rhs. */ +inline static grn_ts_int +grn_ts_op_bitwise_xor_int(grn_ts_int lhs, grn_ts_int rhs) +{ + return lhs ^ rhs; +} + +/* grn_ts_op_equal_bool() returns lhs == rhs. */ +inline static grn_ts_bool +grn_ts_op_equal_bool(grn_ts_bool lhs, grn_ts_bool rhs) +{ + return lhs == rhs; +} + +/* grn_ts_op_equal_int() returns lhs == rhs. */ +inline static grn_ts_bool +grn_ts_op_equal_int(grn_ts_int lhs, grn_ts_int rhs) +{ + return lhs == rhs; +} + +/* grn_ts_op_equal_float() returns lhs == rhs. */ +inline static grn_ts_bool +grn_ts_op_equal_float(grn_ts_float lhs, grn_ts_float rhs) +{ + /* To suppress warnings, "lhs == rhs" is not used. */ + return (lhs <= rhs) && (lhs >= rhs); +} + +/* grn_ts_op_equal_time() returns lhs == rhs. */ +inline static grn_ts_bool +grn_ts_op_equal_time(grn_ts_time lhs, grn_ts_time rhs) +{ + return lhs == rhs; +} + +/* grn_ts_op_equal_text() returns lhs == rhs. */ +inline static grn_ts_bool +grn_ts_op_equal_text(grn_ts_text lhs, grn_ts_text rhs) +{ + return (lhs.size == rhs.size) && !memcmp(lhs.ptr, rhs.ptr, lhs.size); +} + +/* grn_ts_op_equal_geo() returns lhs == rhs. */ +inline static grn_ts_bool +grn_ts_op_equal_geo(grn_ts_geo lhs, grn_ts_geo rhs) +{ + return (lhs.latitude == rhs.latitude) && (lhs.longitude == rhs.longitude); +} + +/* grn_ts_op_equal_ref() returns lhs == rhs. */ +inline static grn_ts_bool +grn_ts_op_equal_ref(grn_ts_ref lhs, grn_ts_ref rhs) +{ + /* Ignore scores. */ + return lhs.id == rhs.id; +} + +#define GRN_TS_OP_EQUAL_VECTOR(kind)\ + size_t i;\ + if (lhs.size != rhs.size) {\ + return GRN_FALSE;\ + }\ + for (i = 0; i < lhs.size; i++) {\ + if (!grn_ts_op_equal_ ## kind(lhs.ptr[i], rhs.ptr[i])) {\ + return GRN_FALSE;\ + }\ + }\ + return GRN_TRUE; +/* grn_ts_op_equal_bool_vector() returns lhs == rhs. */ +inline static grn_ts_bool +grn_ts_op_equal_bool_vector(grn_ts_bool_vector lhs, grn_ts_bool_vector rhs) +{ + GRN_TS_OP_EQUAL_VECTOR(bool) +} + +/* grn_ts_op_equal_int_vector() returns lhs == rhs. */ +inline static grn_ts_bool +grn_ts_op_equal_int_vector(grn_ts_int_vector lhs, grn_ts_int_vector rhs) +{ + GRN_TS_OP_EQUAL_VECTOR(int) +} + +/* grn_ts_op_equal_float_vector() returns lhs == rhs. */ +inline static grn_ts_bool +grn_ts_op_equal_float_vector(grn_ts_float_vector lhs, grn_ts_float_vector rhs) +{ + GRN_TS_OP_EQUAL_VECTOR(float) +} + +/* grn_ts_op_equal_time_vector() returns lhs == rhs. */ +inline static grn_ts_bool +grn_ts_op_equal_time_vector(grn_ts_time_vector lhs, grn_ts_time_vector rhs) +{ + GRN_TS_OP_EQUAL_VECTOR(time) +} + +/* grn_ts_op_equal_text_vector() returns lhs == rhs. */ +inline static grn_ts_bool +grn_ts_op_equal_text_vector(grn_ts_text_vector lhs, grn_ts_text_vector rhs) +{ + GRN_TS_OP_EQUAL_VECTOR(text) +} + +/* grn_ts_op_equal_geo_vector() returns lhs == rhs. */ +inline static grn_ts_bool +grn_ts_op_equal_geo_vector(grn_ts_geo_vector lhs, grn_ts_geo_vector rhs) +{ + GRN_TS_OP_EQUAL_VECTOR(geo) +} + +/* grn_ts_op_equal_ref_vector() returns lhs == rhs. */ +inline static grn_ts_bool +grn_ts_op_equal_ref_vector(grn_ts_ref_vector lhs, grn_ts_ref_vector rhs) +{ + GRN_TS_OP_EQUAL_VECTOR(ref) +} +#undef GRN_TS_OP_EQUAL_VECTOR + +/* grn_ts_op_not_equal_bool() returns lhs != rhs. */ +inline static grn_ts_bool +grn_ts_op_not_equal_bool(grn_ts_bool lhs, grn_ts_bool rhs) +{ + return lhs != rhs; +} + +/* grn_ts_op_not_equal_int() returns lhs != rhs. */ +inline static grn_ts_bool +grn_ts_op_not_equal_int(grn_ts_int lhs, grn_ts_int rhs) +{ + return lhs != rhs; +} + +/* grn_ts_op_not_equal_float() returns lhs != rhs. */ +inline static grn_ts_bool +grn_ts_op_not_equal_float(grn_ts_float lhs, grn_ts_float rhs) +{ + /* To suppress warnings, "lhs != rhs" is not used. */ + return !grn_ts_op_equal_float(lhs, rhs); +} + +/* grn_ts_op_not_equal_time() returns lhs != rhs. */ +inline static grn_ts_bool +grn_ts_op_not_equal_time(grn_ts_time lhs, grn_ts_time rhs) +{ + return lhs != rhs; +} + +/* grn_ts_op_not_equal_text() returns lhs != rhs. */ +inline static grn_ts_bool +grn_ts_op_not_equal_text(grn_ts_text lhs, grn_ts_text rhs) +{ + return (lhs.size != rhs.size) || memcmp(lhs.ptr, rhs.ptr, lhs.size); +} + +/* grn_ts_op_not_equal_geo() returns lhs != rhs. */ +inline static grn_ts_bool +grn_ts_op_not_equal_geo(grn_ts_geo lhs, grn_ts_geo rhs) +{ + return (lhs.latitude != rhs.latitude) || (lhs.longitude != rhs.longitude); +} + +/* grn_ts_op_not_equal_ref() returns lhs != rhs. */ +inline static grn_ts_bool +grn_ts_op_not_equal_ref(grn_ts_ref lhs, grn_ts_ref rhs) +{ + /* Ignore scores. */ + return lhs.id != rhs.id; +} + +#define GRN_TS_OP_NOT_EQUAL_VECTOR(kind)\ + size_t i;\ + if (lhs.size != rhs.size) {\ + return GRN_TRUE;\ + }\ + for (i = 0; i < lhs.size; i++) {\ + if (grn_ts_op_not_equal_ ## kind(lhs.ptr[i], rhs.ptr[i])) {\ + return GRN_TRUE;\ + }\ + }\ + return GRN_FALSE; +/* grn_ts_op_not_equal_bool_vector() returns lhs != rhs. */ +inline static grn_ts_bool +grn_ts_op_not_equal_bool_vector(grn_ts_bool_vector lhs, grn_ts_bool_vector rhs) +{ + GRN_TS_OP_NOT_EQUAL_VECTOR(bool) +} + +/* grn_ts_op_not_equal_int_vector() returns lhs != rhs. */ +inline static grn_ts_bool +grn_ts_op_not_equal_int_vector(grn_ts_int_vector lhs, grn_ts_int_vector rhs) +{ + GRN_TS_OP_NOT_EQUAL_VECTOR(int) +} + +/* grn_ts_op_not_equal_float_vector() returns lhs != rhs. */ +inline static grn_ts_bool +grn_ts_op_not_equal_float_vector(grn_ts_float_vector lhs, + grn_ts_float_vector rhs) +{ + GRN_TS_OP_NOT_EQUAL_VECTOR(float) +} + +/* grn_ts_op_not_equal_time_vector() returns lhs != rhs. */ +inline static grn_ts_bool +grn_ts_op_not_equal_time_vector(grn_ts_time_vector lhs, grn_ts_time_vector rhs) +{ + GRN_TS_OP_NOT_EQUAL_VECTOR(time) +} + +/* grn_ts_op_not_equal_text_vector() returns lhs != rhs. */ +inline static grn_ts_bool +grn_ts_op_not_equal_text_vector(grn_ts_text_vector lhs, grn_ts_text_vector rhs) +{ + GRN_TS_OP_NOT_EQUAL_VECTOR(text) +} + +/* grn_ts_op_not_equal_geo_vector() returns lhs != rhs. */ +inline static grn_ts_bool +grn_ts_op_not_equal_geo_vector(grn_ts_geo_vector lhs, grn_ts_geo_vector rhs) +{ + GRN_TS_OP_NOT_EQUAL_VECTOR(geo) +} + +/* grn_ts_op_not_equal_ref_vector() returns lhs != rhs. */ +inline static grn_ts_bool +grn_ts_op_not_equal_ref_vector(grn_ts_ref_vector lhs, grn_ts_ref_vector rhs) +{ + GRN_TS_OP_NOT_EQUAL_VECTOR(ref) +} +#undef GRN_TS_OP_NOT_EQUAL_VECTOR + +/* grn_ts_op_less_int() returns lhs < rhs. */ +inline static grn_ts_bool +grn_ts_op_less_int(grn_ts_int lhs, grn_ts_int rhs) +{ + return lhs < rhs; +} + +/* grn_ts_op_less_float() returns lhs < rhs. */ +inline static grn_ts_bool +grn_ts_op_less_float(grn_ts_float lhs, grn_ts_float rhs) +{ + return lhs < rhs; +} + +/* grn_ts_op_less_time() returns lhs < rhs. */ +inline static grn_ts_bool +grn_ts_op_less_time(grn_ts_time lhs, grn_ts_time rhs) +{ + return lhs < rhs; +} + +/* grn_ts_op_less_text() returns lhs < rhs. */ +inline static grn_ts_bool +grn_ts_op_less_text(grn_ts_text lhs, grn_ts_text rhs) +{ + size_t min_size = (lhs.size < rhs.size) ? lhs.size : rhs.size; + int cmp = memcmp(lhs.ptr, rhs.ptr, min_size); + return cmp ? (cmp < 0) : (lhs.size < rhs.size); +} + +#define GRN_TS_OP_LESS_VECTOR(kind)\ + size_t i, min_size = (lhs.size < rhs.size) ? lhs.size : rhs.size;\ + for (i = 0; i < min_size; i++) {\ + if (grn_ts_op_not_equal_ ## kind(lhs.ptr[i], rhs.ptr[i])) {\ + if (grn_ts_op_less_ ## kind(lhs.ptr[i], rhs.ptr[i])) {\ + return GRN_TRUE;\ + }\ + }\ + }\ + return lhs.size < rhs.size; +/* grn_ts_op_less_int_vector() returns lhs < rhs. */ +inline static grn_ts_bool +grn_ts_op_less_int_vector(grn_ts_int_vector lhs, grn_ts_int_vector rhs) +{ + GRN_TS_OP_LESS_VECTOR(int) +} + +/* grn_ts_op_less_float_vector() returns lhs < rhs. */ +inline static grn_ts_bool +grn_ts_op_less_float_vector(grn_ts_float_vector lhs, grn_ts_float_vector rhs) +{ + GRN_TS_OP_LESS_VECTOR(float) +} + +/* grn_ts_op_less_time_vector() returns lhs < rhs. */ +inline static grn_ts_bool +grn_ts_op_less_time_vector(grn_ts_time_vector lhs, grn_ts_time_vector rhs) +{ + GRN_TS_OP_LESS_VECTOR(time) +} + +/* grn_ts_op_less_text_vector() returns lhs < rhs. */ +inline static grn_ts_bool +grn_ts_op_less_text_vector(grn_ts_text_vector lhs, grn_ts_text_vector rhs) +{ + GRN_TS_OP_LESS_VECTOR(text) +} +#undef GRN_TS_OP_LESS_VECTOR + +/* grn_ts_op_less_equal_int() returns lhs <= rhs. */ +inline static grn_ts_bool +grn_ts_op_less_equal_int(grn_ts_int lhs, grn_ts_int rhs) +{ + return lhs <= rhs; +} + +/* grn_ts_op_less_equal_float() returns lhs <= rhs. */ +inline static grn_ts_bool +grn_ts_op_less_equal_float(grn_ts_float lhs, grn_ts_float rhs) +{ + return lhs <= rhs; +} + +/* grn_ts_op_less_equal_time() returns lhs <= rhs. */ +inline static grn_ts_bool +grn_ts_op_less_equal_time(grn_ts_time lhs, grn_ts_time rhs) +{ + return lhs <= rhs; +} + +/* grn_ts_op_less_equal_text() returns lhs <= rhs. */ +inline static grn_ts_bool +grn_ts_op_less_equal_text(grn_ts_text lhs, grn_ts_text rhs) +{ + size_t min_size = (lhs.size < rhs.size) ? lhs.size : rhs.size; + int cmp = memcmp(lhs.ptr, rhs.ptr, min_size); + return cmp ? (cmp < 0) : (lhs.size <= rhs.size); +} + +#define GRN_TS_OP_LESS_EQUAL_VECTOR(kind)\ + size_t i, min_size = (lhs.size < rhs.size) ? lhs.size : rhs.size;\ + for (i = 0; i < min_size; i++) {\ + if (grn_ts_op_not_equal_ ## kind(lhs.ptr[i], rhs.ptr[i])) {\ + if (grn_ts_op_less_ ## kind(lhs.ptr[i], rhs.ptr[i])) {\ + return GRN_TRUE;\ + }\ + }\ + }\ + return lhs.size <= rhs.size; +/* grn_ts_op_less_equal_int_vector() returns lhs <= rhs. */ +inline static grn_ts_bool +grn_ts_op_less_equal_int_vector(grn_ts_int_vector lhs, grn_ts_int_vector rhs) +{ + GRN_TS_OP_LESS_EQUAL_VECTOR(int) +} + +/* grn_ts_op_less_equal_float_vector() returns lhs <= rhs. */ +inline static grn_ts_bool +grn_ts_op_less_equal_float_vector(grn_ts_float_vector lhs, + grn_ts_float_vector rhs) +{ + GRN_TS_OP_LESS_EQUAL_VECTOR(float) +} + +/* grn_ts_op_less_equal_time_vector() returns lhs <= rhs. */ +inline static grn_ts_bool +grn_ts_op_less_equal_time_vector(grn_ts_time_vector lhs, + grn_ts_time_vector rhs) +{ + GRN_TS_OP_LESS_EQUAL_VECTOR(time) +} + +/* grn_ts_op_less_equal_text_vector() returns lhs <= rhs. */ +inline static grn_ts_bool +grn_ts_op_less_equal_text_vector(grn_ts_text_vector lhs, + grn_ts_text_vector rhs) +{ + GRN_TS_OP_LESS_EQUAL_VECTOR(text) +} +#undef GRN_TS_OP_LESS_EQUAL_VECTOR + +/* grn_ts_op_greater_int() returns lhs > rhs. */ +inline static grn_ts_bool +grn_ts_op_greater_int(grn_ts_int lhs, grn_ts_int rhs) +{ + return lhs > rhs; +} + +/* grn_ts_op_greater_float() returns lhs > rhs. */ +inline static grn_ts_bool +grn_ts_op_greater_float(grn_ts_float lhs, grn_ts_float rhs) +{ + return lhs > rhs; +} + +/* grn_ts_op_greater_time() returns lhs > rhs. */ +inline static grn_ts_bool +grn_ts_op_greater_time(grn_ts_time lhs, grn_ts_time rhs) +{ + return lhs > rhs; +} + +/* grn_ts_op_greater_text() returns lhs > rhs. */ +inline static grn_ts_bool +grn_ts_op_greater_text(grn_ts_text lhs, grn_ts_text rhs) +{ + size_t min_size = (lhs.size < rhs.size) ? lhs.size : rhs.size; + int cmp = memcmp(lhs.ptr, rhs.ptr, min_size); + return cmp ? (cmp > 0) : (lhs.size > rhs.size); +} + +#define GRN_TS_OP_GREATER_VECTOR(kind)\ + size_t i, min_size = (lhs.size < rhs.size) ? lhs.size : rhs.size;\ + for (i = 0; i < min_size; i++) {\ + if (grn_ts_op_not_equal_ ## kind(lhs.ptr[i], rhs.ptr[i])) {\ + if (grn_ts_op_greater_ ## kind(lhs.ptr[i], rhs.ptr[i])) {\ + return GRN_TRUE;\ + }\ + }\ + }\ + return lhs.size > rhs.size; +/* grn_ts_op_greater_int_vector() returns lhs > rhs. */ +inline static grn_ts_bool +grn_ts_op_greater_int_vector(grn_ts_int_vector lhs, grn_ts_int_vector rhs) +{ + GRN_TS_OP_GREATER_VECTOR(int) +} + +/* grn_ts_op_greater_float_vector() returns lhs > rhs. */ +inline static grn_ts_bool +grn_ts_op_greater_float_vector(grn_ts_float_vector lhs, + grn_ts_float_vector rhs) +{ + GRN_TS_OP_GREATER_VECTOR(float) +} + +/* grn_ts_op_greater_time_vector() returns lhs > rhs. */ +inline static grn_ts_bool +grn_ts_op_greater_time_vector(grn_ts_time_vector lhs, grn_ts_time_vector rhs) +{ + GRN_TS_OP_GREATER_VECTOR(time) +} + +/* grn_ts_op_greater_text_vector() returns lhs > rhs. */ +inline static grn_ts_bool +grn_ts_op_greater_text_vector(grn_ts_text_vector lhs, grn_ts_text_vector rhs) +{ + GRN_TS_OP_GREATER_VECTOR(text) +} +#undef GRN_TS_OP_GREATER_VECTOR + +/* grn_ts_op_greater_equal_int() returns lhs >= rhs. */ +inline static grn_ts_bool +grn_ts_op_greater_equal_int(grn_ts_int lhs, grn_ts_int rhs) +{ + return lhs >= rhs; +} + +/* grn_ts_op_greater_equal_float() returns lhs >= rhs. */ +inline static grn_ts_bool +grn_ts_op_greater_equal_float(grn_ts_float lhs, grn_ts_float rhs) +{ + return lhs >= rhs; +} + +/* grn_ts_op_greater_equal_time() returns lhs >= rhs. */ +inline static grn_ts_bool +grn_ts_op_greater_equal_time(grn_ts_time lhs, grn_ts_time rhs) +{ + return lhs >= rhs; +} + +/* grn_ts_op_greater_equal_text() returns lhs >= rhs. */ +inline static grn_ts_bool +grn_ts_op_greater_equal_text(grn_ts_text lhs, grn_ts_text rhs) +{ + size_t min_size = (lhs.size < rhs.size) ? lhs.size : rhs.size; + int cmp = memcmp(lhs.ptr, rhs.ptr, min_size); + return cmp ? (cmp > 0) : (lhs.size >= rhs.size); +} + +#define GRN_TS_OP_GREATER_EQUAL_VECTOR(kind)\ + size_t i, min_size = (lhs.size < rhs.size) ? lhs.size : rhs.size;\ + for (i = 0; i < min_size; i++) {\ + if (grn_ts_op_not_equal_ ## kind(lhs.ptr[i], rhs.ptr[i])) {\ + if (grn_ts_op_greater_ ## kind(lhs.ptr[i], rhs.ptr[i])) {\ + return GRN_TRUE;\ + }\ + }\ + }\ + return lhs.size >= rhs.size; +/* grn_ts_op_greater_equal_int_vector() returns lhs >= rhs. */ +inline static grn_ts_bool +grn_ts_op_greater_equal_int_vector(grn_ts_int_vector lhs, + grn_ts_int_vector rhs) +{ + GRN_TS_OP_GREATER_EQUAL_VECTOR(int) +} + +/* grn_ts_op_greater_equal_float_vector() returns lhs >= rhs. */ +inline static grn_ts_bool +grn_ts_op_greater_equal_float_vector(grn_ts_float_vector lhs, + grn_ts_float_vector rhs) +{ + GRN_TS_OP_GREATER_EQUAL_VECTOR(float) +} + +/* grn_ts_op_greater_equal_time_vector() returns lhs >= rhs. */ +inline static grn_ts_bool +grn_ts_op_greater_equal_time_vector(grn_ts_time_vector lhs, + grn_ts_time_vector rhs) +{ + GRN_TS_OP_GREATER_EQUAL_VECTOR(time) +} + +/* grn_ts_op_greater_equal_text_vector() returns lhs >= rhs. */ +inline static grn_ts_bool +grn_ts_op_greater_equal_text_vector(grn_ts_text_vector lhs, + grn_ts_text_vector rhs) +{ + GRN_TS_OP_GREATER_EQUAL_VECTOR(text) +} +#undef GRN_TS_OP_GREATER_EQUAL_VECTOR + +/* grn_ts_op_shift_arithmetic_left() returns lhs << rhs. */ +inline static grn_ts_int +grn_ts_op_shift_arithmetic_left(grn_ts_int lhs, grn_ts_int rhs) +{ + return lhs << rhs; +} + +/* grn_ts_op_shift_arithmetic_right() returns lhs << rhs. */ +inline static grn_ts_int +grn_ts_op_shift_arithmetic_right(grn_ts_int lhs, grn_ts_int rhs) +{ + return lhs >> rhs; +} + +/* grn_ts_op_shift_logical_left() returns lhs << rhs. */ +inline static grn_ts_int +grn_ts_op_shift_logical_left(grn_ts_int lhs, grn_ts_int rhs) +{ + return lhs << rhs; +} + +/* grn_ts_op_shift_logical_right() returns lhs << rhs. */ +inline static grn_ts_int +grn_ts_op_shift_logical_right(grn_ts_int lhs, grn_ts_int rhs) +{ + return (uint64_t)lhs >> rhs; +} + +inline static grn_rc +grn_ts_op_plus_int_int(grn_ctx *ctx, grn_ts_int lhs, grn_ts_int rhs, + grn_ts_int *out) +{ + *out = lhs + rhs; + return GRN_SUCCESS; +} + +inline static grn_rc +grn_ts_op_plus_float_float(grn_ctx *ctx, grn_ts_float lhs, grn_ts_float rhs, + grn_ts_float *out) +{ + *out = lhs + rhs; + if (!grn_ts_float_is_valid(*out)) { + GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "%g + %g = %g", lhs, rhs, *out); + } + return GRN_SUCCESS; +} + +inline static grn_rc +grn_ts_op_plus_time_int(grn_ctx *ctx, grn_ts_time lhs, grn_ts_int rhs, + grn_ts_time *out) +{ + *out = lhs + (rhs * 1000000); + return GRN_SUCCESS; +} + +inline static grn_rc +grn_ts_op_plus_time_float(grn_ctx *ctx, grn_ts_time lhs, grn_ts_float rhs, + grn_ts_time *out) +{ + *out = (grn_ts_time)(lhs + (rhs * 1000000.0)); + return GRN_SUCCESS; +} + +inline static grn_rc +grn_ts_op_minus_int_int(grn_ctx *ctx, grn_ts_int lhs, grn_ts_int rhs, + grn_ts_int *out) +{ + *out = lhs - rhs; + return GRN_SUCCESS; +} + +inline static grn_rc +grn_ts_op_minus_float_float(grn_ctx *ctx, grn_ts_float lhs, grn_ts_float rhs, + grn_ts_float *out) +{ + *out = lhs - rhs; + if (!grn_ts_float_is_valid(*out)) { + GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "%g - %g = %g", lhs, rhs, *out); + } + return GRN_SUCCESS; +} + +inline static grn_rc +grn_ts_op_minus_time_time(grn_ctx *ctx, grn_ts_time lhs, grn_ts_time rhs, + grn_ts_float *out) +{ + *out = (lhs - rhs) * 0.000001; + return GRN_SUCCESS; +} + +inline static grn_rc +grn_ts_op_minus_time_int(grn_ctx *ctx, grn_ts_time lhs, grn_ts_int rhs, + grn_ts_time *out) +{ + *out = lhs - (rhs * 1000000); + return GRN_SUCCESS; +} + +inline static grn_rc +grn_ts_op_minus_time_float(grn_ctx *ctx, grn_ts_time lhs, grn_ts_float rhs, + grn_ts_time *out) +{ + *out = lhs - (grn_ts_int)(rhs * 1000000.0); + return GRN_SUCCESS; +} + +inline static grn_rc +grn_ts_op_multiplication_int_int(grn_ctx *ctx, grn_ts_int lhs, grn_ts_int rhs, + grn_ts_int *out) +{ + *out = lhs * rhs; + return GRN_SUCCESS; +} + +inline static grn_rc +grn_ts_op_multiplication_float_float(grn_ctx *ctx, grn_ts_float lhs, + grn_ts_float rhs, grn_ts_float *out) +{ + *out = lhs * rhs; + if (!grn_ts_float_is_valid(*out)) { + GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "%g * %g = %g", lhs, rhs, *out); + } + return GRN_SUCCESS; +} + +inline static grn_rc +grn_ts_op_division_int_int(grn_ctx *ctx, grn_ts_int lhs, grn_ts_int rhs, + grn_ts_int *out) +{ + if (!rhs) { + GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, + "%" GRN_FMT_INT64D " / %" GRN_FMT_INT64D + " causes division by zero", + lhs, rhs); + } + *out = (rhs != -1) ? (lhs / rhs) : -lhs; + return GRN_SUCCESS; +} + +inline static grn_rc +grn_ts_op_division_float_float(grn_ctx *ctx, grn_ts_float lhs, + grn_ts_float rhs, grn_ts_float *out) +{ + *out = lhs / rhs; + if (!grn_ts_float_is_valid(*out)) { + GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "%g / %g = %g", lhs, rhs, *out); + } + return GRN_SUCCESS; +} + +inline static grn_rc +grn_ts_op_modulus_int_int(grn_ctx *ctx, grn_ts_int lhs, grn_ts_int rhs, + grn_ts_int *out) +{ + if (!rhs) { + GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, + "%" GRN_FMT_INT64D " %% %" GRN_FMT_INT64D + " causes division by zero", + lhs, rhs); + } + *out = (rhs != -1) ? (lhs % rhs) : -lhs; + return GRN_SUCCESS; +} + +inline static grn_rc +grn_ts_op_modulus_float_float(grn_ctx *ctx, grn_ts_float lhs, grn_ts_float rhs, + grn_ts_float *out) +{ + *out = fmod(lhs, rhs); + if (!grn_ts_float_is_valid(*out)) { + GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "%g %% %g = %g", lhs, rhs, *out); + } + return GRN_SUCCESS; +} + +static grn_ts_bool +grn_ts_op_match(grn_ts_text lhs, grn_ts_text rhs) +{ + const char *lhs_ptr, *lhs_ptr_last; + if (lhs.size < rhs.size) { + return GRN_FALSE; + } + lhs_ptr_last = lhs.ptr + lhs.size - rhs.size; + for (lhs_ptr = lhs.ptr; lhs_ptr <= lhs_ptr_last; lhs_ptr++) { + size_t i; + for (i = 0; i < rhs.size; i++) { + if (lhs_ptr[i] != rhs.ptr[i]) { + break; + } + } + if (i == rhs.size) { + return GRN_TRUE; + } + } + return GRN_FALSE; +} + +static grn_ts_bool +grn_ts_op_prefix_match(grn_ts_text lhs, grn_ts_text rhs) +{ + size_t i; + if (lhs.size < rhs.size) { + return GRN_FALSE; + } + for (i = 0; i < rhs.size; i++) { + if (lhs.ptr[i] != rhs.ptr[i]) { + return GRN_FALSE; + } + } + return GRN_TRUE; +} + +static grn_ts_bool +grn_ts_op_suffix_match(grn_ts_text lhs, grn_ts_text rhs) +{ + size_t i; + const char *lhs_ptr; + if (lhs.size < rhs.size) { + return GRN_FALSE; + } + lhs_ptr = lhs.ptr + lhs.size - rhs.size; + for (i = 0; i < rhs.size; i++) { + if (lhs_ptr[i] != rhs.ptr[i]) { + return GRN_FALSE; + } + } + return GRN_TRUE; +} + +/*------------------------------------------------------------- + * Groonga objects. + */ + +#define GRN_TS_TABLE_GET_KEY(type)\ + uint32_t key_size;\ + const void *key_ptr = _grn_ ## type ## _key(ctx, type, id, &key_size);\ + if (!key_ptr) {\ + GRN_TS_ERR_RETURN(GRN_UNKNOWN_ERROR, "_grn_" #type "_key failed: %u", id);\ + }\ +/* grn_ts_hash_get_bool_key() gets a reference to a key (_key). */ +static grn_rc +grn_ts_hash_get_bool_key(grn_ctx *ctx, grn_hash *hash, grn_ts_id id, + grn_ts_bool *key) +{ + GRN_TS_TABLE_GET_KEY(hash) + *key = *(const grn_ts_bool *)key_ptr; + return GRN_SUCCESS; +} + +/* grn_ts_hash_get_int8_key() gets a reference to a key (_key). */ +static grn_rc +grn_ts_hash_get_int8_key(grn_ctx *ctx, grn_hash *hash, grn_ts_id id, + grn_ts_int *key) +{ + GRN_TS_TABLE_GET_KEY(hash) + *key = *(const int8_t *)key_ptr; + return GRN_SUCCESS; +} + +/* grn_ts_hash_get_int16_key() gets a reference to a key (_key). */ +static grn_rc +grn_ts_hash_get_int16_key(grn_ctx *ctx, grn_hash *hash, grn_ts_id id, + grn_ts_int *key) +{ + GRN_TS_TABLE_GET_KEY(hash) + *key = *(const int16_t *)key_ptr; + return GRN_SUCCESS; +} + +/* grn_ts_hash_get_int32_key() gets a reference to a key (_key). */ +static grn_rc +grn_ts_hash_get_int32_key(grn_ctx *ctx, grn_hash *hash, grn_ts_id id, + grn_ts_int *key) +{ + GRN_TS_TABLE_GET_KEY(hash) + *key = *(const int32_t *)key_ptr; + return GRN_SUCCESS; +} + +/* grn_ts_hash_get_int64_key() gets a reference to a key (_key). */ +static grn_rc +grn_ts_hash_get_int64_key(grn_ctx *ctx, grn_hash *hash, grn_ts_id id, + grn_ts_int *key) +{ + GRN_TS_TABLE_GET_KEY(hash) + *key = *(const int64_t *)key_ptr; + return GRN_SUCCESS; +} + +/* grn_ts_hash_get_uint8_key() gets a reference to a key (_key). */ +static grn_rc +grn_ts_hash_get_uint8_key(grn_ctx *ctx, grn_hash *hash, grn_ts_id id, + grn_ts_int *key) +{ + GRN_TS_TABLE_GET_KEY(hash) + *key = *(const uint8_t *)key_ptr; + return GRN_SUCCESS; +} + +/* grn_ts_hash_get_uint16_key() gets a reference to a key (_key). */ +static grn_rc +grn_ts_hash_get_uint16_key(grn_ctx *ctx, grn_hash *hash, grn_ts_id id, + grn_ts_int *key) +{ + GRN_TS_TABLE_GET_KEY(hash) + *key = *(const uint16_t *)key_ptr; + return GRN_SUCCESS; +} + +/* grn_ts_hash_get_uint32_key() gets a reference to a key (_key). */ +static grn_rc +grn_ts_hash_get_uint32_key(grn_ctx *ctx, grn_hash *hash, grn_ts_id id, + grn_ts_int *key) +{ + GRN_TS_TABLE_GET_KEY(hash) + *key = *(const uint32_t *)key_ptr; + return GRN_SUCCESS; +} + +/* grn_ts_hash_get_uint64_key() gets a reference to a key (_key). */ +static grn_rc +grn_ts_hash_get_uint64_key(grn_ctx *ctx, grn_hash *hash, grn_ts_id id, + grn_ts_int *key) +{ + GRN_TS_TABLE_GET_KEY(hash) + *key = (grn_ts_int)*(const uint64_t *)key_ptr; + return GRN_SUCCESS; +} + +/* grn_ts_hash_get_float_key() gets a reference to a key (_key). */ +static grn_rc +grn_ts_hash_get_float_key(grn_ctx *ctx, grn_hash *hash, grn_ts_id id, + grn_ts_float *key) +{ + GRN_TS_TABLE_GET_KEY(hash) + *key = *(const grn_ts_float *)key_ptr; + return GRN_SUCCESS; +} + +/* grn_ts_hash_get_time_key() gets a reference to a key (_key). */ +static grn_rc +grn_ts_hash_get_time_key(grn_ctx *ctx, grn_hash *hash, grn_ts_id id, + grn_ts_time *key) +{ + GRN_TS_TABLE_GET_KEY(hash) + *key = *(const grn_ts_time *)key_ptr; + return GRN_SUCCESS; +} + +/* grn_ts_hash_get_geo_key() gets a reference to a key (_key). */ +static grn_rc +grn_ts_hash_get_geo_key(grn_ctx *ctx, grn_hash *hash, grn_ts_id id, + grn_ts_geo *key) +{ + GRN_TS_TABLE_GET_KEY(hash) + *key = *(const grn_ts_geo *)key_ptr; + return GRN_SUCCESS; +} + +/* grn_ts_hash_get_text_key() gets a reference to a key (_key). */ +static grn_rc +grn_ts_hash_get_text_key(grn_ctx *ctx, grn_hash *hash, grn_ts_id id, + grn_ts_text *key) +{ + GRN_TS_TABLE_GET_KEY(hash) + key->ptr = key_ptr; + key->size = key_size; + return GRN_SUCCESS; +} + +/* grn_ts_hash_get_ref_key() gets a reference to a key (_key). */ +static grn_rc +grn_ts_hash_get_ref_key(grn_ctx *ctx, grn_hash *hash, grn_ts_id id, + grn_ts_ref *key) +{ + GRN_TS_TABLE_GET_KEY(hash) + key->id = *(const grn_ts_id *)key_ptr; + return GRN_SUCCESS; +} + +/* grn_ts_pat_get_bool_key() gets a reference to a key (_key). */ +static grn_rc +grn_ts_pat_get_bool_key(grn_ctx *ctx, grn_pat *pat, grn_ts_id id, + grn_ts_bool *key) +{ + GRN_TS_TABLE_GET_KEY(pat) + *key = *(const grn_ts_bool *)key_ptr; + return GRN_SUCCESS; +} + +/* grn_ts_pat_get_int8_key() gets a reference to a key (_key). */ +static grn_rc +grn_ts_pat_get_int8_key(grn_ctx *ctx, grn_pat *pat, grn_ts_id id, + grn_ts_int *key) +{ + int8_t tmp; + GRN_TS_TABLE_GET_KEY(pat) + grn_ntohi(&tmp, key_ptr, sizeof(tmp)); + *key = tmp; + return GRN_SUCCESS; +} + +/* grn_ts_pat_get_int16_key() gets a reference to a key (_key). */ +static grn_rc +grn_ts_pat_get_int16_key(grn_ctx *ctx, grn_pat *pat, grn_ts_id id, + grn_ts_int *key) +{ + int16_t tmp; + GRN_TS_TABLE_GET_KEY(pat) + grn_ntohi(&tmp, key_ptr, sizeof(tmp)); + *key = tmp; + return GRN_SUCCESS; +} + +/* grn_ts_pat_get_int32_key() gets a reference to a key (_key). */ +static grn_rc +grn_ts_pat_get_int32_key(grn_ctx *ctx, grn_pat *pat, grn_ts_id id, + grn_ts_int *key) +{ + int32_t tmp; + GRN_TS_TABLE_GET_KEY(pat) + grn_ntohi(&tmp, key_ptr, sizeof(tmp)); + *key = tmp; + return GRN_SUCCESS; +} + +/* grn_ts_pat_get_int64_key() gets a reference to a key (_key). */ +static grn_rc +grn_ts_pat_get_int64_key(grn_ctx *ctx, grn_pat *pat, grn_ts_id id, + grn_ts_int *key) +{ + GRN_TS_TABLE_GET_KEY(pat) + grn_ntohi(key, key_ptr, sizeof(grn_ts_int)); + return GRN_SUCCESS; +} + +/* grn_ts_pat_get_uint8_key() gets a reference to a key (_key). */ +static grn_rc +grn_ts_pat_get_uint8_key(grn_ctx *ctx, grn_pat *pat, grn_ts_id id, + grn_ts_int *key) +{ + GRN_TS_TABLE_GET_KEY(pat) + *key = *(const uint8_t *)key_ptr; + return GRN_SUCCESS; +} + +/* grn_ts_pat_get_uint16_key() gets a reference to a key (_key). */ +static grn_rc +grn_ts_pat_get_uint16_key(grn_ctx *ctx, grn_pat *pat, grn_ts_id id, + grn_ts_int *key) +{ + uint16_t tmp; + GRN_TS_TABLE_GET_KEY(pat) + grn_ntoh(&tmp, key_ptr, sizeof(tmp)); + *key = tmp; + return GRN_SUCCESS; +} + +/* grn_ts_pat_get_uint32_key() gets a reference to a key (_key). */ +static grn_rc +grn_ts_pat_get_uint32_key(grn_ctx *ctx, grn_pat *pat, grn_ts_id id, + grn_ts_int *key) +{ + uint32_t tmp; + GRN_TS_TABLE_GET_KEY(pat) + grn_ntoh(&tmp, key_ptr, sizeof(tmp)); + *key = tmp; + return GRN_SUCCESS; +} + +/* grn_ts_pat_get_uint64_key() gets a reference to a key (_key). */ +static grn_rc +grn_ts_pat_get_uint64_key(grn_ctx *ctx, grn_pat *pat, grn_ts_id id, + grn_ts_int *key) +{ + GRN_TS_TABLE_GET_KEY(pat) + grn_ntoh(key, key_ptr, sizeof(grn_ts_int)); + return GRN_SUCCESS; +} + +/* grn_ts_pat_get_float_key() gets a reference to a key (_key). */ +static grn_rc +grn_ts_pat_get_float_key(grn_ctx *ctx, grn_pat *pat, grn_ts_id id, + grn_ts_float *key) +{ + int64_t tmp; + GRN_TS_TABLE_GET_KEY(pat) + grn_ntoh(&tmp, key_ptr, sizeof(tmp)); + tmp ^= (((tmp ^ ((int64_t)1 << 63)) >> 63) | ((int64_t)1 << 63)); + *(int64_t *)key = tmp; + return GRN_SUCCESS; +} + +/* grn_ts_pat_get_time_key() gets a reference to a key (_key). */ +static grn_rc +grn_ts_pat_get_time_key(grn_ctx *ctx, grn_pat *pat, grn_ts_id id, + grn_ts_time *key) +{ + GRN_TS_TABLE_GET_KEY(pat) + grn_ntohi(key, key_ptr, sizeof(grn_ts_time)); + return GRN_SUCCESS; +} + +/* grn_ts_pat_get_geo_key() gets a reference to a key (_key). */ +static grn_rc +grn_ts_pat_get_geo_key(grn_ctx *ctx, grn_pat *pat, grn_ts_id id, + grn_ts_geo *key) +{ + GRN_TS_TABLE_GET_KEY(pat) + grn_ntog(key, key_ptr, sizeof(grn_ts_geo)); + return GRN_SUCCESS; +} + +/* grn_ts_pat_get_text_key() gets a reference to a key (_key). */ +static grn_rc +grn_ts_pat_get_text_key(grn_ctx *ctx, grn_pat *pat, grn_ts_id id, + grn_ts_text *key) +{ + GRN_TS_TABLE_GET_KEY(pat) + key->ptr = key_ptr; + key->size = key_size; + return GRN_SUCCESS; +} + +/* grn_ts_pat_get_ref_key() gets a reference to a key (_key). */ +static grn_rc +grn_ts_pat_get_ref_key(grn_ctx *ctx, grn_pat *pat, grn_ts_id id, + grn_ts_ref *key) +{ + GRN_TS_TABLE_GET_KEY(pat) + grn_ntoh(&key->id, key_ptr, sizeof(key->id)); + return GRN_SUCCESS; +} + +/* grn_ts_dat_get_text_key() gets a reference to a key (_key). */ +static grn_rc +grn_ts_dat_get_text_key(grn_ctx *ctx, grn_dat *dat, grn_ts_id id, + grn_ts_text *key) +{ + GRN_TS_TABLE_GET_KEY(dat) + key->ptr = key_ptr; + key->size = key_size; + return GRN_SUCCESS; +} +#undef GRN_TS_TABLE_GET_KEY + +/*------------------------------------------------------------- + * grn_ts_expr_id_node. + */ + +typedef struct { + GRN_TS_EXPR_NODE_COMMON_MEMBERS +} grn_ts_expr_id_node; + +/* grn_ts_expr_id_node_init() initializes a node. */ +static void +grn_ts_expr_id_node_init(grn_ctx *ctx, grn_ts_expr_id_node *node) +{ + memset(node, 0, sizeof(*node)); + node->type = GRN_TS_EXPR_ID_NODE; + node->data_kind = GRN_TS_INT; + node->data_type = GRN_DB_UINT32; +} + +/* grn_ts_expr_id_node_fin() finalizes a node. */ +static void +grn_ts_expr_id_node_fin(grn_ctx *ctx, grn_ts_expr_id_node *node) +{ + /* Nothing to do. */ +} + +grn_rc +grn_ts_expr_id_node_open(grn_ctx *ctx, grn_ts_expr_node **node) +{ + grn_ts_expr_id_node *new_node = GRN_MALLOCN(grn_ts_expr_id_node, 1); + if (!new_node) { + GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE, + "GRN_MALLOCN failed: %" GRN_FMT_SIZE " x 1", + sizeof(grn_ts_expr_id_node)); + } + grn_ts_expr_id_node_init(ctx, new_node); + *node = (grn_ts_expr_node *)new_node; + return GRN_SUCCESS; +} + +/* grn_ts_expr_id_node_close() destroys a node. */ +static void +grn_ts_expr_id_node_close(grn_ctx *ctx, grn_ts_expr_id_node *node) +{ + grn_ts_expr_id_node_fin(ctx, node); + GRN_FREE(node); +} + +/* grn_ts_expr_id_node_evaluate() outputs IDs. */ +static grn_rc +grn_ts_expr_id_node_evaluate(grn_ctx *ctx, grn_ts_expr_id_node *node, + const grn_ts_record *in, size_t n_in, void *out) +{ + size_t i; + grn_ts_int *out_ptr = (grn_ts_int *)out; + for (i = 0; i < n_in; i++) { + out_ptr[i] = (grn_ts_int)in[i].id; + } + return GRN_SUCCESS; +} + +/*------------------------------------------------------------- + * grn_ts_expr_score_node. + */ + +typedef struct { + GRN_TS_EXPR_NODE_COMMON_MEMBERS +} grn_ts_expr_score_node; + +/* grn_ts_expr_score_node_init() initializes a node. */ +static void +grn_ts_expr_score_node_init(grn_ctx *ctx, grn_ts_expr_score_node *node) +{ + memset(node, 0, sizeof(*node)); + node->type = GRN_TS_EXPR_SCORE_NODE; + node->data_kind = GRN_TS_FLOAT; + node->data_type = GRN_DB_FLOAT; +} + +/* grn_ts_expr_score_node_fin() finalizes a node. */ +static void +grn_ts_expr_score_node_fin(grn_ctx *ctx, grn_ts_expr_score_node *node) +{ + /* Nothing to do. */ +} + +grn_rc +grn_ts_expr_score_node_open(grn_ctx *ctx, grn_ts_expr_node **node) +{ + grn_ts_expr_score_node *new_node = GRN_MALLOCN(grn_ts_expr_score_node, 1); + if (!new_node) { + GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE, + "GRN_MALLOCN failed: %" GRN_FMT_SIZE " x 1", + sizeof(grn_ts_expr_score_node)); + } + grn_ts_expr_score_node_init(ctx, new_node); + *node = (grn_ts_expr_node *)new_node; + return GRN_SUCCESS; +} + +/* grn_ts_expr_score_node_close() destroys a node. */ +static void +grn_ts_expr_score_node_close(grn_ctx *ctx, grn_ts_expr_score_node *node) +{ + grn_ts_expr_score_node_fin(ctx, node); + GRN_FREE(node); +} + +/* grn_ts_expr_score_node_evaluate() outputs scores. */ +static grn_rc +grn_ts_expr_score_node_evaluate(grn_ctx *ctx, grn_ts_expr_score_node *node, + const grn_ts_record *in, size_t n_in, + void *out) +{ + size_t i; + grn_ts_float *out_ptr = (grn_ts_float *)out; + for (i = 0; i < n_in; i++) { + out_ptr[i] = (grn_ts_float)in[i].score; + } + return GRN_SUCCESS; +} + +/* grn_ts_expr_score_node_adjust() does nothing. */ +static grn_rc +grn_ts_expr_score_node_adjust(grn_ctx *ctx, grn_ts_expr_score_node *node, + grn_ts_record *io, size_t n_io) +{ + /* Nothing to do. */ + return GRN_SUCCESS; +} + +/*------------------------------------------------------------- + * grn_ts_expr_key_node. + */ + +typedef struct { + GRN_TS_EXPR_NODE_COMMON_MEMBERS + grn_obj *table; + grn_ts_buf buf; +} grn_ts_expr_key_node; + +/* grn_ts_expr_key_node_init() initializes a node. */ +static void +grn_ts_expr_key_node_init(grn_ctx *ctx, grn_ts_expr_key_node *node) +{ + memset(node, 0, sizeof(*node)); + node->type = GRN_TS_EXPR_KEY_NODE; + node->table = NULL; + grn_ts_buf_init(ctx, &node->buf); +} + +/* grn_ts_expr_key_node_fin() finalizes a node. */ +static void +grn_ts_expr_key_node_fin(grn_ctx *ctx, grn_ts_expr_key_node *node) +{ + grn_ts_buf_fin(ctx, &node->buf); + if (node->table) { + grn_obj_unlink(ctx, node->table); + } +} + +grn_rc +grn_ts_expr_key_node_open(grn_ctx *ctx, grn_obj *table, + grn_ts_expr_node **node) +{ + grn_rc rc; + grn_ts_expr_key_node *new_node; + if (!grn_ts_table_has_key(ctx, table)) { + GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "the table has no _key"); + } + new_node = GRN_MALLOCN(grn_ts_expr_key_node, 1); + if (!new_node) { + GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE, + "GRN_MALLOCN failed: %" GRN_FMT_SIZE " x 1", + sizeof(grn_ts_expr_key_node)); + } + grn_ts_expr_key_node_init(ctx, new_node); + rc = grn_ts_obj_increment_ref_count(ctx, table); + if (rc != GRN_SUCCESS) { + grn_ts_expr_key_node_fin(ctx, new_node); + GRN_FREE(new_node); + return rc; + } + new_node->data_kind = grn_ts_data_type_to_kind(table->header.domain); + new_node->data_type = table->header.domain; + new_node->table = table; + *node = (grn_ts_expr_node *)new_node; + return GRN_SUCCESS; +} + +/* grn_ts_expr_key_node_close() destroys a node. */ +static void +grn_ts_expr_key_node_close(grn_ctx *ctx, grn_ts_expr_key_node *node) +{ + grn_ts_expr_key_node_fin(ctx, node); + GRN_FREE(node); +} + +#define GRN_TS_EXPR_KEY_NODE_EVALUATE_CASE(table, KIND, kind)\ + case GRN_TS_ ## KIND: {\ + grn_ts_ ## kind *out_ptr = (grn_ts_ ## kind *)out;\ + for (i = 0; i < n_in; i++) {\ + rc = grn_ts_ ## table ## _get_ ## kind ## _key(ctx, table, in[i].id,\ + &out_ptr[i]);\ + if (rc != GRN_SUCCESS) {\ + out_ptr[i] = grn_ts_ ## kind ## _zero();\ + }\ + }\ + return GRN_SUCCESS;\ + } +#define GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(table, TYPE, type)\ + case GRN_DB_ ## TYPE: {\ + grn_ts_int *out_ptr = (grn_ts_int *)out;\ + for (i = 0; i < n_in; i++) {\ + rc = grn_ts_ ## table ## _get_ ## type ## _key(ctx, table, in[i].id,\ + &out_ptr[i]);\ + if (rc != GRN_SUCCESS) {\ + out_ptr[i] = grn_ts_int_zero();\ + }\ + }\ + return GRN_SUCCESS;\ + } +#define GRN_TS_EXPR_KEY_NODE_EVALUATE_TEXT_CASE(table)\ + case GRN_TS_TEXT: {\ + char *buf_ptr;\ + grn_ts_text *out_ptr = (grn_ts_text *)out;\ + node->buf.pos = 0;\ + for (i = 0; i < n_in; i++) {\ + grn_ts_text key;\ + rc = grn_ts_ ## table ## _get_text_key(ctx, table, in[i].id, &key);\ + if (rc != GRN_SUCCESS) {\ + key = grn_ts_text_zero();\ + }\ + rc = grn_ts_buf_write(ctx, &node->buf, key.ptr, key.size);\ + if (rc != GRN_SUCCESS) {\ + return rc;\ + }\ + out_ptr[i].size = key.size;\ + }\ + buf_ptr = (char *)node->buf.ptr;\ + for (i = 0; i < n_in; i++) {\ + out_ptr[i].ptr = buf_ptr;\ + buf_ptr += out_ptr[i].size;\ + }\ + return GRN_SUCCESS;\ + } +#define GRN_TS_EXPR_KEY_NODE_EVALUATE_REF_CASE(table)\ + case GRN_TS_REF: {\ + grn_ts_ref *out_ptr = (grn_ts_ref *)out;\ + for (i = 0; i < n_in; i++) {\ + rc = grn_ts_ ## table ## _get_ref_key(ctx, table, in[i].id,\ + &out_ptr[i]);\ + if (rc != GRN_SUCCESS) {\ + out_ptr[i] = grn_ts_ref_zero();\ + }\ + out_ptr[i].score = in[i].score;\ + }\ + return GRN_SUCCESS;\ + } +/* grn_ts_expr_key_node_evaluate() outputs keys. */ +static grn_rc +grn_ts_expr_key_node_evaluate(grn_ctx *ctx, grn_ts_expr_key_node *node, + const grn_ts_record *in, size_t n_in, void *out) +{ + size_t i; + grn_rc rc; + switch (node->table->header.type) { + case GRN_TABLE_HASH_KEY: { + grn_hash *hash = (grn_hash *)node->table; + switch (node->data_kind) { + GRN_TS_EXPR_KEY_NODE_EVALUATE_CASE(hash, BOOL, bool) + case GRN_TS_INT: { + switch (node->data_type) { + GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(hash, INT8, int8) + GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(hash, INT16, int16) + GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(hash, INT32, int32) + GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(hash, INT64, int64) + GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(hash, UINT8, uint8) + GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(hash, UINT16, uint16) + GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(hash, UINT32, uint32) + GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(hash, UINT64, uint64) + } + } + GRN_TS_EXPR_KEY_NODE_EVALUATE_CASE(hash, FLOAT, float) + GRN_TS_EXPR_KEY_NODE_EVALUATE_CASE(hash, TIME, time) + GRN_TS_EXPR_KEY_NODE_EVALUATE_TEXT_CASE(hash) + GRN_TS_EXPR_KEY_NODE_EVALUATE_CASE(hash, GEO, geo) + GRN_TS_EXPR_KEY_NODE_EVALUATE_REF_CASE(hash) + default: { + GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d", + node->data_kind); + } + } + } + case GRN_TABLE_PAT_KEY: { + grn_pat *pat = (grn_pat *)node->table; + switch (node->data_kind) { + GRN_TS_EXPR_KEY_NODE_EVALUATE_CASE(pat, BOOL, bool) + case GRN_TS_INT: { + switch (node->data_type) { + GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(pat, INT8, int8) + GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(pat, INT16, int16) + GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(pat, INT32, int32) + GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(pat, INT64, int64) + GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(pat, UINT8, uint8) + GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(pat, UINT16, uint16) + GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(pat, UINT32, uint32) + GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(pat, UINT64, uint64) + } + } + GRN_TS_EXPR_KEY_NODE_EVALUATE_CASE(pat, FLOAT, float) + GRN_TS_EXPR_KEY_NODE_EVALUATE_CASE(pat, TIME, time) + GRN_TS_EXPR_KEY_NODE_EVALUATE_TEXT_CASE(pat) + GRN_TS_EXPR_KEY_NODE_EVALUATE_CASE(pat, GEO, geo) + GRN_TS_EXPR_KEY_NODE_EVALUATE_REF_CASE(pat) + default: { + GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d", + node->data_kind); + } + } + } + case GRN_TABLE_DAT_KEY: { + grn_dat *dat = (grn_dat *)node->table; + switch (node->data_kind) { + GRN_TS_EXPR_KEY_NODE_EVALUATE_TEXT_CASE(dat) + /* GRN_TABLE_DAT_KEY supports only Text. */ + default: { + GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d", + node->data_kind); + } + } + } + /* GRN_TABLE_NO_KEY doesn't support _key. */ + default: { + GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid table type: %d", + node->table->header.type); + } + } +} +#undef GRN_TS_EXPR_KEY_NODE_EVALUATE_REF_CASE +#undef GRN_TS_EXPR_KEY_NODE_EVALUATE_TEXT_CASE +#undef GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE +#undef GRN_TS_EXPR_KEY_NODE_EVALUATE_CASE + +/* grn_ts_expr_key_node_filter() filters records. */ +static grn_rc +grn_ts_expr_key_node_filter(grn_ctx *ctx, grn_ts_expr_key_node *node, + grn_ts_record *in, size_t n_in, + grn_ts_record *out, size_t *n_out) +{ + size_t i, count; + grn_ts_bool key; + switch (node->table->header.type) { + case GRN_TABLE_HASH_KEY: { + grn_hash *hash = (grn_hash *)node->table; + for (i = 0, count = 0; i < n_in; i++) { + grn_rc rc = grn_ts_hash_get_bool_key(ctx, hash, in[i].id, &key); + if (rc != GRN_SUCCESS) { + key = grn_ts_bool_zero(); + } + if (key) { + out[count++] = in[i]; + } + } + *n_out = count; + return GRN_SUCCESS; + } + case GRN_TABLE_PAT_KEY: { + grn_pat *pat = (grn_pat *)node->table; + for (i = 0, count = 0; i < n_in; i++) { + grn_rc rc = grn_ts_pat_get_bool_key(ctx, pat, in[i].id, &key); + if (rc != GRN_SUCCESS) { + key = grn_ts_bool_zero(); + } + if (key) { + out[count++] = in[i]; + } + } + *n_out = count; + return GRN_SUCCESS; + } + /* GRN_TABLE_DAT_KEY and GRN_TABLE_NO_KEY don't support a Bool key. */ + default: { + GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid table type: %d", + node->table->header.type); + } + } +} + +/* grn_ts_expr_key_node_adjust() updates scores. */ +static grn_rc +grn_ts_expr_key_node_adjust(grn_ctx *ctx, grn_ts_expr_key_node *node, + grn_ts_record *io, size_t n_io) +{ + size_t i; + grn_ts_float key; + switch (node->table->header.type) { + case GRN_TABLE_HASH_KEY: { + grn_hash *hash = (grn_hash *)node->table; + for (i = 0; i < n_io; i++) { + grn_rc rc = grn_ts_hash_get_float_key(ctx, hash, io[i].id, &key); + if (rc != GRN_SUCCESS) { + key = grn_ts_float_zero(); + } + io[i].score = (grn_ts_score)key; + } + return GRN_SUCCESS; + } + case GRN_TABLE_PAT_KEY: { + grn_pat *pat = (grn_pat *)node->table; + for (i = 0; i < n_io; i++) { + grn_rc rc = grn_ts_pat_get_float_key(ctx, pat, io[i].id, &key); + if (rc != GRN_SUCCESS) { + key = grn_ts_float_zero(); + } + io[i].score = (grn_ts_score)key; + } + return GRN_SUCCESS; + } + /* GRN_TABLE_DAT_KEY and GRN_TABLE_NO_KEY don't support a Float key. */ + default: { + GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid table type: %d", + node->table->header.type); + } + } +} + +/*------------------------------------------------------------- + * grn_ts_expr_value_node. + */ + +typedef struct { + GRN_TS_EXPR_NODE_COMMON_MEMBERS + grn_obj *table; +} grn_ts_expr_value_node; + +/* grn_ts_expr_value_node_init() initializes a node. */ +static void +grn_ts_expr_value_node_init(grn_ctx *ctx, grn_ts_expr_value_node *node) +{ + memset(node, 0, sizeof(*node)); + node->type = GRN_TS_EXPR_VALUE_NODE; + node->table = NULL; +} + +/* grn_ts_expr_value_node_fin() finalizes a node. */ +static void +grn_ts_expr_value_node_fin(grn_ctx *ctx, grn_ts_expr_value_node *node) +{ + if (node->table) { + grn_obj_unlink(ctx, node->table); + } +} + +grn_rc +grn_ts_expr_value_node_open(grn_ctx *ctx, grn_obj *table, + grn_ts_expr_node **node) +{ + grn_rc rc; + grn_ts_expr_value_node *new_node; + if (!grn_ts_table_has_value(ctx, table)) { + GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "table has no _value"); + } + new_node = GRN_MALLOCN(grn_ts_expr_value_node, 1); + if (!new_node) { + GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE, + "GRN_MALLOCN failed: %" GRN_FMT_SIZE " x 1", + sizeof(grn_ts_expr_value_node)); + } + grn_ts_expr_value_node_init(ctx, new_node); + rc = grn_ts_obj_increment_ref_count(ctx, table); + if (rc != GRN_SUCCESS) { + GRN_FREE(new_node); + return rc; + } + new_node->data_kind = grn_ts_data_type_to_kind(DB_OBJ(table)->range); + new_node->data_type = DB_OBJ(table)->range; + new_node->table = table; + *node = (grn_ts_expr_node *)new_node; + return GRN_SUCCESS; +} + +/* grn_ts_expr_value_node_close() destroys a node. */ +static void +grn_ts_expr_value_node_close(grn_ctx *ctx, grn_ts_expr_value_node *node) +{ + grn_ts_expr_value_node_fin(ctx, node); + GRN_FREE(node); +} + +#define GRN_TS_EXPR_VALUE_NODE_EVALUATE_CASE(KIND, kind)\ + case GRN_TS_ ## KIND: {\ + size_t i;\ + grn_ts_ ## kind *out_ptr = (grn_ts_ ## kind *)out;\ + for (i = 0; i < n_in; i++) {\ + const void *ptr = grn_ts_table_get_value(ctx, node->table, in[i].id);\ + if (ptr) {\ + out_ptr[i] = *(const grn_ts_ ## kind *)ptr;\ + } else {\ + out_ptr[i] = grn_ts_ ## kind ## _zero();\ + }\ + }\ + return GRN_SUCCESS;\ + } +#define GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE(TYPE, type)\ + case GRN_DB_ ## TYPE: {\ + size_t i;\ + grn_ts_int *out_ptr = (grn_ts_int *)out;\ + for (i = 0; i < n_in; i++) {\ + const void *ptr = grn_ts_table_get_value(ctx, node->table, in[i].id);\ + if (ptr) {\ + out_ptr[i] = (grn_ts_int)*(const type ## _t *)ptr;\ + } else {\ + out_ptr[i] = grn_ts_int_zero();\ + }\ + }\ + return GRN_SUCCESS;\ + } +/* grn_ts_expr_value_node_evaluate() outputs values. */ +static grn_rc +grn_ts_expr_value_node_evaluate(grn_ctx *ctx, grn_ts_expr_value_node *node, + const grn_ts_record *in, size_t n_in, + void *out) +{ + switch (node->data_kind) { + GRN_TS_EXPR_VALUE_NODE_EVALUATE_CASE(BOOL, bool) + case GRN_TS_INT: { + switch (node->data_type) { + GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE(INT8, int8) + GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE(INT16, int16) + GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE(INT32, int32) + GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE(INT64, int64) + GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE(UINT8, uint8) + GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE(UINT16, uint16) + GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE(UINT32, uint32) + GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE(UINT64, uint64) + default: { + GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data type: %d", + node->data_type); + } + } + } + GRN_TS_EXPR_VALUE_NODE_EVALUATE_CASE(FLOAT, float) + GRN_TS_EXPR_VALUE_NODE_EVALUATE_CASE(TIME, time) + GRN_TS_EXPR_VALUE_NODE_EVALUATE_CASE(GEO, geo) + case GRN_TS_REF: { + size_t i; + grn_ts_ref *out_ptr = (grn_ts_ref *)out; + for (i = 0; i < n_in; i++) { + const void *ptr = grn_ts_table_get_value(ctx, node->table, in[i].id); + if (ptr) { + out_ptr[i].id = *(const grn_ts_id *)ptr; + out_ptr[i].score = in[i].score; + } else { + out_ptr[i] = grn_ts_ref_zero(); + } + } + return GRN_SUCCESS; + } + default: { + GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d", + node->data_kind); + } + } +} +#undef GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE +#undef GRN_TS_EXPR_VALUE_NODE_EVALUATE_CASE + +/* grn_ts_expr_value_node_filter() filters records. */ +static grn_rc +grn_ts_expr_value_node_filter(grn_ctx *ctx, grn_ts_expr_value_node *node, + grn_ts_record *in, size_t n_in, + grn_ts_record *out, size_t *n_out) +{ + size_t i, count = 0; + for (i = 0; i < n_in; i++) { + const void *ptr = grn_ts_table_get_value(ctx, node->table, in[i].id); + if (ptr && *(const grn_ts_bool *)ptr) { + out[count++] = in[i]; + } + } + *n_out = count; + return GRN_SUCCESS; +} + +/* grn_ts_expr_value_node_adjust() updates scores. */ +static grn_rc +grn_ts_expr_value_node_adjust(grn_ctx *ctx, grn_ts_expr_value_node *node, + grn_ts_record *io, size_t n_io) +{ + size_t i; + for (i = 0; i < n_io; i++) { + const void *ptr = grn_ts_table_get_value(ctx, node->table, io[i].id); + if (ptr) { + io[i].score = (grn_ts_score)*(const grn_ts_float *)ptr; + } + } + return GRN_SUCCESS; +} + +/*------------------------------------------------------------- + * grn_ts_expr_const_node. + */ + +typedef struct { + GRN_TS_EXPR_NODE_COMMON_MEMBERS + grn_ts_any content; + grn_ts_buf text_buf; + grn_ts_buf vector_buf; +} grn_ts_expr_const_node; + +/* grn_ts_expr_const_node_init() initializes a node. */ +static void +grn_ts_expr_const_node_init(grn_ctx *ctx, grn_ts_expr_const_node *node) +{ + memset(node, 0, sizeof(*node)); + node->type = GRN_TS_EXPR_CONST_NODE; + grn_ts_buf_init(ctx, &node->text_buf); + grn_ts_buf_init(ctx, &node->vector_buf); +} + +/* grn_ts_expr_const_node_fin() finalizes a node. */ +static void +grn_ts_expr_const_node_fin(grn_ctx *ctx, grn_ts_expr_const_node *node) +{ + grn_ts_buf_fin(ctx, &node->vector_buf); + grn_ts_buf_fin(ctx, &node->text_buf); +} + +#define GRN_TS_EXPR_CONST_NODE_SET_SCALAR_CASE(KIND, kind)\ + case GRN_TS_ ## KIND: {\ + node->content.as_ ## kind = value.as_ ## kind;\ + return GRN_SUCCESS;\ + } +/* grn_ts_expr_const_node_set_scalar() sets a scalar value. */ +static grn_rc +grn_ts_expr_const_node_set_scalar(grn_ctx *ctx, grn_ts_expr_const_node *node, + grn_ts_any value) +{ + switch (node->data_kind) { + GRN_TS_EXPR_CONST_NODE_SET_SCALAR_CASE(BOOL, bool) + GRN_TS_EXPR_CONST_NODE_SET_SCALAR_CASE(INT, int) + GRN_TS_EXPR_CONST_NODE_SET_SCALAR_CASE(FLOAT, float) + GRN_TS_EXPR_CONST_NODE_SET_SCALAR_CASE(TIME, time) + case GRN_TS_TEXT: { + grn_rc rc = grn_ts_buf_write(ctx, &node->text_buf, + value.as_text.ptr, value.as_text.size); + if (rc != GRN_SUCCESS) { + return rc; + } + node->content.as_text.ptr = (const char *)node->text_buf.ptr; + node->content.as_text.size = value.as_text.size; + return GRN_SUCCESS; + } + GRN_TS_EXPR_CONST_NODE_SET_SCALAR_CASE(GEO, geo) + default: { + GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d", + node->data_kind); + } + } +} +#undef GRN_TS_EXPR_CONST_NODE_SET_SCALAR_CASE + +#define GRN_TS_EXPR_CONST_NODE_SET_VECTOR_CASE(KIND, kind)\ + case GRN_TS_ ## KIND ## _VECTOR: {\ + grn_rc rc;\ + size_t n_bytes;\ + const grn_ts_ ## kind *buf_ptr;\ + grn_ts_ ## kind ## _vector vector;\ + vector = value.as_ ## kind ## _vector;\ + n_bytes = sizeof(grn_ts_ ## kind) * vector.size;\ + rc = grn_ts_buf_write(ctx, &node->vector_buf, vector.ptr, n_bytes);\ + if (rc != GRN_SUCCESS) {\ + return rc;\ + }\ + buf_ptr = (const grn_ts_ ## kind *)node->vector_buf.ptr;\ + node->content.as_ ## kind ## _vector.ptr = buf_ptr;\ + node->content.as_ ## kind ## _vector.size = vector.size;\ + return GRN_SUCCESS;\ + } +/* grn_ts_expr_const_node_set_vector() sets a vector value. */ +static grn_rc +grn_ts_expr_const_node_set_vector(grn_ctx *ctx, grn_ts_expr_const_node *node, + grn_ts_any value) +{ + switch (node->data_kind) { + GRN_TS_EXPR_CONST_NODE_SET_VECTOR_CASE(BOOL, bool) + GRN_TS_EXPR_CONST_NODE_SET_VECTOR_CASE(INT, int) + GRN_TS_EXPR_CONST_NODE_SET_VECTOR_CASE(FLOAT, float) + GRN_TS_EXPR_CONST_NODE_SET_VECTOR_CASE(TIME, time) + case GRN_TS_TEXT_VECTOR: { + grn_rc rc; + size_t i, n_bytes, offset, total_size; + grn_ts_text_vector vector = value.as_text_vector; + grn_ts_text *vector_buf; + char *text_buf; + n_bytes = sizeof(grn_ts_text) * vector.size; + rc = grn_ts_buf_resize(ctx, &node->vector_buf, n_bytes); + if (rc != GRN_SUCCESS) { + return rc; + } + vector_buf = (grn_ts_text *)node->vector_buf.ptr; + total_size = 0; + for (i = 0; i < vector.size; i++) { + total_size += vector.ptr[i].size; + } + rc = grn_ts_buf_resize(ctx, &node->text_buf, total_size); + if (rc != GRN_SUCCESS) { + return rc; + } + text_buf = (char *)node->text_buf.ptr; + offset = 0; + for (i = 0; i < vector.size; i++) { + grn_memcpy(text_buf + offset, vector.ptr[i].ptr, vector.ptr[i].size); + vector_buf[i].ptr = text_buf + offset; + vector_buf[i].size = vector.ptr[i].size; + offset += vector.ptr[i].size; + } + node->content.as_text_vector.ptr = vector_buf; + node->content.as_text_vector.size = vector.size; + return GRN_SUCCESS; + } + GRN_TS_EXPR_CONST_NODE_SET_VECTOR_CASE(GEO, geo) + default: { + GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d", + node->data_kind); + } + } +} +#undef GRN_TS_EXPR_CONST_NODE_SET_VECTOR_CASE + +#define GRN_TS_EXPR_CONST_NODE_CHECK_VALUE(KIND, kind)\ + case GRN_TS_ ## KIND: {\ + if (!grn_ts_ ## kind ## _is_valid(value.as_ ## kind)) {\ + GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");\ + }\ + return GRN_SUCCESS;\ + } +static grn_rc +grn_ts_expr_const_node_check_value(grn_ctx *ctx, grn_ts_data_kind kind, + grn_ts_any value) +{ + switch (kind) { + GRN_TS_EXPR_CONST_NODE_CHECK_VALUE(BOOL, bool) + GRN_TS_EXPR_CONST_NODE_CHECK_VALUE(INT, int) + GRN_TS_EXPR_CONST_NODE_CHECK_VALUE(FLOAT, float) + GRN_TS_EXPR_CONST_NODE_CHECK_VALUE(TIME, time) + GRN_TS_EXPR_CONST_NODE_CHECK_VALUE(TEXT, text) + GRN_TS_EXPR_CONST_NODE_CHECK_VALUE(GEO, geo) + GRN_TS_EXPR_CONST_NODE_CHECK_VALUE(BOOL_VECTOR, bool_vector) + GRN_TS_EXPR_CONST_NODE_CHECK_VALUE(INT_VECTOR, int_vector) + GRN_TS_EXPR_CONST_NODE_CHECK_VALUE(FLOAT_VECTOR, float_vector) + GRN_TS_EXPR_CONST_NODE_CHECK_VALUE(TIME_VECTOR, time_vector) + GRN_TS_EXPR_CONST_NODE_CHECK_VALUE(TEXT_VECTOR, text_vector) + GRN_TS_EXPR_CONST_NODE_CHECK_VALUE(GEO_VECTOR, geo_vector) + default: { + GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument"); + } + } +} +#undef GRN_TS_EXPR_CONST_NODE_CHECK_VALUE + +grn_rc +grn_ts_expr_const_node_open(grn_ctx *ctx, grn_ts_data_kind data_kind, + grn_ts_data_type data_type, + grn_ts_any value, grn_ts_expr_node **node) +{ + grn_rc rc = grn_ts_expr_const_node_check_value(ctx, data_kind, value); + grn_ts_expr_const_node *new_node; + if (rc != GRN_SUCCESS) { + return rc; + } + new_node = GRN_MALLOCN(grn_ts_expr_const_node, 1); + if (!new_node) { + GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE, + "GRN_MALLOCN failed: %" GRN_FMT_SIZE " x 1", + sizeof(grn_ts_expr_const_node)); + } + grn_ts_expr_const_node_init(ctx, new_node); + new_node->data_kind = data_kind; + if (data_type != GRN_DB_VOID) { + new_node->data_type = data_type; + } else { + new_node->data_type = grn_ts_data_kind_to_type(data_kind); + } + if (data_kind & GRN_TS_VECTOR_FLAG) { + rc = grn_ts_expr_const_node_set_vector(ctx, new_node, value); + } else { + rc = grn_ts_expr_const_node_set_scalar(ctx, new_node, value); + } + if (rc != GRN_SUCCESS) { + grn_ts_expr_const_node_fin(ctx, new_node); + GRN_FREE(new_node); + return rc; + } + *node = (grn_ts_expr_node *)new_node; + return GRN_SUCCESS; +} + +/* grn_ts_expr_const_node_close() destroys a node. */ +static void +grn_ts_expr_const_node_close(grn_ctx *ctx, grn_ts_expr_const_node *node) +{ + grn_ts_expr_const_node_fin(ctx, node); + GRN_FREE(node); +} + +#define GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE(KIND, kind)\ + case GRN_TS_ ## KIND: {\ + size_t i;\ + grn_ts_ ## kind *out_ptr = (grn_ts_ ## kind *)out;\ + for (i = 0; i < n_in; i++) {\ + out_ptr[i] = node->content.as_ ## kind;\ + }\ + return GRN_SUCCESS;\ + } +#define GRN_TS_EXPR_CONST_NODE_EVALUATE_VECTOR_CASE(KIND, kind)\ + GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE(KIND ## _VECTOR, kind ## _vector) +/* grn_ts_expr_const_node_evaluate() outputs the stored const. */ +static grn_rc +grn_ts_expr_const_node_evaluate(grn_ctx *ctx, grn_ts_expr_const_node *node, + const grn_ts_record *in, size_t n_in, + void *out) +{ + switch (node->data_kind) { + GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE(BOOL, bool) + GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE(INT, int) + GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE(FLOAT, float) + GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE(TIME, time) + GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE(TEXT, text) + GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE(GEO, geo) + GRN_TS_EXPR_CONST_NODE_EVALUATE_VECTOR_CASE(BOOL, bool) + GRN_TS_EXPR_CONST_NODE_EVALUATE_VECTOR_CASE(INT, int) + GRN_TS_EXPR_CONST_NODE_EVALUATE_VECTOR_CASE(FLOAT, float) + GRN_TS_EXPR_CONST_NODE_EVALUATE_VECTOR_CASE(TIME, time) + GRN_TS_EXPR_CONST_NODE_EVALUATE_VECTOR_CASE(TEXT, text) + GRN_TS_EXPR_CONST_NODE_EVALUATE_VECTOR_CASE(GEO, geo) + default: { + GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d", + node->data_kind); + } + } +} +#undef GRN_TS_EXPR_CONST_NODE_EVALUATE_VECTOR_CASE +#undef GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE + +/* grn_ts_expr_const_node_filter() filters records. */ +static grn_rc +grn_ts_expr_const_node_filter(grn_ctx *ctx, grn_ts_expr_const_node *node, + grn_ts_record *in, size_t n_in, + grn_ts_record *out, size_t *n_out) +{ + if (node->content.as_bool) { + /* All the records pass through the filter. */ + if (in != out) { + size_t i; + for (i = 0; i < n_in; i++) { + out[i] = in[i]; + } + } + *n_out = n_in; + } else { + /* All the records are discarded. */ + *n_out = 0; + } + return GRN_SUCCESS; +} + +/* grn_ts_expr_const_node_adjust() updates scores. */ +static grn_rc +grn_ts_expr_const_node_adjust(grn_ctx *ctx, grn_ts_expr_const_node *node, + grn_ts_record *io, size_t n_io) +{ + size_t i; + grn_ts_score score = (grn_ts_score)node->content.as_float; + for (i = 0; i < n_io; i++) { + io[i].score = score; + } + return GRN_SUCCESS; +} + +/*------------------------------------------------------------- + * grn_ts_expr_column_node. + */ + +typedef struct { + GRN_TS_EXPR_NODE_COMMON_MEMBERS + grn_obj *column; + grn_ts_buf buf; + grn_ts_buf body_buf; + grn_ja_reader *reader; +} grn_ts_expr_column_node; + +/* grn_ts_expr_column_node_init() initializes a node. */ +static void +grn_ts_expr_column_node_init(grn_ctx *ctx, grn_ts_expr_column_node *node) +{ + memset(node, 0, sizeof(*node)); + node->type = GRN_TS_EXPR_COLUMN_NODE; + node->column = NULL; + grn_ts_buf_init(ctx, &node->buf); + grn_ts_buf_init(ctx, &node->body_buf); + node->reader = NULL; +} + +/* grn_ts_expr_column_node_fin() finalizes a node. */ +static void +grn_ts_expr_column_node_fin(grn_ctx *ctx, grn_ts_expr_column_node *node) +{ + if (node->reader) { + grn_ja_reader_close(ctx, node->reader); + } + grn_ts_buf_fin(ctx, &node->body_buf); + grn_ts_buf_fin(ctx, &node->buf); + if (node->column) { + grn_obj_unlink(ctx, node->column); + } +} + +#define GRN_TS_EXPR_COLUMN_NODE_OPEN_CASE(TYPE)\ + case GRN_DB_ ## TYPE: {\ + GRN_ ## TYPE ## _INIT(&new_node->buf, GRN_OBJ_VECTOR);\ + break;\ + } +grn_rc +grn_ts_expr_column_node_open(grn_ctx *ctx, grn_obj *column, + grn_ts_expr_node **node) +{ + grn_rc rc; + grn_ts_expr_column_node *new_node = GRN_MALLOCN(grn_ts_expr_column_node, 1); + if (!new_node) { + GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE, + "GRN_MALLOCN failed: %" GRN_FMT_SIZE " x 1", + sizeof(grn_ts_expr_column_node)); + } + grn_ts_expr_column_node_init(ctx, new_node); + new_node->data_kind = grn_ts_data_type_to_kind(DB_OBJ(column)->range); + if (column->header.type == GRN_COLUMN_VAR_SIZE) { + grn_obj_flags type = column->header.flags & GRN_OBJ_COLUMN_TYPE_MASK; + if (type == GRN_OBJ_COLUMN_VECTOR) { + new_node->data_kind |= GRN_TS_VECTOR_FLAG; + } + } + new_node->data_type = DB_OBJ(column)->range; + rc = grn_ts_obj_increment_ref_count(ctx, column); + if (rc != GRN_SUCCESS) { + grn_ts_expr_column_node_fin(ctx, new_node); + GRN_FREE(new_node); + return rc; + } + new_node->column = column; + *node = (grn_ts_expr_node *)new_node; + return GRN_SUCCESS; +} +#undef GRN_TS_EXPR_COLUMN_NODE_OPEN_CASE + +/* grn_ts_expr_column_node_close() destroys a node. */ +static void +grn_ts_expr_column_node_close(grn_ctx *ctx, grn_ts_expr_column_node *node) +{ + grn_ts_expr_column_node_fin(ctx, node); + GRN_FREE(node); +} + +#define GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_CASE(KIND, kind)\ + case GRN_TS_ ## KIND: {\ + size_t i;\ + grn_ts_ ## kind *out_ptr = (grn_ts_ ## kind *)out;\ + grn_ra *ra = (grn_ra *)node->column;\ + grn_ra_cache cache;\ + GRN_RA_CACHE_INIT(ra, &cache);\ + for (i = 0; i < n_in; i++) {\ + grn_ts_ ## kind *ptr = NULL;\ + if (in[i].id) {\ + ptr = (grn_ts_ ## kind *)grn_ra_ref_cache(ctx, ra, in[i].id, &cache);\ + }\ + out_ptr[i] = ptr ? *ptr : grn_ts_ ## kind ## _zero();\ + }\ + GRN_RA_CACHE_FIN(ra, &cache);\ + return GRN_SUCCESS;\ + } +#define GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_INT_CASE(TYPE, type)\ + case GRN_DB_ ## TYPE: {\ + size_t i;\ + grn_ts_int *out_ptr = (grn_ts_int *)out;\ + grn_ra *ra = (grn_ra *)node->column;\ + grn_ra_cache cache;\ + GRN_RA_CACHE_INIT(ra, &cache);\ + for (i = 0; i < n_in; i++) {\ + type ## _t *ptr = NULL;\ + if (in[i].id) {\ + ptr = (type ## _t *)grn_ra_ref_cache(ctx, ra, in[i].id, &cache);\ + }\ + out_ptr[i] = ptr ? (grn_ts_int)*ptr : grn_ts_int_zero();\ + }\ + GRN_RA_CACHE_FIN(ra, &cache);\ + return GRN_SUCCESS;\ + } +/* grn_ts_expr_column_node_evaluate_scalar() outputs scalar column values. */ +static grn_rc +grn_ts_expr_column_node_evaluate_scalar(grn_ctx *ctx, + grn_ts_expr_column_node *node, + const grn_ts_record *in, size_t n_in, + void *out) +{ + switch (node->data_kind) { + GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_CASE(BOOL, bool) + case GRN_TS_INT: { + switch (node->data_type) { + GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_INT_CASE(INT8, int8) + GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_INT_CASE(INT16, int16) + GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_INT_CASE(INT32, int32) + GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_INT_CASE(INT64, int64) + GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_INT_CASE(UINT8, uint8) + GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_INT_CASE(UINT16, uint16) + GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_INT_CASE(UINT32, uint32) + /* The behavior is undefined if a value is greater than 2^63 - 1. */ + GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_INT_CASE(UINT64, uint64) + default: { + GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data type: %d", + node->data_type); + } + } + } + GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_CASE(FLOAT, float) + GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_CASE(TIME, time) + case GRN_TS_TEXT: { + size_t i; + char *buf_ptr; + grn_rc rc; + grn_ts_text *out_ptr = (grn_ts_text *)out; + if (!node->reader) { + rc = grn_ja_reader_open(ctx, (grn_ja *)node->column, &node->reader); + if (rc != GRN_SUCCESS) { + GRN_TS_ERR_RETURN(rc, "grn_ja_reader_open failed"); + } + } else { + grn_ja_reader_unref(ctx, node->reader); + } + node->buf.pos = 0; + for (i = 0; i < n_in; i++) { + rc = grn_ja_reader_seek(ctx, node->reader, in[i].id); + if (rc == GRN_SUCCESS) { + if (node->reader->ref_avail) { + void *addr; + rc = grn_ja_reader_ref(ctx, node->reader, &addr); + if (rc == GRN_SUCCESS) { + out_ptr[i].ptr = (char *)addr; + } + } else { + rc = grn_ts_buf_reserve(ctx, &node->buf, + node->buf.pos + node->reader->value_size); + if (rc == GRN_SUCCESS) { + rc = grn_ja_reader_read(ctx, node->reader, + (char *)node->buf.ptr + node->buf.pos); + if (rc == GRN_SUCCESS) { + out_ptr[i].ptr = NULL; + node->buf.pos += node->reader->value_size; + } + } + } + } + if (rc == GRN_SUCCESS) { + out_ptr[i].size = node->reader->value_size; + } else { + out_ptr[i].ptr = NULL; + out_ptr[i].size = 0; + } + } + buf_ptr = (char *)node->buf.ptr; + for (i = 0; i < n_in; i++) { + if (!out_ptr[i].ptr) { + out_ptr[i].ptr = buf_ptr; + buf_ptr += out_ptr[i].size; + } + } + return GRN_SUCCESS; + } + GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_CASE(GEO, geo) + case GRN_TS_REF: { + size_t i; + grn_ts_ref *out_ptr = (grn_ts_ref *)out; + grn_ra *ra = (grn_ra *)node->column; + grn_ra_cache cache; + GRN_RA_CACHE_INIT(ra, &cache); + for (i = 0; i < n_in; i++) { + grn_ts_id *ptr = NULL; + if (in[i].id) { + ptr = (grn_ts_id *)grn_ra_ref_cache(ctx, ra, in[i].id, &cache); + } + out_ptr[i].id = ptr ? *ptr : GRN_ID_NIL; + out_ptr[i].score = in[i].score; + } + GRN_RA_CACHE_FIN(ra, &cache); + return GRN_SUCCESS; + } + default: { + GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d", + node->data_kind); + } + } +} +#undef GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_INT_CASE +#undef GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_CASE + +/* + * grn_ts_expr_column_node_evaluate_text_vector() outputs text vector column + * values. + */ +static grn_rc +grn_ts_expr_column_node_evaluate_text_vector(grn_ctx *ctx, + grn_ts_expr_column_node *node, + const grn_ts_record *in, + size_t n_in, void *out) +{ + grn_rc rc; + char *buf_ptr; + size_t i, j, n_bytes, n_values, total_n_bytes = 0, total_n_values = 0; + grn_ts_text *text_ptr; + grn_ts_text_vector *out_ptr = (grn_ts_text_vector *)out; + /* Read encoded values into node->body_buf and get the size of each value. */ + node->body_buf.pos = 0; + for (i = 0; i < n_in; i++) { + char *ptr; + rc = grn_ts_ja_get_value(ctx, node->column, in[i].id, + &node->body_buf, &n_bytes); + if (rc == GRN_SUCCESS) { + ptr = (char *)node->body_buf.ptr + total_n_bytes; + GRN_B_DEC(n_values, ptr); + } else { + n_bytes = 0; + n_values = 0; + } + grn_memcpy(&out_ptr[i].ptr, &n_bytes, sizeof(n_bytes)); + out_ptr[i].size = n_values; + total_n_bytes += n_bytes; + total_n_values += n_values; + } + /* Resize node->buf. */ + n_bytes = sizeof(grn_ts_text) * total_n_values; + rc = grn_ts_buf_reserve(ctx, &node->buf, n_bytes); + if (rc != GRN_SUCCESS) { + return rc; + } + /* Decode values and compose the result. */ + buf_ptr = (char *)node->body_buf.ptr; + text_ptr = (grn_ts_text *)node->buf.ptr; + for (i = 0; i < n_in; i++) { + char *ptr = buf_ptr; + grn_memcpy(&n_bytes, &out_ptr[i].ptr, sizeof(n_bytes)); + buf_ptr += n_bytes; + GRN_B_DEC(n_values, ptr); + out_ptr[i].ptr = text_ptr; + for (j = 0; j < out_ptr[i].size; j++) { + GRN_B_DEC(text_ptr[j].size, ptr); + } + for (j = 0; j < out_ptr[i].size; j++) { + text_ptr[j].ptr = ptr; + ptr += text_ptr[j].size; + } + text_ptr += out_ptr[i].size; + } + return GRN_SUCCESS; +} + +/* + * grn_ts_expr_column_node_evaluate_ref_vector() outputs ref vector column + * values. + */ +static grn_rc +grn_ts_expr_column_node_evaluate_ref_vector(grn_ctx *ctx, + grn_ts_expr_column_node *node, + const grn_ts_record *in, + size_t n_in, void *out) +{ + grn_rc rc; + size_t i, j, n_bytes, offset = 0; + grn_ts_id *buf_ptr; + grn_ts_ref *ref_ptr; + grn_ts_ref_vector *out_ptr = (grn_ts_ref_vector *)out; + /* Read column values into node->body_buf and get the size of each value. */ + node->body_buf.pos = 0; + for (i = 0; i < n_in; i++) { + size_t size; + rc = grn_ts_ja_get_value(ctx, node->column, in[i].id, + &node->body_buf, &size); + if (rc == GRN_SUCCESS) { + out_ptr[i].size = size / sizeof(grn_ts_id); + offset += out_ptr[i].size; + } else { + out_ptr[i].size = 0; + } + } + /* Resize node->buf. */ + n_bytes = sizeof(grn_ts_ref) * offset; + rc = grn_ts_buf_reserve(ctx, &node->buf, n_bytes); + if (rc != GRN_SUCCESS) { + return rc; + } + /* Compose the result. */ + buf_ptr = (grn_ts_id *)node->body_buf.ptr; + ref_ptr = (grn_ts_ref *)node->buf.ptr; + for (i = 0; i < n_in; i++) { + out_ptr[i].ptr = ref_ptr; + for (j = 0; j < out_ptr[i].size; j++, buf_ptr++, ref_ptr++) { + ref_ptr->id = *buf_ptr; + ref_ptr->score = in[i].score; + } + } + return GRN_SUCCESS; +} + +#define GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_CASE(KIND, kind)\ + case GRN_TS_ ## KIND ## _VECTOR: {\ + size_t i;\ + grn_ts_ ## kind *buf_ptr;\ + grn_ts_ ## kind ## _vector *out_ptr = (grn_ts_ ## kind ## _vector *)out;\ + /* Read column values into node->buf and save the size of each value. */\ + node->buf.pos = 0;\ + for (i = 0; i < n_in; i++) {\ + size_t n_bytes;\ + grn_rc rc = grn_ts_ja_get_value(ctx, node->column, in[i].id,\ + &node->buf, &n_bytes);\ + if (rc == GRN_SUCCESS) {\ + out_ptr[i].size = n_bytes / sizeof(grn_ts_ ## kind);\ + } else {\ + out_ptr[i].size = 0;\ + }\ + }\ + buf_ptr = (grn_ts_ ## kind *)node->buf.ptr;\ + for (i = 0; i < n_in; i++) {\ + out_ptr[i].ptr = buf_ptr;\ + buf_ptr += out_ptr[i].size;\ + }\ + return GRN_SUCCESS;\ + } +#define GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_INT_CASE(TYPE, type)\ + case GRN_DB_ ## TYPE: {\ + size_t i, j;\ + grn_ts_int *buf_ptr;\ + grn_ts_int_vector *out_ptr = (grn_ts_int_vector *)out;\ + /* + * Read column values into body_buf and typecast the values to grn_ts_int. + * Then, store the grn_ts_int values into node->buf and save the size of + * each value. + */\ + node->buf.pos = 0;\ + for (i = 0; i < n_in; i++) {\ + grn_rc rc;\ + size_t n_bytes, new_n_bytes;\ + node->body_buf.pos = 0;\ + rc = grn_ts_ja_get_value(ctx, node->column, in[i].id,\ + &node->body_buf, &n_bytes);\ + if (rc == GRN_SUCCESS) {\ + out_ptr[i].size = n_bytes / sizeof(type ## _t);\ + } else {\ + out_ptr[i].size = 0;\ + }\ + new_n_bytes = node->buf.pos + (sizeof(grn_ts_int) * out_ptr[i].size);\ + rc = grn_ts_buf_reserve(ctx, &node->buf, new_n_bytes);\ + if (rc == GRN_SUCCESS) {\ + type ## _t *src_ptr = (type ## _t *)node->body_buf.ptr;\ + grn_ts_int *dest_ptr;\ + dest_ptr = (grn_ts_int *)((char *)node->buf.ptr + node->buf.pos);\ + for (j = 0; j < out_ptr[i].size; j++) {\ + dest_ptr[j] = (grn_ts_int)src_ptr[j];\ + }\ + node->buf.pos = new_n_bytes;\ + } else {\ + out_ptr[i].size = 0;\ + }\ + }\ + buf_ptr = (grn_ts_int *)node->buf.ptr;\ + for (i = 0; i < n_in; i++) {\ + out_ptr[i].ptr = buf_ptr;\ + buf_ptr += out_ptr[i].size;\ + }\ + return GRN_SUCCESS;\ + } +/* grn_ts_expr_column_node_evaluate_vector() outputs vector column values. */ +static grn_rc +grn_ts_expr_column_node_evaluate_vector(grn_ctx *ctx, + grn_ts_expr_column_node *node, + const grn_ts_record *in, size_t n_in, + void *out) +{ + switch (node->data_kind) { + GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_CASE(BOOL, bool) + case GRN_TS_INT_VECTOR: { + switch (node->data_type) { + GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_INT_CASE(INT8, int8) + GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_INT_CASE(INT16, int16) + GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_INT_CASE(INT32, int32) + GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_INT_CASE(INT64, int64) + GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_INT_CASE(UINT8, uint8) + GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_INT_CASE(UINT16, uint16) + GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_INT_CASE(UINT32, uint32) + /* The behavior is undefined if a value is greater than 2^63 - 1. */ + GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_INT_CASE(UINT64, uint64) + default: { + GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data type: %d", + node->data_type); + } + } + } + GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_CASE(FLOAT, float) + GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_CASE(TIME, time) + case GRN_TS_TEXT_VECTOR: { + return grn_ts_expr_column_node_evaluate_text_vector(ctx, node, in, n_in, + out); + } + GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_CASE(GEO, geo) + case GRN_TS_REF_VECTOR: { + return grn_ts_expr_column_node_evaluate_ref_vector(ctx, node, in, n_in, + out); + } + default: { + GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d", + node->data_kind); + } + } +} +#undef GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_INT_CASE +#undef GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_CASE + +/* grn_ts_expr_column_node_evaluate() outputs column values. */ +static grn_rc +grn_ts_expr_column_node_evaluate(grn_ctx *ctx, grn_ts_expr_column_node *node, + const grn_ts_record *in, size_t n_in, + void *out) +{ + if (node->data_kind & GRN_TS_VECTOR_FLAG) { + return grn_ts_expr_column_node_evaluate_vector(ctx, node, in, n_in, out); + } else { + return grn_ts_expr_column_node_evaluate_scalar(ctx, node, in, n_in, out); + } +} + +/* grn_ts_expr_column_node_filter() filters records. */ +static grn_rc +grn_ts_expr_column_node_filter(grn_ctx *ctx, grn_ts_expr_column_node *node, + grn_ts_record *in, size_t n_in, + grn_ts_record *out, size_t *n_out) +{ + size_t i, count = 0; + grn_ra *ra = (grn_ra *)node->column; + grn_ra_cache cache; + GRN_RA_CACHE_INIT(ra, &cache); + for (i = 0; i < n_in; i++) { + grn_ts_bool *ptr = NULL; + if (in[i].id) { + ptr = grn_ra_ref_cache(ctx, ra, in[i].id, &cache); + } + if (ptr && *ptr) { + out[count++] = in[i]; + } + } + GRN_RA_CACHE_FIN(ra, &cache); + *n_out = count; + return GRN_SUCCESS; +} + +/* grn_ts_expr_column_node_adjust() updates scores. */ +static grn_rc +grn_ts_expr_column_node_adjust(grn_ctx *ctx, grn_ts_expr_column_node *node, + grn_ts_record *io, size_t n_io) +{ + size_t i; + grn_ra *ra = (grn_ra *)node->column; + grn_ra_cache cache; + GRN_RA_CACHE_INIT(ra, &cache); + for (i = 0; i < n_io; i++) { + grn_ts_float *ptr = NULL; + if (io[i].id) { + ptr = grn_ra_ref_cache(ctx, ra, io[i].id, &cache); + } + if (ptr) { + io[i].score = (grn_ts_score)*ptr; + } + } + GRN_RA_CACHE_FIN(ra, &cache); + return GRN_SUCCESS; +} + +/*------------------------------------------------------------- + * grn_ts_expr_op_node. + */ + +enum { + GRN_TS_EXPR_OP_NODE_MAX_N_ARGS = 3, + GRN_TS_EXPR_OP_NODE_N_BUFS = 3 +}; + +typedef struct { + GRN_TS_EXPR_NODE_COMMON_MEMBERS + grn_ts_op_type op_type; + grn_ts_expr_node *args[GRN_TS_EXPR_OP_NODE_MAX_N_ARGS]; + size_t n_args; + grn_ts_buf bufs[GRN_TS_EXPR_OP_NODE_N_BUFS]; +} grn_ts_expr_op_node; + +/* grn_ts_expr_op_node_init() initializes a node. */ +static void +grn_ts_expr_op_node_init(grn_ctx *ctx, grn_ts_expr_op_node *node) +{ + size_t i; + memset(node, 0, sizeof(*node)); + node->type = GRN_TS_EXPR_OP_NODE; + for (i = 0; i < GRN_TS_EXPR_OP_NODE_MAX_N_ARGS; i++) { + node->args[i] = NULL; + } + for (i = 0; i < GRN_TS_EXPR_OP_NODE_N_BUFS; i++) { + grn_ts_buf_init(ctx, &node->bufs[i]); + } +} + +/* grn_ts_expr_op_node_fin() finalizes a node. */ +static void +grn_ts_expr_op_node_fin(grn_ctx *ctx, grn_ts_expr_op_node *node) +{ + size_t i; + for (i = 0; i < GRN_TS_EXPR_OP_NODE_N_BUFS; i++) { + grn_ts_buf_fin(ctx, &node->bufs[i]); + } + for (i = 0; i < GRN_TS_EXPR_OP_NODE_MAX_N_ARGS; i++) { + if (node->args[i]) { + grn_ts_expr_node_close(ctx, node->args[i]); + } + } +} + +/* + * grn_ts_expr_op_node_deref_args_for_equal() resolves references if required. + */ +static grn_rc +grn_ts_expr_op_node_deref_args_for_equal(grn_ctx *ctx, + grn_ts_expr_op_node *node) +{ + grn_rc rc; + if (node->n_args != 2) { + GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid #args: %" GRN_FMT_SIZE, + node->n_args); + } + if ((node->args[0]->data_kind & ~GRN_TS_VECTOR_FLAG) != GRN_TS_REF) { + return grn_ts_expr_node_deref(ctx, &node->args[1]); + } + if ((node->args[1]->data_kind & ~GRN_TS_VECTOR_FLAG) != GRN_TS_REF) { + return grn_ts_expr_node_deref(ctx, &node->args[0]); + } + + /* FIXME: Arguments should be compared as references if possible. */ + rc = grn_ts_expr_node_deref(ctx, &node->args[0]); + if (rc != GRN_SUCCESS) { + return rc; + } + rc = grn_ts_expr_node_deref(ctx, &node->args[1]); + if (rc != GRN_SUCCESS) { + return rc; + } + return GRN_SUCCESS; +} + +/* grn_ts_expr_op_node_deref_args() resolves references if required. */ +static grn_rc +grn_ts_expr_op_node_deref_args(grn_ctx *ctx, grn_ts_expr_op_node *node) +{ + switch (node->op_type) { + case GRN_TS_OP_EQUAL: + case GRN_TS_OP_NOT_EQUAL: { + return grn_ts_expr_op_node_deref_args_for_equal(ctx, node); + } + /* TODO: Add a ternary operator. */ + default: { + size_t i; + for (i = 0; i < node->n_args; i++) { + grn_rc rc = grn_ts_expr_node_deref(ctx, &node->args[i]); + if (rc != GRN_SUCCESS) { + return rc; + } + } + return GRN_SUCCESS; + } + } +} + +/* + * grn_ts_op_plus_check_args() checks arguments. Note that arguments are + * rearranged in some cases. + */ +static grn_rc +grn_ts_op_plus_check_args(grn_ctx *ctx, grn_ts_expr_op_node *node) +{ + grn_rc rc; + if ((node->args[0]->data_kind == GRN_TS_INT) && + (node->args[1]->data_kind == GRN_TS_FLOAT)) { + rc = grn_ts_expr_op_node_open(ctx, GRN_TS_OP_FLOAT, &node->args[0], + 1, &node->args[0]); + if (rc != GRN_SUCCESS) { + node->args[0] = NULL; + return rc; + } + } else if ((node->args[0]->data_kind == GRN_TS_FLOAT) && + (node->args[1]->data_kind == GRN_TS_INT)) { + rc = grn_ts_expr_op_node_open(ctx, GRN_TS_OP_FLOAT, &node->args[1], + 1, &node->args[1]); + if (rc != GRN_SUCCESS) { + node->args[1] = NULL; + return rc; + } + } + + switch (node->args[0]->data_kind) { + case GRN_TS_INT: { + switch (node->args[1]->data_kind) { + case GRN_TS_INT: { + /* Int + Int = Int. */ + node->data_kind = GRN_TS_INT; + node->data_type = GRN_DB_INT64; + return GRN_SUCCESS; + } + case GRN_TS_TIME: { + /* Int + Time = Time + Int = Time. */ + grn_ts_expr_node *tmp = node->args[0]; + node->args[0] = node->args[1]; + node->args[1] = tmp; + node->data_kind = GRN_TS_TIME; + node->data_type = GRN_DB_TIME; + return GRN_SUCCESS; + } + default: { + GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d", + node->args[1]->data_kind); + } + } + } + case GRN_TS_FLOAT: { + switch (node->args[1]->data_kind) { + case GRN_TS_FLOAT: { + /* Float + Float = Float. */ + node->data_kind = GRN_TS_FLOAT; + node->data_type = GRN_DB_FLOAT; + return GRN_SUCCESS; + } + case GRN_TS_TIME: { + /* Float + Time = Time + Float = Time. */ + grn_ts_expr_node *tmp = node->args[0]; + node->args[0] = node->args[1]; + node->args[1] = tmp; + node->data_kind = GRN_TS_TIME; + node->data_type = GRN_DB_TIME; + return GRN_SUCCESS; + } + default: { + GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d", + node->args[1]->data_kind); + } + } + } + case GRN_TS_TIME: { + switch (node->args[1]->data_kind) { + case GRN_TS_INT: + case GRN_TS_FLOAT: { + /* Time + Int or Float = Time. */ + node->data_kind = GRN_TS_TIME; + node->data_type = GRN_DB_TIME; + return GRN_SUCCESS; + } + default: { + GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d", + node->args[1]->data_kind); + } + } + } + default: { + GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d", + node->args[0]->data_kind); + } + } +} + +/* grn_ts_op_minus_check_args() checks arguments. */ +static grn_rc +grn_ts_op_minus_check_args(grn_ctx *ctx, grn_ts_expr_op_node *node) +{ + grn_rc rc; + if ((node->args[0]->data_kind == GRN_TS_INT) && + (node->args[1]->data_kind == GRN_TS_FLOAT)) { + rc = grn_ts_expr_op_node_open(ctx, GRN_TS_OP_FLOAT, &node->args[0], + 1, &node->args[0]); + if (rc != GRN_SUCCESS) { + node->args[0] = NULL; + return rc; + } + } else if ((node->args[0]->data_kind == GRN_TS_FLOAT) && + (node->args[1]->data_kind == GRN_TS_INT)) { + rc = grn_ts_expr_op_node_open(ctx, GRN_TS_OP_FLOAT, &node->args[1], + 1, &node->args[1]); + if (rc != GRN_SUCCESS) { + node->args[1] = NULL; + return rc; + } + } + + switch (node->args[0]->data_kind) { + case GRN_TS_INT: { + if (node->args[1]->data_kind != GRN_TS_INT) { + GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d", + node->args[1]->data_kind); + } + /* Int - Int = Int. */ + node->data_kind = GRN_TS_INT; + node->data_type = GRN_DB_INT64; + return GRN_SUCCESS; + } + case GRN_TS_FLOAT: { + if (node->args[1]->data_kind != GRN_TS_FLOAT) { + GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d", + node->args[1]->data_kind); + } + /* Float - Float = Float. */ + node->data_kind = GRN_TS_FLOAT; + node->data_type = GRN_DB_FLOAT; + return GRN_SUCCESS; + } + case GRN_TS_TIME: { + switch (node->args[1]->data_kind) { + case GRN_TS_INT: + case GRN_TS_FLOAT: { + /* Time - Int or Float = Time. */ + node->data_kind = GRN_TS_TIME; + node->data_type = GRN_DB_TIME; + return GRN_SUCCESS; + } + case GRN_TS_TIME: { + /* Time - Time = Float. */ + node->data_kind = GRN_TS_FLOAT; + node->data_type = GRN_DB_FLOAT; + return GRN_SUCCESS; + } + default: { + GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d", + node->args[1]->data_kind); + } + } + } + default: { + GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d", + node->args[0]->data_kind); + } + } +} + +/* + * grn_ts_expr_op_node_typecast_args_for_cmp() inserts a typecast operator for + * comparison. + */ +static grn_rc +grn_ts_expr_op_node_typecast_args_for_cmp(grn_ctx *ctx, + grn_ts_expr_op_node *node) +{ + grn_rc rc; + if ((node->args[0]->data_kind == GRN_TS_INT) && + (node->args[1]->data_kind == GRN_TS_FLOAT)) { + rc = grn_ts_expr_op_node_open(ctx, GRN_TS_OP_FLOAT, &node->args[0], + 1, &node->args[0]); + if (rc != GRN_SUCCESS) { + node->args[0] = NULL; + return rc; + } + } else if ((node->args[0]->data_kind == GRN_TS_FLOAT) && + (node->args[1]->data_kind == GRN_TS_INT)) { + rc = grn_ts_expr_op_node_open(ctx, GRN_TS_OP_FLOAT, &node->args[1], + 1, &node->args[1]); + if (rc != GRN_SUCCESS) { + node->args[1] = NULL; + return rc; + } + } else if ((node->args[0]->data_kind == GRN_TS_TIME) && + (node->args[1]->data_kind == GRN_TS_TEXT)) { + rc = grn_ts_expr_op_node_open(ctx, GRN_TS_OP_TIME, &node->args[1], + 1, &node->args[1]); + if (rc != GRN_SUCCESS) { + node->args[1] = NULL; + return rc; + } + } else if ((node->args[0]->data_kind == GRN_TS_TEXT) && + (node->args[1]->data_kind == GRN_TS_TIME)) { + rc = grn_ts_expr_op_node_open(ctx, GRN_TS_OP_TIME, &node->args[0], + 1, &node->args[0]); + if (rc != GRN_SUCCESS) { + node->args[0] = NULL; + return rc; + } + } else { + GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, + "data kind conflict: %d != %d", + node->args[0]->data_kind, + node->args[1]->data_kind); + } + return GRN_SUCCESS; +} + +/* + * grn_ts_expr_op_node_check_args() checks the combination of an operator and + * its arguments. + */ +static grn_rc +grn_ts_expr_op_node_check_args(grn_ctx *ctx, grn_ts_expr_op_node *node) +{ + switch (node->op_type) { + case GRN_TS_OP_LOGICAL_NOT: { + if (node->args[0]->data_kind != GRN_TS_BOOL) { + GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d", + node->args[0]->data_kind); + } + node->data_kind = GRN_TS_BOOL; + node->data_type = GRN_DB_BOOL; + return GRN_SUCCESS; + } + case GRN_TS_OP_BITWISE_NOT: { + switch (node->args[0]->data_kind) { + case GRN_TS_BOOL: + case GRN_TS_INT: { + node->data_kind = node->args[0]->data_kind; + node->data_type = grn_ts_data_kind_to_type(node->data_kind); + return GRN_SUCCESS; + } + default: { + GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d", + node->args[0]->data_kind); + } + } + } + case GRN_TS_OP_POSITIVE: + case GRN_TS_OP_NEGATIVE: { + if ((node->args[0]->data_kind != GRN_TS_INT) && + (node->args[0]->data_kind != GRN_TS_FLOAT)) { + GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d", + node->args[0]->data_kind); + } + node->data_kind = node->args[0]->data_kind; + node->data_type = grn_ts_data_kind_to_type(node->data_kind); + return GRN_SUCCESS; + } + case GRN_TS_OP_FLOAT: { + if (node->args[0]->data_kind != GRN_TS_INT) { + GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d", + node->args[0]->data_kind); + } + node->data_kind = GRN_TS_FLOAT; + node->data_type = GRN_DB_FLOAT; + return GRN_SUCCESS; + } + case GRN_TS_OP_TIME: { + if (node->args[0]->data_kind != GRN_TS_TEXT) { + GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d", + node->args[0]->data_kind); + } + node->data_kind = GRN_TS_TIME; + node->data_type = GRN_DB_TIME; + return GRN_SUCCESS; + } + case GRN_TS_OP_LOGICAL_AND: + case GRN_TS_OP_LOGICAL_OR: + case GRN_TS_OP_LOGICAL_SUB: { + if ((node->args[0]->data_kind != GRN_TS_BOOL) || + (node->args[1]->data_kind != GRN_TS_BOOL)) { + GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d, %d", + node->args[0]->data_kind, node->args[1]->data_kind); + } + node->data_kind = GRN_TS_BOOL; + node->data_type = GRN_DB_BOOL; + return GRN_SUCCESS; + } + case GRN_TS_OP_BITWISE_AND: + case GRN_TS_OP_BITWISE_OR: + case GRN_TS_OP_BITWISE_XOR: { + if (node->args[0]->data_kind != node->args[1]->data_kind) { + GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "data kind conflict: %d != %d", + node->args[0]->data_kind, node->args[1]->data_kind); + } + switch (node->args[0]->data_kind) { + case GRN_TS_BOOL: + case GRN_TS_INT: { + node->data_kind = node->args[0]->data_kind; + node->data_type = grn_ts_data_kind_to_type(node->data_kind); + return GRN_SUCCESS; + } + default: { + GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d", + node->args[0]->data_kind); + } + } + node->data_kind = GRN_TS_BOOL; + node->data_type = GRN_DB_BOOL; + return GRN_SUCCESS; + } + case GRN_TS_OP_EQUAL: + case GRN_TS_OP_NOT_EQUAL: { + grn_ts_data_kind scalar_data_kind; + if (node->args[0]->data_kind != node->args[1]->data_kind) { + grn_rc rc = grn_ts_expr_op_node_typecast_args_for_cmp(ctx, node); + if (rc != GRN_SUCCESS) { + return rc; + } + } + scalar_data_kind = node->args[0]->data_kind & ~GRN_TS_VECTOR_FLAG; + if (((scalar_data_kind == GRN_TS_REF) || + (scalar_data_kind == GRN_TS_GEO)) && + (node->args[0]->data_type != node->args[1]->data_type)) { + GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "data type conflict: %d != %d", + node->args[0]->data_type, node->args[1]->data_type); + } + node->data_kind = GRN_TS_BOOL; + node->data_type = GRN_DB_BOOL; + return GRN_SUCCESS; + } + case GRN_TS_OP_LESS: + case GRN_TS_OP_LESS_EQUAL: + case GRN_TS_OP_GREATER: + case GRN_TS_OP_GREATER_EQUAL: { + if (node->args[0]->data_kind != node->args[1]->data_kind) { + grn_rc rc = grn_ts_expr_op_node_typecast_args_for_cmp(ctx, node); + if (rc != GRN_SUCCESS) { + return rc; + } + } + switch (node->args[0]->data_kind) { + case GRN_TS_INT: + case GRN_TS_FLOAT: + case GRN_TS_TIME: + case GRN_TS_TEXT: + case GRN_TS_INT_VECTOR: + case GRN_TS_FLOAT_VECTOR: + case GRN_TS_TIME_VECTOR: + case GRN_TS_TEXT_VECTOR: { + node->data_kind = GRN_TS_BOOL; + node->data_type = GRN_DB_BOOL; + return GRN_SUCCESS; + } + default: { + GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d", + node->args[0]->data_kind); + } + } + case GRN_TS_OP_SHIFT_ARITHMETIC_LEFT: + case GRN_TS_OP_SHIFT_ARITHMETIC_RIGHT: + case GRN_TS_OP_SHIFT_LOGICAL_LEFT: + case GRN_TS_OP_SHIFT_LOGICAL_RIGHT: { + if ((node->args[0]->data_kind != GRN_TS_INT) || + (node->args[1]->data_kind != GRN_TS_INT)) { + GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d, %d", + node->args[0]->data_kind, + node->args[1]->data_kind); + } + node->data_kind = GRN_TS_INT; + node->data_type = GRN_DB_INT64; + return GRN_SUCCESS; + } + case GRN_TS_OP_PLUS: { + return grn_ts_op_plus_check_args(ctx, node); + } + case GRN_TS_OP_MINUS: { + return grn_ts_op_minus_check_args(ctx, node); + } + case GRN_TS_OP_MULTIPLICATION: + case GRN_TS_OP_DIVISION: + case GRN_TS_OP_MODULUS: { + if (node->args[0]->data_kind != node->args[1]->data_kind) { + grn_rc rc; + if ((node->args[0]->data_kind == GRN_TS_INT) && + (node->args[1]->data_kind == GRN_TS_FLOAT)) { + rc = grn_ts_expr_op_node_open(ctx, GRN_TS_OP_FLOAT, &node->args[0], + 1, &node->args[0]); + if (rc != GRN_SUCCESS) { + node->args[0] = NULL; + return rc; + } + } else if ((node->args[0]->data_kind == GRN_TS_FLOAT) && + (node->args[1]->data_kind == GRN_TS_INT)) { + rc = grn_ts_expr_op_node_open(ctx, GRN_TS_OP_FLOAT, &node->args[1], + 1, &node->args[1]); + if (rc != GRN_SUCCESS) { + node->args[1] = NULL; + return rc; + } + } else { + GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, + "data kind conflict: %d != %d", + node->args[0]->data_kind, + node->args[1]->data_kind); + } + } + switch (node->args[0]->data_kind) { + case GRN_TS_INT: + case GRN_TS_FLOAT: { + node->data_kind = node->args[0]->data_kind; + node->data_type = grn_ts_data_kind_to_type(node->data_kind); + return GRN_SUCCESS; + } + default: { + GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d", + node->args[0]->data_kind); + } + } + } + } + case GRN_TS_OP_MATCH: + case GRN_TS_OP_PREFIX_MATCH: + case GRN_TS_OP_SUFFIX_MATCH: { + if ((node->args[0]->data_kind != GRN_TS_TEXT) || + (node->args[1]->data_kind != GRN_TS_TEXT)) { + GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d, %d", + node->args[0]->data_kind, + node->args[1]->data_kind); + } + node->data_kind = GRN_TS_BOOL; + node->data_type = GRN_DB_BOOL; + return GRN_SUCCESS; + } + default: { + GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid operator: %d", + node->op_type); + } + } +} + +/* grn_ts_expr_op_node_setup() sets up an operator node. */ +static grn_rc +grn_ts_expr_op_node_setup(grn_ctx *ctx, grn_ts_expr_op_node *node) +{ + grn_rc rc = grn_ts_expr_op_node_deref_args(ctx, node); + if (rc != GRN_SUCCESS) { + return rc; + } + rc = grn_ts_expr_op_node_check_args(ctx, node); + if (rc != GRN_SUCCESS) { + return rc; + } + if (node->data_kind == GRN_TS_VOID) { + GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d", + GRN_TS_VOID); + } else if (node->data_type == GRN_DB_VOID) { + GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data type: %d", + GRN_DB_VOID); + } + return GRN_SUCCESS; +} + +grn_rc +grn_ts_expr_op_node_open(grn_ctx *ctx, grn_ts_op_type op_type, + grn_ts_expr_node **args, size_t n_args, + grn_ts_expr_node **node) +{ + size_t i; + grn_rc rc; + grn_ts_expr_op_node *new_node = GRN_MALLOCN(grn_ts_expr_op_node, 1); + if (!new_node) { + for (i = 0; i < n_args; i++) { + grn_ts_expr_node_close(ctx, args[i]); + } + GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE, + "GRN_MALLOCN failed: %" GRN_FMT_SIZE " x 1", + sizeof(grn_ts_expr_op_node)); + } + grn_ts_expr_op_node_init(ctx, new_node); + new_node->op_type = op_type; + for (i = 0; i < n_args; i++) { + new_node->args[i] = args[i]; + } + new_node->n_args = n_args; + rc = grn_ts_expr_op_node_setup(ctx, new_node); + if (rc != GRN_SUCCESS) { + grn_ts_expr_op_node_fin(ctx, new_node); + GRN_FREE(new_node); + return rc; + } + *node = (grn_ts_expr_node *)new_node; + return GRN_SUCCESS; +} + +/* grn_ts_expr_op_node_close() destroys a node. */ +static void +grn_ts_expr_op_node_close(grn_ctx *ctx, grn_ts_expr_op_node *node) +{ + grn_ts_expr_op_node_fin(ctx, node); + GRN_FREE(node); +} + +/* grn_ts_op_logical_not_evaluate() evaluates an operator. */ +static grn_rc +grn_ts_op_logical_not_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node, + const grn_ts_record *in, size_t n_in, void *out) +{ + size_t i; + grn_ts_bool *out_ptr = (grn_ts_bool *)out; + grn_rc rc = grn_ts_expr_node_evaluate(ctx, node->args[0], in, n_in, out); + if (rc != GRN_SUCCESS) { + return rc; + } + for (i = 0; i < n_in; i++) { + out_ptr[i] = grn_ts_op_logical_not_bool(out_ptr[i]); + } + return GRN_SUCCESS; +} + +/* grn_ts_op_bitwise_not_evaluate() evaluates an operator. */ +static grn_rc +grn_ts_op_bitwise_not_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node, + const grn_ts_record *in, size_t n_in, void *out) +{ + size_t i; + grn_rc rc = grn_ts_expr_node_evaluate(ctx, node->args[0], in, n_in, out); + if (rc != GRN_SUCCESS) { + return rc; + } + switch (node->data_kind) { + case GRN_TS_BOOL: { + grn_ts_bool *out_ptr = (grn_ts_bool *)out; + for (i = 0; i < n_in; i++) { + out_ptr[i] = grn_ts_op_bitwise_not_bool(out_ptr[i]); + } + return GRN_SUCCESS; + } + case GRN_TS_INT: { + grn_ts_int *out_ptr = (grn_ts_int *)out; + for (i = 0; i < n_in; i++) { + out_ptr[i] = grn_ts_op_bitwise_not_int(out_ptr[i]); + } + return GRN_SUCCESS; + } + default: { + GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d", + node->data_kind); + } + } +} + +#define GRN_TS_OP_SIGN_EVALUATE_CASE(type, KIND, kind) \ + case GRN_TS_ ## KIND: {\ + grn_ts_ ## kind *out_ptr = (grn_ts_ ## kind *)out;\ + for (i = 0; i < n_in; i++) {\ + out_ptr[i] = grn_ts_op_ ## type ## _ ## kind(out_ptr[i]);\ + }\ + return GRN_SUCCESS;\ + } +#define GRN_TS_OP_SIGN_EVALUATE(type) \ + size_t i;\ + grn_rc rc = grn_ts_expr_node_evaluate(ctx, node->args[0], in, n_in, out);\ + if (rc != GRN_SUCCESS) {\ + return rc;\ + }\ + switch (node->data_kind) {\ + GRN_TS_OP_SIGN_EVALUATE_CASE(type, INT, int)\ + GRN_TS_OP_SIGN_EVALUATE_CASE(type, FLOAT, float)\ + default: {\ + GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",\ + node->data_kind);\ + }\ + } +/* grn_ts_op_positive_evaluate() evaluates an operator. */ +static grn_rc +grn_ts_op_positive_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node, + const grn_ts_record *in, size_t n_in, void *out) +{ + GRN_TS_OP_SIGN_EVALUATE(positive) +} + +/* grn_ts_op_negative_evaluate() evaluates an operator. */ +static grn_rc +grn_ts_op_negative_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node, + const grn_ts_record *in, size_t n_in, void *out) +{ + GRN_TS_OP_SIGN_EVALUATE(negative) +} +#undef GRN_TS_OP_SIGN_EVALUATE +#undef GRN_TS_OP_SIGN_EVALUATE_CASE + +/* grn_ts_op_float_evaluate() evaluates an operator. */ +static grn_rc +grn_ts_op_float_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node, + const grn_ts_record *in, size_t n_in, void *out) +{ + size_t i; + grn_ts_int *buf_ptr; + grn_ts_float *out_ptr = (grn_ts_float *)out; + grn_rc rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[0], in, n_in, + &node->bufs[0]); + if (rc != GRN_SUCCESS) { + return rc; + } + buf_ptr = (grn_ts_int *)node->bufs[0].ptr; + for (i = 0; i < n_in; i++) { + rc = grn_ts_op_float(ctx, buf_ptr[i], &out_ptr[i]); + if (rc != GRN_SUCCESS) { + return rc; + } + } + return GRN_SUCCESS; +} + +/* grn_ts_op_time_evaluate() evaluates an operator. */ +static grn_rc +grn_ts_op_time_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node, + const grn_ts_record *in, size_t n_in, void *out) +{ + size_t i; + grn_ts_text *buf_ptr; + grn_ts_time *out_ptr = (grn_ts_time *)out; + grn_rc rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[0], in, n_in, + &node->bufs[0]); + if (rc != GRN_SUCCESS) { + return rc; + } + buf_ptr = (grn_ts_text *)node->bufs[0].ptr; + for (i = 0; i < n_in; i++) { + rc = grn_ts_op_time(ctx, buf_ptr[i], &out_ptr[i]); + if (rc != GRN_SUCCESS) { + return rc; + } + } + return GRN_SUCCESS; +} + +/* grn_ts_op_logical_and_evaluate() evaluates an operator. */ +static grn_rc +grn_ts_op_logical_and_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node, + const grn_ts_record *in, size_t n_in, void *out) +{ + size_t i, j, count; + grn_rc rc; + grn_ts_bool *buf_ptrs[2], *out_ptr = (grn_ts_bool *)out; + grn_ts_buf *tmp_in_buf = &node->bufs[2]; + grn_ts_record *tmp_in; + + /* Evaluate the 1st argument. */ + rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[0], in, n_in, + &node->bufs[0]); + if (rc != GRN_SUCCESS) { + return rc; + } + buf_ptrs[0] = (grn_ts_bool *)node->bufs[0].ptr; + + /* Create a list of true records. */ + rc = grn_ts_buf_reserve(ctx, tmp_in_buf, sizeof(grn_ts_record) * n_in); + if (rc != GRN_SUCCESS) { + return rc; + } + tmp_in = (grn_ts_record *)tmp_in_buf->ptr; + count = 0; + for (i = 0; i < n_in; i++) { + if (buf_ptrs[0][i]) { + tmp_in[count++] = in[i]; + } + } + + /* Evaluate the 2nd argument. */ + rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[1], tmp_in, count, + &node->bufs[1]); + buf_ptrs[1] = (grn_ts_bool *)node->bufs[1].ptr; + + /* Merge the results. */ + count = 0; + for (i = 0, j = 0; i < n_in; i++) { + out_ptr[count++] = buf_ptrs[0][i] && buf_ptrs[1][j++]; + } + return GRN_SUCCESS; +} + +/* grn_ts_op_logical_or_evaluate() evaluates an operator. */ +static grn_rc +grn_ts_op_logical_or_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node, + const grn_ts_record *in, size_t n_in, void *out) +{ + size_t i, j, count; + grn_rc rc; + grn_ts_bool *buf_ptrs[2], *out_ptr = (grn_ts_bool *)out; + grn_ts_buf *tmp_in_buf = &node->bufs[2]; + grn_ts_record *tmp_in; + + /* Evaluate the 1st argument. */ + rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[0], in, n_in, + &node->bufs[0]); + if (rc != GRN_SUCCESS) { + return rc; + } + buf_ptrs[0] = (grn_ts_bool *)node->bufs[0].ptr; + + /* Create a list of false records. */ + rc = grn_ts_buf_reserve(ctx, tmp_in_buf, sizeof(grn_ts_record) * n_in); + if (rc != GRN_SUCCESS) { + return rc; + } + tmp_in = (grn_ts_record *)tmp_in_buf->ptr; + count = 0; + for (i = 0; i < n_in; i++) { + if (!buf_ptrs[0][i]) { + tmp_in[count++] = in[i]; + } + } + + /* Evaluate the 2nd argument. */ + rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[1], tmp_in, count, + &node->bufs[1]); + buf_ptrs[1] = (grn_ts_bool *)node->bufs[1].ptr; + + /* Merge the results. */ + count = 0; + for (i = 0, j = 0; i < n_in; i++) { + out_ptr[count++] = buf_ptrs[0][i] || buf_ptrs[1][j++]; + } + return GRN_SUCCESS; +} + +/* grn_ts_op_logical_sub_evaluate() evaluates an operator. */ +static grn_rc +grn_ts_op_logical_sub_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node, + const grn_ts_record *in, size_t n_in, void *out) +{ + size_t i, j, count; + grn_rc rc; + grn_ts_bool *buf_ptrs[2], *out_ptr = (grn_ts_bool *)out; + grn_ts_buf *tmp_in_buf = &node->bufs[2]; + grn_ts_record *tmp_in; + + /* Evaluate the 1st argument. */ + rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[0], in, n_in, + &node->bufs[0]); + if (rc != GRN_SUCCESS) { + return rc; + } + buf_ptrs[0] = (grn_ts_bool *)node->bufs[0].ptr; + + /* Create a list of true records. */ + rc = grn_ts_buf_reserve(ctx, tmp_in_buf, sizeof(grn_ts_record) * n_in); + if (rc != GRN_SUCCESS) { + return rc; + } + tmp_in = (grn_ts_record *)tmp_in_buf->ptr; + count = 0; + for (i = 0; i < n_in; i++) { + if (buf_ptrs[0][i]) { + tmp_in[count++] = in[i]; + } + } + + /* Evaluate the 2nd argument. */ + rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[1], tmp_in, count, + &node->bufs[1]); + buf_ptrs[1] = (grn_ts_bool *)node->bufs[1].ptr; + + /* Merge the results. */ + count = 0; + for (i = 0, j = 0; i < n_in; i++) { + out_ptr[count++] = buf_ptrs[0][i] && + grn_ts_op_logical_not_bool(buf_ptrs[1][j++]); + } + return GRN_SUCCESS; +} + +#define GRN_TS_OP_BITWISE_EVALUATE_CASE(type, KIND, kind)\ + case GRN_TS_ ## KIND: {\ + /* + * Use the output buffer to put evaluation results of the 1st argument, + * because the data kind is same. + */\ + size_t i;\ + grn_rc rc;\ + grn_ts_ ## kind *out_ptr = (grn_ts_ ## kind *)out;\ + rc = grn_ts_expr_node_evaluate(ctx, node->args[0], in, n_in, out);\ + if (rc == GRN_SUCCESS) {\ + rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[1],\ + in, n_in, &node->bufs[0]);\ + if (rc == GRN_SUCCESS) {\ + grn_ts_ ## kind *buf_ptr = (grn_ts_ ## kind *)node->bufs[0].ptr;\ + for (i = 0; i < n_in; i++) {\ + out_ptr[i] = grn_ts_op_bitwise_ ## type ## _ ## kind(out_ptr[i],\ + buf_ptr[i]);\ + }\ + }\ + }\ + return rc;\ + } +/* grn_ts_op_bitwise_and_evaluate() evaluates an operator. */ +static grn_rc +grn_ts_op_bitwise_and_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node, + const grn_ts_record *in, size_t n_in, void *out) +{ + switch (node->args[0]->data_kind) { + GRN_TS_OP_BITWISE_EVALUATE_CASE(and, BOOL, bool) + GRN_TS_OP_BITWISE_EVALUATE_CASE(and, INT, int) + default: { + GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d", + node->args[0]->data_kind); + } + } +} + +/* grn_ts_op_bitwise_or_evaluate() evaluates an operator. */ +static grn_rc +grn_ts_op_bitwise_or_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node, + const grn_ts_record *in, size_t n_in, void *out) +{ + switch (node->args[0]->data_kind) { + GRN_TS_OP_BITWISE_EVALUATE_CASE(or, BOOL, bool) + GRN_TS_OP_BITWISE_EVALUATE_CASE(or, INT, int) + default: { + GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d", + node->args[0]->data_kind); + } + } +} + +/* grn_ts_op_bitwise_xor_evaluate() evaluates an operator. */ +static grn_rc +grn_ts_op_bitwise_xor_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node, + const grn_ts_record *in, size_t n_in, void *out) +{ + switch (node->args[0]->data_kind) { + GRN_TS_OP_BITWISE_EVALUATE_CASE(xor, BOOL, bool) + GRN_TS_OP_BITWISE_EVALUATE_CASE(xor, INT, int) + default: { + GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d", + node->args[0]->data_kind); + } + } +} +#undef GRN_TS_OP_BITWISE_EVALUATE_CASE + +#define GRN_TS_OP_CHK_EVALUATE_CASE(type, KIND, kind)\ + case GRN_TS_ ## KIND: {\ + grn_ts_ ## kind *buf_ptrs[] = {\ + (grn_ts_ ## kind *)node->bufs[0].ptr,\ + (grn_ts_ ## kind *)node->bufs[1].ptr\ + };\ + for (i = 0; i < n_in; i++) {\ + out_ptr[i] = grn_ts_op_ ## type ## _ ## kind(buf_ptrs[0][i],\ + buf_ptrs[1][i]);\ + }\ + return GRN_SUCCESS;\ + } +#define GRN_TS_OP_CHK_EVALUATE_VECTOR_CASE(type, KIND, kind)\ + GRN_TS_OP_CHK_EVALUATE_CASE(type, KIND ## _VECTOR, kind ## _vector) +#define GRN_TS_OP_CHK_EVALUATE(type)\ + size_t i;\ + grn_rc rc;\ + grn_ts_bool *out_ptr = (grn_ts_bool *)out;\ + if (node->args[0]->data_kind == GRN_TS_BOOL) {\ + /* + * Use the output buffer to put evaluation results of the 1st argument, + * because the data kind is same. + */\ + rc = grn_ts_expr_node_evaluate(ctx, node->args[0], in, n_in, out);\ + if (rc == GRN_SUCCESS) {\ + grn_ts_buf *buf = &node->bufs[0];\ + rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[1],\ + in, n_in, buf);\ + if (rc == GRN_SUCCESS) {\ + grn_ts_bool *buf_ptr = (grn_ts_bool *)buf->ptr;\ + for (i = 0; i < n_in; i++) {\ + out_ptr[i] = grn_ts_op_ ## type ## _bool(out_ptr[i], buf_ptr[i]);\ + }\ + }\ + }\ + return rc;\ + }\ + for (i = 0; i < 2; i++) {\ + rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[i], in, n_in,\ + &node->bufs[i]);\ + if (rc != GRN_SUCCESS) {\ + return rc;\ + }\ + }\ + switch (node->args[0]->data_kind) {\ + GRN_TS_OP_CHK_EVALUATE_CASE(type, INT, int)\ + GRN_TS_OP_CHK_EVALUATE_CASE(type, FLOAT, float)\ + GRN_TS_OP_CHK_EVALUATE_CASE(type, TIME, time)\ + GRN_TS_OP_CHK_EVALUATE_CASE(type, TEXT, text)\ + GRN_TS_OP_CHK_EVALUATE_CASE(type, GEO, geo)\ + GRN_TS_OP_CHK_EVALUATE_CASE(type, REF, ref)\ + GRN_TS_OP_CHK_EVALUATE_VECTOR_CASE(type, BOOL, bool)\ + GRN_TS_OP_CHK_EVALUATE_VECTOR_CASE(type, INT, int)\ + GRN_TS_OP_CHK_EVALUATE_VECTOR_CASE(type, FLOAT, float)\ + GRN_TS_OP_CHK_EVALUATE_VECTOR_CASE(type, TIME, time)\ + GRN_TS_OP_CHK_EVALUATE_VECTOR_CASE(type, TEXT, text)\ + GRN_TS_OP_CHK_EVALUATE_VECTOR_CASE(type, GEO, geo)\ + GRN_TS_OP_CHK_EVALUATE_VECTOR_CASE(type, REF, ref)\ + default: {\ + GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",\ + node->args[0]->data_kind);\ + }\ + } +/* grn_ts_op_equal_evaluate() evaluates an operator. */ +static grn_rc +grn_ts_op_equal_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node, + const grn_ts_record *in, size_t n_in, void *out) +{ + GRN_TS_OP_CHK_EVALUATE(equal) +} + +/* grn_ts_op_not_equal_evaluate() evaluates an operator. */ +static grn_rc +grn_ts_op_not_equal_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node, + const grn_ts_record *in, size_t n_in, void *out) +{ + GRN_TS_OP_CHK_EVALUATE(not_equal) +} +#undef GRN_TS_OP_CHK_EVALUATE +#undef GRN_TS_OP_CHK_EVALUATE_VECTOR_CASE +#undef GRN_TS_OP_CHK_EVALUATE_CASE + +#define GRN_TS_OP_CMP_EVALUATE_CASE(type, KIND, kind)\ + case GRN_TS_ ## KIND: {\ + grn_ts_ ## kind *buf_ptrs[] = {\ + (grn_ts_ ## kind *)node->bufs[0].ptr,\ + (grn_ts_ ## kind *)node->bufs[1].ptr\ + };\ + for (i = 0; i < n_in; i++) {\ + out_ptr[i] = grn_ts_op_ ## type ## _ ## kind(buf_ptrs[0][i],\ + buf_ptrs[1][i]);\ + }\ + return GRN_SUCCESS;\ + } +#define GRN_TS_OP_CMP_EVALUATE_VECTOR_CASE(type, KIND, kind)\ + GRN_TS_OP_CMP_EVALUATE_CASE(type, KIND ## _VECTOR, kind ## _vector) +#define GRN_TS_OP_CMP_EVALUATE(type)\ + size_t i;\ + grn_rc rc;\ + grn_ts_bool *out_ptr = (grn_ts_bool *)out;\ + for (i = 0; i < 2; i++) {\ + rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[i], in, n_in,\ + &node->bufs[i]);\ + if (rc != GRN_SUCCESS) {\ + return rc;\ + }\ + }\ + switch (node->args[0]->data_kind) {\ + GRN_TS_OP_CMP_EVALUATE_CASE(type, INT, int)\ + GRN_TS_OP_CMP_EVALUATE_CASE(type, FLOAT, float)\ + GRN_TS_OP_CMP_EVALUATE_CASE(type, TIME, time)\ + GRN_TS_OP_CMP_EVALUATE_CASE(type, TEXT, text)\ + GRN_TS_OP_CMP_EVALUATE_VECTOR_CASE(type, INT, int)\ + GRN_TS_OP_CMP_EVALUATE_VECTOR_CASE(type, FLOAT, float)\ + GRN_TS_OP_CMP_EVALUATE_VECTOR_CASE(type, TIME, time)\ + GRN_TS_OP_CMP_EVALUATE_VECTOR_CASE(type, TEXT, text)\ + default: {\ + GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",\ + node->args[0]->data_kind);\ + }\ + } +/* grn_ts_op_less_evaluate() evaluates an operator. */ +static grn_rc +grn_ts_op_less_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node, + const grn_ts_record *in, size_t n_in, void *out) +{ + GRN_TS_OP_CMP_EVALUATE(less) +} + +/* grn_ts_op_less_equal_evaluate() evaluates an operator. */ +static grn_rc +grn_ts_op_less_equal_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node, + const grn_ts_record *in, size_t n_in, void *out) +{ + GRN_TS_OP_CMP_EVALUATE(less_equal) +} + +/* grn_ts_op_greater_evaluate() evaluates an operator. */ +static grn_rc +grn_ts_op_greater_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node, + const grn_ts_record *in, size_t n_in, void *out) +{ + GRN_TS_OP_CMP_EVALUATE(greater) +} + +/* grn_ts_op_greater_equal_evaluate() evaluates an operator. */ +static grn_rc +grn_ts_op_greater_equal_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node, + const grn_ts_record *in, size_t n_in, + void *out) +{ + GRN_TS_OP_CMP_EVALUATE(greater_equal) +} +#undef GRN_TS_OP_CMP_EVALUATE +#undef GRN_TS_OP_CMP_EVALUATE_VECTOR_CASE +#undef GRN_TS_OP_CMP_EVALUATE_CASE + +#define GRN_TS_OP_SHIFT_EVALUATE(type)\ + size_t i;\ + grn_rc rc;\ + grn_ts_int *out_ptr = (grn_ts_int *)out;\ + rc = grn_ts_expr_node_evaluate(ctx, node->args[0], in, n_in, out);\ + if (rc == GRN_SUCCESS) {\ + rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[1],\ + in, n_in, &node->bufs[0]);\ + if (rc == GRN_SUCCESS) {\ + grn_ts_int *buf_ptr = (grn_ts_int *)node->bufs[0].ptr;\ + for (i = 0; i < n_in; i++) {\ + out_ptr[i] = grn_ts_op_shift_ ## type(out_ptr[i], buf_ptr[i]);\ + }\ + }\ + }\ + return rc; +/* grn_ts_op_shift_arithmetic_left_evaluate() evaluates an operator. */ +static grn_rc +grn_ts_op_shift_arithmetic_left_evaluate(grn_ctx *ctx, + grn_ts_expr_op_node *node, + const grn_ts_record *in, size_t n_in, + void *out) +{ + GRN_TS_OP_SHIFT_EVALUATE(arithmetic_left) +} + +/* grn_ts_op_shift_arithmetic_right_evaluate() evaluates an operator. */ +static grn_rc +grn_ts_op_shift_arithmetic_right_evaluate(grn_ctx *ctx, + grn_ts_expr_op_node *node, + const grn_ts_record *in, size_t n_in, + void *out) +{ + GRN_TS_OP_SHIFT_EVALUATE(arithmetic_right) +} + +/* grn_ts_op_shift_logical_left_evaluate() evaluates an operator. */ +static grn_rc +grn_ts_op_shift_logical_left_evaluate(grn_ctx *ctx, + grn_ts_expr_op_node *node, + const grn_ts_record *in, size_t n_in, + void *out) +{ + GRN_TS_OP_SHIFT_EVALUATE(logical_left) +} + +/* grn_ts_op_shift_logical_right_evaluate() evaluates an operator. */ +static grn_rc +grn_ts_op_shift_logical_right_evaluate(grn_ctx *ctx, + grn_ts_expr_op_node *node, + const grn_ts_record *in, size_t n_in, + void *out) +{ + GRN_TS_OP_SHIFT_EVALUATE(logical_right) +} +#undef GRN_TS_OP_SHIFT_EVALUATE + +#define GRN_TS_OP_ARITH_EVALUATE(type, lhs_kind, rhs_kind)\ + /* + * Use the output buffer to put evaluation results of the 1st argument, + * because the data kind is same. + */\ + size_t i;\ + grn_rc rc;\ + grn_ts_ ## lhs_kind *out_ptr = (grn_ts_ ## lhs_kind *)out;\ + rc = grn_ts_expr_node_evaluate(ctx, node->args[0], in, n_in, out);\ + if (rc == GRN_SUCCESS) {\ + rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[1],\ + in, n_in, &node->bufs[0]);\ + if (rc == GRN_SUCCESS) {\ + grn_ts_ ## rhs_kind *buf_ptr = (grn_ts_ ## rhs_kind *)node->bufs[0].ptr;\ + for (i = 0; i < n_in; i++) {\ + rc = grn_ts_op_ ## type ## _ ## lhs_kind ## _ ## rhs_kind(\ + ctx, out_ptr[i], buf_ptr[i], &out_ptr[i]);\ + if (rc != GRN_SUCCESS) {\ + return rc;\ + }\ + }\ + }\ + }\ + return rc; + +#define GRN_TS_OP_ARITH_EVALUATE_CASE(type, KIND, kind)\ + case GRN_TS_ ## KIND: {\ + /* + * Use the output buffer to put evaluation results of the 1st argument, + * because the data kind is same. + */\ + size_t i;\ + grn_rc rc;\ + grn_ts_ ## kind *out_ptr = (grn_ts_ ## kind *)out;\ + rc = grn_ts_expr_node_evaluate(ctx, node->args[0], in, n_in, out);\ + if (rc == GRN_SUCCESS) {\ + rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[1],\ + in, n_in, &node->bufs[0]);\ + if (rc == GRN_SUCCESS) {\ + grn_ts_ ## kind *buf_ptr = (grn_ts_ ## kind *)node->bufs[0].ptr;\ + for (i = 0; i < n_in; i++) {\ + out_ptr[i] = grn_ts_op_ ## type ## _ ## kind(out_ptr[i],\ + buf_ptr[i]);\ + }\ + }\ + }\ + return rc;\ + } +#define GRN_TS_OP_ARITH_EVALUATE_TIME_CASE(type, KIND, lhs, rhs)\ + case GRN_TS_ ## KIND: {\ + /* + * Use the output buffer to put evaluation results of the 1st argument, + * because the data kind is same. + */\ + size_t i;\ + grn_rc rc;\ + grn_ts_ ## lhs *out_ptr = (grn_ts_ ## lhs *)out;\ + rc = grn_ts_expr_node_evaluate(ctx, node->args[0], in, n_in, out);\ + if (rc == GRN_SUCCESS) {\ + rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[1],\ + in, n_in, &node->bufs[0]);\ + if (rc == GRN_SUCCESS) {\ + grn_ts_ ## rhs *buf_ptr = (grn_ts_ ## rhs *)node->bufs[0].ptr;\ + for (i = 0; i < n_in; i++) {\ + out_ptr[i] = grn_ts_op_ ## type ## _ ## lhs ## _ ## rhs(out_ptr[i],\ + buf_ptr[i]);\ + }\ + }\ + }\ + return rc;\ + } +/* grn_ts_op_plus_evaluate() evaluates an operator. */ +static grn_rc +grn_ts_op_plus_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node, + const grn_ts_record *in, size_t n_in, void *out) +{ + switch (node->args[0]->data_kind) { + case GRN_TS_INT: { + GRN_TS_OP_ARITH_EVALUATE(plus, int, int) + } + case GRN_TS_FLOAT: { + GRN_TS_OP_ARITH_EVALUATE(plus, float, float) + } + case GRN_TS_TIME: { + switch (node->args[1]->data_kind) { + case GRN_TS_INT: { + GRN_TS_OP_ARITH_EVALUATE(plus, time, int) + } + case GRN_TS_FLOAT: { + GRN_TS_OP_ARITH_EVALUATE(plus, time, float) + } + default: { + GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "data kind conflict: %d, %d", + node->args[0]->data_kind, + node->args[1]->data_kind); + } + } + } + default: { + GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d", + node->args[0]->data_kind); + } + } +} + +/* grn_ts_op_minus_evaluate() evaluates an operator. */ +static grn_rc +grn_ts_op_minus_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node, + const grn_ts_record *in, size_t n_in, void *out) +{ + switch (node->args[0]->data_kind) { + case GRN_TS_INT: { + GRN_TS_OP_ARITH_EVALUATE(minus, int, int) + } + case GRN_TS_FLOAT: { + GRN_TS_OP_ARITH_EVALUATE(minus, float, float) + } + case GRN_TS_TIME: { + switch (node->args[1]->data_kind) { + case GRN_TS_INT: { + GRN_TS_OP_ARITH_EVALUATE(minus, time, int) + } + case GRN_TS_FLOAT: { + GRN_TS_OP_ARITH_EVALUATE(minus, time, float) + } + case GRN_TS_TIME: { + size_t i; + grn_rc rc; + grn_ts_float *out_ptr = (grn_ts_float *)out; + grn_ts_time *buf_ptrs[2]; + rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[0], in, n_in, + &node->bufs[0]); + if (rc != GRN_SUCCESS) { + return rc; + } + rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[1], in, n_in, + &node->bufs[1]); + if (rc != GRN_SUCCESS) { + return rc; + } + buf_ptrs[0] = (grn_ts_time *)node->bufs[0].ptr; + buf_ptrs[1] = (grn_ts_time *)node->bufs[1].ptr; + for (i = 0; i < n_in; i++) { + rc = grn_ts_op_minus_time_time(ctx, buf_ptrs[0][i], buf_ptrs[1][i], + &out_ptr[i]); + if (rc != GRN_SUCCESS) { + return rc; + } + } + return GRN_SUCCESS; + } + default: { + GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "data kind conflict: %d, %d", + node->args[0]->data_kind, + node->args[1]->data_kind); + } + } + } + default: { + GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d", + node->args[0]->data_kind); + } + } +} +#undef GRN_TS_OP_ARITH_EVALUATE_TIME_CASE + +/* grn_ts_op_multiplication_evaluate() evaluates an operator. */ +static grn_rc +grn_ts_op_multiplication_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node, + const grn_ts_record *in, size_t n_in, + void *out) +{ + switch (node->data_kind) { + case GRN_TS_INT: { + GRN_TS_OP_ARITH_EVALUATE(multiplication, int, int) + } + case GRN_TS_FLOAT: { + GRN_TS_OP_ARITH_EVALUATE(multiplication, float, float) + } + default: { + GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d", + node->data_kind); + } + } +} + +/* grn_ts_op_division_evaluate() evaluates an operator. */ +static grn_rc +grn_ts_op_division_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node, + const grn_ts_record *in, size_t n_in, void *out) +{ + switch (node->data_kind) { + case GRN_TS_INT: { + GRN_TS_OP_ARITH_EVALUATE(division, int, int) + } + case GRN_TS_FLOAT: { + GRN_TS_OP_ARITH_EVALUATE(division, float, float) + } + default: { + GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d", + node->data_kind); + } + } +} + +/* grn_ts_op_modulus_evaluate() evaluates an operator. */ +static grn_rc +grn_ts_op_modulus_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node, + const grn_ts_record *in, size_t n_in, void *out) +{ + switch (node->data_kind) { + case GRN_TS_INT: { + GRN_TS_OP_ARITH_EVALUATE(modulus, int, int) + } + case GRN_TS_FLOAT: { + GRN_TS_OP_ARITH_EVALUATE(modulus, float, float) + } + default: { + GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d", + node->data_kind); + } + } +} +#undef GRN_TS_OP_ARITH_EVALUATE_CASE + +#define GRN_TS_OP_MATCH_EVALUATE(type)\ + size_t i;\ + grn_rc rc;\ + grn_ts_bool *out_ptr = (grn_ts_bool *)out;\ + grn_ts_text *buf_ptrs[2];\ + for (i = 0; i < 2; i++) {\ + rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[i], in, n_in,\ + &node->bufs[i]);\ + if (rc != GRN_SUCCESS) {\ + return rc;\ + }\ + }\ + buf_ptrs[0] = (grn_ts_text *)node->bufs[0].ptr;\ + buf_ptrs[1] = (grn_ts_text *)node->bufs[1].ptr;\ + for (i = 0; i < n_in; i++) {\ + out_ptr[i] = grn_ts_op_ ## type(buf_ptrs[0][i], buf_ptrs[1][i]);\ + }\ + return GRN_SUCCESS;\ +/* grn_ts_op_match_evaluate() evaluates an operator. */ +static grn_rc +grn_ts_op_match_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node, + const grn_ts_record *in, size_t n_in, void *out) +{ + GRN_TS_OP_MATCH_EVALUATE(match) +} + +/* grn_ts_op_prefix_match_evaluate() evaluates an operator. */ +static grn_rc +grn_ts_op_prefix_match_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node, + const grn_ts_record *in, size_t n_in, + void *out) +{ + GRN_TS_OP_MATCH_EVALUATE(prefix_match) +} + +/* grn_ts_op_suffix_match_evaluate() evaluates an operator. */ +static grn_rc +grn_ts_op_suffix_match_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node, + const grn_ts_record *in, size_t n_in, + void *out) +{ + GRN_TS_OP_MATCH_EVALUATE(suffix_match) +} +#undef GRN_TS_OP_MATCH_EVALUATE + +/* grn_ts_expr_op_node_evaluate() evaluates an operator. */ +static grn_rc +grn_ts_expr_op_node_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node, + const grn_ts_record *in, size_t n_in, void *out) +{ + switch (node->op_type) { + case GRN_TS_OP_LOGICAL_NOT: { + return grn_ts_op_logical_not_evaluate(ctx, node, in, n_in, out); + } + case GRN_TS_OP_BITWISE_NOT: { + return grn_ts_op_bitwise_not_evaluate(ctx, node, in, n_in, out); + } + case GRN_TS_OP_POSITIVE: { + return grn_ts_op_positive_evaluate(ctx, node, in, n_in, out); + } + case GRN_TS_OP_NEGATIVE: { + return grn_ts_op_negative_evaluate(ctx, node, in, n_in, out); + } + case GRN_TS_OP_FLOAT: { + return grn_ts_op_float_evaluate(ctx, node, in, n_in, out); + } + case GRN_TS_OP_TIME: { + return grn_ts_op_time_evaluate(ctx, node, in, n_in, out); + } + case GRN_TS_OP_LOGICAL_AND: { + return grn_ts_op_logical_and_evaluate(ctx, node, in, n_in, out); + } + case GRN_TS_OP_LOGICAL_OR: { + return grn_ts_op_logical_or_evaluate(ctx, node, in, n_in, out); + } + case GRN_TS_OP_LOGICAL_SUB: { + return grn_ts_op_logical_sub_evaluate(ctx, node, in, n_in, out); + } + case GRN_TS_OP_BITWISE_AND: { + return grn_ts_op_bitwise_and_evaluate(ctx, node, in, n_in, out); + } + case GRN_TS_OP_BITWISE_OR: { + return grn_ts_op_bitwise_or_evaluate(ctx, node, in, n_in, out); + } + case GRN_TS_OP_BITWISE_XOR: { + return grn_ts_op_bitwise_xor_evaluate(ctx, node, in, n_in, out); + } + case GRN_TS_OP_EQUAL: { + return grn_ts_op_equal_evaluate(ctx, node, in, n_in, out); + } + case GRN_TS_OP_NOT_EQUAL: { + return grn_ts_op_not_equal_evaluate(ctx, node, in, n_in, out); + } + case GRN_TS_OP_LESS: { + return grn_ts_op_less_evaluate(ctx, node, in, n_in, out); + } + case GRN_TS_OP_LESS_EQUAL: { + return grn_ts_op_less_equal_evaluate(ctx, node, in, n_in, out); + } + case GRN_TS_OP_GREATER: { + return grn_ts_op_greater_evaluate(ctx, node, in, n_in, out); + } + case GRN_TS_OP_GREATER_EQUAL: { + return grn_ts_op_greater_equal_evaluate(ctx, node, in, n_in, out); + } + case GRN_TS_OP_SHIFT_ARITHMETIC_LEFT: { + return grn_ts_op_shift_arithmetic_left_evaluate(ctx, node, in, n_in, out); + } + case GRN_TS_OP_SHIFT_ARITHMETIC_RIGHT: { + return grn_ts_op_shift_arithmetic_right_evaluate(ctx, node, in, n_in, out); + } + case GRN_TS_OP_SHIFT_LOGICAL_LEFT: { + return grn_ts_op_shift_logical_left_evaluate(ctx, node, in, n_in, out); + } + case GRN_TS_OP_SHIFT_LOGICAL_RIGHT: { + return grn_ts_op_shift_logical_right_evaluate(ctx, node, in, n_in, out); + } + case GRN_TS_OP_PLUS: { + return grn_ts_op_plus_evaluate(ctx, node, in, n_in, out); + } + case GRN_TS_OP_MINUS: { + return grn_ts_op_minus_evaluate(ctx, node, in, n_in, out); + } + case GRN_TS_OP_MULTIPLICATION: { + return grn_ts_op_multiplication_evaluate(ctx, node, in, n_in, out); + } + case GRN_TS_OP_DIVISION: { + return grn_ts_op_division_evaluate(ctx, node, in, n_in, out); + } + case GRN_TS_OP_MODULUS: { + return grn_ts_op_modulus_evaluate(ctx, node, in, n_in, out); + } + case GRN_TS_OP_MATCH: { + return grn_ts_op_match_evaluate(ctx, node, in, n_in, out); + } + case GRN_TS_OP_PREFIX_MATCH: { + return grn_ts_op_prefix_match_evaluate(ctx, node, in, n_in, out); + } + case GRN_TS_OP_SUFFIX_MATCH: { + return grn_ts_op_suffix_match_evaluate(ctx, node, in, n_in, out); + } + // TODO: Add operators. + default: { + GRN_TS_ERR_RETURN(GRN_OPERATION_NOT_SUPPORTED, + "operator not supported: %d", node->op_type); + } + } +} + +/* grn_ts_op_logical_not_filter() filters records. */ +static grn_rc +grn_ts_op_logical_not_filter(grn_ctx *ctx, grn_ts_expr_op_node *node, + grn_ts_record *in, size_t n_in, + grn_ts_record *out, size_t *n_out) +{ + size_t i, count; + grn_rc rc; + grn_ts_bool *buf_ptr; + rc = grn_ts_buf_reserve(ctx, &node->bufs[0], sizeof(grn_ts_bool) * n_in); + if (rc != GRN_SUCCESS) { + return rc; + } + buf_ptr = (grn_ts_bool *)node->bufs[0].ptr; + rc = grn_ts_expr_node_evaluate(ctx, node->args[0], in, n_in, buf_ptr); + if (rc != GRN_SUCCESS) { + return rc; + } + for (i = 0, count = 0; i < n_in; i++) { + if (grn_ts_op_logical_not_bool(buf_ptr[i])) { + out[count++] = in[i]; + } + } + *n_out = count; + return GRN_SUCCESS; +} + +/* grn_ts_op_bitwise_not_filter() filters records. */ +static grn_rc +grn_ts_op_bitwise_not_filter(grn_ctx *ctx, grn_ts_expr_op_node *node, + grn_ts_record *in, size_t n_in, + grn_ts_record *out, size_t *n_out) +{ + size_t i, count; + grn_rc rc; + grn_ts_bool *buf_ptr; + rc = grn_ts_buf_reserve(ctx, &node->bufs[0], sizeof(grn_ts_bool) * n_in); + if (rc != GRN_SUCCESS) { + return rc; + } + buf_ptr = (grn_ts_bool *)node->bufs[0].ptr; + rc = grn_ts_expr_node_evaluate(ctx, node->args[0], in, n_in, buf_ptr); + if (rc != GRN_SUCCESS) { + return rc; + } + for (i = 0, count = 0; i < n_in; i++) { + if (grn_ts_op_bitwise_not_bool(buf_ptr[i])) { + out[count++] = in[i]; + } + } + *n_out = count; + return GRN_SUCCESS; +} + +/* grn_ts_op_logical_and_filter() filters records. */ +static grn_rc +grn_ts_op_logical_and_filter(grn_ctx *ctx, grn_ts_expr_op_node *node, + grn_ts_record *in, size_t n_in, + grn_ts_record *out, size_t *n_out) +{ + grn_rc rc = grn_ts_expr_node_filter(ctx, node->args[0], in, n_in, + out, n_out); + if (rc != GRN_SUCCESS) { + return rc; + } + return grn_ts_expr_node_filter(ctx, node->args[1], out, *n_out, out, n_out); +} + +/* grn_ts_op_logical_or_filter() filters records. */ +static grn_rc +grn_ts_op_logical_or_filter(grn_ctx *ctx, grn_ts_expr_op_node *node, + grn_ts_record *in, size_t n_in, + grn_ts_record *out, size_t *n_out) +{ + size_t i, j, count; + grn_rc rc; + grn_ts_bool *buf_ptrs[2]; + grn_ts_buf *tmp_in_buf = &node->bufs[2]; + grn_ts_record *tmp_in; + + /* Evaluate the 1st argument. */ + rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[0], in, n_in, + &node->bufs[0]); + if (rc != GRN_SUCCESS) { + return rc; + } + buf_ptrs[0] = (grn_ts_bool *)node->bufs[0].ptr; + + /* Create a list of false records. */ + rc = grn_ts_buf_reserve(ctx, tmp_in_buf, sizeof(grn_ts_record) * n_in); + if (rc != GRN_SUCCESS) { + return rc; + } + tmp_in = (grn_ts_record *)tmp_in_buf->ptr; + count = 0; + for (i = 0; i < n_in; i++) { + if (!buf_ptrs[0][i]) { + tmp_in[count++] = in[i]; + } + } + + /* Evaluate the 2nd argument. */ + rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[1], tmp_in, count, + &node->bufs[1]); + buf_ptrs[1] = (grn_ts_bool *)node->bufs[1].ptr; + + /* Merge the results. */ + count = 0; + for (i = 0, j = 0; i < n_in; i++) { + if (buf_ptrs[0][i] || buf_ptrs[1][j++]) { + out[count++] = in[i]; + } + } + *n_out = count; + return GRN_SUCCESS; +} + +/* grn_ts_op_logical_sub_filter() filters records. */ +static grn_rc +grn_ts_op_logical_sub_filter(grn_ctx *ctx, grn_ts_expr_op_node *node, + grn_ts_record *in, size_t n_in, + grn_ts_record *out, size_t *n_out) +{ + size_t i, n, count; + grn_ts_bool *buf_ptr; + grn_rc rc = grn_ts_expr_node_filter(ctx, node->args[0], in, n_in, out, &n); + if (rc != GRN_SUCCESS) { + return rc; + } + rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[1], out, n, + &node->bufs[0]); + buf_ptr = (grn_ts_bool *)node->bufs[0].ptr; + for (i = 0, count = 0; i < n; i++) { + if (grn_ts_op_logical_not_bool(buf_ptr[i])) { + out[count++] = out[i]; + } + } + *n_out = count; + return GRN_SUCCESS; +} + +#define GRN_TS_OP_BITWISE_FILTER(type)\ + size_t i, count = 0;\ + grn_ts_bool *buf_ptrs[2];\ + for (i = 0; i < 2; i++) {\ + grn_rc rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[i], in, n_in,\ + &node->bufs[i]);\ + if (rc != GRN_SUCCESS) {\ + return rc;\ + }\ + buf_ptrs[i] = (grn_ts_bool *)node->bufs[i].ptr;\ + }\ + for (i = 0; i < n_in; i++) {\ + if (grn_ts_op_bitwise_ ## type ## _bool(buf_ptrs[0][i], buf_ptrs[1][i])) {\ + out[count++] = in[i];\ + }\ + }\ + *n_out = count;\ + return GRN_SUCCESS;\ +/* grn_ts_op_bitwise_and_filter() filters records. */ +static grn_rc +grn_ts_op_bitwise_and_filter(grn_ctx *ctx, grn_ts_expr_op_node *node, + grn_ts_record *in, size_t n_in, + grn_ts_record *out, size_t *n_out) +{ + GRN_TS_OP_BITWISE_FILTER(and); +} + +/* grn_ts_op_bitwise_or_filter() filters records. */ +static grn_rc +grn_ts_op_bitwise_or_filter(grn_ctx *ctx, grn_ts_expr_op_node *node, + grn_ts_record *in, size_t n_in, + grn_ts_record *out, size_t *n_out) +{ + GRN_TS_OP_BITWISE_FILTER(or); +} + +/* grn_ts_op_bitwise_xor_filter() filters records. */ +static grn_rc +grn_ts_op_bitwise_xor_filter(grn_ctx *ctx, grn_ts_expr_op_node *node, + grn_ts_record *in, size_t n_in, + grn_ts_record *out, size_t *n_out) +{ + GRN_TS_OP_BITWISE_FILTER(xor); +} +#undef GRN_TS_OP_BITWISE_FILTER_CASE + +#define GRN_TS_OP_CHK_FILTER_CASE(type, KIND, kind)\ + case GRN_TS_ ## KIND: {\ + grn_ts_ ## kind *buf_ptrs[] = {\ + (grn_ts_ ## kind *)node->bufs[0].ptr,\ + (grn_ts_ ## kind *)node->bufs[1].ptr\ + };\ + for (i = 0; i < n_in; i++) {\ + if (grn_ts_op_ ## type ## _ ## kind(buf_ptrs[0][i], buf_ptrs[1][i])) {\ + out[count++] = in[i];\ + }\ + }\ + *n_out = count;\ + return GRN_SUCCESS;\ + } +#define GRN_TS_OP_CHK_FILTER_VECTOR_CASE(type, KIND, kind)\ + GRN_TS_OP_CHK_FILTER_CASE(type, KIND ## _VECTOR, kind ## _vector) +#define GRN_TS_OP_CHK_FILTER(type)\ + size_t i, count = 0;\ + for (i = 0; i < 2; i++) {\ + grn_rc rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[i], in, n_in,\ + &node->bufs[i]);\ + if (rc != GRN_SUCCESS) {\ + return rc;\ + }\ + }\ + switch (node->args[0]->data_kind) {\ + GRN_TS_OP_CHK_FILTER_CASE(type, BOOL, bool)\ + GRN_TS_OP_CHK_FILTER_CASE(type, INT, int)\ + GRN_TS_OP_CHK_FILTER_CASE(type, FLOAT, float)\ + GRN_TS_OP_CHK_FILTER_CASE(type, TIME, time)\ + GRN_TS_OP_CHK_FILTER_CASE(type, TEXT, text)\ + GRN_TS_OP_CHK_FILTER_CASE(type, GEO, geo)\ + GRN_TS_OP_CHK_FILTER_CASE(type, REF, ref)\ + GRN_TS_OP_CHK_FILTER_VECTOR_CASE(type, BOOL, bool)\ + GRN_TS_OP_CHK_FILTER_VECTOR_CASE(type, INT, int)\ + GRN_TS_OP_CHK_FILTER_VECTOR_CASE(type, FLOAT, float)\ + GRN_TS_OP_CHK_FILTER_VECTOR_CASE(type, TIME, time)\ + GRN_TS_OP_CHK_FILTER_VECTOR_CASE(type, TEXT, text)\ + GRN_TS_OP_CHK_FILTER_VECTOR_CASE(type, GEO, geo)\ + GRN_TS_OP_CHK_FILTER_VECTOR_CASE(type, REF, ref)\ + default: {\ + GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",\ + node->args[0]->data_kind);\ + }\ + } +/* grn_ts_op_equal_filter() filters records. */ +static grn_rc +grn_ts_op_equal_filter(grn_ctx *ctx, grn_ts_expr_op_node *node, + const grn_ts_record *in, size_t n_in, + grn_ts_record *out, size_t *n_out) +{ + GRN_TS_OP_CHK_FILTER(equal) +} + +/* grn_ts_op_not_equal_filter() filters records. */ +static grn_rc +grn_ts_op_not_equal_filter(grn_ctx *ctx, grn_ts_expr_op_node *node, + const grn_ts_record *in, size_t n_in, + grn_ts_record *out, size_t *n_out) +{ + GRN_TS_OP_CHK_FILTER(not_equal) +} +#undef GRN_TS_OP_CHK_FILTER +#undef GRN_TS_OP_CHK_FILTER_VECTOR_CASE +#undef GRN_TS_OP_CHK_FILTER_CASE + +#define GRN_TS_OP_CMP_FILTER_CASE(type, KIND, kind)\ + case GRN_TS_ ## KIND: {\ + grn_ts_ ## kind *buf_ptrs[] = {\ + (grn_ts_ ## kind *)node->bufs[0].ptr,\ + (grn_ts_ ## kind *)node->bufs[1].ptr\ + };\ + for (i = 0; i < n_in; i++) {\ + if (grn_ts_op_ ## type ## _ ## kind(buf_ptrs[0][i], buf_ptrs[1][i])) {\ + out[count++] = in[i];\ + }\ + }\ + *n_out = count;\ + return GRN_SUCCESS;\ + } +#define GRN_TS_OP_CMP_FILTER_VECTOR_CASE(type, KIND, kind)\ + GRN_TS_OP_CMP_FILTER_CASE(type, KIND ## _VECTOR, kind ## _vector) +#define GRN_TS_OP_CMP_FILTER(type)\ + size_t i, count = 0;\ + for (i = 0; i < 2; i++) {\ + grn_rc rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[i], in, n_in,\ + &node->bufs[i]);\ + if (rc != GRN_SUCCESS) {\ + return rc;\ + }\ + }\ + switch (node->args[0]->data_kind) {\ + GRN_TS_OP_CMP_FILTER_CASE(type, INT, int)\ + GRN_TS_OP_CMP_FILTER_CASE(type, FLOAT, float)\ + GRN_TS_OP_CMP_FILTER_CASE(type, TIME, time)\ + GRN_TS_OP_CMP_FILTER_CASE(type, TEXT, text)\ + GRN_TS_OP_CMP_FILTER_VECTOR_CASE(type, INT, int)\ + GRN_TS_OP_CMP_FILTER_VECTOR_CASE(type, FLOAT, float)\ + GRN_TS_OP_CMP_FILTER_VECTOR_CASE(type, TIME, time)\ + GRN_TS_OP_CMP_FILTER_VECTOR_CASE(type, TEXT, text)\ + default: {\ + GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",\ + node->args[0]->data_kind);\ + }\ + } +/* grn_ts_op_less_filter() filters records. */ +static grn_rc +grn_ts_op_less_filter(grn_ctx *ctx, grn_ts_expr_op_node *node, + const grn_ts_record *in, size_t n_in, + grn_ts_record *out, size_t *n_out) +{ + GRN_TS_OP_CMP_FILTER(less) +} + +/* grn_ts_op_less_equal_filter() filters records. */ +static grn_rc +grn_ts_op_less_equal_filter(grn_ctx *ctx, grn_ts_expr_op_node *node, + const grn_ts_record *in, size_t n_in, + grn_ts_record *out, size_t *n_out) +{ + GRN_TS_OP_CMP_FILTER(less_equal) +} + +/* grn_ts_op_greater_filter() filters records. */ +static grn_rc +grn_ts_op_greater_filter(grn_ctx *ctx, grn_ts_expr_op_node *node, + const grn_ts_record *in, size_t n_in, + grn_ts_record *out, size_t *n_out) +{ + GRN_TS_OP_CMP_FILTER(greater) +} + +/* grn_ts_op_greater_equal_filter() filters records. */ +static grn_rc +grn_ts_op_greater_equal_filter(grn_ctx *ctx, grn_ts_expr_op_node *node, + const grn_ts_record *in, size_t n_in, + grn_ts_record *out, size_t *n_out) +{ + GRN_TS_OP_CMP_FILTER(greater_equal) +} +#undef GRN_TS_OP_CMP_FILTER +#undef GRN_TS_OP_CMP_FILTER_VECTOR_CASE +#undef GRN_TS_OP_CMP_FILTER_CASE + +#define GRN_TS_OP_MATCH_FILTER_CASE(type, KIND, kind)\ + case GRN_TS_ ## KIND: {\ + grn_ts_ ## kind *buf_ptrs[] = {\ + (grn_ts_ ## kind *)node->bufs[0].ptr,\ + (grn_ts_ ## kind *)node->bufs[1].ptr\ + };\ + for (i = 0; i < n_in; i++) {\ + if (grn_ts_op_ ## type ## _ ## kind(buf_ptrs[0][i], buf_ptrs[1][i])) {\ + out[count++] = in[i];\ + }\ + }\ + *n_out = count;\ + return GRN_SUCCESS;\ + } + +#define GRN_TS_OP_MATCH_FILTER(type)\ + size_t i, count = 0;\ + grn_ts_text *buf_ptrs[2];\ + for (i = 0; i < 2; i++) {\ + grn_rc rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[i], in, n_in,\ + &node->bufs[i]);\ + if (rc != GRN_SUCCESS) {\ + return rc;\ + }\ + }\ + buf_ptrs[0] = (grn_ts_text *)node->bufs[0].ptr;\ + buf_ptrs[1] = (grn_ts_text *)node->bufs[1].ptr;\ + for (i = 0; i < n_in; i++) {\ + if (grn_ts_op_ ## type(buf_ptrs[0][i], buf_ptrs[1][i])) {\ + out[count++] = in[i];\ + }\ + }\ + *n_out = count;\ + return GRN_SUCCESS;\ +/* grn_ts_op_match_filter() filters records. */ +static grn_rc +grn_ts_op_match_filter(grn_ctx *ctx, grn_ts_expr_op_node *node, + const grn_ts_record *in, size_t n_in, + grn_ts_record *out, size_t *n_out) +{ + GRN_TS_OP_MATCH_FILTER(match) +} + +/* grn_ts_op_prefix_match_filter() filters records. */ +static grn_rc +grn_ts_op_prefix_match_filter(grn_ctx *ctx, grn_ts_expr_op_node *node, + const grn_ts_record *in, size_t n_in, + grn_ts_record *out, size_t *n_out) +{ + GRN_TS_OP_MATCH_FILTER(prefix_match) +} + +/* grn_ts_op_suffix_match_filter() filters records. */ +static grn_rc +grn_ts_op_suffix_match_filter(grn_ctx *ctx, grn_ts_expr_op_node *node, + const grn_ts_record *in, size_t n_in, + grn_ts_record *out, size_t *n_out) +{ + GRN_TS_OP_MATCH_FILTER(suffix_match) +} +#undef GRN_TS_OP_MATCH_FILTER + +/* grn_ts_expr_op_node_filter() filters records. */ +static grn_rc +grn_ts_expr_op_node_filter(grn_ctx *ctx, grn_ts_expr_op_node *node, + grn_ts_record *in, size_t n_in, + grn_ts_record *out, size_t *n_out) +{ + switch (node->op_type) { + case GRN_TS_OP_LOGICAL_NOT: { + return grn_ts_op_logical_not_filter(ctx, node, in, n_in, out, n_out); + } + case GRN_TS_OP_BITWISE_NOT: { + return grn_ts_op_bitwise_not_filter(ctx, node, in, n_in, out, n_out); + } + case GRN_TS_OP_LOGICAL_AND: { + return grn_ts_op_logical_and_filter(ctx, node, in, n_in, out, n_out); + } + case GRN_TS_OP_LOGICAL_OR: { + return grn_ts_op_logical_or_filter(ctx, node, in, n_in, out, n_out); + } + case GRN_TS_OP_LOGICAL_SUB: { + return grn_ts_op_logical_sub_filter(ctx, node, in, n_in, out, n_out); + } + case GRN_TS_OP_BITWISE_AND: { + return grn_ts_op_bitwise_and_filter(ctx, node, in, n_in, out, n_out); + } + case GRN_TS_OP_BITWISE_OR: { + return grn_ts_op_bitwise_or_filter(ctx, node, in, n_in, out, n_out); + } + case GRN_TS_OP_BITWISE_XOR: { + return grn_ts_op_bitwise_xor_filter(ctx, node, in, n_in, out, n_out); + } + case GRN_TS_OP_EQUAL: { + return grn_ts_op_equal_filter(ctx, node, in, n_in, out, n_out); + } + case GRN_TS_OP_NOT_EQUAL: { + return grn_ts_op_not_equal_filter(ctx, node, in, n_in, out, n_out); + } + case GRN_TS_OP_LESS: { + return grn_ts_op_less_filter(ctx, node, in, n_in, out, n_out); + } + case GRN_TS_OP_LESS_EQUAL: { + return grn_ts_op_less_equal_filter(ctx, node, in, n_in, out, n_out); + } + case GRN_TS_OP_GREATER: { + return grn_ts_op_greater_filter(ctx, node, in, n_in, out, n_out); + } + case GRN_TS_OP_GREATER_EQUAL: { + return grn_ts_op_greater_equal_filter(ctx, node, in, n_in, out, n_out); + } + case GRN_TS_OP_MATCH: { + return grn_ts_op_match_filter(ctx, node, in, n_in, out, n_out); + } + case GRN_TS_OP_PREFIX_MATCH: { + return grn_ts_op_prefix_match_filter(ctx, node, in, n_in, out, n_out); + } + case GRN_TS_OP_SUFFIX_MATCH: { + return grn_ts_op_suffix_match_filter(ctx, node, in, n_in, out, n_out); + } + // TODO: Add operators. + default: { + GRN_TS_ERR_RETURN(GRN_OPERATION_NOT_SUPPORTED, + "operator not supported: %d", node->op_type); + } + } +} + +#define GRN_TS_OP_SIGN_ADJUST(type)\ + size_t i;\ + grn_ts_float *buf_ptr;\ + grn_rc rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[0], io, n_io,\ + &node->bufs[0]);\ + if (rc != GRN_SUCCESS) {\ + return rc;\ + }\ + buf_ptr = (grn_ts_float *)node->bufs[0].ptr;\ + for (i = 0; i < n_io; i++) {\ + grn_ts_float result = grn_ts_op_ ## type ## _float(buf_ptr[i]);\ + io[i].score = (grn_ts_score)result;\ + if (!isfinite(io[i].score)) {\ + GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid score: %g", result);\ + }\ + }\ + return GRN_SUCCESS; +/* grn_ts_op_positive_adjust() updates scores. */ +static grn_rc +grn_ts_op_positive_adjust(grn_ctx *ctx, grn_ts_expr_op_node *node, + grn_ts_record *io, size_t n_io) +{ + GRN_TS_OP_SIGN_ADJUST(positive) +} + +/* grn_ts_op_negative_adjust() updates scores. */ +static grn_rc +grn_ts_op_negative_adjust(grn_ctx *ctx, grn_ts_expr_op_node *node, + grn_ts_record *io, size_t n_io) +{ + GRN_TS_OP_SIGN_ADJUST(negative) +} +#undef GRN_TS_OP_SIGN_ADJUST + +/* grn_ts_op_float_adjust() updates scores. */ +static grn_rc +grn_ts_op_float_adjust(grn_ctx *ctx, grn_ts_expr_op_node *node, + grn_ts_record *io, size_t n_io) +{ + size_t i; + grn_ts_int *buf_ptr; + grn_rc rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[0], io, n_io, + &node->bufs[0]); + if (rc != GRN_SUCCESS) { + return rc; + } + buf_ptr = (grn_ts_int *)node->bufs[0].ptr; + for (i = 0; i < n_io; i++) { + grn_ts_float result; + rc = grn_ts_op_float(ctx, buf_ptr[i], &result); + io[i].score = (grn_ts_score)result; + if (!isfinite(io[i].score)) { + GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid score: %g", result); + } + } + return GRN_SUCCESS; +} + +#define GRN_TS_OP_ARITH_ADJUST(type)\ + grn_rc rc;\ + size_t i;\ + grn_ts_float *buf_ptrs[2];\ + for (i = 0; i < 2; i++) {\ + rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[i], io, n_io,\ + &node->bufs[i]);\ + if (rc != GRN_SUCCESS) {\ + return rc;\ + }\ + }\ + buf_ptrs[0] = (grn_ts_float *)node->bufs[0].ptr;\ + buf_ptrs[1] = (grn_ts_float *)node->bufs[1].ptr;\ + for (i = 0; i < n_io; i++) {\ + grn_ts_float result;\ + rc = grn_ts_op_ ## type ## _float_float(ctx, buf_ptrs[0][i],\ + buf_ptrs[1][i], &result);\ + io[i].score = (grn_ts_score)result;\ + if (!isfinite(io[i].score)) {\ + GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid score: %g", result);\ + }\ + }\ + return GRN_SUCCESS; +/* grn_ts_op_plus_adjust() updates scores. */ +static grn_rc +grn_ts_op_plus_adjust(grn_ctx *ctx, grn_ts_expr_op_node *node, + grn_ts_record *io, size_t n_io) +{ + GRN_TS_OP_ARITH_ADJUST(plus) +} + +/* grn_ts_op_minus_adjust() updates scores. */ +static grn_rc +grn_ts_op_minus_adjust(grn_ctx *ctx, grn_ts_expr_op_node *node, + grn_ts_record *io, size_t n_io) +{ + GRN_TS_OP_ARITH_ADJUST(minus) +} + +/* grn_ts_op_multiplication_adjust() updates scores. */ +static grn_rc +grn_ts_op_multiplication_adjust(grn_ctx *ctx, grn_ts_expr_op_node *node, + grn_ts_record *io, size_t n_io) +{ + GRN_TS_OP_ARITH_ADJUST(multiplication) +} + +/* grn_ts_op_division_adjust() updates scores. */ +static grn_rc +grn_ts_op_division_adjust(grn_ctx *ctx, grn_ts_expr_op_node *node, + grn_ts_record *io, size_t n_io) +{ + GRN_TS_OP_ARITH_ADJUST(division) +} + +/* grn_ts_op_modulus_adjust() updates scores. */ +static grn_rc +grn_ts_op_modulus_adjust(grn_ctx *ctx, grn_ts_expr_op_node *node, + grn_ts_record *io, size_t n_io) +{ + GRN_TS_OP_ARITH_ADJUST(modulus) +} +#undef GRN_TS_OP_ARITH_ADJUST + +/* grn_ts_expr_op_node_adjust() updates scores. */ +static grn_rc +grn_ts_expr_op_node_adjust(grn_ctx *ctx, grn_ts_expr_op_node *node, + grn_ts_record *io, size_t n_io) +{ + switch (node->op_type) { + case GRN_TS_OP_POSITIVE: { + return grn_ts_op_positive_adjust(ctx, node, io, n_io); + } + case GRN_TS_OP_NEGATIVE: { + return grn_ts_op_negative_adjust(ctx, node, io, n_io); + } + case GRN_TS_OP_FLOAT: { + return grn_ts_op_float_adjust(ctx, node, io, n_io); + } + case GRN_TS_OP_PLUS: { + return grn_ts_op_plus_adjust(ctx, node, io, n_io); + } + case GRN_TS_OP_MINUS: { + return grn_ts_op_minus_adjust(ctx, node, io, n_io); + } + case GRN_TS_OP_MULTIPLICATION: { + return grn_ts_op_multiplication_adjust(ctx, node, io, n_io); + } + case GRN_TS_OP_DIVISION: { + return grn_ts_op_division_adjust(ctx, node, io, n_io); + } + case GRN_TS_OP_MODULUS: { + return grn_ts_op_modulus_adjust(ctx, node, io, n_io); + } + // TODO: Add operators. + default: { + GRN_TS_ERR_RETURN(GRN_OPERATION_NOT_SUPPORTED, + "operator not supported: %d", node->op_type); + } + } +} + +/*------------------------------------------------------------- + * grn_ts_expr_bridge_node. + */ + +enum { GRN_TS_EXPR_BRIDGE_NODE_N_BUFS = 2 }; + +typedef struct { + GRN_TS_EXPR_NODE_COMMON_MEMBERS + grn_ts_expr_node *src; + grn_ts_expr_node *dest; + grn_ts_buf bufs[GRN_TS_EXPR_BRIDGE_NODE_N_BUFS]; +} grn_ts_expr_bridge_node; + +/* grn_ts_expr_bridge_node_init() initializes a node. */ +static void +grn_ts_expr_bridge_node_init(grn_ctx *ctx, grn_ts_expr_bridge_node *node) +{ + size_t i; + memset(node, 0, sizeof(*node)); + node->type = GRN_TS_EXPR_BRIDGE_NODE; + node->src = NULL; + node->dest = NULL; + for (i = 0; i < GRN_TS_EXPR_BRIDGE_NODE_N_BUFS; i++) { + grn_ts_buf_init(ctx, &node->bufs[i]); + } +} + +/* grn_ts_expr_bridge_node_fin() finalizes a node. */ +static void +grn_ts_expr_bridge_node_fin(grn_ctx *ctx, grn_ts_expr_bridge_node *node) +{ + size_t i; + for (i = 0; i < GRN_TS_EXPR_BRIDGE_NODE_N_BUFS; i++) { + grn_ts_buf_fin(ctx, &node->bufs[i]); + } + if (node->dest) { + grn_ts_expr_node_close(ctx, node->dest); + } + if (node->src) { + grn_ts_expr_node_close(ctx, node->src); + } +} + +grn_rc +grn_ts_expr_bridge_node_open(grn_ctx *ctx, grn_ts_expr_node *src, + grn_ts_expr_node *dest, grn_ts_expr_node **node) +{ + grn_ts_expr_bridge_node *new_node = GRN_MALLOCN(grn_ts_expr_bridge_node, 1); + if (!new_node) { + GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE, + "GRN_MALLOCN failed: %" GRN_FMT_SIZE " x 1", + sizeof(grn_ts_expr_bridge_node)); + } + grn_ts_expr_bridge_node_init(ctx, new_node); + new_node->data_kind = dest->data_kind; + new_node->data_type = dest->data_type; + new_node->src = src; + new_node->dest = dest; + *node = (grn_ts_expr_node *)new_node; + return GRN_SUCCESS; +} + +/* grn_ts_expr_bridge_node_close() destroys a node. */ +static void +grn_ts_expr_bridge_node_close(grn_ctx *ctx, grn_ts_expr_bridge_node *node) +{ + grn_ts_expr_bridge_node_fin(ctx, node); + GRN_FREE(node); +} + +/* grn_ts_expr_bridge_node_evaluate() evaluates a bridge. */ +static grn_rc +grn_ts_expr_bridge_node_evaluate(grn_ctx *ctx, grn_ts_expr_bridge_node *node, + const grn_ts_record *in, size_t n_in, + void *out) +{ + grn_ts_record *tmp; + grn_rc rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->src, in, n_in, + &node->bufs[0]); + if (rc != GRN_SUCCESS) { + return rc; + } + tmp = (grn_ts_record *)node->bufs[0].ptr; + return grn_ts_expr_node_evaluate(ctx, node->dest, tmp, n_in, out); +} + +/* grn_ts_expr_bridge_node_filter() filters records. */ +static grn_rc +grn_ts_expr_bridge_node_filter(grn_ctx *ctx, grn_ts_expr_bridge_node *node, + grn_ts_record *in, size_t n_in, + grn_ts_record *out, size_t *n_out) +{ + size_t i, count; + grn_ts_bool *values; + grn_ts_record *tmp; + grn_rc rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->src, in, n_in, + &node->bufs[0]); + if (rc != GRN_SUCCESS) { + return rc; + } + tmp = (grn_ts_record *)node->bufs[0].ptr; + rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->dest, in, n_in, + &node->bufs[1]); + if (rc != GRN_SUCCESS) { + return rc; + } + values = (grn_ts_bool *)&node->bufs[1].ptr; + for (i = 0, count = 0; i < n_in; i++) { + if (values[i]) { + out[count++] = in[i]; + } + } + *n_out = count; + return GRN_SUCCESS; +} + +/* grn_ts_expr_bridge_node_adjust() updates scores. */ +static grn_rc +grn_ts_expr_bridge_node_adjust(grn_ctx *ctx, grn_ts_expr_bridge_node *node, + grn_ts_record *io, size_t n_io) +{ + size_t i; + grn_ts_record *tmp; + grn_rc rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->src, io, n_io, + &node->bufs[0]); + if (rc != GRN_SUCCESS) { + return rc; + } + tmp = (grn_ts_record *)node->bufs[0].ptr; + rc = grn_ts_expr_node_adjust(ctx, node->dest, tmp, n_io); + if (rc != GRN_SUCCESS) { + return rc; + } + for (i = 0; i < n_io; i++) { + io[i].score = tmp[i].score; + } + return GRN_SUCCESS; +} + +/*------------------------------------------------------------- + * grn_ts_expr_node. + */ + +#define GRN_TS_EXPR_NODE_CLOSE_CASE(TYPE, type)\ + case GRN_TS_EXPR_ ## TYPE ## _NODE: {\ + grn_ts_expr_ ## type ## _node *type ## _node;\ + type ## _node = (grn_ts_expr_ ## type ## _node *)node;\ + grn_ts_expr_ ## type ## _node_close(ctx, type ## _node);\ + return;\ + } +void +grn_ts_expr_node_close(grn_ctx *ctx, grn_ts_expr_node *node) +{ + switch (node->type) { + GRN_TS_EXPR_NODE_CLOSE_CASE(ID, id) + GRN_TS_EXPR_NODE_CLOSE_CASE(SCORE, score) + GRN_TS_EXPR_NODE_CLOSE_CASE(KEY, key) + GRN_TS_EXPR_NODE_CLOSE_CASE(VALUE, value) + GRN_TS_EXPR_NODE_CLOSE_CASE(CONST, const) + GRN_TS_EXPR_NODE_CLOSE_CASE(COLUMN, column) + GRN_TS_EXPR_NODE_CLOSE_CASE(OP, op) + GRN_TS_EXPR_NODE_CLOSE_CASE(BRIDGE, bridge) + } +} +#undef GRN_TS_EXPR_NODE_CLOSE_CASE + +/* grn_ts_expr_node_deref_once() resolves a reference. */ +static grn_rc +grn_ts_expr_node_deref_once(grn_ctx *ctx, grn_ts_expr_node *in, + grn_ts_expr_node **out) +{ + grn_rc rc; + grn_id table_id = in->data_type; + grn_ts_expr_node *key_node, *bridge_node; + grn_obj *table = grn_ctx_at(ctx, table_id); + if (!table) { + GRN_TS_ERR_RETURN(GRN_UNKNOWN_ERROR, "grn_ctx_at failed: %d", table_id); + } + if (!grn_ts_obj_is_table(ctx, table)) { + grn_obj_unlink(ctx, table); + GRN_TS_ERR_RETURN(GRN_UNKNOWN_ERROR, "not table: %d", table_id); + } + rc = grn_ts_expr_key_node_open(ctx, table, &key_node); + grn_obj_unlink(ctx, table); + if (rc != GRN_SUCCESS) { + return rc; + } + rc = grn_ts_expr_bridge_node_open(ctx, in, key_node, &bridge_node); + if (rc != GRN_SUCCESS) { + grn_ts_expr_node_close(ctx, key_node); + return rc; + } + *out = bridge_node; + return GRN_SUCCESS; +} + +grn_rc +grn_ts_expr_node_deref(grn_ctx *ctx, grn_ts_expr_node **node_ptr) +{ + grn_ts_expr_node *node = *node_ptr, **in_ptr = NULL; + while ((node->data_kind & ~GRN_TS_VECTOR_FLAG) == GRN_TS_REF) { + grn_ts_expr_node *new_node= 0; + grn_rc rc = grn_ts_expr_node_deref_once(ctx, node, &new_node); + if (rc != GRN_SUCCESS) { + if (in_ptr) { + *in_ptr = NULL; + grn_ts_expr_node_close(ctx, node); + } + return rc; + } + if (node == *node_ptr) { + grn_ts_expr_bridge_node *bridge_node; + bridge_node = (grn_ts_expr_bridge_node *)new_node; + if (bridge_node->src != node) { + GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "broken bridge node"); + } + in_ptr = &bridge_node->src; + } + node = new_node; + } + *node_ptr = node; + return GRN_SUCCESS; +} + +#define GRN_TS_EXPR_NODE_EVALUATE_CASE(TYPE, type)\ + case GRN_TS_EXPR_ ## TYPE ## _NODE: {\ + grn_ts_expr_ ## type ## _node *type ## _node;\ + type ## _node = (grn_ts_expr_ ## type ## _node *)node;\ + return grn_ts_expr_ ## type ## _node_evaluate(ctx, type ## _node,\ + in, n_in, out);\ + } +grn_rc +grn_ts_expr_node_evaluate(grn_ctx *ctx, grn_ts_expr_node *node, + const grn_ts_record *in, size_t n_in, void *out) +{ + switch (node->type) { + GRN_TS_EXPR_NODE_EVALUATE_CASE(ID, id) + GRN_TS_EXPR_NODE_EVALUATE_CASE(SCORE, score) + GRN_TS_EXPR_NODE_EVALUATE_CASE(KEY, key) + GRN_TS_EXPR_NODE_EVALUATE_CASE(VALUE, value) + GRN_TS_EXPR_NODE_EVALUATE_CASE(CONST, const) + GRN_TS_EXPR_NODE_EVALUATE_CASE(COLUMN, column) + GRN_TS_EXPR_NODE_EVALUATE_CASE(OP, op) + GRN_TS_EXPR_NODE_EVALUATE_CASE(BRIDGE, bridge) + default: { + GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, + "invalid node type: %d", node->type); + } + } +} +#undef GRN_TS_EXPR_NODE_EVALUATE_CASE + +#define GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_CASE(KIND, kind)\ + case GRN_TS_ ## KIND: {\ + grn_rc rc = grn_ts_buf_reserve(ctx, out, sizeof(grn_ts_ ## kind) * n_in);\ + if (rc != GRN_SUCCESS) {\ + return rc;\ + }\ + return grn_ts_expr_node_evaluate(ctx, node, in, n_in, out->ptr);\ + } +#define GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_VECTOR_CASE(KIND, kind)\ + GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_CASE(KIND ## _VECTOR, kind ## _vector) +grn_rc +grn_ts_expr_node_evaluate_to_buf(grn_ctx *ctx, grn_ts_expr_node *node, + const grn_ts_record *in, size_t n_in, + grn_ts_buf *out) +{ + switch (node->data_kind) { + GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_CASE(BOOL, bool) + GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_CASE(INT, int) + GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_CASE(FLOAT, float) + GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_CASE(TIME, time) + GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_CASE(TEXT, text) + GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_CASE(GEO, geo) + GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_CASE(REF, ref) + GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_VECTOR_CASE(BOOL, bool) + GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_VECTOR_CASE(INT, int) + GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_VECTOR_CASE(FLOAT, float) + GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_VECTOR_CASE(TIME, time) + GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_VECTOR_CASE(TEXT, text) + GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_VECTOR_CASE(GEO, geo) + GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_VECTOR_CASE(REF, ref) + default: { + GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, + "invalid data kind: %d", node->data_kind); + } + } +} +#undef GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_VECTOR_CASE +#undef GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_CASE + +#define GRN_TS_EXPR_NODE_FILTER_CASE(TYPE, type)\ + case GRN_TS_EXPR_ ## TYPE ## _NODE: {\ + grn_ts_expr_ ## type ## _node *type ## _node;\ + type ## _node = (grn_ts_expr_ ## type ## _node *)node;\ + return grn_ts_expr_ ## type ## _node_filter(ctx, type ## _node,\ + in, n_in, out, n_out);\ + } +grn_rc +grn_ts_expr_node_filter(grn_ctx *ctx, grn_ts_expr_node *node, + grn_ts_record *in, size_t n_in, + grn_ts_record *out, size_t *n_out) +{ + if (node->data_kind != GRN_TS_BOOL) { + GRN_TS_ERR_RETURN(GRN_OPERATION_NOT_SUPPORTED, + "invalid data kind: %d", node->data_kind); + } + switch (node->type) { + GRN_TS_EXPR_NODE_FILTER_CASE(KEY, key) + GRN_TS_EXPR_NODE_FILTER_CASE(VALUE, value) + GRN_TS_EXPR_NODE_FILTER_CASE(CONST, const) + GRN_TS_EXPR_NODE_FILTER_CASE(COLUMN, column) + GRN_TS_EXPR_NODE_FILTER_CASE(OP, op) + GRN_TS_EXPR_NODE_FILTER_CASE(BRIDGE, bridge) + default: { + GRN_TS_ERR_RETURN(GRN_OPERATION_NOT_SUPPORTED, + "invalid node type: %d", node->type); + } + } +} +#undef GRN_TS_EXPR_NODE_FILTER_CASE + +#define GRN_TS_EXPR_NODE_ADJUST_CASE(TYPE, type)\ + case GRN_TS_EXPR_ ## TYPE ## _NODE: {\ + grn_ts_expr_ ## type ## _node *type ## _node;\ + type ## _node = (grn_ts_expr_ ## type ## _node *)node;\ + return grn_ts_expr_ ## type ## _node_adjust(ctx, type ## _node, io, n_io);\ + } +grn_rc +grn_ts_expr_node_adjust(grn_ctx *ctx, grn_ts_expr_node *node, + grn_ts_record *io, size_t n_io) +{ + if (node->data_kind != GRN_TS_FLOAT) { + GRN_TS_ERR_RETURN(GRN_OPERATION_NOT_SUPPORTED, + "invalid data kind: %d", node->data_kind); + } + switch (node->type) { + GRN_TS_EXPR_NODE_ADJUST_CASE(SCORE, score) + GRN_TS_EXPR_NODE_ADJUST_CASE(KEY, key) + GRN_TS_EXPR_NODE_ADJUST_CASE(VALUE, value) + GRN_TS_EXPR_NODE_ADJUST_CASE(CONST, const) + GRN_TS_EXPR_NODE_ADJUST_CASE(COLUMN, column) + GRN_TS_EXPR_NODE_ADJUST_CASE(OP, op) + GRN_TS_EXPR_NODE_ADJUST_CASE(BRIDGE, bridge) + default: { + GRN_TS_ERR_RETURN(GRN_OPERATION_NOT_SUPPORTED, + "invalid node type: %d", node->type); + } + } +} +#undef GRN_TS_EXPR_NODE_ADJUST_CASE -- cgit v1.2.3