susumu.yata
null+****@clear*****
Wed Sep 2 10:58:34 JST 2015
susumu.yata 2015-09-02 10:58:34 +0900 (Wed, 02 Sep 2015) New Revision: 38b65e3591e494e9bc57a865e1009f5239156745 https://github.com/groonga/groonga/commit/38b65e3591e494e9bc57a865e1009f5239156745 Message: grn_ts: reimplementation with C Added files: lib/ts.c Removed files: lib/grn_ts.hpp lib/ts.cpp Modified files: lib/CMakeLists.txt lib/grn_ts.h lib/sources.am Modified: lib/CMakeLists.txt (+1 -1) =================================================================== --- lib/CMakeLists.txt 2015-09-01 21:58:28 +0900 (17995ea) +++ lib/CMakeLists.txt 2015-09-02 10:58:34 +0900 (1a7da11) @@ -36,7 +36,7 @@ string(REGEX REPLACE "([^;]+)" "mrb/\\1" set_source_files_properties(${LIBGROONGA_SOURCES} ${LIBGRNMRB_SOURCES} PROPERTIES COMPILE_FLAGS "${GRN_C_COMPILE_FLAGS}") -set_source_files_properties(dat.cpp ts.cpp ${LIBGRNDAT_SOURCES} +set_source_files_properties(dat.cpp ${LIBGRNDAT_SOURCES} PROPERTIES COMPILE_FLAGS "${GRN_CXX_COMPILE_FLAGS}") Modified: lib/grn_ts.h (+287 -36) =================================================================== --- lib/grn_ts.h 2015-09-01 21:58:28 +0900 (4f19e64) +++ lib/grn_ts.h 2015-09-02 10:58:34 +0900 (4504c7d) @@ -19,58 +19,93 @@ #ifndef GRN_TS_H #define GRN_TS_H +#ifdef GRN_WITH_TS + +#include <stddef.h> +#include <stdint.h> + #include "grn.h" #ifdef __cplusplus extern "C" { #endif -// Constant values. +/*------------------------------------------------------------- + * Enumeration types. + */ +/* grn_builtin_type or table ID. */ typedef grn_id grn_ts_data_type; +enum { GRN_TS_VECTOR_FLAG = 1 << 7 }; + typedef enum { - GRN_TS_VOID, // GRN_DB_VOID. - GRN_TS_BOOL, // GRN_DB_BOOL. - GRN_TS_INT, // GRN_DB_(U)INT8/16/32/64. - GRN_TS_FLOAT, // GRN_DB_FLOAT. - GRN_TS_TIME, // GRN_DB_TIME. - GRN_TS_TEXT, // GRN_DB_(SHORT_/LONG_)TEST. - GRN_TS_GEO_POINT, // GRN_DB_TOKYO/WGS84_GEO_POINT. - GRN_TS_REF // Table reference. + GRN_TS_VOID = 0, /* GRN_DB_VOID */ + GRN_TS_BOOL = 1, /* GRN_DB_BOOL */ + GRN_TS_INT = 2, /* GRN_DB_[U]INT(8/16/32/64) */ + GRN_TS_FLOAT = 3, /* GRN_DB_FLOAT */ + GRN_TS_TIME = 4, /* GRN_DB_TIME */ + GRN_TS_TEXT = 5, /* GRN_DB_[SHORT_/LONG_]TEST */ + GRN_TS_GEO_POINT = 6, /* GRN_DB_(TOKYO/WGS84)_GEO_POINT */ + GRN_TS_REF = 7, /* Table reference. */ + GRN_TS_BOOL_VECTOR = GRN_TS_VECTOR_FLAG | GRN_TS_BOOL, + GRN_TS_INT_VECTOR = GRN_TS_VECTOR_FLAG | GRN_TS_INT, + GRN_TS_FLOAT_VECTOR = GRN_TS_VECTOR_FLAG | GRN_TS_FLOAT, + GRN_TS_TIME_VECTOR = GRN_TS_VECTOR_FLAG | GRN_TS_TIME, + GRN_TS_TEXT_VECTOR = GRN_TS_VECTOR_FLAG | GRN_TS_TEXT, + GRN_TS_GEO_POINT_VECTOR = GRN_TS_VECTOR_FLAG | GRN_TS_GEO_POINT, + GRN_TS_REF_VECTOR = GRN_TS_VECTOR_FLAG | GRN_TS_REF } grn_ts_data_kind; typedef enum { - GRN_TS_NOP, - GRN_TS_LOGICAL_NOT, - GRN_TS_LOGICAL_AND, - GRN_TS_LOGICAL_OR, - GRN_TS_EQUAL, - GRN_TS_NOT_EQUAL, - GRN_TS_LESS, - GRN_TS_LESS_EQUAL, - GRN_TS_GREATER, - GRN_TS_GREATER_EQUAL -} grn_ts_operator_type; + /* Invalid operator. */ + GRN_TS_OP_NOP, + + /* Unary operators. */ + GRN_TS_OP_LOGICAL_NOT, /* ! */ + GRN_TS_OP_BITWISE_NOT, /* ~ */ + GRN_TS_OP_POSITIVE, /* + */ + GRN_TS_OP_NEGATIVE, /* - */ + + /* Binary operators. */ + GRN_TS_OP_LOGICAL_AND, /* && */ + GRN_TS_OP_LOGICAL_OR, /* || */ + GRN_TS_OP_BITWISE_AND, /* & */ + GRN_TS_OP_BITWISE_OR, /* | */ + GRN_TS_OP_BITWISE_XOR, /* ^ */ + GRN_TS_OP_EQUAL, /* == */ + GRN_TS_OP_NOT_EQUAL, /* != */ + GRN_TS_OP_LESS, /* < */ + GRN_TS_OP_LESS_EQUAL, /* <= */ + GRN_TS_OP_GREATER, /* > */ + GRN_TS_OP_GREATER_EQUAL /* >= */ +} grn_ts_op_type; typedef enum { - GRN_TS_ID_NODE, - GRN_TS_SCORE_NODE, - GRN_TS_CONSTANT_NODE, - GRN_TS_COLUMN_NODE, - GRN_TS_OPERATOR_NODE -} grn_ts_expression_node_type; + GRN_TS_EXPR_INCOMPLETE, /* An incomplete expression. */ + GRN_TS_EXPR_BROKEN, /* A broken expression. */ + /* Any operation fails for a broken expression. */ + GRN_TS_EXPR_ID, /* An expression associated with _id. */ + GRN_TS_EXPR_SCORE, /* An expression associated with _score. */ + GRN_TS_EXPR_CONST, /* A const. */ + GRN_TS_EXPR_VARIABLE /* An expression that contains a variable. */ +} grn_ts_expr_type; typedef enum { - GRN_TS_INCOMPLETE, - GRN_TS_ID, - GRN_TS_SCORE, - GRN_TS_CONSTANT, - GRN_TS_VARIABLE -} grn_ts_expression_type; + GRN_TS_EXPR_ID_NODE, /* Associated with the ID (_id). */ + GRN_TS_EXPR_SCORE_NODE, /* Asscoaited with the score (_score). */ + GRN_TS_EXPR_KEY_NODE, /* Asscoaited with the key (_key). */ + GRN_TS_EXPR_VALUE_NODE, /* Asscoaited with the embedded value (_value). */ + GRN_TS_EXPR_CONST_NODE, /* Associated with a const. */ + GRN_TS_EXPR_COLUMN_NODE, /* Associated with a column. */ + GRN_TS_EXPR_OP_NODE /* Associated with an operator. */ +} grn_ts_expr_node_type; -// Built-in data types. +/*------------------------------------------------------------- + * Built-in data types. + */ +/* ID (_id), score (_score), and record types. */ typedef grn_id grn_ts_id; typedef float grn_ts_score; typedef struct { @@ -78,6 +113,7 @@ typedef struct { grn_ts_score score; } grn_ts_record; +/* Built-in scalar data types. */ typedef grn_bool grn_ts_bool; typedef int64_t grn_ts_int; typedef double grn_ts_float; @@ -87,10 +123,223 @@ typedef struct { size_t size; } grn_ts_text; typedef grn_geo_point grn_ts_geo_point; +typedef grn_geo_point grn_ts_tokyo_geo_point; +typedef grn_geo_point grn_ts_wgs84_geo_point; +typedef grn_ts_record grn_ts_ref; + +/* Built-in vector data types. */ +typedef struct { + const grn_ts_bool *ptr; + size_t size; +} grn_ts_bool_vector; +typedef struct { + const grn_ts_int *ptr; + size_t size; +} grn_ts_int_vector; +typedef struct { + const grn_ts_float *ptr; + size_t size; +} grn_ts_float_vector; +typedef struct { + const grn_ts_time *ptr; + size_t size; +} grn_ts_time_vector; typedef struct { - const void *ptr; + const grn_ts_text *ptr; size_t size; -} grn_ts_vector; +} grn_ts_text_vector; +typedef struct { + const grn_ts_geo_point *ptr; + size_t size; +} grn_ts_geo_point_vector; +typedef grn_ts_geo_point_vector grn_ts_tokyo_geo_point_vector; +typedef grn_ts_geo_point_vector grn_ts_wgs84_geo_point_vector; +typedef struct { + const grn_ts_ref *ptr; + size_t size; +} grn_ts_ref_vector; + +/*------------------------------------------------------------- + * Expression components. + */ + +#define GRN_TS_EXPR_NODE_COMMON_MEMBERS\ + grn_ts_expr_node_type type; /* Node type. */\ + grn_ts_data_kind data_kind; /* Abstract data type. */\ + grn_ts_data_type data_type; /* Detailed data type. */ + +typedef struct { + GRN_TS_EXPR_NODE_COMMON_MEMBERS +} grn_ts_expr_node; + +typedef struct { + grn_obj *table; /* Associated table. */ + grn_obj *curr_table; /* Current table. */ + grn_ts_expr_type type; /* Expression type. */ + grn_ts_data_kind data_kind; /* Abstract data type. */ + grn_ts_data_type data_type; /* Detailed data type. */ + grn_ts_expr_node *root; /* Root node. */ + grn_ts_expr_node **nodes; /* Buffer for a node stack. */ + size_t n_nodes; /* Number of nodes. */ + size_t max_n_nodes; /* Max. number (capacity) of nodes. */ + grn_ts_expr_node **stack; /* Node stack. */ + size_t stack_depth; /* Node stack's current depth. */ + size_t stack_size; /* Node stack's size (capacity). */ +} grn_ts_expr; + +/* grn_ts_expr_open() creates an empty expression. */ +grn_rc grn_ts_expr_open(grn_ctx *ctx, grn_obj *table, grn_ts_expr **expr); + +/* grn_ts_expr_parse() creates an expression from a string. */ +grn_rc grn_ts_expr_parse(grn_ctx *ctx, grn_obj *table, + const char *str, size_t str_size, + grn_ts_expr **expr); + +/* grn_ts_expr_close() destroys an expression. */ +grn_rc grn_ts_expr_close(grn_ctx *ctx, grn_ts_expr *expr); + +/* + * grn_ts_expr_get_table() returns the associated table. + * If arguments are invalid, the return value is NULL. + */ +grn_obj *grn_ts_expr_get_table(grn_ctx *ctx, grn_ts_expr *expr); + +/* + * grn_ts_expr_get_type() returns the expression type. + * If arguments are invalid, the return value is GRN_EXPR_BROKEN. + */ +grn_ts_expr_type grn_ts_expr_get_type(grn_ctx *ctx, grn_ts_expr *expr); + +/* + * grn_ts_expr_get_data_kind() returns the data kind. + * If arguments are invalid, the return value is GRN_TS_VOID. + */ +grn_ts_data_kind grn_ts_expr_get_data_kind(grn_ctx *ctx, grn_ts_expr *expr); + +/* + * grn_ts_expr_get_data_type() returns the data type. + * If arguments are invalid, the return value is GRN_DB_VOID. + */ + +grn_ts_data_type grn_ts_expr_get_data_type(grn_ctx *ctx, grn_ts_expr *expr); + +/* + * grn_ts_expr_get_root() returns the root node. + * If arguments are invalid, the return value is NULL. + */ +grn_ts_expr_node *grn_ts_expr_get_root(grn_ctx *ctx, grn_ts_expr *expr); + +/* grn_ts_expr_push() pushes expression nodes expressed by a string. */ +grn_rc grn_ts_expr_push(grn_ctx *ctx, grn_ts_expr *expr, + const char *str, size_t str_size); + +/* + * grn_ts_expr_push_obj() pushes an object. + * + * Acceptable objects are as follows: + * - Consts + * - GRN_BULK: GRN_DB_*. + * - GRN_UVECTOR: GRN_DB_* except GRN_DB_[SHORT/LONG_]TEXT. + * - GRN_VECTOR: GRN_DB_[SHORT/LONG_]TEXT. + * - Columns + * - GRN_ACCESSOR: _id, _score, _key, and _value. + * - GRN_COLUMN_FIX_SIZE: GRN_DB_* except GRN_DB_[SHORT/LONG_]TEXT. + * - GRN_COLUMN_VAR_SIZE: GRN_DB_[SHORT/LONG_]TEXT. + */ +grn_rc grn_ts_expr_push_obj(grn_ctx *ctx, grn_ts_expr *expr, grn_obj *obj); + +/* grn_ts_expr_push_id() pushes "_id". */ +grn_rc grn_ts_expr_push_id(grn_ctx *ctx, grn_ts_expr *expr); +/* grn_ts_expr_push_score() pushes "_score". */ +grn_rc grn_ts_expr_push_score(grn_ctx *ctx, grn_ts_expr *expr); +/* grn_ts_expr_push_key() pushes "_key". */ +grn_rc grn_ts_expr_push_key(grn_ctx *ctx, grn_ts_expr *expr); +/* grn_ts_expr_push_key() pushes "_value". */ +grn_rc grn_ts_expr_push_value(grn_ctx *ctx, grn_ts_expr *expr); +/* grn_ts_expr_push_const() pushes a column. */ +grn_rc grn_ts_expr_push_const(grn_ctx *ctx, grn_ts_expr *expr, + grn_ts_data_kind kind, const void *value); +/* grn_ts_expr_push_column() pushes a column. */ +grn_rc grn_ts_expr_push_column(grn_ctx *ctx, grn_ts_expr *expr, + grn_obj *column); +/* grn_ts_expr_push_operator() pushes an operator. */ +grn_rc grn_ts_expr_push_operator(grn_ctx *ctx, grn_ts_expr *expr, + grn_ts_op_type op_type); + +/* grn_ts_expr_push_bool() pushes a Bool const. */ +grn_rc grn_ts_expr_push_bool(grn_ctx *ctx, grn_ts_expr *expr, + grn_ts_bool value); +/* grn_ts_expr_push_int() pushes an Int64 const. */ +grn_rc grn_ts_expr_push_int(grn_ctx *ctx, grn_ts_expr *expr, + grn_ts_int value); +/* grn_ts_expr_push_float() pushes a Float const. */ +grn_rc grn_ts_expr_push_float(grn_ctx *ctx, grn_ts_expr *expr, + grn_ts_float value); +/* grn_ts_expr_push_time() pushes a Time const. */ +grn_rc grn_ts_expr_push_time(grn_ctx *ctx, grn_ts_expr *expr, + grn_ts_time value); +/* grn_ts_expr_push_text() pushes a Text const. */ +grn_rc grn_ts_expr_push_text(grn_ctx *ctx, grn_ts_expr *expr, + grn_ts_text value); +/* grn_ts_expr_push_geo_point() pushes a GeoPoint const. */ +grn_rc grn_ts_expr_push_geo_point(grn_ctx *ctx, grn_ts_expr *expr, + grn_ts_geo_point value); +/* grn_ts_expr_push_tokyo_geo_point() pushes a TokyoGeoPoint const. */ +grn_rc grn_ts_expr_push_tokyo_geo_point(grn_ctx *ctx, grn_ts_expr *expr, + grn_ts_geo_point value); +/* grn_ts_expr_push_wgs84_geo_point() pushes a WGS84GeoPoint const. */ +grn_rc grn_ts_expr_push_wgs84_geo_point(grn_ctx *ctx, grn_ts_expr *expr, + grn_ts_geo_point value); +/* grn_ts_expr_push_bool_vector() pushes a Bool vector const. */ +grn_rc grn_ts_expr_push_bool_vector(grn_ctx *ctx, grn_ts_expr *expr, + grn_ts_bool_vector value); +/* grn_ts_expr_push_int_vector() pushes an Int64 vector const. */ +grn_rc grn_ts_expr_push_int_vector(grn_ctx *ctx, grn_ts_expr *expr, + grn_ts_int_vector value); +/* grn_ts_expr_push_float_vector() pushes a Float vector const. */ +grn_rc grn_ts_expr_push_float_vector(grn_ctx *ctx, grn_ts_expr *expr, + grn_ts_float_vector value); +/* grn_ts_expr_push_time_vector() pushes a Time vector const. */ +grn_rc grn_ts_expr_push_time_vector(grn_ctx *ctx, grn_ts_expr *expr, + grn_ts_time_vector value); +/* grn_ts_expr_push_text_vector() pushes a Text vector const. */ +grn_rc grn_ts_expr_push_text_vector(grn_ctx *ctx, grn_ts_expr *expr, + grn_ts_text_vector value); +/* grn_ts_expr_push_geo_point_vector() pushes a GeoPoint vector const. */ +grn_rc grn_ts_expr_push_geo_point_vector(grn_ctx *ctx, grn_ts_expr *expr, + grn_ts_geo_point_vector value); +/* + * grn_ts_expr_push_tokyo_geo_point_vector() pushes a TokyoGeoPoint vector + * const. + */ +grn_rc grn_ts_expr_push_tokyo_geo_point_vector(grn_ctx *ctx, grn_ts_expr *expr, + grn_ts_geo_point_vector value); +/* + * grn_ts_expr_push_wgs84_geo_point_vector() pushes a WGS84GeoPoint vector + * const. + */ +grn_rc grn_ts_expr_push_wgs84_geo_point_vector(grn_ctx *ctx, grn_ts_expr *expr, + grn_ts_geo_point_vector value); + +/* grn_rc grn_ts_expr_complete() completes an expression. */ +grn_rc grn_ts_expr_complete(grn_ctx *ctx, grn_ts_expr *expr); + +/* grn_ts_expr_evaluate() evaluates an expression. */ +grn_rc grn_ts_expr_evaluate(grn_ctx *ctx, grn_ts_expr *expr, + const grn_ts_record *in, size_t n_in, void *out); + +/* grn_ts_expr_filter() filters records. */ +grn_rc grn_ts_expr_filter(grn_ctx *ctx, grn_ts_expr *expr, + grn_ts_record *in, size_t n_in, + grn_ts_record *out, size_t *n_out); + +/* grn_ts_expr_adjust() updates scores. */ +grn_rc grn_ts_expr_adjust(grn_ctx *ctx, grn_ts_expr *expr, + grn_ts_record *io, size_t n_io); + +/*------------------------------------------------------------- + * API. + */ /* * grn_ts_select() finds records passing through a filter (specified by @@ -108,10 +357,12 @@ typedef struct { grn_rc grn_ts_select(grn_ctx *ctx, grn_obj *table, const char *filter, size_t filter_size, const char *output_columns, size_t output_columns_size, - int offset, int limit); + size_t offset, size_t limit); #ifdef __cplusplus } #endif +#endif /* GRN_WITH_TS */ + #endif /* GRN_TS_H */ Deleted: lib/grn_ts.hpp (+0 -250) 100644 =================================================================== --- lib/grn_ts.hpp 2015-09-01 21:58:28 +0900 (631fc49) +++ /dev/null @@ -1,250 +0,0 @@ -/* -*- c-basic-offset: 2 -*- */ -/* - Copyright(C) 2015 Brazil - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License version 2.1 as published by the Free Software Foundation. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef GRN_TS_HPP -#define GRN_TS_HPP - -#include <cstring> -#include <vector> - -#include "grn_ts.h" - -namespace grn { -namespace ts { - -// Constant values. - -typedef grn_ts_operator_type OperatorType; -typedef grn_ts_data_type DataType; -typedef grn_ts_data_kind DataKind; - -typedef grn_ts_expression_node_type ExpressionNodeType; -typedef grn_ts_expression_type ExpressionType; - -// Built-in data types. - -typedef grn_ts_id ID; -typedef grn_ts_score Score; -typedef grn_ts_record Record; - -struct Bool { - typedef grn_ts_bool Raw; - Raw raw; - - Bool() : raw() {} - Bool(const Bool &value) : raw(value.raw) {} - explicit Bool(Raw value) : raw(value) {} - ~Bool() {} -}; - -inline bool operator!(Bool value) { return !value.raw; } -inline bool operator==(Bool lhs, Bool rhs) { return lhs.raw == rhs.raw; } -inline bool operator!=(Bool lhs, Bool rhs) { return lhs.raw != rhs.raw; } - -struct Int { - typedef grn_ts_int Raw; - Raw raw; - - Int() : raw() {} - Int(const Int &value) : raw(value.raw) {} - explicit Int(Raw value) : raw(value) {} - ~Int() {} -}; - -inline bool operator==(Int lhs, Int rhs) { return lhs.raw == rhs.raw; } -inline bool operator!=(Int lhs, Int rhs) { return lhs.raw != rhs.raw; } -inline bool operator<(Int lhs, Int rhs) { return lhs.raw < rhs.raw; } -inline bool operator<=(Int lhs, Int rhs) { return lhs.raw <= rhs.raw; } -inline bool operator>(Int lhs, Int rhs) { return lhs.raw > rhs.raw; } -inline bool operator>=(Int lhs, Int rhs) { return lhs.raw >= rhs.raw; } - -struct Float { - typedef grn_ts_float Raw; - Raw raw; - - Float() : raw() {} - Float(const Float &value) : raw(value.raw) {} - explicit Float(Raw value) : raw(value) {} - ~Float() {} -}; - -inline bool operator==(Float lhs, Float rhs) { - return (lhs.raw <= rhs.raw) && (lhs.raw >= rhs.raw); -} -inline bool operator!=(Float lhs, Float rhs) { - return (lhs.raw < rhs.raw) || (lhs.raw > rhs.raw); -} -inline bool operator<(Float lhs, Float rhs) { return lhs.raw < rhs.raw; } -inline bool operator<=(Float lhs, Float rhs) { return lhs.raw <= rhs.raw; } -inline bool operator>(Float lhs, Float rhs) { return lhs.raw > rhs.raw; } -inline bool operator>=(Float lhs, Float rhs) { return lhs.raw >= rhs.raw; } - -struct Time { - typedef grn_ts_time Raw; - Raw raw; - - Time() : raw() {} - Time(const Time &value) : raw(value.raw) {} - explicit Time(Raw value) : raw(value) {} - ~Time() {} -}; - -inline bool operator==(Time lhs, Time rhs) { return lhs.raw == rhs.raw; } -inline bool operator!=(Time lhs, Time rhs) { return lhs.raw != rhs.raw; } -inline bool operator<(Time lhs, Time rhs) { return lhs.raw < rhs.raw; } -inline bool operator<=(Time lhs, Time rhs) { return lhs.raw <= rhs.raw; } -inline bool operator>(Time lhs, Time rhs) { return lhs.raw > rhs.raw; } -inline bool operator>=(Time lhs, Time rhs) { return lhs.raw >= rhs.raw; } - -struct Text { - typedef grn_ts_text Raw; - Raw raw; - - Text() : raw() {} - Text(const Text &value) : raw(value.raw) {} - explicit Text(const Raw &value) : raw(value) {} - Text(const char *ptr, size_t size) : raw((Raw){ptr, size}) {} - ~Text() {} -}; - -inline bool operator==(const Text &lhs, const Text &rhs) { - if (lhs.raw.size != rhs.raw.size) { - return false; - } - return std::memcmp(lhs.raw.ptr, rhs.raw.ptr, lhs.raw.size) == 0; -} -inline bool operator!=(const Text &lhs, const Text &rhs) { - if (lhs.raw.size != rhs.raw.size) { - return true; - } - return std::memcmp(lhs.raw.ptr, rhs.raw.ptr, lhs.raw.size) != 0; -} -inline bool operator<(const Text &lhs, const Text &rhs) { - size_t min_size = (lhs.raw.size < rhs.raw.size) ? - lhs.raw.size : rhs.raw.size; - int result = std::memcmp(lhs.raw.ptr, rhs.raw.ptr, min_size); - if (result == 0) { - return lhs.raw.size < rhs.raw.size; - } - return result < 0; -} -inline bool operator<=(const Text &lhs, const Text &rhs) { - size_t min_size = (lhs.raw.size < rhs.raw.size) ? - lhs.raw.size : rhs.raw.size; - int result = std::memcmp(lhs.raw.ptr, rhs.raw.ptr, min_size); - if (result == 0) { - return lhs.raw.size <= rhs.raw.size; - } - return result <= 0; -} -inline bool operator>(const Text &lhs, const Text &rhs) { return rhs < lhs; } -inline bool operator>=(const Text &lhs, const Text &rhs) { return rhs <= lhs; } - -struct GeoPoint { - typedef grn_ts_geo_point Raw; - Raw raw; - - GeoPoint() : raw() {} - GeoPoint(const GeoPoint &value) : raw(value.raw) {} - explicit GeoPoint(Raw value) : raw(value) {} - GeoPoint(int latitude, int longitude) : raw((Raw){ latitude, longitude }) {} - ~GeoPoint() {} -}; - -inline bool operator==(GeoPoint lhs, GeoPoint rhs) { - return (lhs.raw.latitude == rhs.raw.latitude) && - (lhs.raw.longitude == rhs.raw.longitude); -} -inline bool operator!=(GeoPoint lhs, GeoPoint rhs) { - return (lhs.raw.latitude != rhs.raw.latitude) || - (lhs.raw.longitude != rhs.raw.longitude); -} - -// Cursor is a base class which provides an interface for sequential access to -// records. -class Cursor { - public: - Cursor() {} - virtual ~Cursor() {} - - // FIXME: Give me options. - static grn_rc open_table_cursor(grn_ctx *ctx, grn_obj *table, - Cursor **cursor); - - virtual grn_rc read(Record *records, size_t size, size_t *count); -}; - -// ExpressionNode is an element of Expression. -class ExpressionNode; - -// Expression is a class which represents an expression. -class Expression { - public: - Expression(grn_ctx *ctx, grn_obj *table); - ~Expression(); - - static grn_rc open(grn_ctx *ctx, grn_obj *table, Expression **expression); - static grn_rc parse(grn_ctx *ctx, grn_obj *table, - const char *query, size_t query_size, - Expression **expression); - - ExpressionType type() const { - return type_; - } - DataKind data_kind() const; - DataType data_type() const; - DataType output_type() const; - int dimension() const; - - grn_rc push_object(grn_obj *obj); - grn_rc push_operator(OperatorType operator_type); - - grn_rc filter(Record *input, size_t input_size, - Record *output, size_t *output_size); - grn_rc adjust(Record *records, size_t num_records); - - grn_rc evaluate(const Record *records, size_t num_records, void *results); - - private: - grn_ctx *ctx_; - grn_obj *table_; - ExpressionType type_; - DataType output_type_; - std::vector<ExpressionNode *> stack_; - - // Disable copy and assignment. - Expression(const Expression &); - Expression &operator=(const Expression &); - - ExpressionNode *root() const; - - void update_type(); - - grn_rc push_constant_object(grn_obj *obj); - grn_rc push_column_object(grn_obj *obj); - - grn_rc create_unary_node(OperatorType operator_type, - ExpressionNode *arg, ExpressionNode **node); - grn_rc create_binary_node(OperatorType operator_type, - ExpressionNode *arg1, ExpressionNode *arg2, ExpressionNode **node); -}; - -} // namespace ts -} // namespace grn - -#endif // GRN_TS_HPP Modified: lib/sources.am (+1 -2) =================================================================== --- lib/sources.am 2015-09-01 21:58:28 +0900 (8aea371) +++ lib/sources.am 2015-09-02 10:58:34 +0900 (70306da) @@ -11,9 +11,8 @@ libgroonga_la_SOURCES = \ grn_dat.h \ db.c \ grn_db.h \ - ts.cpp \ + ts.c \ grn_ts.h \ - grn_ts.hpp \ error.c \ grn_error.h \ expr.c \ Added: lib/ts.c (+2962 -0) 100644 =================================================================== --- /dev/null +++ lib/ts.c 2015-09-02 10:58:34 +0900 (daf8fee) @@ -0,0 +1,2962 @@ +/* -*- c-basic-offset: 2 -*- */ +/* + Copyright(C) 2015 Brazil + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License version 2.1 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* TS is an acronym for "Turbo Selector". */ + +#ifdef GRN_WITH_TS + +#include "grn_ts.h" + +#include <ctype.h> +#include <math.h> +#include <string.h> + +#include "grn_ctx_impl.h" +#include "grn_db.h" +#include "grn_geo.h" +#include "grn_output.h" +#include "grn_store.h" +#include "grn_str.h" + +/*------------------------------------------------------------- + * Miscellaneous. + */ + +enum { GRN_TS_BATCH_SIZE = 1024 }; + +/* grn_ts_bool_is_valid() returns whether a value is valid or not. */ +inline static grn_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_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_bool +grn_ts_float_is_valid(grn_ts_float value) { + return !isnan(value); +} + +/* grn_ts_time_is_valid() returns whether a value is valid or not. */ +inline static grn_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_bool +grn_ts_text_is_valid(grn_ts_text value) { + return value.ptr || !value.size; +} + +/* grn_ts_geo_point_is_valid() returns whether a value is valid or not. */ +inline static grn_bool +grn_ts_geo_point_is_valid(grn_ts_geo_point 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_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_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_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_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_bool +grn_ts_text_vector_is_valid(grn_ts_text_vector value) { + GRN_TS_VECTOR_IS_VALID(text) +} + +/* + * grn_ts_geo_point_vector_is_valid() returns whether a value is valid or + * not. + */ +inline static grn_bool +grn_ts_geo_point_vector_is_valid(grn_ts_geo_point_vector value) { + GRN_TS_VECTOR_IS_VALID(geo_point) +} +#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_point_zero() returns a zero. */ +inline static grn_ts_geo_point +grn_ts_geo_point_zero(void) { + return (grn_ts_geo_point){ 0, 0 }; +} + +/* grn_ts_geo_point_zero() returns a zero. */ +inline static grn_ts_ref +grn_ts_ref_zero(void) { + return (grn_ts_ref){ 0, 0.0 }; +} + +/* grn_ts_bool_vector_zero() returns a zero. */ +inline static grn_ts_bool_vector +grn_ts_bool_vector_zero(void) { + return (grn_ts_bool_vector){ NULL, 0 }; +} + +/* grn_ts_int_vector_zero() returns a zero. */ +inline static grn_ts_int_vector +grn_ts_int_vector_zero(void) { + return (grn_ts_int_vector){ NULL, 0 }; +} + +/* grn_ts_float_vector_zero() returns a zero. */ +inline static grn_ts_float_vector +grn_ts_float_vector_zero(void) { + return (grn_ts_float_vector){ NULL, 0 }; +} + +/* grn_ts_time_vector_zero() returns a zero. */ +inline static grn_ts_time_vector +grn_ts_time_vector_zero(void) { + return (grn_ts_time_vector){ NULL, 0 }; +} + +/* grn_ts_text_vector_zero() returns a zero. */ +inline static grn_ts_text_vector +grn_ts_text_vector_zero(void) { + return (grn_ts_text_vector){ NULL, 0 }; +} + +/* grn_ts_geo_point_vector_zero() returns a zero. */ +inline static grn_ts_geo_point_vector +grn_ts_geo_point_vector_zero(void) { + return (grn_ts_geo_point_vector){ NULL, 0 }; +} + +/* grn_ts_ref_vector_zero() returns a zero. */ +inline static grn_ts_ref_vector +grn_ts_ref_vector_zero(void) { + return (grn_ts_ref_vector){ NULL, 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_POINT; + } + 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_POINT: { + /* GRN_DB_TOKYO_GEO_POINT or GRN_DB_WGS84_GEO_POINT. */ + return GRN_DB_VOID; + } + default: { + return GRN_DB_VOID; + } + } +} + +/* + * grn_ts_obj_increment_ref_count() increments the reference count of an + * object. + */ +static grn_rc +grn_ts_obj_increment_ref_count(grn_ctx *ctx, grn_obj *obj) { + grn_obj *obj_clone = grn_ctx_at(ctx, grn_obj_id(ctx, obj)); + if (!obj_clone) { + return GRN_INVALID_ARGUMENT; + } + if (obj_clone != obj) { + grn_obj_unlink(ctx, obj_clone); + return GRN_INVALID_ARGUMENT; + } + return GRN_SUCCESS; +} + +/* grn_ts_obj_is_table() returns whether an object is a column or not */ +static grn_bool +grn_ts_obj_is_table(grn_ctx *ctx, grn_obj *obj) { + return grn_obj_is_table(ctx, obj); +} + +/* grn_ts_obj_is_column() returns whether an object is a column or not */ +static grn_bool +grn_ts_obj_is_column(grn_ctx *ctx, grn_obj *obj) { + switch (obj->header.type) { + case GRN_COLUMN_FIX_SIZE: + case GRN_COLUMN_VAR_SIZE: { + return GRN_TRUE; + } + /* GRN_COLUMN_INDEX is not supported. */ + default: { + return GRN_FALSE; + } + } +} + +/* grn_ts_table_has_key() returns whether a table has _key or not. */ +static grn_bool +grn_ts_table_has_key(grn_ctx *ctx, grn_obj *table) { + switch (table->header.type) { + case GRN_TABLE_HASH_KEY: + case GRN_TABLE_PAT_KEY: + case GRN_TABLE_DAT_KEY: { + return GRN_TRUE; + } + default: { + return GRN_FALSE; + } + } +} + +/* grn_ts_table_has_value() returns whether a table has _value or not. */ +static grn_bool +grn_ts_table_has_value(grn_ctx *ctx, grn_obj *table) { + return DB_OBJ(table)->range != GRN_DB_VOID; +} + +/* grn_ts_table_get_value() writes a value (_value) into buf. */ +static size_t +grn_ts_table_get_value(grn_ctx *ctx, grn_obj *table, grn_id id, void *buf) { + switch (table->header.type) { + case GRN_TABLE_HASH_KEY: { + return grn_hash_get_value(ctx, (grn_hash *)table, id, buf); + } + case GRN_TABLE_PAT_KEY: { + return grn_pat_get_value(ctx, (grn_pat *)table, id, buf); + } + case GRN_TABLE_NO_KEY: { + return grn_array_get_value(ctx, (grn_array *)table, id, buf); + } + default: { + return 0; + } + } +} + +/*------------------------------------------------------------- + * grn_ts_expr_node. + */ + +typedef struct { + GRN_TS_EXPR_NODE_COMMON_MEMBERS +} grn_ts_expr_id_node; + +typedef struct { + GRN_TS_EXPR_NODE_COMMON_MEMBERS +} grn_ts_expr_score_node; + +typedef struct { + GRN_TS_EXPR_NODE_COMMON_MEMBERS + grn_obj *table; + grn_obj buf; +} grn_ts_expr_key_node; + +typedef struct { + GRN_TS_EXPR_NODE_COMMON_MEMBERS + grn_obj *table; +} grn_ts_expr_value_node; + +typedef struct { + GRN_TS_EXPR_NODE_COMMON_MEMBERS + union { + grn_ts_bool bool_value; + grn_ts_int int_value; + grn_ts_float float_value; + grn_ts_time time_value; + grn_ts_text text_value; + grn_ts_geo_point geo_point_value; + grn_ts_bool_vector bool_vector_value; + grn_ts_int_vector int_vector_value; + grn_ts_float_vector float_vector_value; + grn_ts_time_vector time_vector_value; + grn_ts_text_vector text_vector_value; + grn_ts_geo_point_vector geo_point_vector_value; + } content; + char *text_buf; + void *vector_buf; +} grn_ts_expr_const_node; + +typedef struct { + GRN_TS_EXPR_NODE_COMMON_MEMBERS + grn_obj *column; + grn_obj buf; + union { + void *buf; + struct { + grn_ts_text *ptr; + size_t size; + } text_buf; + struct { + grn_ts_ref *ptr; + size_t size; + } ref_buf; + } body; +} grn_ts_expr_column_node; + +typedef struct { + GRN_TS_EXPR_NODE_COMMON_MEMBERS + grn_ts_op_type op_type; + // TODO +} grn_ts_expr_op_node; + +/* grn_ts_expr_node_fin() finalizes a node. */ +static grn_rc +grn_ts_expr_node_fin(grn_ctx *ctx, grn_ts_expr_node *node) { + switch (node->type) { + case GRN_TS_EXPR_ID_NODE: + case GRN_TS_EXPR_SCORE_NODE: { + return GRN_SUCCESS; + } + case GRN_TS_EXPR_KEY_NODE: { + grn_ts_expr_key_node *key_node = (grn_ts_expr_key_node *)node; + GRN_OBJ_FIN(ctx, &key_node->buf); + if (key_node->table) { + grn_obj_unlink(ctx, key_node->table); + } + return GRN_SUCCESS; + } + case GRN_TS_EXPR_VALUE_NODE: { + grn_ts_expr_value_node *value_node = (grn_ts_expr_value_node *)node; + if (value_node->table) { + grn_obj_unlink(ctx, value_node->table); + } + return GRN_SUCCESS; + } + case GRN_TS_EXPR_CONST_NODE: { + grn_ts_expr_const_node *const_node = (grn_ts_expr_const_node *)node; + if (const_node->vector_buf) { + GRN_FREE(const_node->vector_buf); + } + if (const_node->text_buf) { + GRN_FREE(const_node->text_buf); + } + return GRN_SUCCESS; + } + case GRN_TS_EXPR_COLUMN_NODE: { + grn_ts_expr_column_node *column_node = (grn_ts_expr_column_node *)node; + if (column_node->body.buf) { + GRN_FREE(column_node->body.buf); + } + GRN_OBJ_FIN(ctx, &column_node->buf); + if (column_node->column) { + grn_obj_unlink(ctx, column_node->column); + } + return GRN_SUCCESS; + } + case GRN_TS_EXPR_OP_NODE: { + // TODO: Unlink objects and free memory. + return GRN_SUCCESS; + } + default: { + return GRN_INVALID_ARGUMENT; + } + } +} + +/* grn_ts_expr_node_close() destroys a node. */ +static grn_rc +grn_ts_expr_node_close(grn_ctx *ctx, grn_ts_expr_node *node) { + grn_rc rc; + if (!node) { + return GRN_SUCCESS; + } + rc = grn_ts_expr_node_fin(ctx, node); + GRN_FREE(node); + return rc; +} + +/* grn_ts_expr_id_node_open() creates a node associated with ID (_id). */ +static 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) { + return GRN_NO_MEMORY_AVAILABLE; + } + new_node->type = GRN_TS_EXPR_ID_NODE; + new_node->data_kind = GRN_TS_INT; + new_node->data_type = GRN_DB_UINT32; + *node = (grn_ts_expr_node *)new_node; + return GRN_SUCCESS; +} + +/* + * grn_ts_expr_score_node_open() creates a node associated with score + * (_score). + */ +static 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) { + return GRN_NO_MEMORY_AVAILABLE; + } + new_node->type = GRN_TS_EXPR_SCORE_NODE; + new_node->data_kind = GRN_TS_FLOAT; + new_node->data_type = GRN_DB_FLOAT; + *node = (grn_ts_expr_node *)new_node; + return GRN_SUCCESS; +} + +/* grn_ts_expr_key_node_open() creates a node associated with key (_key). */ +static 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)) { + return GRN_INVALID_ARGUMENT; + } + new_node = GRN_MALLOCN(grn_ts_expr_key_node, 1); + if (!new_node) { + return GRN_NO_MEMORY_AVAILABLE; + } + rc = grn_ts_obj_increment_ref_count(ctx, table); + if (rc != GRN_SUCCESS) { + GRN_FREE(new_node); + return rc; + } + new_node->type = GRN_TS_EXPR_KEY_NODE; + new_node->data_kind = grn_ts_data_type_to_kind(table->header.domain); + new_node->data_type = table->header.domain; + new_node->table = table; + GRN_TEXT_INIT(&new_node->buf, 0); + *node = (grn_ts_expr_node *)new_node; + return GRN_SUCCESS; +} + +/* + * grn_ts_expr_value_node_open() creates a node associated with value + * (_value). + */ +static 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)) { + return GRN_INVALID_ARGUMENT; + } + new_node = GRN_MALLOCN(grn_ts_expr_value_node, 1); + if (!new_node) { + return GRN_NO_MEMORY_AVAILABLE; + } + memset(new_node, 0, sizeof(*new_node)); + rc = grn_ts_obj_increment_ref_count(ctx, table); + if (rc != GRN_SUCCESS) { + GRN_FREE(new_node); + return rc; + } + new_node->type = GRN_TS_EXPR_VALUE_NODE; + 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; +} + +#define GRN_TS_EXPR_CONST_NODE_OPEN_CASE_BLOCK(KIND, kind)\ + case GRN_TS_ ## KIND: {\ + node->content.kind ## _value = *(const grn_ts_ ## kind *)value;\ + return GRN_SUCCESS;\ + } +/* grn_ts_expr_const_node_init_scalar() initializes a const scalar node. */ +static grn_rc +grn_ts_expr_const_node_init_scalar(grn_ctx *ctx, grn_ts_expr_const_node *node, + const void *value) { + switch (node->data_kind) { + GRN_TS_EXPR_CONST_NODE_OPEN_CASE_BLOCK(BOOL, bool) + GRN_TS_EXPR_CONST_NODE_OPEN_CASE_BLOCK(INT, int) + GRN_TS_EXPR_CONST_NODE_OPEN_CASE_BLOCK(FLOAT, float) + GRN_TS_EXPR_CONST_NODE_OPEN_CASE_BLOCK(TIME, time) + case GRN_TS_TEXT: { + grn_ts_text text_value; + char *text_buf; + text_value = *(const grn_ts_text *)value; + if (!text_value.size) { + node->content.text_value.ptr = NULL; + node->content.text_value.size = 0; + return GRN_SUCCESS; + } + text_buf = (char *)GRN_MALLOC(text_value.size); + if (!text_buf) { + return GRN_NO_MEMORY_AVAILABLE; + } + node->text_buf = text_buf; + grn_memcpy(text_buf, text_value.ptr, text_value.size); + node->content.text_value.ptr = text_buf; + node->content.text_value.size = text_value.size; + return GRN_SUCCESS; + } + GRN_TS_EXPR_CONST_NODE_OPEN_CASE_BLOCK(GEO_POINT, geo_point) + default: { + return GRN_INVALID_ARGUMENT; + } + } +} +#undef GRN_TS_EXPR_CONST_NODE_OPEN_CASE_BLOCK + +#define GRN_TS_EXPR_CONST_NODE_OPEN_VECTOR_CASE_BLOCK(KIND, kind)\ + case GRN_TS_ ## KIND ## _VECTOR: {\ + grn_ts_ ## kind ## _vector vector;\ + grn_ts_ ## kind *vector_buf;\ + vector = *(const grn_ts_ ## kind ## _vector *)value;\ + if (!vector.size) {\ + node->content.kind ## _vector_value.ptr = NULL;\ + node->content.kind ## _vector_value.size = 0;\ + return GRN_SUCCESS;\ + }\ + vector_buf = GRN_MALLOCN(grn_ts_ ## kind, vector.size);\ + if (!vector_buf) {\ + return GRN_NO_MEMORY_AVAILABLE;\ + }\ + node->vector_buf = vector_buf;\ + grn_memcpy(vector_buf, vector.ptr,\ + sizeof(grn_ts_ ## kind) * vector.size);\ + node->content.kind ## _vector_value.ptr = vector_buf;\ + node->content.kind ## _vector_value.size = vector.size;\ + return GRN_SUCCESS;\ + } +/* grn_ts_expr_const_node_init_vector() initializes a const vector node. */ +static grn_rc +grn_ts_expr_const_node_init_vector(grn_ctx *ctx, grn_ts_expr_const_node *node, + const void *value) { + switch (node->data_kind) { + GRN_TS_EXPR_CONST_NODE_OPEN_VECTOR_CASE_BLOCK(BOOL, bool) + GRN_TS_EXPR_CONST_NODE_OPEN_VECTOR_CASE_BLOCK(INT, int) + GRN_TS_EXPR_CONST_NODE_OPEN_VECTOR_CASE_BLOCK(FLOAT, float) + GRN_TS_EXPR_CONST_NODE_OPEN_VECTOR_CASE_BLOCK(TIME, time) + case GRN_TS_TEXT_VECTOR: { + size_t i, offset = 0, total_size = 0; + grn_ts_text_vector vector; + grn_ts_text *vector_buf; + char *text_buf; + vector = *(const grn_ts_text_vector *)value; + if (!vector.size) { + node->content.text_vector_value.ptr = NULL; + node->content.text_vector_value.size = 0; + return GRN_SUCCESS; + } + vector_buf = GRN_MALLOCN(grn_ts_text, vector.size); + if (!vector_buf) { + return GRN_NO_MEMORY_AVAILABLE; + } + node->vector_buf = vector_buf; + for (i = 0; i < vector.size; i++) { + total_size += vector.ptr[i].size; + } + if (total_size) { + text_buf = (char *)GRN_MALLOC(total_size); + if (!text_buf) { + return GRN_NO_MEMORY_AVAILABLE; + } + node->text_buf = text_buf; + } + 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.text_vector_value.ptr = vector_buf; + node->content.text_vector_value.size = vector.size; + return GRN_SUCCESS; + } + GRN_TS_EXPR_CONST_NODE_OPEN_VECTOR_CASE_BLOCK(GEO_POINT, geo_point) + default: { + return GRN_UNKNOWN_ERROR; + } + } +} +#undef GRN_TS_EXPR_CONST_NODE_OPEN_VECTOR_CASE_BLOCK + +/* grn_ts_expr_const_node_open() creates a node associated with a const. */ +static grn_rc +grn_ts_expr_const_node_open(grn_ctx *ctx, grn_ts_data_kind kind, + const void *value, grn_ts_expr_node **node) { + grn_rc rc = GRN_SUCCESS; + grn_ts_expr_const_node *new_node = GRN_MALLOCN(grn_ts_expr_const_node, 1); + if (!new_node) { + return GRN_NO_MEMORY_AVAILABLE; + } + new_node->type = GRN_TS_EXPR_CONST_NODE; + new_node->data_kind = kind; + new_node->data_type = grn_ts_data_kind_to_type(kind); + new_node->text_buf = NULL; + new_node->vector_buf = NULL; + if (kind & GRN_TS_VECTOR_FLAG) { + rc = grn_ts_expr_const_node_init_vector(ctx, new_node, value); + } else { + rc = grn_ts_expr_const_node_init_scalar(ctx, new_node, value); + } + if (rc != GRN_SUCCESS) { + grn_ts_expr_node_close(ctx, (grn_ts_expr_node *)new_node); + return rc; + } + *node = (grn_ts_expr_node *)new_node; + return GRN_SUCCESS; +} + +/* grn_ts_expr_column_node_open() creates a node associated with a column. */ +static 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) { + return GRN_NO_MEMORY_AVAILABLE; + } + memset(new_node, 0, sizeof(*new_node)); + rc = grn_ts_obj_increment_ref_count(ctx, column); + if (rc != GRN_SUCCESS) { + GRN_FREE(new_node); + return rc; + } + new_node->type = GRN_TS_EXPR_COLUMN_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; + new_node->column = column; + GRN_TEXT_INIT(&new_node->buf, 0); + new_node->body.buf = NULL; + *node = (grn_ts_expr_node *)new_node; + return GRN_SUCCESS; +} + +/* 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_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; +} + +#define GRN_TS_EXPR_KEY_NODE_EVALUATE_CASE_BLOCK(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++) {\ + if (!grn_table_get_key(ctx, node->table, in[i].id, &out_ptr[i],\ + sizeof(grn_ts_ ## kind))) {\ + out_ptr[i] = grn_ts_ ## kind ## _zero();\ + }\ + }\ + return GRN_SUCCESS;\ + } +#define GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE_BLOCK(TYPE, type)\ + case GRN_DB_ ## TYPE: {\ + for (i = 0; i < n_in; i++) {\ + type ## _t key;\ + if (grn_table_get_key(ctx, node->table, in[i].id, &key,\ + sizeof(type ## _t))) {\ + out_ptr[i] = (grn_ts_int)key;\ + } else {\ + out_ptr[i] = grn_ts_int_zero();\ + }\ + }\ + return GRN_SUCCESS;\ + } +/* grn_ts_expr_key_node_evaluate() outputs keys. */ +/* FIXME: Errors are ignored. */ +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) { + switch (node->data_kind) { + GRN_TS_EXPR_KEY_NODE_EVALUATE_CASE_BLOCK(BOOL, bool) + case GRN_TS_INT: { + size_t i; + grn_ts_int *out_ptr = (grn_ts_int *)out; + switch (node->data_type) { + GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE_BLOCK(INT8, int8) + GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE_BLOCK(INT16, int16) + GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE_BLOCK(INT32, int32) + GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE_BLOCK(INT64, int64) + GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE_BLOCK(UINT8, uint8) + GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE_BLOCK(UINT16, uint16) + GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE_BLOCK(UINT32, uint32) + GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE_BLOCK(UINT64, uint64) + default: { + return GRN_OBJECT_CORRUPT; + } + } + } + GRN_TS_EXPR_KEY_NODE_EVALUATE_CASE_BLOCK(FLOAT, float) + GRN_TS_EXPR_KEY_NODE_EVALUATE_CASE_BLOCK(TIME, time) + case GRN_TS_TEXT: { + size_t i; + char *buf_ptr; + grn_ts_text *out_ptr = (grn_ts_text *)out; + GRN_BULK_REWIND(&node->buf); + for (i = 0; i < n_in; i++) { + out_ptr[i].size = grn_table_get_key2(ctx, node->table, in[i].id, + &node->buf); + } + buf_ptr = GRN_BULK_HEAD(&node->buf); + 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_KEY_NODE_EVALUATE_CASE_BLOCK(GEO_POINT, geo_point) + case GRN_TS_REF: { + size_t i; + grn_ts_ref *out_ptr = (grn_ts_ref *)out; + for (i = 0; i < n_in; i++) { + if (!grn_table_get_key(ctx, node->table, in[i].id, &out_ptr[i].id, + sizeof(grn_ts_id))) { + out_ptr[i].id = GRN_ID_NIL; + } + out_ptr[i].score = in[i].score; + } + return GRN_SUCCESS; + } + default: { + return GRN_OBJECT_CORRUPT; + } + } +} +#undef GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE_BLOCK +#undef GRN_TS_EXPR_KEY_NODE_EVALUATE_CASE_BLOCK + +#define GRN_TS_EXPR_VALUE_NODE_EVALUATE_CASE_BLOCK(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++) {\ + if (!grn_ts_table_get_value(ctx, node->table, in[i].id,\ + &out_ptr[i])) {\ + out_ptr[i] = grn_ts_ ## kind ## _zero();\ + }\ + }\ + return GRN_SUCCESS;\ + } +#define GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE_BLOCK(TYPE, type)\ + case GRN_DB_ ## TYPE: {\ + for (i = 0; i < n_in; i++) {\ + type ## _t value;\ + if (grn_ts_table_get_value(ctx, node->table, in[i].id, &value)) {\ + out_ptr[i] = (grn_ts_int)value;\ + } else {\ + out_ptr[i] = grn_ts_int_zero();\ + }\ + }\ + return GRN_SUCCESS;\ + } +/* grn_ts_expr_value_node_evaluate() outputs values. */ +/* FIXME: Errors are ignored. */ +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_BLOCK(BOOL, bool) + case GRN_TS_INT: { + size_t i; + grn_ts_int *out_ptr = (grn_ts_int *)out; + switch (node->data_type) { + GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE_BLOCK(INT8, int8) + GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE_BLOCK(INT16, int16) + GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE_BLOCK(INT32, int32) + GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE_BLOCK(INT64, int64) + GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE_BLOCK(UINT8, uint8) + GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE_BLOCK(UINT16, uint16) + GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE_BLOCK(UINT32, uint32) + GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE_BLOCK(UINT64, uint64) + default: { + return GRN_OBJECT_CORRUPT; + } + } + } + GRN_TS_EXPR_VALUE_NODE_EVALUATE_CASE_BLOCK(FLOAT, float) + GRN_TS_EXPR_VALUE_NODE_EVALUATE_CASE_BLOCK(TIME, time) + GRN_TS_EXPR_VALUE_NODE_EVALUATE_CASE_BLOCK(GEO_POINT, geo_point) + case GRN_TS_REF: { + size_t i; + grn_ts_ref *out_ptr = (grn_ts_ref *)out; + for (i = 0; i < n_in; i++) { + if (!grn_ts_table_get_value(ctx, node->table, in[i].id, + &out_ptr[i].id)) { + out_ptr[i].id = GRN_ID_NIL; + } + out_ptr[i].score = in[i].score; + } + return GRN_SUCCESS; + } + default: { + return GRN_OBJECT_CORRUPT; + } + } +} +#undef GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE_BLOCK +#undef GRN_TS_EXPR_VALUE_NODE_EVALUATE_CASE_BLOCK + +#define GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE_BLOCK(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.kind ## _value;\ + }\ + return GRN_SUCCESS;\ + } +#define GRN_TS_EXPR_CONST_NODE_EVALUATE_VECTOR_CASE_BLOCK(KIND, kind)\ + GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE_BLOCK(KIND ## _VECTOR, kind ## _vector) +/* grn_ts_expr_const_node_evaluate() outputs consts. */ +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_BLOCK(BOOL, bool) + GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE_BLOCK(INT, int) + GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE_BLOCK(FLOAT, float) + GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE_BLOCK(TIME, time) + GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE_BLOCK(TEXT, text) + GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE_BLOCK(GEO_POINT, geo_point) + GRN_TS_EXPR_CONST_NODE_EVALUATE_VECTOR_CASE_BLOCK(BOOL, bool) + GRN_TS_EXPR_CONST_NODE_EVALUATE_VECTOR_CASE_BLOCK(INT, int) + GRN_TS_EXPR_CONST_NODE_EVALUATE_VECTOR_CASE_BLOCK(FLOAT, float) + GRN_TS_EXPR_CONST_NODE_EVALUATE_VECTOR_CASE_BLOCK(TIME, time) + GRN_TS_EXPR_CONST_NODE_EVALUATE_VECTOR_CASE_BLOCK(TEXT, text) + GRN_TS_EXPR_CONST_NODE_EVALUATE_VECTOR_CASE_BLOCK(GEO_POINT, geo_point) + default: { + return GRN_INVALID_ARGUMENT; + } + } +} +#undef GRN_TS_EXPR_CONST_NODE_EVALUATE_VECTOR_CASE_BLOCK +#undef GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE_BLOCK + +#define GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_CASE_BLOCK(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_BLOCK(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. */ +/* FIXME: Errors are ignored. */ +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_BLOCK(BOOL, bool) + case GRN_TS_INT: { + switch (node->data_type) { + GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_INT_CASE_BLOCK(INT8, int8) + GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_INT_CASE_BLOCK(INT16, int16) + GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_INT_CASE_BLOCK(INT32, int32) + GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_INT_CASE_BLOCK(INT64, int64) + GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_INT_CASE_BLOCK(UINT8, uint8) + GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_INT_CASE_BLOCK(UINT16, uint16) + GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_INT_CASE_BLOCK(UINT32, uint32) + /* The behavior is undefined if a value is greater than 2^63 - 1. */ + GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_INT_CASE_BLOCK(UINT64, uint64) + default: { + return GRN_OBJECT_CORRUPT; + } + } + } + GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_CASE_BLOCK(FLOAT, float) + GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_CASE_BLOCK(TIME, time) + case GRN_TS_TEXT: { + size_t i, offset = 0; + char *buf_ptr; + grn_ja *ja = (grn_ja *)node->column; + grn_ts_text *out_ptr = (grn_ts_text *)out; + /* Read column values into node->buf and save the size of each value. */ + GRN_BULK_REWIND(&node->buf); + for (i = 0; i < n_in; i++) { + if (grn_ja_get_value(ctx, ja, in[i].id, &node->buf)) { + size_t size = GRN_BULK_VSIZE(&node->buf); + out_ptr[i].size = size - offset; + offset = size; + } else { + out_ptr[i].size = 0; + } + } + buf_ptr = GRN_BULK_HEAD(&node->buf); + 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_SCALAR_CASE_BLOCK(GEO_POINT, geo_point) + 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: { + return GRN_OBJECT_CORRUPT; + } + } +} +#undef GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_INT_CASE_BLOCK +#undef GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_CASE_BLOCK + +#define GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_CASE_BLOCK(KIND, kind)\ + case GRN_TS_ ## KIND ## _VECTOR: {\ + size_t i, offset = 0;\ + 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. */\ + GRN_BULK_REWIND(&node->buf);\ + for (i = 0; i < n_in; i++) {\ + if (grn_obj_get_value(ctx, node->column, in[i].id, &node->buf)) {\ + size_t size = GRN_BULK_VSIZE(&node->buf) / sizeof(grn_ts_ ## kind);\ + out_ptr[i].size = size - offset;\ + offset = size;\ + } else {\ + return GRN_UNKNOWN_ERROR;\ + }\ + }\ + buf_ptr = (grn_ts_ ## kind *)GRN_BULK_HEAD(&node->buf);\ + 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_BLOCK(TYPE, type)\ + case GRN_DB_ ## TYPE: {\ + size_t i, j;\ + grn_obj src_buf;\ + grn_ts_int *buf_ptr;\ + grn_ts_int_vector *out_ptr = (grn_ts_int_vector *)out;\ + GRN_ ## TYPE ## _INIT(&src_buf, GRN_OBJ_VECTOR);\ + /* + * Read column values into src_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. + */\ + GRN_BULK_REWIND(&node->buf);\ + for (i = 0; i < n_in; i++) {\ + GRN_BULK_REWIND(&src_buf);\ + if (grn_obj_get_value(ctx, node->column, in[i].id, &src_buf)) {\ + type ## _t *src_ptr = (type ## _t *)GRN_BULK_HEAD(&src_buf);\ + out_ptr[i].size = GRN_BULK_VSIZE(&src_buf) / sizeof(type ## _t);\ + for (j = 0; j < out_ptr[i].size; j++) {\ + grn_ts_int value = (grn_ts_int)src_ptr[j];\ + grn_rc rc = grn_bulk_write(ctx, &node->buf, (char *)&value,\ + sizeof(value));\ + if (rc != GRN_SUCCESS) {\ + GRN_OBJ_FIN(ctx, &src_buf);\ + return rc;\ + }\ + }\ + } else {\ + GRN_OBJ_FIN(ctx, &src_buf);\ + return GRN_UNKNOWN_ERROR;\ + }\ + }\ + buf_ptr = (grn_ts_int *)GRN_BULK_HEAD(&node->buf);\ + for (i = 0; i < n_in; i++) {\ + out_ptr[i].ptr = buf_ptr;\ + buf_ptr += out_ptr[i].size;\ + }\ + GRN_OBJ_FIN(ctx, &src_buf);\ + return GRN_SUCCESS;\ + } +/* grn_ts_expr_column_node_evaluate_vector() outputs vector column values. */ +/* FIXME: Errors are ignored. */ +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_BLOCK(BOOL, bool) + case GRN_TS_INT_VECTOR: { + switch (node->data_type) { + GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_INT_CASE_BLOCK(INT8, int8) + GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_INT_CASE_BLOCK(INT16, int16) + GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_INT_CASE_BLOCK(INT32, int32) + GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_INT_CASE_BLOCK(INT64, int64) + GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_INT_CASE_BLOCK(UINT8, uint8) + GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_INT_CASE_BLOCK(UINT16, uint16) + GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_INT_CASE_BLOCK(UINT32, uint32) + /* The behavior is undefined if a value is greater than 2^63 - 1. */ + GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_INT_CASE_BLOCK(UINT64, uint64) + default: { + return GRN_OBJECT_CORRUPT; + } + } + } + GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_CASE_BLOCK(FLOAT, float) + GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_CASE_BLOCK(TIME, time) + case GRN_TS_TEXT_VECTOR: { + size_t i, offset = 0; + grn_ts_text *text_ptr; + grn_ts_text_vector *out_ptr = (grn_ts_text_vector *)out; + /* Read column values into node->buf and save the size of each value. */ + GRN_BULK_REWIND(&node->buf); + for (i = 0; i < n_in; i++) { + if (grn_obj_get_value(ctx, node->column, in[i].id, &node->buf)) { + size_t size = grn_vector_size(ctx, &node->buf); + out_ptr[i].size = size - offset; + offset = size; + } else { + out_ptr[i].size = 0; + } + } + /* Resize node->body.text_buf. */ + if (node->body.text_buf.size < offset) { + size_t n_bytes = sizeof(grn_ts_text) * offset; + grn_ts_text *new_buf; + new_buf = (grn_ts_text *)GRN_REALLOC(node->body.text_buf.ptr, n_bytes); + if (!new_buf) { + return GRN_NO_MEMORY_AVAILABLE; + } + node->body.text_buf.ptr = new_buf; + node->body.text_buf.size = offset; + } + /* Compose the result. */ + text_ptr = node->body.text_buf.ptr; + for (i = 0; i < offset; i++) { + text_ptr[i].size = grn_vector_get_element(ctx, &node->buf, i, + &text_ptr[i].ptr, + NULL, NULL); + } + for (i = 0; i < n_in; i++) { + out_ptr[i].ptr = text_ptr; + text_ptr += out_ptr[i].size; + } + return GRN_SUCCESS; + } + GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_CASE_BLOCK(GEO_POINT, geo_point) + case GRN_TS_REF_VECTOR: { + size_t i, j, 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->buf and save the size of each value. */ + GRN_BULK_REWIND(&node->buf); + for (i = 0; i < n_in; i++) { + if (grn_obj_get_value(ctx, node->column, in[i].id, &node->buf)) { + size_t size = GRN_BULK_VSIZE(&node->buf) / sizeof(grn_ts_id); + out_ptr[i].size = size - offset; + offset = size; + } else { + return GRN_UNKNOWN_ERROR; + } + } + /* Resize node->body.ref_buf. */ + if (node->body.ref_buf.size < offset) { + size_t n_bytes = sizeof(grn_ts_ref) * offset; + grn_ts_ref *new_buf; + new_buf = (grn_ts_ref *)GRN_REALLOC(node->body.ref_buf.ptr, n_bytes); + if (!new_buf) { + return GRN_NO_MEMORY_AVAILABLE; + } + node->body.ref_buf.ptr = new_buf; + node->body.ref_buf.size = offset; + } + /* Compose the result. */ + buf_ptr = (grn_ts_id *)GRN_BULK_HEAD(&node->buf); + ref_ptr = node->body.ref_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; + } + default: { + return GRN_OBJECT_CORRUPT; + } + } +} +#undef GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_INT_CASE_BLOCK +#undef GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_CASE_BLOCK + +/* 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_op_node_evaluate() outputs results of 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) { + // TODO + return GRN_SUCCESS; +} + +#define GRN_TS_EXPR_NODE_EVALUATE_CASE_BLOCK(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_ts_expr_node_evaluate() evaluates a subexpression. */ +static 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_BLOCK(ID, id) + GRN_TS_EXPR_NODE_EVALUATE_CASE_BLOCK(SCORE, score) + GRN_TS_EXPR_NODE_EVALUATE_CASE_BLOCK(KEY, key) + GRN_TS_EXPR_NODE_EVALUATE_CASE_BLOCK(VALUE, value) + GRN_TS_EXPR_NODE_EVALUATE_CASE_BLOCK(CONST, const) + GRN_TS_EXPR_NODE_EVALUATE_CASE_BLOCK(COLUMN, column) + GRN_TS_EXPR_NODE_EVALUATE_CASE_BLOCK(OP, op) + default: { + return GRN_INVALID_ARGUMENT; + } + } +} +#undef GRN_TS_EXPR_NODE_EVALUATE_CASE_BLOCK + +/* 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 = 0; + for (i = 0; i < n_in; i++) { + grn_ts_bool key; + grn_table_get_key(ctx, node->table, in[i].id, &key, sizeof(key)); + if (key) { + out[count++] = in[i]; + } + } + *n_out = count; + return GRN_SUCCESS; +} + +/* 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++) { + grn_ts_bool value; + grn_ts_table_get_value(ctx, node->table, in[i].id, &value); + if (value) { + out[count++] = in[i]; + } + } + *n_out = count; + return GRN_SUCCESS; +} + +/* 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.bool_value) { + if (in != out) { + size_t i; + for (i = 0; i < n_in; i++) { + out[i] = in[i]; + } + } + *n_out = n_in; + } else { + *n_out = 0; + } + return GRN_SUCCESS; +} + +/* 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_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) { + // TODO + return GRN_SUCCESS; +} + +#define GRN_TS_EXPR_NODE_FILTER_CASE_BLOCK(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_ts_expr_node_filter() filters records. */ +static 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) { + return GRN_INVALID_ARGUMENT; + } + switch (node->type) { + GRN_TS_EXPR_NODE_FILTER_CASE_BLOCK(KEY, key) + GRN_TS_EXPR_NODE_FILTER_CASE_BLOCK(VALUE, value) + GRN_TS_EXPR_NODE_FILTER_CASE_BLOCK(CONST, const) + GRN_TS_EXPR_NODE_FILTER_CASE_BLOCK(COLUMN, column) + GRN_TS_EXPR_NODE_FILTER_CASE_BLOCK(OP, op) + default: { + return GRN_INVALID_ARGUMENT; + } + } +} +#undef GRN_TS_EXPR_NODE_FILTER_CASE_BLOCK + +/* grn_ts_expr_score_node_adjust() updates scores. */ +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_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; + for (i = 0; i < n_io; i++) { + grn_ts_float key; + grn_table_get_key(ctx, node->table, io[i].id, &key, sizeof(key)); + io[i].score = (grn_ts_score)key; + } + 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++) { + grn_ts_float value; + grn_ts_table_get_value(ctx, node->table, io[i].id, &value); + io[i].score = (grn_ts_score)value; + } + 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.float_value; + for (i = 0; i < n_io; i++) { + io[i].score = score; + } + return GRN_SUCCESS; +} + +/* grn_ts_expr_column_node_adjust() updates scores. */ +/* FIXME: Errors are ignored. */ +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_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) { + // TODO + return GRN_SUCCESS; +} + +#define GRN_TS_EXPR_NODE_ADJUST_CASE_BLOCK(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_ts_expr_node_adjust() updates scores. */ +static 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) { + return GRN_INVALID_ARGUMENT; + } + switch (node->type) { + GRN_TS_EXPR_NODE_ADJUST_CASE_BLOCK(SCORE, score) + GRN_TS_EXPR_NODE_ADJUST_CASE_BLOCK(KEY, key) + GRN_TS_EXPR_NODE_ADJUST_CASE_BLOCK(VALUE, value) + GRN_TS_EXPR_NODE_ADJUST_CASE_BLOCK(CONST, const) + GRN_TS_EXPR_NODE_ADJUST_CASE_BLOCK(COLUMN, column) + GRN_TS_EXPR_NODE_ADJUST_CASE_BLOCK(OP, op) + default: { + return GRN_INVALID_ARGUMENT; + } + } +} +#undef GRN_TS_EXPR_NODE_ADJUST_CASE_BLOCK + +/*------------------------------------------------------------- + * grn_ts_expr. + */ + +/* grn_ts_expr_init() initializes an expression. */ +static grn_rc +grn_ts_expr_init(grn_ctx *ctx, grn_ts_expr *expr, grn_obj *table) { + /* Increment a reference count for table and curr_table. */ + grn_rc rc = grn_ts_obj_increment_ref_count(ctx, table); + if (rc != GRN_SUCCESS) { + return rc; + } + rc = grn_ts_obj_increment_ref_count(ctx, table); + if (rc != GRN_SUCCESS) { + grn_obj_unlink(ctx, table); + return rc; + } + memset(expr, 0, sizeof(*expr)); + expr->table = table; + expr->curr_table = table; + expr->root = NULL; + expr->nodes = NULL; + expr->stack = NULL; + // TODO: Initialize new members. + return GRN_SUCCESS; +} + +grn_rc +grn_ts_expr_open(grn_ctx *ctx, grn_obj *table, grn_ts_expr **expr) { + grn_rc rc; + grn_ts_expr *new_expr; + if (!ctx || !table || !grn_ts_obj_is_table(ctx, table) || !expr) { + return GRN_INVALID_ARGUMENT; + } + new_expr = GRN_MALLOCN(grn_ts_expr, 1); + if (!new_expr) { + return GRN_NO_MEMORY_AVAILABLE; + } + rc = grn_ts_expr_init(ctx, new_expr, table); + if (rc != GRN_SUCCESS) { + GRN_FREE(new_expr); + return rc; + } + *expr = new_expr; + return GRN_SUCCESS; +} + +grn_rc +grn_ts_expr_parse(grn_ctx *ctx, grn_obj *table, + const char *str, size_t str_size, grn_ts_expr **expr) { + grn_rc rc; + grn_ts_expr *new_expr; + if (!ctx || !table || !grn_ts_obj_is_table(ctx, table) || + !str || !str_size || !expr) { + return GRN_INVALID_ARGUMENT; + } + rc = grn_ts_expr_open(ctx, table, &new_expr); + if (rc != GRN_SUCCESS) { + return rc; + } + // TODO: Hmm... + { + rc = grn_ts_expr_push(ctx, new_expr, str, str_size); + if (rc != GRN_SUCCESS) { + grn_ts_expr_close(ctx, new_expr); + return rc; + } + rc = grn_ts_expr_complete(ctx, new_expr); + if (rc != GRN_SUCCESS) { + grn_ts_expr_close(ctx, new_expr); + return rc; + } + } + *expr = new_expr; + return GRN_SUCCESS; +} + +/* grn_ts_expr_fin() finalizes an expression. */ +static grn_rc +grn_ts_expr_fin(grn_ctx *ctx, grn_ts_expr *expr) { + grn_rc rc = GRN_SUCCESS; + // TODO: Finalize new members. + if (expr->stack) { + GRN_FREE(expr->stack); + } + if (expr->nodes) { + size_t i; + for (i = 0; i < expr->n_nodes; i++) { + if (expr->nodes[i]) { + grn_rc rc_new = grn_ts_expr_node_close(ctx, expr->nodes[i]); + if (rc == GRN_SUCCESS) { + rc = rc_new; + } + } + } + GRN_FREE(expr->nodes); + } + if (expr->curr_table) { + grn_obj_unlink(ctx, expr->curr_table); + } + if (expr->table) { + grn_obj_unlink(ctx, expr->table); + } + return rc; +} + +grn_rc +grn_ts_expr_close(grn_ctx *ctx, grn_ts_expr *expr) { + grn_rc rc; + if (!ctx || !expr) { + return GRN_INVALID_ARGUMENT; + } + rc = grn_ts_expr_fin(ctx, expr); + GRN_FREE(expr); + return rc; +} + +grn_obj * +grn_ts_expr_get_table(grn_ctx *ctx, grn_ts_expr *expr) { + if (!ctx || !expr) { + return NULL; + } + /* The reference counting will never fail in practice. */ + if (grn_ts_obj_increment_ref_count(ctx, expr->table) != GRN_SUCCESS) { + return NULL; + } + return expr->table; +} + +grn_ts_expr_type +grn_ts_expr_get_type(grn_ctx *ctx, grn_ts_expr *expr) { + return (!ctx || !expr) ? GRN_TS_EXPR_BROKEN : expr->type; +} + +grn_ts_data_kind +grn_ts_expr_get_data_kind(grn_ctx *ctx, grn_ts_expr *expr) { + return (!ctx || !expr) ? GRN_TS_VOID : expr->data_kind; +} + +grn_ts_data_type +grn_ts_expr_get_data_type(grn_ctx *ctx, grn_ts_expr *expr) { + return (!ctx || !expr) ? GRN_DB_VOID : expr->data_type; +} + +grn_ts_expr_node * +grn_ts_expr_get_root(grn_ctx *ctx, grn_ts_expr *expr) { + return (!ctx || !expr) ? NULL : expr->root; +} + +/* grn_ts_expr_reserve_nodes() extends a node buffer for a new node. */ +static grn_rc +grn_ts_expr_reserve_nodes(grn_ctx *ctx, grn_ts_expr *expr) { + size_t i, n_bytes, new_max_n_nodes; + grn_ts_expr_node **new_nodes; + if (expr->n_nodes < expr->max_n_nodes) { + return GRN_SUCCESS; + } + new_max_n_nodes = expr->n_nodes * 2; + if (!new_max_n_nodes) { + new_max_n_nodes = 1; + } + n_bytes = sizeof(grn_ts_expr_node *) * new_max_n_nodes; + new_nodes = (grn_ts_expr_node **)GRN_REALLOC(expr->nodes, n_bytes); + if (!new_nodes) { + return GRN_NO_MEMORY_AVAILABLE; + } + for (i = expr->n_nodes; i < new_max_n_nodes; i++) { + new_nodes[i] = NULL; + } + expr->nodes = new_nodes; + expr->max_n_nodes = new_max_n_nodes; + return GRN_SUCCESS; +} + +/* + * grn_ts_expr_open_id_node() opens and registers an ID node. + * Registered nodes will be closed in grn_ts_expr_fin(). + */ +static grn_rc +grn_ts_expr_open_id_node(grn_ctx *ctx, grn_ts_expr *expr, + grn_ts_expr_node **node) { + grn_ts_expr_node *new_node; + grn_rc rc = grn_ts_expr_reserve_nodes(ctx, expr); + if (rc != GRN_SUCCESS) { + return rc; + } + rc = grn_ts_expr_id_node_open(ctx, &new_node); + if (rc != GRN_SUCCESS) { + return rc; + } + expr->nodes[expr->n_nodes++] = new_node; + *node = new_node; + return GRN_SUCCESS; +} + +/* + * grn_ts_expr_open_score_node() opens and registers a score node. + * Registered nodes will be closed in grn_ts_expr_fin(). + */ +static grn_rc +grn_ts_expr_open_score_node(grn_ctx *ctx, grn_ts_expr *expr, + grn_ts_expr_node **node) { + grn_ts_expr_node *new_node; + grn_rc rc = grn_ts_expr_reserve_nodes(ctx, expr); + if (rc != GRN_SUCCESS) { + return rc; + } + rc = grn_ts_expr_score_node_open(ctx, &new_node); + if (rc != GRN_SUCCESS) { + return rc; + } + expr->nodes[expr->n_nodes++] = new_node; + *node = new_node; + return GRN_SUCCESS; +} + +/* + * grn_ts_expr_open_key_node() opens and registers a key node. + * Registered nodes will be closed in grn_ts_expr_fin(). + */ +static grn_rc +grn_ts_expr_open_key_node(grn_ctx *ctx, grn_ts_expr *expr, + grn_ts_expr_node **node) { + grn_ts_expr_node *new_node; + grn_rc rc = grn_ts_expr_reserve_nodes(ctx, expr); + if (rc != GRN_SUCCESS) { + return rc; + } + rc = grn_ts_expr_key_node_open(ctx, expr->curr_table, &new_node); + if (rc != GRN_SUCCESS) { + return rc; + } + expr->nodes[expr->n_nodes++] = new_node; + *node = new_node; + return GRN_SUCCESS; +} + +/* + * grn_ts_expr_open_value_node() opens and registers a value node. + * Registered nodes will be closed in grn_ts_expr_fin(). + */ +static grn_rc +grn_ts_expr_open_value_node(grn_ctx *ctx, grn_ts_expr *expr, + grn_ts_expr_node **node) { + grn_ts_expr_node *new_node; + grn_rc rc = grn_ts_expr_reserve_nodes(ctx, expr); + if (rc != GRN_SUCCESS) { + return rc; + } + rc = grn_ts_expr_value_node_open(ctx, expr->curr_table, &new_node); + if (rc != GRN_SUCCESS) { + return rc; + } + expr->nodes[expr->n_nodes++] = new_node; + *node = new_node; + return GRN_SUCCESS; +} + +/* + * grn_ts_expr_open_const_node() opens and registers a const node. + * Registered nodes will be closed in grn_ts_expr_fin(). + */ +static grn_rc +grn_ts_expr_open_const_node(grn_ctx *ctx, grn_ts_expr *expr, + grn_ts_data_kind kind, const void *value, + grn_ts_expr_node **node) { + grn_ts_expr_node *new_node; + grn_rc rc = grn_ts_expr_reserve_nodes(ctx, expr); + if (rc != GRN_SUCCESS) { + return rc; + } + rc = grn_ts_expr_const_node_open(ctx, kind, value, &new_node); + if (rc != GRN_SUCCESS) { + return rc; + } + expr->nodes[expr->n_nodes++] = new_node; + *node = new_node; + return GRN_SUCCESS; +} + +/* + * grn_ts_expr_open_column_node() opens and registers a column. + * Registered nodes will be closed in grn_ts_expr_fin(). + */ +static grn_rc +grn_ts_expr_open_column_node(grn_ctx *ctx, grn_ts_expr *expr, + grn_obj *column, grn_ts_expr_node **node) { + grn_ts_expr_node *new_node; + grn_rc rc = grn_ts_expr_reserve_nodes(ctx, expr); + if (rc != GRN_SUCCESS) { + return rc; + } + rc = grn_ts_expr_column_node_open(ctx, column, &new_node); + if (rc != GRN_SUCCESS) { + return rc; + } + expr->nodes[expr->n_nodes++] = new_node; + *node = new_node; + return GRN_SUCCESS; +} + +/* grn_ts_expr_push_node() pushes a node to stack. */ +static grn_rc +grn_ts_expr_push_node(grn_ctx *ctx, grn_ts_expr *expr, + grn_ts_expr_node *node) { + if (expr->stack_depth == expr->stack_size) { + size_t i, n_bytes, new_size; + grn_ts_expr_node **new_stack; + new_size = expr->stack_size * 2; + if (!new_size) { + new_size = 1; + } + n_bytes = sizeof(grn_ts_expr_node *) * new_size; + new_stack = GRN_REALLOC(expr->stack, n_bytes); + if (!new_stack) { + return GRN_NO_MEMORY_AVAILABLE; + } + for (i = expr->stack_size; i < new_size; i++) { + new_stack[i] = NULL; + } + expr->stack = new_stack; + expr->stack_size = new_size; + } + expr->stack[expr->stack_depth++] = node; + return GRN_SUCCESS; +} + +grn_rc +grn_ts_expr_push(grn_ctx *ctx, grn_ts_expr *expr, + const char *str, size_t str_size) { + if (!ctx || !expr || (expr->type == GRN_TS_EXPR_BROKEN) || + !str || !str_size) { + return GRN_INVALID_ARGUMENT; + } + if ((str_size == GRN_COLUMN_NAME_ID_LEN) && + !memcmp(str, GRN_COLUMN_NAME_ID, GRN_COLUMN_NAME_ID_LEN)) { + return grn_ts_expr_push_id(ctx, expr); + } else if ((str_size == GRN_COLUMN_NAME_KEY_LEN) && + !memcmp(str, GRN_COLUMN_NAME_KEY, GRN_COLUMN_NAME_KEY_LEN)) { + return grn_ts_expr_push_key(ctx, expr); + } else if ((str_size == GRN_COLUMN_NAME_VALUE_LEN) && + !memcmp(str, GRN_COLUMN_NAME_VALUE, GRN_COLUMN_NAME_VALUE_LEN)) { + return grn_ts_expr_push_value(ctx, expr); + } else if ((str_size == GRN_COLUMN_NAME_SCORE_LEN) && + !memcmp(str, GRN_COLUMN_NAME_SCORE, GRN_COLUMN_NAME_SCORE_LEN)) { + return grn_ts_expr_push_score(ctx, expr); + } else if ((str_size == 4) && !memcmp(str, "true", 4)) { + return grn_ts_expr_push_bool(ctx, expr, GRN_TRUE); + } else if ((str_size == 5) && !memcmp(str, "false", 5)) { + return grn_ts_expr_push_bool(ctx, expr, GRN_FALSE); + } else if (isdigit((unsigned char)str[0])) { + char buf[1024]; + grn_ts_int value; + if (str_size >= sizeof(buf)) { + return GRN_INVALID_ARGUMENT; + } + memcpy(buf, str, str_size); + buf[str_size] = '\0'; + value = strtol(buf, NULL, 10); + return grn_ts_expr_push_int(ctx, expr, value); + } else { + grn_rc rc; + grn_obj *column = grn_obj_column(ctx, expr->curr_table, str, str_size); + if (!column) { + return GRN_INVALID_ARGUMENT; + } + rc = grn_ts_expr_push_column(ctx, expr, column); + grn_obj_unlink(ctx, column); + return rc; + } + // TODO: Parse the given string and push it. + return GRN_SUCCESS; +} + +#define GRN_TS_EXPR_PUSH_BULK_CASE_BLOCK(TYPE, kind)\ + case GRN_DB_ ## TYPE: {\ + return grn_ts_expr_push_ ## kind(ctx, expr, GRN_ ## TYPE ## _VALUE(obj));\ + } +/* grn_ts_expr_push_bulk() pushes a scalar. */ +static grn_rc +grn_ts_expr_push_bulk(grn_ctx *ctx, grn_ts_expr *expr, grn_obj *obj) { + switch (obj->header.domain) { + GRN_TS_EXPR_PUSH_BULK_CASE_BLOCK(BOOL, bool) + GRN_TS_EXPR_PUSH_BULK_CASE_BLOCK(INT8, int) + GRN_TS_EXPR_PUSH_BULK_CASE_BLOCK(INT16, int) + GRN_TS_EXPR_PUSH_BULK_CASE_BLOCK(INT32, int) + GRN_TS_EXPR_PUSH_BULK_CASE_BLOCK(INT64, int) + GRN_TS_EXPR_PUSH_BULK_CASE_BLOCK(UINT8, int) + GRN_TS_EXPR_PUSH_BULK_CASE_BLOCK(UINT16, int) + GRN_TS_EXPR_PUSH_BULK_CASE_BLOCK(UINT32, int) + /* The behavior is undefined if a value is greater than 2^63 - 1. */ + GRN_TS_EXPR_PUSH_BULK_CASE_BLOCK(UINT64, int) + GRN_TS_EXPR_PUSH_BULK_CASE_BLOCK(FLOAT, float) + GRN_TS_EXPR_PUSH_BULK_CASE_BLOCK(TIME, time) + case GRN_DB_SHORT_TEXT: + case GRN_DB_TEXT: + case GRN_DB_LONG_TEXT: { + grn_ts_text value = { GRN_TEXT_VALUE(obj), GRN_TEXT_LEN(obj) }; + return grn_ts_expr_push_text(ctx, expr, value); + } + case GRN_DB_TOKYO_GEO_POINT: { + grn_ts_geo_point value; + GRN_GEO_POINT_VALUE(obj, value.latitude, value.longitude); + return grn_ts_expr_push_tokyo_geo_point(ctx, expr, value); + } + case GRN_DB_WGS84_GEO_POINT: { + grn_ts_geo_point value; + GRN_GEO_POINT_VALUE(obj, value.latitude, value.longitude); + return grn_ts_expr_push_wgs84_geo_point(ctx, expr, value); + } + default: { + return GRN_INVALID_ARGUMENT; + } + } +} +#undef GRN_TS_EXPR_PUSH_BULK_CASE_BLOCK + +#define GRN_TS_EXPR_PUSH_UVECTOR_CASE_BLOCK(TYPE, kind)\ + case GRN_DB_ ## TYPE: {\ + grn_ts_ ## kind ##_vector value = { (grn_ts_ ## kind *)GRN_BULK_HEAD(obj),\ + grn_uvector_size(ctx, obj) };\ + return grn_ts_expr_push_ ## kind ## _vector(ctx, expr, value);\ + } +#define GRN_TS_EXPR_PUSH_UVECTOR_CASE_BLOCK_WITH_TYPECAST(TYPE, kind)\ + case GRN_DB_ ## TYPE: {\ + size_t i;\ + grn_rc rc;\ + grn_ts_ ## kind ## _vector value = { NULL, grn_uvector_size(ctx, obj) };\ + if (!value.size) {\ + return grn_ts_expr_push_ ## kind ## _vector(ctx, expr, value);\ + }\ + grn_ts_ ## kind *buf = GRN_MALLOCN(grn_ts_ ## kind, value.size);\ + if (!buf) {\ + return GRN_NO_MEMORY_AVAILABLE;\ + }\ + for (i = 0; i < value.size; i++) {\ + buf[i] = GRN_ ## TYPE ##_VALUE_AT(obj, i);\ + }\ + value.ptr = buf;\ + rc = grn_ts_expr_push_ ## kind ## _vector(ctx, expr, value);\ + GRN_FREE(buf);\ + return rc;\ + } +/* grn_ts_expr_push_uvector() pushes an array of fixed-size values. */ +static grn_rc +grn_ts_expr_push_uvector(grn_ctx *ctx, grn_ts_expr *expr, grn_obj *obj) { + switch (obj->header.domain) { + GRN_TS_EXPR_PUSH_UVECTOR_CASE_BLOCK(BOOL, bool) + GRN_TS_EXPR_PUSH_UVECTOR_CASE_BLOCK_WITH_TYPECAST(INT8, int) + GRN_TS_EXPR_PUSH_UVECTOR_CASE_BLOCK_WITH_TYPECAST(INT16, int) + GRN_TS_EXPR_PUSH_UVECTOR_CASE_BLOCK_WITH_TYPECAST(INT32, int) + GRN_TS_EXPR_PUSH_UVECTOR_CASE_BLOCK(INT64, int) + GRN_TS_EXPR_PUSH_UVECTOR_CASE_BLOCK_WITH_TYPECAST(UINT8, int) + GRN_TS_EXPR_PUSH_UVECTOR_CASE_BLOCK_WITH_TYPECAST(UINT16, int) + GRN_TS_EXPR_PUSH_UVECTOR_CASE_BLOCK_WITH_TYPECAST(UINT32, int) + GRN_TS_EXPR_PUSH_UVECTOR_CASE_BLOCK(UINT64, int) + GRN_TS_EXPR_PUSH_UVECTOR_CASE_BLOCK(TIME, time) + GRN_TS_EXPR_PUSH_UVECTOR_CASE_BLOCK(TOKYO_GEO_POINT, tokyo_geo_point) + GRN_TS_EXPR_PUSH_UVECTOR_CASE_BLOCK(WGS84_GEO_POINT, wgs84_geo_point) + default: { + return GRN_INVALID_ARGUMENT; + } + } +} +#undef GRN_TS_EXPR_PUSH_UVECTOR_CASE_BLOCK_WITH_TYPECAST +#undef GRN_TS_EXPR_PUSH_UVECTOR_CASE_BLOCK + +/* grn_ts_expr_push_uvector() pushes an array of texts. */ +static grn_rc +grn_ts_expr_push_vector(grn_ctx *ctx, grn_ts_expr *expr, grn_obj *obj) { + switch (obj->header.domain) { + case GRN_DB_SHORT_TEXT: + case GRN_DB_TEXT: + case GRN_DB_LONG_TEXT: { + size_t i; + grn_rc rc; + grn_ts_text_vector value = { NULL, grn_vector_size(ctx, obj) }; + if (!value.size) { + return grn_ts_expr_push_text_vector(ctx, expr, value); + } + grn_ts_text *buf = GRN_MALLOCN(grn_ts_text, value.size); + if (!buf) { + return GRN_NO_MEMORY_AVAILABLE; + } + for (i = 0; i < value.size; i++) { + buf[i].size = grn_vector_get_element(ctx, obj, i, &buf[i].ptr, + NULL, NULL); + } + value.ptr = buf; + rc = grn_ts_expr_push_text_vector(ctx, expr, value); + GRN_FREE(buf); + return rc; + } + default: { + return GRN_INVALID_ARGUMENT; + } + } +} + +static grn_rc +grn_ts_expr_push_accessor(grn_ctx *ctx, grn_ts_expr *expr, + grn_accessor *accessor) { + if (accessor->next) { + return GRN_INVALID_ARGUMENT; + } + switch (accessor->action) { + case GRN_ACCESSOR_GET_ID: { + return grn_ts_expr_push_id(ctx, expr); + } + case GRN_ACCESSOR_GET_SCORE: { + return grn_ts_expr_push_score(ctx, expr); + } + case GRN_ACCESSOR_GET_KEY: { + return grn_ts_expr_push_key(ctx, expr); + } + case GRN_ACCESSOR_GET_VALUE: { + return grn_ts_expr_push_value(ctx, expr); + } + default: { + return GRN_INVALID_ARGUMENT; + } + } +} + +grn_rc +grn_ts_expr_push_obj(grn_ctx *ctx, grn_ts_expr *expr, grn_obj *obj) { + if (!ctx || !expr || (expr->type == GRN_TS_EXPR_BROKEN) || !obj) { + return GRN_INVALID_ARGUMENT; + } + switch (obj->header.type) { + case GRN_BULK: { + return grn_ts_expr_push_bulk(ctx, expr, obj); + } + case GRN_UVECTOR: { + return grn_ts_expr_push_uvector(ctx, expr, obj); + } + case GRN_VECTOR: { + return grn_ts_expr_push_vector(ctx, expr, obj); + } + case GRN_ACCESSOR: { + return grn_ts_expr_push_accessor(ctx, expr, (grn_accessor *)obj); + } + case GRN_COLUMN_FIX_SIZE: + case GRN_COLUMN_VAR_SIZE: { + return grn_ts_expr_push_column(ctx, expr, obj); + } + default: { + return GRN_INVALID_ARGUMENT; + } + } +} + +grn_rc +grn_ts_expr_push_id(grn_ctx *ctx, grn_ts_expr *expr) { + grn_rc rc; + grn_ts_expr_node *node; + if (!ctx || !expr || (expr->type == GRN_TS_EXPR_BROKEN)) { + return GRN_INVALID_ARGUMENT; + } + rc = grn_ts_expr_open_id_node(ctx, expr, &node); + if (rc != GRN_SUCCESS) { + return rc; + } + rc = grn_ts_expr_push_node(ctx, expr, node); + if (rc != GRN_SUCCESS) { + return rc; + } + return GRN_SUCCESS; +} + +grn_rc +grn_ts_expr_push_score(grn_ctx *ctx, grn_ts_expr *expr) { + grn_rc rc; + grn_ts_expr_node *node; + if (!ctx || !expr || (expr->type == GRN_TS_EXPR_BROKEN)) { + return GRN_INVALID_ARGUMENT; + } + rc = grn_ts_expr_open_score_node(ctx, expr, &node); + if (rc != GRN_SUCCESS) { + return rc; + } + rc = grn_ts_expr_push_node(ctx, expr, node); + if (rc != GRN_SUCCESS) { + return rc; + } + return GRN_SUCCESS; +} + +grn_rc +grn_ts_expr_push_key(grn_ctx *ctx, grn_ts_expr *expr) { + grn_rc rc; + grn_ts_expr_node *node; + if (!ctx || !expr || (expr->type == GRN_TS_EXPR_BROKEN)) { + return GRN_INVALID_ARGUMENT; + } + rc = grn_ts_expr_open_key_node(ctx, expr, &node); + if (rc != GRN_SUCCESS) { + return rc; + } + rc = grn_ts_expr_push_node(ctx, expr, node); + if (rc != GRN_SUCCESS) { + return rc; + } + return GRN_SUCCESS; +} + +grn_rc +grn_ts_expr_push_value(grn_ctx *ctx, grn_ts_expr *expr) { + grn_rc rc; + grn_ts_expr_node *node; + if (!ctx || !expr || (expr->type == GRN_TS_EXPR_BROKEN)) { + return GRN_INVALID_ARGUMENT; + } + rc = grn_ts_expr_open_value_node(ctx, expr, &node); + if (rc != GRN_SUCCESS) { + return rc; + } + rc = grn_ts_expr_push_node(ctx, expr, node); + if (rc != GRN_SUCCESS) { + return rc; + } + return GRN_SUCCESS; +} + +#define GRN_TS_EXPR_PUSH_CONST_CASE_BLOCK(KIND, kind)\ + case GRN_TS_ ## KIND: {\ + return grn_ts_expr_push_ ## kind(ctx, expr,\ + *(const grn_ts_ ## kind *)value);\ + } +grn_rc +grn_ts_expr_push_const(grn_ctx *ctx, grn_ts_expr *expr, + grn_ts_data_kind kind, const void *value) { + if (!ctx || !expr || (expr->type == GRN_TS_EXPR_BROKEN) || !value) { + return GRN_INVALID_ARGUMENT; + } + switch (kind) { + GRN_TS_EXPR_PUSH_CONST_CASE_BLOCK(BOOL, bool) + GRN_TS_EXPR_PUSH_CONST_CASE_BLOCK(INT, int) + GRN_TS_EXPR_PUSH_CONST_CASE_BLOCK(FLOAT, float) + GRN_TS_EXPR_PUSH_CONST_CASE_BLOCK(TIME, time) + GRN_TS_EXPR_PUSH_CONST_CASE_BLOCK(TEXT, text) + GRN_TS_EXPR_PUSH_CONST_CASE_BLOCK(GEO_POINT, geo_point) + GRN_TS_EXPR_PUSH_CONST_CASE_BLOCK(BOOL_VECTOR, bool_vector) + GRN_TS_EXPR_PUSH_CONST_CASE_BLOCK(INT_VECTOR, int_vector) + GRN_TS_EXPR_PUSH_CONST_CASE_BLOCK(FLOAT_VECTOR, float_vector) + GRN_TS_EXPR_PUSH_CONST_CASE_BLOCK(TIME_VECTOR, time_vector) + GRN_TS_EXPR_PUSH_CONST_CASE_BLOCK(TEXT_VECTOR, text_vector) + GRN_TS_EXPR_PUSH_CONST_CASE_BLOCK(GEO_POINT_VECTOR, geo_point_vector) + default: { + return GRN_INVALID_ARGUMENT; + } + } +} +#undef GRN_TS_EXPR_PUSH_CONST_CASE_BLOCK + +grn_rc +grn_ts_expr_push_column(grn_ctx *ctx, grn_ts_expr *expr, grn_obj *column) { + grn_rc rc; + grn_ts_expr_node *node; + if (!ctx || !expr || (expr->type == GRN_TS_EXPR_BROKEN) || + !column || !grn_ts_obj_is_column(ctx, column) || + (DB_OBJ(expr->curr_table)->id != column->header.domain)) { + return GRN_INVALID_ARGUMENT; + } + rc = grn_ts_expr_open_column_node(ctx, expr, column, &node); + if (rc != GRN_SUCCESS) { + return rc; + } + rc = grn_ts_expr_push_node(ctx, expr, node); + if (rc != GRN_SUCCESS) { + return rc; + } + return GRN_SUCCESS; +} + +grn_rc +grn_ts_expr_push_operator(grn_ctx *ctx, grn_ts_expr *expr, + grn_ts_op_type op_type) { + if (!ctx || !expr || (expr->type == GRN_TS_EXPR_BROKEN)) { + return GRN_INVALID_ARGUMENT; + } + // TODO + return GRN_SUCCESS; +} + +#define GRN_TS_EXPR_PUSH_CONST(KIND, kind)\ + grn_rc rc;\ + grn_ts_expr_node *node;\ + if (!ctx || !expr || (expr->type == GRN_TS_EXPR_BROKEN) ||\ + !grn_ts_ ## kind ## _is_valid(value)) {\ + return GRN_INVALID_ARGUMENT;\ + }\ + rc = grn_ts_expr_open_const_node(ctx, expr, GRN_TS_ ## KIND, &value, &node);\ + if (rc != GRN_SUCCESS) {\ + return rc;\ + }\ + rc = grn_ts_expr_push_node(ctx, expr, node);\ + if (rc != GRN_SUCCESS) {\ + return rc;\ + } +grn_rc +grn_ts_expr_push_bool(grn_ctx *ctx, grn_ts_expr *expr, grn_ts_bool value) { + GRN_TS_EXPR_PUSH_CONST(BOOL, bool) + return GRN_SUCCESS; +} + +grn_rc +grn_ts_expr_push_int(grn_ctx *ctx, grn_ts_expr *expr, grn_ts_int value) { + GRN_TS_EXPR_PUSH_CONST(INT, int) + return GRN_SUCCESS; +} + +grn_rc +grn_ts_expr_push_float(grn_ctx *ctx, grn_ts_expr *expr, grn_ts_float value) { + GRN_TS_EXPR_PUSH_CONST(FLOAT, float) + return GRN_SUCCESS; +} + +grn_rc +grn_ts_expr_push_time(grn_ctx *ctx, grn_ts_expr *expr, grn_ts_time value) { + GRN_TS_EXPR_PUSH_CONST(TIME, time) + return GRN_SUCCESS; +} + +grn_rc +grn_ts_expr_push_text(grn_ctx *ctx, grn_ts_expr *expr, grn_ts_text value) { + GRN_TS_EXPR_PUSH_CONST(TEXT, text) + return GRN_SUCCESS; +} + +grn_rc +grn_ts_expr_push_geo_point(grn_ctx *ctx, grn_ts_expr *expr, + grn_ts_geo_point value) { + GRN_TS_EXPR_PUSH_CONST(GEO_POINT, geo_point) + return GRN_SUCCESS; +} + +grn_rc +grn_ts_expr_push_tokyo_geo_point(grn_ctx *ctx, grn_ts_expr *expr, + grn_ts_geo_point value) { + GRN_TS_EXPR_PUSH_CONST(GEO_POINT, geo_point) + node->data_type = GRN_DB_TOKYO_GEO_POINT; + return GRN_SUCCESS; +} + +grn_rc +grn_ts_expr_push_wgs84_geo_point(grn_ctx *ctx, grn_ts_expr *expr, + grn_ts_geo_point value) { + GRN_TS_EXPR_PUSH_CONST(GEO_POINT, geo_point) + node->data_type = GRN_DB_WGS84_GEO_POINT; + return GRN_SUCCESS; +} + +grn_rc +grn_ts_expr_push_bool_vector(grn_ctx *ctx, grn_ts_expr *expr, + grn_ts_bool_vector value) { + GRN_TS_EXPR_PUSH_CONST(BOOL_VECTOR, bool_vector) + return GRN_SUCCESS; +} + +grn_rc +grn_ts_expr_push_int_vector(grn_ctx *ctx, grn_ts_expr *expr, + grn_ts_int_vector value) { + GRN_TS_EXPR_PUSH_CONST(INT_VECTOR, int_vector) + return GRN_SUCCESS; +} + +grn_rc +grn_ts_expr_push_float_vector(grn_ctx *ctx, grn_ts_expr *expr, + grn_ts_float_vector value) { + GRN_TS_EXPR_PUSH_CONST(FLOAT_VECTOR, float_vector) + return GRN_SUCCESS; +} + +grn_rc +grn_ts_expr_push_time_vector(grn_ctx *ctx, grn_ts_expr *expr, + grn_ts_time_vector value) { + GRN_TS_EXPR_PUSH_CONST(TIME_VECTOR, time_vector) + return GRN_SUCCESS; +} + +grn_rc +grn_ts_expr_push_text_vector(grn_ctx *ctx, grn_ts_expr *expr, + grn_ts_text_vector value) { + GRN_TS_EXPR_PUSH_CONST(TEXT_VECTOR, text_vector) + return GRN_SUCCESS; +} + +grn_rc +grn_ts_expr_push_geo_point_vector(grn_ctx *ctx, grn_ts_expr *expr, + grn_ts_geo_point_vector value) { + GRN_TS_EXPR_PUSH_CONST(GEO_POINT_VECTOR, geo_point_vector) + return GRN_SUCCESS; +} + +grn_rc +grn_ts_expr_push_tokyo_geo_point_vector(grn_ctx *ctx, grn_ts_expr *expr, + grn_ts_geo_point_vector value) { + GRN_TS_EXPR_PUSH_CONST(GEO_POINT_VECTOR, geo_point_vector) + node->data_type = GRN_DB_TOKYO_GEO_POINT; + return GRN_SUCCESS; +} + +grn_rc +grn_ts_expr_push_wgs84_geo_point_vector(grn_ctx *ctx, grn_ts_expr *expr, + grn_ts_geo_point_vector value) { + GRN_TS_EXPR_PUSH_CONST(GEO_POINT_VECTOR, geo_point_vector) + node->data_type = GRN_DB_TOKYO_GEO_POINT; + return GRN_SUCCESS; +} +#undef GRN_TS_EXPR_PUSH_CONST + +grn_rc +grn_ts_expr_complete(grn_ctx *ctx, grn_ts_expr *expr) { + grn_ts_expr_node *root; + if (!ctx || !expr || (expr->type != GRN_TS_EXPR_INCOMPLETE)) { + return GRN_INVALID_ARGUMENT; + } + if (expr->stack_depth != 1) { + return GRN_INVALID_ARGUMENT; + } + root = expr->stack[0]; + switch (root->data_kind) { + case GRN_TS_REF: + case GRN_TS_REF_VECTOR: { + return GRN_INVALID_ARGUMENT; + } + default: { + break; + } + } + switch (root->type) { + case GRN_TS_EXPR_ID_NODE: { + expr->type = GRN_TS_EXPR_ID; + break; + } + case GRN_TS_EXPR_SCORE_NODE: { + expr->type = GRN_TS_EXPR_SCORE; + break; + } + case GRN_TS_EXPR_KEY_NODE: + case GRN_TS_EXPR_VALUE_NODE: { + expr->type = GRN_TS_EXPR_VARIABLE; + break; + } + case GRN_TS_EXPR_CONST_NODE: { + expr->type = GRN_TS_EXPR_CONST; + break; + } + case GRN_TS_EXPR_COLUMN_NODE: + case GRN_TS_EXPR_OP_NODE: { + expr->type = GRN_TS_EXPR_VARIABLE; + break; + } + default: { + return GRN_INVALID_ARGUMENT; + } + } + expr->data_type = root->data_type; + expr->data_kind = root->data_kind; + expr->root = root; + return GRN_SUCCESS; +} + +grn_rc +grn_ts_expr_evaluate(grn_ctx *ctx, grn_ts_expr *expr, + const grn_ts_record *in, size_t n_in, void *out) { + if (!ctx || !expr || (expr->type == GRN_TS_EXPR_INCOMPLETE) || + (expr->type == GRN_TS_EXPR_BROKEN) || (!in && n_in) || (n_in && !out)) { + return GRN_INVALID_ARGUMENT; + } + if (!n_in) { + return GRN_SUCCESS; + } + return grn_ts_expr_node_evaluate(ctx, expr->root, in, n_in, out); +} + +grn_rc +grn_ts_expr_filter(grn_ctx *ctx, grn_ts_expr *expr, + grn_ts_record *in, size_t n_in, + grn_ts_record *out, size_t *n_out) { + if (!ctx || !expr || (expr->type == GRN_TS_EXPR_INCOMPLETE) || + (expr->type == GRN_TS_EXPR_BROKEN) || (!in && n_in) || + !out || !n_out) { + return GRN_INVALID_ARGUMENT; + } + if (!n_in) { + *n_out = 0; + return GRN_SUCCESS; + } + return grn_ts_expr_node_filter(ctx, expr->root, in, n_in, out, n_out); +} + +grn_rc +grn_ts_expr_adjust(grn_ctx *ctx, grn_ts_expr *expr, + grn_ts_record *io, size_t n_io) { + if (!ctx || !expr || (expr->type == GRN_TS_EXPR_INCOMPLETE) || + (expr->type == GRN_TS_EXPR_BROKEN) || (!io && n_io)) { + return GRN_INVALID_ARGUMENT; + } + if (!n_io) { + return GRN_SUCCESS; + } + return grn_ts_expr_node_adjust(ctx, expr->root, io, n_io); +} + +/*------------------------------------------------------------- + * API. + */ + +/* grn_ts_select_filter() applies a filter to all the records of a table. */ +static grn_rc +grn_ts_select_filter(grn_ctx *ctx, grn_obj *table, + const char *str, size_t str_size, + size_t offset, size_t limit, + grn_ts_record **out, size_t *n_out, size_t *n_hits) { + grn_rc rc, tmp_rc; + grn_table_cursor *cursor; + grn_ts_expr *expr; + grn_ts_record *buf = NULL; + size_t buf_size = 0; + + *out = NULL; + *n_out = 0; + *n_hits = 0; + + cursor = grn_table_cursor_open(ctx, table, NULL, 0, NULL, 0, 0, -1, + GRN_CURSOR_ASCENDING | GRN_CURSOR_BY_ID); + if (!cursor) { + return (ctx->rc != GRN_SUCCESS) ? ctx->rc : GRN_UNKNOWN_ERROR; + } + + rc = grn_ts_expr_parse(ctx, table, str, str_size, &expr); + if (rc == GRN_SUCCESS) { + for ( ; ; ) { + size_t i, batch_size; + grn_ts_record *batch; + + /* Extend the record buffer. */ + if (buf_size < (*n_out + GRN_TS_BATCH_SIZE)) { + size_t new_size = buf_size ? (buf_size * 2) : GRN_TS_BATCH_SIZE; + size_t n_bytes = sizeof(grn_ts_record) * new_size; + grn_ts_record *new_buf = (grn_ts_record *)GRN_REALLOC(buf, n_bytes); + if (!new_buf) { + rc = GRN_NO_MEMORY_AVAILABLE; + break; + } + buf = new_buf; + buf_size = new_size; + } + + /* Read records from the cursor. */ + batch = buf + *n_out; + for (i = 0; i < GRN_TS_BATCH_SIZE; i++) { + batch[i].id = grn_table_cursor_next(ctx, cursor); + if (batch[i].id == GRN_ID_NIL) { + break; + } + batch[i].score = 0.0; + } + batch_size = i; + if (!batch_size) { + break; + } + + /* Apply the filter. */ + rc = grn_ts_expr_filter(ctx, expr, batch, batch_size, + batch, &batch_size); + if (rc != GRN_SUCCESS) { + break; + } + *n_hits += batch_size; + + /* Apply the offset and the limit. */ + if (offset) { + if (batch_size <= offset) { + offset -= batch_size; + batch_size = 0; + } else { + size_t n_bytes = sizeof(grn_ts_record) * (batch_size - offset); + memcpy(batch, batch + offset, n_bytes); + batch_size -= offset; + offset = 0; + } + } + if (batch_size <= limit) { + limit -= batch_size; + } else { + batch_size = limit; + limit = 0; + } + *n_out += batch_size; + } + tmp_rc = grn_ts_expr_close(ctx, expr); + if (rc == GRN_SUCCESS) { + rc = tmp_rc; + } + } + + tmp_rc = grn_table_cursor_close(ctx, cursor); + if (rc == GRN_SUCCESS) { + rc = tmp_rc; + } + + if (rc != GRN_SUCCESS) { + if (buf) { + GRN_FREE(buf); + } + *n_out = 0; + *n_hits = 0; + return rc; + } + *out = buf; + return GRN_SUCCESS; +} + +/* grn_ts_select_output() outputs the results. */ +/* FIXME: Too long. */ +/* FIXME: Errors are ignored. */ +static grn_rc +grn_ts_select_output(grn_ctx *ctx, grn_obj *table, + const char *str, size_t str_size, + const grn_ts_record *in, size_t n_in, size_t n_hits) { + const char *rest = str; + size_t rest_size = str_size; + grn_ts_expr **exprs = NULL; + size_t i, j, k, n_exprs = 0; + grn_obj name_buf; + grn_ts_text *names = NULL; + + GRN_TEXT_INIT(&name_buf, GRN_OBJ_VECTOR); + while (rest_size) { + const char *name = rest; + size_t name_size; + + /* Find a delimiter. */ + for (i = 0; i < rest_size; i++) { + if (rest[i] == ',') { + break; + } + } + name_size = i; + + rest += name_size; + rest_size -= name_size; + if (rest_size) { + rest++; + rest_size--; + } + + /* Trim spaces. */ + for (i = 0; i < name_size; i++) { + if (!isspace((unsigned char)name[i])) { + break; + } + } + name += i; + name_size -= i; + for (i = name_size; i > 0; i--) { + if (!isspace((unsigned char)name[i - 1])) { + break; + } + } + name_size = i; + if (!name_size) { + continue; + } + + /* Add column names to name_buf. */ + if (name[name_size - 1] == '*') { + /* Expand a wildcard. */ + grn_hash *columns = grn_hash_create(ctx, NULL, sizeof(grn_id), 0, + GRN_OBJ_TABLE_HASH_KEY | + GRN_HASH_TINY); + if (columns) { + if (grn_table_columns(ctx, table, "", 0, (grn_obj *)columns)) { + grn_id *key; + GRN_HASH_EACH(ctx, columns, id, &key, NULL, NULL, { + grn_obj *column = grn_ctx_at(ctx, *key); + if (column) { + char buf[1024]; + size_t len = grn_column_name(ctx, column, buf, 1024); + grn_vector_add_element(ctx, &name_buf, buf, len, 0, GRN_DB_TEXT); + grn_obj_unlink(ctx, column); + } + }); + } + grn_hash_close(ctx, columns); + } + } else { + grn_vector_add_element(ctx, &name_buf, name, name_size, 0, GRN_DB_TEXT); + } + } + + /* Create expressions. */ + n_exprs = grn_vector_size(ctx, &name_buf); + if (n_exprs) { + size_t count = 0; + names = GRN_MALLOCN(grn_ts_text, n_exprs); + exprs = GRN_MALLOCN(grn_ts_expr *, n_exprs); + if (!names || !exprs) { + n_exprs = 0; + } + for (i = 0; i < n_exprs; i++) { + names[i].size = grn_vector_get_element(ctx, &name_buf, i, &names[i].ptr, + NULL, NULL); + if (grn_ts_expr_parse(ctx, table, names[i].ptr, names[i].size, + &exprs[i]) != GRN_SUCCESS) { + exprs[i] = NULL; + } + } + for (i = 0; i < n_exprs; i++) { + if (exprs[i]) { + names[count] = names[i]; + exprs[count] = exprs[i]; + count++; + } + } + n_exprs = count; + } + + GRN_OUTPUT_ARRAY_OPEN("RESULT", 1); + GRN_OUTPUT_ARRAY_OPEN("RESULTSET", 2 + n_in); + + GRN_OUTPUT_ARRAY_OPEN("NHITS", 1); + grn_text_ulltoa(ctx, ctx->impl->outbuf, n_hits); + GRN_OUTPUT_ARRAY_CLOSE(); /* NHITS. */ + + GRN_OUTPUT_ARRAY_OPEN("COLUMNS", n_exprs); + for (size_t i = 0; i < n_exprs; ++i) { + GRN_OUTPUT_ARRAY_OPEN("COLUMN", 2); + GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, '"'); + GRN_TEXT_PUT(ctx, ctx->impl->outbuf, names[i].ptr, names[i].size); + GRN_TEXT_PUT(ctx, ctx->impl->outbuf, "\",\"", 3); + switch (exprs[i]->data_type) { + case GRN_DB_VOID: { + if (exprs[i]->data_kind == GRN_TS_GEO_POINT) { + GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "GeoPoint"); + } else { + GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "Void"); + } + break; + } +#define GRN_TS_SELECT_OUTPUT_TYPE_CASE_BLOCK(TYPE, name)\ + case GRN_DB_ ## TYPE: {\ + GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, name);\ + break;\ + } + GRN_TS_SELECT_OUTPUT_TYPE_CASE_BLOCK(BOOL, "Bool") + GRN_TS_SELECT_OUTPUT_TYPE_CASE_BLOCK(INT8, "Int8") + GRN_TS_SELECT_OUTPUT_TYPE_CASE_BLOCK(INT16, "Int16") + GRN_TS_SELECT_OUTPUT_TYPE_CASE_BLOCK(INT32, "Int32") + GRN_TS_SELECT_OUTPUT_TYPE_CASE_BLOCK(INT64, "Int64") + GRN_TS_SELECT_OUTPUT_TYPE_CASE_BLOCK(UINT8, "UInt8") + GRN_TS_SELECT_OUTPUT_TYPE_CASE_BLOCK(UINT16, "UInt16") + GRN_TS_SELECT_OUTPUT_TYPE_CASE_BLOCK(UINT32, "UInt32") + GRN_TS_SELECT_OUTPUT_TYPE_CASE_BLOCK(UINT64, "UInt64") + GRN_TS_SELECT_OUTPUT_TYPE_CASE_BLOCK(FLOAT, "Float") + GRN_TS_SELECT_OUTPUT_TYPE_CASE_BLOCK(TIME, "Time") + GRN_TS_SELECT_OUTPUT_TYPE_CASE_BLOCK(SHORT_TEXT, "ShortText") + GRN_TS_SELECT_OUTPUT_TYPE_CASE_BLOCK(TEXT, "Text") + GRN_TS_SELECT_OUTPUT_TYPE_CASE_BLOCK(LONG_TEXT, "LongText") + GRN_TS_SELECT_OUTPUT_TYPE_CASE_BLOCK(TOKYO_GEO_POINT, "TokyoGeoPoint") + GRN_TS_SELECT_OUTPUT_TYPE_CASE_BLOCK(WGS84_GEO_POINT, "WGS84GeoPoint") +#undef GRN_TS_SELECT_OUTPUT_TYPE_CASE_BLOCK + default: { + grn_obj *obj = grn_ctx_at(ctx, exprs[i]->data_type); + if (obj && grn_ts_obj_is_table(ctx, obj)) { + char name[GRN_TABLE_MAX_KEY_SIZE]; + int len = grn_obj_name(ctx, obj, name, sizeof(name)); + GRN_TEXT_PUT(ctx, ctx->impl->outbuf, name, len); + grn_obj_unlink(ctx, obj); + } else { + GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "Unknown"); + } + break; + } + } + GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, '"'); + GRN_OUTPUT_ARRAY_CLOSE(); + } + GRN_OUTPUT_ARRAY_CLOSE(); /* COLUMNS. */ + + if (n_in) { + size_t count = 0; + void **bufs = GRN_MALLOCN(void *, n_exprs); + if (bufs) { + for (i = 0; i < n_exprs; i++) { + switch (exprs[i]->data_kind) { +#define GRN_TS_SELECT_OUTPUT_MALLOC_CASE_BLOCK(KIND, kind)\ + case GRN_TS_ ## KIND: {\ + bufs[i] = GRN_MALLOCN(grn_ts_ ## kind, GRN_TS_BATCH_SIZE);\ + break;\ + } +#define GRN_TS_SELECT_OUTPUT_MALLOC_VECTOR_CASE_BLOCK(KIND, kind)\ + GRN_TS_SELECT_OUTPUT_MALLOC_CASE_BLOCK(KIND ## _VECTOR, kind ## _vector) + GRN_TS_SELECT_OUTPUT_MALLOC_CASE_BLOCK(BOOL, bool) + GRN_TS_SELECT_OUTPUT_MALLOC_CASE_BLOCK(INT, int) + GRN_TS_SELECT_OUTPUT_MALLOC_CASE_BLOCK(FLOAT, float) + GRN_TS_SELECT_OUTPUT_MALLOC_CASE_BLOCK(TIME, time) + GRN_TS_SELECT_OUTPUT_MALLOC_CASE_BLOCK(TEXT, text) + GRN_TS_SELECT_OUTPUT_MALLOC_CASE_BLOCK(GEO_POINT, geo_point) + GRN_TS_SELECT_OUTPUT_MALLOC_VECTOR_CASE_BLOCK(BOOL, bool) + GRN_TS_SELECT_OUTPUT_MALLOC_VECTOR_CASE_BLOCK(INT, int) + GRN_TS_SELECT_OUTPUT_MALLOC_VECTOR_CASE_BLOCK(FLOAT, float) + GRN_TS_SELECT_OUTPUT_MALLOC_VECTOR_CASE_BLOCK(TIME, time) + GRN_TS_SELECT_OUTPUT_MALLOC_VECTOR_CASE_BLOCK(TEXT, text) + GRN_TS_SELECT_OUTPUT_MALLOC_VECTOR_CASE_BLOCK(GEO_POINT, geo_point) +#undef GRN_TS_SELECT_OUTPUT_MALLOC_VECTOR_CASE_BLOCK +#undef GRN_TS_SELECT_OUTPUT_MALLOC_CASE_BLOCK + default: { + bufs[i] = NULL; + break; + } + } + } + while (count < n_in) { + size_t batch_size = GRN_TS_BATCH_SIZE; + if (batch_size > (n_in - count)) { + batch_size = n_in - count; + } + for (i = 0; i < n_exprs; ++i) { + if (!bufs[i]) { + continue; + } + grn_ts_expr_evaluate(ctx, exprs[i], in + count, batch_size, bufs[i]); + } + for (i = 0; i < batch_size; ++i) { + GRN_OUTPUT_ARRAY_OPEN("HIT", n_exprs); + for (j = 0; j < n_exprs; ++j) { + if (j) { + GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ','); + } + if (!bufs[j]) { + GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "null"); + continue; + } + /* TODO: Define a function for each data kind. */ + switch (exprs[j]->data_kind) { + case GRN_TS_BOOL: { + grn_ts_bool *batch = (grn_ts_bool *)bufs[j]; + if (batch[i]) { + GRN_TEXT_PUT(ctx, ctx->impl->outbuf, "true", 4); + } else { + GRN_TEXT_PUT(ctx, ctx->impl->outbuf, "false", 5); + } + break; + } + case GRN_TS_INT: { + grn_ts_int *batch = (grn_ts_int *)bufs[j]; + grn_text_lltoa(ctx, ctx->impl->outbuf, batch[i]); + break; + } + case GRN_TS_FLOAT: { + grn_ts_float *batch = (grn_ts_float *)bufs[j]; + grn_text_ftoa(ctx, ctx->impl->outbuf, batch[i]); + break; + } + case GRN_TS_TIME: { + grn_ts_time *batch = (grn_ts_time *)bufs[j]; + grn_text_ftoa(ctx, ctx->impl->outbuf, batch[i] * 0.000001); + break; + } + case GRN_TS_TEXT: { + grn_ts_text *batch = (grn_ts_text *)bufs[j]; + grn_text_esc(ctx, ctx->impl->outbuf, + batch[i].ptr, batch[i].size); + break; + } + case GRN_TS_GEO_POINT: { + grn_ts_geo_point *batch = (grn_ts_geo_point *)bufs[j]; + GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, '"'); + grn_text_itoa(ctx, ctx->impl->outbuf, batch[i].latitude); + GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, 'x'); + grn_text_itoa(ctx, ctx->impl->outbuf, batch[i].longitude); + GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, '"'); + break; + } + case GRN_TS_BOOL_VECTOR: { + grn_ts_bool_vector vector; + vector = ((grn_ts_bool_vector *)bufs[j])[i]; + GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, '['); + for (k = 0; k < vector.size; ++k) { + if (k) { + GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ','); + } + if (vector.ptr[k]) { + GRN_TEXT_PUT(ctx, ctx->impl->outbuf, "true", 4); + } else { + GRN_TEXT_PUT(ctx, ctx->impl->outbuf, "false", 5); + } + } + GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ']'); + break; + } + case GRN_TS_INT_VECTOR: { + grn_ts_int_vector vector; + vector = ((grn_ts_int_vector *)bufs[j])[i]; + GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, '['); + for (k = 0; k < vector.size; ++k) { + if (k) { + GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ','); + } + grn_text_lltoa(ctx, ctx->impl->outbuf, vector.ptr[k]); + } + GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ']'); + break; + } + case GRN_TS_FLOAT_VECTOR: { + grn_ts_float_vector vector; + vector = ((grn_ts_float_vector *)bufs[j])[i]; + GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, '['); + for (k = 0; k < vector.size; ++k) { + if (k) { + GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ','); + } + grn_text_ftoa(ctx, ctx->impl->outbuf, vector.ptr[k]); + } + GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ']'); + break; + } + case GRN_TS_TIME_VECTOR: { + grn_ts_time_vector vector; + vector = ((grn_ts_time_vector *)bufs[j])[i]; + GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, '['); + for (k = 0; k < vector.size; ++k) { + if (k) { + GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ','); + } + grn_text_ftoa(ctx, ctx->impl->outbuf, + vector.ptr[k] * 0.000001); + } + GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ']'); + break; + } + case GRN_TS_TEXT_VECTOR: { + grn_ts_text_vector vector; + vector = ((grn_ts_text_vector *)bufs[j])[i]; + GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, '['); + for (k = 0; k < vector.size; ++k) { + if (k) { + GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ','); + } + grn_text_esc(ctx, ctx->impl->outbuf, + vector.ptr[k].ptr, vector.ptr[k].size); + } + GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ']'); + break; + } + case GRN_TS_GEO_POINT_VECTOR: { + grn_ts_geo_point_vector vector; + vector = ((grn_ts_geo_point_vector *)bufs[j])[i]; + GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, '['); + for (k = 0; k < vector.size; ++k) { + if (k) { + GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ','); + } + GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, '"'); + grn_text_itoa(ctx, ctx->impl->outbuf, + vector.ptr[k].latitude); + GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, 'x'); + grn_text_itoa(ctx, ctx->impl->outbuf, + vector.ptr[k].longitude); + GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, '"'); + } + GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ']'); + break; + } + default: { + break; + } + } + } + GRN_OUTPUT_ARRAY_CLOSE(); /* HITS. */ + } + count += batch_size; + } + for (i = 0; i < n_exprs; i++) { + if (bufs[i]) { + GRN_FREE(bufs[i]); + } + } + GRN_FREE(bufs); + } + } + GRN_OUTPUT_ARRAY_CLOSE(); /* RESULTSET. */ + GRN_OUTPUT_ARRAY_CLOSE(); /* RESET. */ + + /* Finalize. */ + if (exprs) { + for (i = 0; i < n_exprs; i++) { + if (exprs[i]) { + grn_ts_expr_close(ctx, exprs[i]); + } + } + GRN_FREE(exprs); + } + if (names) { + GRN_FREE(names); + } + GRN_OBJ_FIN(ctx, &name_buf); + return GRN_SUCCESS; +} + +grn_rc +grn_ts_select(grn_ctx *ctx, grn_obj *table, + const char *filter, size_t filter_size, + const char *output_columns, size_t output_columns_size, + size_t offset, size_t limit) { + grn_rc rc; + grn_ts_record *records = NULL; + size_t n_records, n_hits; + if (!ctx || !table || !grn_ts_obj_is_table(ctx, table) || + (!filter && filter_size) || (!output_columns && output_columns_size)) { + return GRN_INVALID_ARGUMENT; + } + rc = grn_ts_select_filter(ctx, table, filter, filter_size, offset, limit, + &records, &n_records, &n_hits); + if (rc == GRN_SUCCESS) { + rc = grn_ts_select_output(ctx, table, output_columns, output_columns_size, + records, n_records, n_hits); + } + if (records) { + GRN_FREE(records); + } + return rc; +} + +#endif /* GRN_WITH_TS */ Deleted: lib/ts.cpp (+0 -3739) 100644 =================================================================== --- lib/ts.cpp 2015-09-01 21:58:28 +0900 (022c6cc) +++ /dev/null @@ -1,3739 +0,0 @@ -/* -*- c-basic-offset: 2 -*- */ -/* - Copyright(C) 2015 Brazil - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License version 2.1 as published by the Free Software Foundation. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -/* TS is an acronym for "Turbo Selector". */ - -#ifdef GRN_WITH_TS - -#include "grn_ts.hpp" - -#include <cctype> -#include <cstdio> -#include <cstdlib> -#include <limits> -#include <memory> -#include <string> - -#include <iostream> // for debug! - -#include "grn_ctx_impl.h" -#include "grn_db.h" -#include "grn_output.h" -#include "grn_str.h" - -namespace { - -enum { - GRN_TS_MAX_DATA_TYPE = GRN_DB_WGS84_GEO_POINT, - GRN_TS_MAX_BATCH_SIZE = 1024 -}; - -grn_ts_data_kind grn_ts_data_type_to_kind(grn_ts_data_type data_type) { - switch (data_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_POINT; - } - default: { - return GRN_TS_REF; - } - } -} - -} // namespace - -namespace grn { -namespace ts { - -// -- TableCursor -- - -// TableCursor is a wrapper for grn_table_cursor: -// - GRN_CURSOR_PAT_KEY -// - GRN_CURSOR_DAT_KEY -// - GRN_CURSOR_HASH_KEY -// - GRN_CURSOR_NO_KEY -class TableCursor : public Cursor { - public: - ~TableCursor() { - grn_table_cursor_close(ctx_, cursor_); - } - - static grn_rc open(grn_ctx *ctx, grn_obj *cursor, Score default_score, - Cursor **wrapper); - - grn_rc read(Record *records, size_t size, size_t *count); - - private: - grn_ctx *ctx_; - grn_obj *cursor_; - Score default_score_; - - TableCursor(grn_ctx *ctx, grn_obj *cursor, Score default_score) - : Cursor(), ctx_(ctx), cursor_(cursor), default_score_(default_score) {} -}; - -grn_rc TableCursor::open(grn_ctx *ctx, grn_obj *cursor, Score default_score, - Cursor **wrapper) { - if (!ctx || !cursor || !wrapper) { - return GRN_INVALID_ARGUMENT; - } - switch (cursor->header.type) { - case GRN_CURSOR_TABLE_PAT_KEY: - case GRN_CURSOR_TABLE_DAT_KEY: - case GRN_CURSOR_TABLE_HASH_KEY: - case GRN_CURSOR_TABLE_NO_KEY: { - break; - } - default: { - return GRN_INVALID_ARGUMENT; - } - } - TableCursor *new_wrapper = - new (std::nothrow) TableCursor(ctx, cursor, default_score); - if (!new_wrapper) { - return GRN_NO_MEMORY_AVAILABLE; - } - *wrapper = new_wrapper; - return GRN_SUCCESS; -} - -grn_rc TableCursor::read(Record *records, size_t size, size_t *count) { - if ((!records && (size != 0)) || !count) { - return GRN_INVALID_ARGUMENT; - } - switch (cursor_->header.type) { - case GRN_CURSOR_TABLE_PAT_KEY: { - for (size_t i = 0; i < size; ++i) { - grn_id id = grn_pat_cursor_next( - ctx_, reinterpret_cast<grn_pat_cursor *>(cursor_)); - if (id == GRN_ID_NIL) { - *count = i; - return GRN_SUCCESS; - } - records[i].id = id; - records[i].score = default_score_; - } - break; - } - case GRN_CURSOR_TABLE_DAT_KEY: { - for (size_t i = 0; i < size; ++i) { - grn_id id = grn_dat_cursor_next( - ctx_, reinterpret_cast<grn_dat_cursor *>(cursor_)); - if (id == GRN_ID_NIL) { - *count = i; - return GRN_SUCCESS; - } - records[i].id = id; - records[i].score = default_score_; - } - break; - } - case GRN_CURSOR_TABLE_HASH_KEY: { - for (size_t i = 0; i < size; ++i) { - grn_id id = grn_hash_cursor_next( - ctx_, reinterpret_cast<grn_hash_cursor *>(cursor_)); - if (id == GRN_ID_NIL) { - *count = i; - return GRN_SUCCESS; - } - records[i].id = id; - records[i].score = default_score_; - } - break; - } - case GRN_CURSOR_TABLE_NO_KEY: { - for (size_t i = 0; i < size; ++i) { - grn_id id = grn_array_cursor_next( - ctx_, reinterpret_cast<grn_array_cursor *>(cursor_)); - if (id == GRN_ID_NIL) { - *count = i; - return GRN_SUCCESS; - } - records[i].id = id; - records[i].score = default_score_; - } - break; - } - default: { - return GRN_UNKNOWN_ERROR; - } - } - *count = size; - return GRN_SUCCESS; -} - -// -- Cursor -- - -grn_rc Cursor::open_table_cursor( - grn_ctx *ctx, grn_obj *table, Cursor **cursor) { - if (!ctx || !grn_obj_is_table(ctx, table) || !cursor) { - return GRN_INVALID_ARGUMENT; - } - grn_table_cursor *table_cursor = grn_table_cursor_open( - ctx, table, NULL, 0, NULL, 0, 0, -1, - GRN_CURSOR_ASCENDING | GRN_CURSOR_BY_ID); - if (!table_cursor) { - return ctx->rc; - } - grn_rc rc = TableCursor::open(ctx, table_cursor, 0.0, cursor); - if (rc != GRN_SUCCESS) { - grn_table_cursor_close(ctx, table_cursor); - } - return rc; -} - -grn_rc Cursor::read(Record *records, size_t size, size_t *count) { - if ((!records && (size != 0)) || !count) { - return GRN_INVALID_ARGUMENT; - } - *count = 0; - return GRN_SUCCESS; -} - -// -- ExpressionNode -- - -class ExpressionNode { - public: - ExpressionNode() {} - virtual ~ExpressionNode() {} - - virtual ExpressionNodeType type() const = 0; - virtual DataKind data_kind() const = 0; - virtual DataType data_type() const = 0; - virtual grn_obj *ref_table() const = 0; - virtual int dimension() const = 0; - - virtual grn_rc filter(Record *input, size_t input_size, - Record *output, size_t *output_size) { - return GRN_OPERATION_NOT_SUPPORTED; - } - virtual grn_rc adjust(Record *records, size_t num_records) { - return GRN_OPERATION_NOT_SUPPORTED; - } - virtual grn_rc evaluate(const Record *records, size_t num_records, - void *results) = 0; -}; - -// -- IDNode -- - -class IDNode : public ExpressionNode { - public: - ~IDNode() {} - - static grn_rc open(ExpressionNode **node) { - ExpressionNode *new_node = new (std::nothrow) IDNode; - if (!new_node) { - return GRN_NO_MEMORY_AVAILABLE; - } - *node = new_node; - return GRN_SUCCESS; - } - - ExpressionNodeType type() const { - return GRN_TS_ID_NODE; - } - DataKind data_kind() const { - return GRN_TS_INT; - } - DataType data_type() const { - return GRN_DB_UINT32; - } - grn_obj *ref_table() const { - return NULL; - } - int dimension() const { - return 0; - } - - grn_rc evaluate(const Record *records, size_t num_records, void *results) { - for (size_t i = 0; i < num_records; ++i) { - static_cast<grn_ts_int *>(results)[i] = records[i].id; - } - return GRN_SUCCESS; - } - - private: - IDNode() : ExpressionNode() {} -}; - -// -- ScoreNode -- - -class ScoreNode : public ExpressionNode { - public: - ~ScoreNode() {} - - static grn_rc open(ExpressionNode **node) { - ExpressionNode *new_node = new (std::nothrow) ScoreNode; - if (!new_node) { - return GRN_NO_MEMORY_AVAILABLE; - } - *node = new_node; - return GRN_SUCCESS; - } - - ExpressionNodeType type() const { - return GRN_TS_SCORE_NODE; - } - DataKind data_kind() const { - return GRN_TS_FLOAT; - } - DataType data_type() const { - return GRN_DB_FLOAT; - } - grn_obj *ref_table() const { - return NULL; - } - int dimension() const { - return 0; - } - - grn_rc adjust(Record *records, size_t num_records) { - return GRN_SUCCESS; - } - grn_rc evaluate( - const Record *records, size_t num_records, void *results) { - for (size_t i = 0; i < num_records; ++i) { - static_cast<grn_ts_float *>(results)[i] = records[i].score; - } - return GRN_SUCCESS; - } - - private: - ScoreNode() : ExpressionNode() {} -}; - -// -- ConstantNode -- - -class ConstantNode : public ExpressionNode { - public: - ~ConstantNode() { - if (obj_) { - grn_obj_unlink(ctx_, obj_); - } - if (buf_) { - grn_obj_unlink(ctx_, buf_); - } - } - - static grn_rc open(grn_ctx *ctx, grn_obj *obj, ExpressionNode **node); - - ExpressionNodeType type() const { - return GRN_TS_CONSTANT_NODE; - } - DataKind data_kind() const { - return data_kind_; - } - DataType data_type() const { - return data_type_; - } - grn_obj *ref_table() const { - return NULL; - } - int dimension() const { - return dimension_; - } - - grn_rc filter(Record *input, size_t input_size, - Record *output, size_t *output_size); - grn_rc adjust(Record *records, size_t num_records); - grn_rc evaluate(const Record *records, size_t num_records, void *results); - - private: - grn_ctx *ctx_; - grn_obj *obj_; - grn_obj *buf_; - DataKind data_kind_; - DataType data_type_; - int dimension_; - - static grn_rc convert(grn_ctx *ctx, grn_obj *obj, - grn_obj **new_obj, grn_obj **buf); - static grn_rc convert_bulk(grn_ctx *ctx, grn_obj *obj, - grn_obj **new_obj, grn_obj **buf); - static grn_rc convert_uvector(grn_ctx *ctx, grn_obj *obj, - grn_obj **new_obj, grn_obj **buf); - static grn_rc convert_vector(grn_ctx *ctx, grn_obj *obj, - grn_obj **new_obj, grn_obj **buf); - - ConstantNode(grn_ctx *ctx, grn_obj *obj, grn_obj *buf, - DataType data_type, int dimension) - : ExpressionNode(), - ctx_(ctx), - obj_(obj), - buf_(buf), - data_kind_(grn_ts_data_type_to_kind(data_type)), - data_type_(data_type), - dimension_(dimension) {} -}; - -grn_rc ConstantNode::open(grn_ctx *ctx, grn_obj *obj, ExpressionNode **node) { - grn_obj *new_obj; - grn_obj *buf; - grn_rc rc = convert(ctx, obj, &new_obj, &buf); - if (rc != GRN_SUCCESS) { - return rc; - } - DataType data_type = obj->header.domain; - int dimension = obj->header.type != GRN_BULK; - ConstantNode *new_node = new (std::nothrow) ConstantNode( - ctx, new_obj ? new_obj : obj, buf, data_type, dimension); - if (!new_node) { - if (new_obj) { - grn_obj_close(ctx, new_obj); - } - if (buf) { - grn_obj_close(ctx, buf); - } - return GRN_NO_MEMORY_AVAILABLE; - } - if (new_obj) { - grn_obj_unlink(ctx, obj); - } - *node = new_node; - return GRN_SUCCESS; -} - -grn_rc ConstantNode::filter(Record *input, size_t input_size, - Record *output, size_t *output_size) { - if ((dimension() != 0) || (data_kind() != GRN_TS_BOOL)) { - return GRN_OPERATION_NOT_PERMITTED; - } - grn_ts_bool value = GRN_BOOL_VALUE(obj_); - if (value) { - // If the I/O areas are the same, there is no need to copy records. - if (input != output) { - for (size_t i = 0; i < input_size; ++i) { - output[i] = input[i]; - } - } - *output_size = input_size; - } else { - *output_size = 0; - } - return GRN_SUCCESS; -} - -grn_rc ConstantNode::adjust(Record *records, size_t num_records) { - if ((dimension() != 0) || (data_kind() != GRN_TS_FLOAT)) { - return GRN_OPERATION_NOT_PERMITTED; - } - grn_ts_float value = GRN_FLOAT_VALUE(obj_); - for (size_t i = 0; i < num_records; ++i) { - records[i].score = value; - } - return GRN_SUCCESS; -} - -grn_rc ConstantNode::evaluate(const Record *records, size_t num_records, - void *results) { - if (num_records == 0) { - return GRN_SUCCESS; - } - if (dimension() == 0) { - // Scalar types. - switch (data_kind()) { - case GRN_TS_BOOL: { - grn_ts_bool value = GRN_BOOL_VALUE(obj_); - for (size_t i = 0; i < num_records; ++i) { - static_cast<grn_ts_bool *>(results)[i] = value; - } - break; - } - case GRN_TS_INT: - case GRN_TS_FLOAT: - case GRN_TS_TIME: - case GRN_TS_GEO_POINT: { - const void *head = GRN_BULK_HEAD(obj_); - char *ptr = static_cast<char *>(results); - for (size_t i = 0; i < num_records; ++i) { - std::memcpy(ptr, head, 8); - ptr += 8; - } - break; - } - case GRN_TS_TEXT: { - grn_ts_text value; - value.ptr = GRN_BULK_HEAD(obj_); - value.size = GRN_BULK_VSIZE(obj_); - for (size_t i = 0; i < num_records; ++i) { - static_cast<grn_ts_text *>(results)[i] = value; - } - break; - } - default: { - return GRN_UNKNOWN_ERROR; - } - } - } else { - // Vector types. - switch (data_kind()) { - case GRN_TS_BOOL: - case GRN_TS_INT: - case GRN_TS_FLOAT: - case GRN_TS_TIME: - case GRN_TS_GEO_POINT: { - grn_ts_vector value; - value.ptr = GRN_BULK_HEAD(obj_); - value.size = grn_vector_size(ctx_, obj_); - for (size_t i = 0; i < num_records; ++i) { - static_cast<grn_ts_vector *>(results)[i] = value; - } - break; - } - case GRN_TS_TEXT: { - grn_ts_vector value; - value.ptr = GRN_BULK_HEAD(obj_); - value.size = GRN_BULK_VSIZE(obj_) / sizeof(grn_ts_text); - for (size_t i = 0; i < num_records; ++i) { - static_cast<grn_ts_vector *>(results)[i] = value; - } - break; - } - default: { - return GRN_UNKNOWN_ERROR; - } - } - } - return GRN_SUCCESS; -} - -grn_rc ConstantNode::convert(grn_ctx *ctx, grn_obj *obj, - grn_obj **new_obj, grn_obj **buf) { - *new_obj = NULL; - *buf = NULL; - switch (obj->header.type) { - case GRN_BULK: { - return convert_bulk(ctx, obj, new_obj, buf); - } - case GRN_UVECTOR: { - return convert_uvector(ctx, obj, new_obj, buf); - } - case GRN_VECTOR: { - return convert_vector(ctx, obj, new_obj, buf); - } - default: { - return GRN_INVALID_ARGUMENT; - } - } -} - -#define GRN_TS_CONVERT_BULK_INT_CASE_BLOCK(type)\ - case GRN_DB_ ## type: {\ - GRN_INT64_SET(ctx, *new_obj, GRN_ ## type ## _VALUE(obj));\ - break;\ - } -grn_rc ConstantNode::convert_bulk(grn_ctx *ctx, grn_obj *obj, - grn_obj **new_obj, grn_obj **buf) { - switch (obj->header.domain) { - case GRN_DB_BOOL: - case GRN_DB_INT64: - case GRN_DB_FLOAT: - case GRN_DB_TIME: - case GRN_DB_SHORT_TEXT: - case GRN_DB_TEXT: - case GRN_DB_LONG_TEXT: - case GRN_DB_TOKYO_GEO_POINT: - case GRN_DB_WGS84_GEO_POINT: { - return GRN_SUCCESS; - } - case GRN_DB_INT8: - case GRN_DB_INT16: - case GRN_DB_INT32: - case GRN_DB_UINT8: - case GRN_DB_UINT16: - case GRN_DB_UINT32: - case GRN_DB_UINT64: { - *new_obj = grn_obj_open(ctx, GRN_BULK, 0, GRN_DB_INT64); - if (!*new_obj) { - return GRN_NO_MEMORY_AVAILABLE; - } - switch (obj->header.domain) { - GRN_TS_CONVERT_BULK_INT_CASE_BLOCK(INT8) - GRN_TS_CONVERT_BULK_INT_CASE_BLOCK(INT16) - GRN_TS_CONVERT_BULK_INT_CASE_BLOCK(INT32) - GRN_TS_CONVERT_BULK_INT_CASE_BLOCK(UINT8) - GRN_TS_CONVERT_BULK_INT_CASE_BLOCK(UINT16) - GRN_TS_CONVERT_BULK_INT_CASE_BLOCK(UINT32) - GRN_TS_CONVERT_BULK_INT_CASE_BLOCK(UINT64) - default: { - return GRN_UNKNOWN_ERROR; - } - } - return GRN_SUCCESS; - } - default: { - return GRN_INVALID_ARGUMENT; - } - } -} -#undef GRN_TS_CONVERT_BULK_INT_CASE_BLOCK - -#define GRN_TS_CONVERT_UVECTOR_INT_CASE_BLOCK(type)\ - case GRN_DB_ ## type: {\ - for (size_t i = 0; i < size; ++i) {\ - GRN_INT64_SET_AT(ctx, *new_obj, i, GRN_ ## type ## _VALUE_AT(obj, i));\ - }\ - break;\ - } -grn_rc ConstantNode::convert_uvector(grn_ctx *ctx, grn_obj *obj, - grn_obj **new_obj, grn_obj **buf) { - switch (obj->header.domain) { - case GRN_DB_BOOL: - case GRN_DB_INT64: - case GRN_DB_FLOAT: - case GRN_DB_TIME: - case GRN_DB_TOKYO_GEO_POINT: - case GRN_DB_WGS84_GEO_POINT: { - return GRN_SUCCESS; - } - case GRN_DB_INT8: - case GRN_DB_INT16: - case GRN_DB_INT32: - case GRN_DB_UINT8: - case GRN_DB_UINT16: - case GRN_DB_UINT32: - case GRN_DB_UINT64: { - *new_obj = grn_obj_open(ctx, GRN_UVECTOR, 0, GRN_DB_INT64); - if (!new_obj) { - return GRN_NO_MEMORY_AVAILABLE; - } - size_t size = grn_vector_size(ctx, obj); - switch (obj->header.domain) { - GRN_TS_CONVERT_UVECTOR_INT_CASE_BLOCK(INT8) - GRN_TS_CONVERT_UVECTOR_INT_CASE_BLOCK(INT16) - GRN_TS_CONVERT_UVECTOR_INT_CASE_BLOCK(INT32) - GRN_TS_CONVERT_UVECTOR_INT_CASE_BLOCK(UINT8) - GRN_TS_CONVERT_UVECTOR_INT_CASE_BLOCK(UINT16) - GRN_TS_CONVERT_UVECTOR_INT_CASE_BLOCK(UINT32) - GRN_TS_CONVERT_UVECTOR_INT_CASE_BLOCK(UINT64) - default: { - return GRN_UNKNOWN_ERROR; - } - } - return GRN_SUCCESS; - } - default: { - return GRN_INVALID_ARGUMENT; - } - } -} -#undef GRN_TS_CONVERT_UVECTOR_INT_CASE_BLOCK - -grn_rc ConstantNode::convert_vector(grn_ctx *ctx, grn_obj *obj, - grn_obj **new_obj, grn_obj **buf) { - switch (obj->header.domain) { - case GRN_DB_SHORT_TEXT: - case GRN_DB_TEXT: - case GRN_DB_LONG_TEXT: { - break; - } - default: { - return GRN_INVALID_ARGUMENT; - } - } - grn_rc rc = GRN_SUCCESS; - *new_obj = grn_obj_open(ctx, GRN_BULK, 0, GRN_DB_TEXT); - if (!*new_obj) { - return GRN_NO_MEMORY_AVAILABLE; - } - size_t size = grn_vector_size(ctx, obj); - rc = grn_bulk_resize(ctx, *new_obj, sizeof(grn_ts_text) * size); - if (rc == GRN_SUCCESS) { - *buf = grn_obj_open(ctx, GRN_BULK, 0, GRN_DB_TEXT); - if (!*buf) { - grn_obj_close(ctx, *new_obj); - return GRN_NO_MEMORY_AVAILABLE; - } - grn_ts_text *values = - reinterpret_cast<grn_ts_text *>(GRN_BULK_HEAD(*new_obj)); - for (size_t i = 0; i < size; ++i) { - const char *ptr; - values[i].size = grn_vector_get_element(ctx, obj, i, &ptr, NULL, NULL); - GRN_TEXT_PUT(ctx, *buf, ptr, values[i].size); - if (rc != GRN_SUCCESS) { - break; - } - } - if (rc == GRN_SUCCESS) { - const char *ptr = GRN_BULK_HEAD(*buf); - for (size_t i = 0; i < size; ++i) { - values[i].ptr = ptr; - ptr += values[i].size; - } - } - } - if (rc != GRN_SUCCESS) { - if (*new_obj) { - grn_obj_close(ctx, *new_obj); - } - if (*buf) { - grn_obj_close(ctx, *buf); - } - } - return GRN_SUCCESS; -} - -// -- ColumnNode -- - -class ColumnNode : public ExpressionNode { - public: - ~ColumnNode() { - if (column_) { - grn_obj_unlink(ctx_, column_); - } - if (ref_table_) { - grn_obj_unlink(ctx_, ref_table_); - } - if (buf_) { - grn_obj_close(ctx_, buf_); - } - if (deep_buf_) { - grn_obj_close(ctx_, deep_buf_); - } - } - - static grn_rc open(grn_ctx *ctx, grn_obj *column, ExpressionNode **node); - - ExpressionNodeType type() const { - return GRN_TS_COLUMN_NODE; - } - DataKind data_kind() const { - return data_kind_; - } - DataType data_type() const { - return data_type_; - } - grn_obj *ref_table() const { - return NULL; - } - int dimension() const { - return dimension_; - } - - grn_rc filter(Record *input, size_t input_size, - Record *output, size_t *output_size); - grn_rc adjust(Record *records, size_t num_records); - grn_rc evaluate(const Record *records, size_t num_records, void *results); - - private: - grn_ctx *ctx_; - grn_obj *column_; - grn_obj *buf_; - grn_obj *deep_buf_; - DataKind data_kind_; - DataType data_type_; - grn_obj *ref_table_; - int dimension_; - - ColumnNode(grn_ctx *ctx, grn_obj *column, DataType data_type, - grn_obj *ref_table, int dimension) - : ExpressionNode(), - ctx_(ctx), - column_(column), - buf_(NULL), - deep_buf_(NULL), - data_kind_(grn_ts_data_type_to_kind(data_type)), - data_type_(data_type), - ref_table_(ref_table), - dimension_(dimension) {} - - grn_rc evaluate_scalar(const Record *records, size_t num_records, - void *results); - grn_rc evaluate_scalar_text(const Record *records, size_t num_records, - void *results); - grn_rc evaluate_vector(const Record *records, size_t num_records, - void *results); - grn_rc evaluate_vector_int(const Record *records, size_t num_records, - void *results); - grn_rc evaluate_vector_text(const Record *records, size_t num_records, - void *results); -}; - -grn_rc ColumnNode::open(grn_ctx *ctx, grn_obj *column, ExpressionNode **node) { - DataType data_type = GRN_DB_VOID; - grn_obj *ref_table = NULL; - int dimension = 0; - switch (column->header.type) { - case GRN_COLUMN_FIX_SIZE: - case GRN_COLUMN_VAR_SIZE: { - data_type = DB_OBJ(column)->range; - if (column->header.type == GRN_COLUMN_VAR_SIZE) { - grn_obj_flags column_type = - column->header.flags & GRN_OBJ_COLUMN_TYPE_MASK; - if (column_type == GRN_OBJ_COLUMN_VECTOR) { - dimension = 1; - } - } - break; - } - case GRN_ACCESSOR: { - grn_accessor *accessor = (grn_accessor *)column; - switch (accessor->action) { - case GRN_ACCESSOR_GET_ID: { - return IDNode::open(node); - } - case GRN_ACCESSOR_GET_KEY: { - data_type = accessor->obj->header.domain; - break; - } - case GRN_ACCESSOR_GET_VALUE: { - data_type = DB_OBJ(accessor->obj)->range; - break; - } - case GRN_ACCESSOR_GET_SCORE: { - return IDNode::open(node); - } - default: { - return GRN_INVALID_ARGUMENT; - } - } - break; - } - default: { - return GRN_INVALID_ARGUMENT; - } - } - if (data_type > GRN_TS_MAX_DATA_TYPE) { - ref_table = grn_ctx_at(ctx, column->header.domain); - if (!ref_table) { - if (ctx->rc != GRN_SUCCESS) { - return ctx->rc; - } - return GRN_UNKNOWN_ERROR; - } else if (!grn_obj_is_table(ctx, ref_table)) { - grn_obj_unlink(ctx, ref_table); - return GRN_UNKNOWN_ERROR; - } - } - ColumnNode *new_node = new (std::nothrow) ColumnNode( - ctx, column, data_type, ref_table, dimension); - if (!new_node) { - return GRN_NO_MEMORY_AVAILABLE; - } - *node = new_node; - return GRN_SUCCESS; -} - -grn_rc ColumnNode::filter(Record *input, size_t input_size, - Record *output, size_t *output_size) { - if ((dimension() != 0) || (data_kind() != GRN_TS_BOOL)) { - return GRN_OPERATION_NOT_PERMITTED; - } - grn_obj value; - GRN_BOOL_INIT(&value, 0); - size_t count = 0; - for (size_t i = 0; i < input_size; ++i) { - GRN_BULK_REWIND(&value); - grn_obj_get_value(ctx_, column_, input[i].id, &value); - if (ctx_->rc != GRN_SUCCESS) { - return ctx_->rc; - } - if (GRN_BOOL_VALUE(&value)) { - output[count] = input[i]; - ++count; - } - } - GRN_OBJ_FIN(ctx_, &value); - *output_size = count; - return GRN_SUCCESS; -} - -grn_rc ColumnNode::adjust(Record *records, size_t num_records) { - if ((dimension() != 0) || (data_kind() != GRN_TS_FLOAT)) { - return GRN_OPERATION_NOT_PERMITTED; - } - grn_obj value; - GRN_FLOAT_INIT(&value, 0); - for (size_t i = 0; i < num_records; ++i) { - GRN_BULK_REWIND(&value); - grn_obj_get_value(ctx_, column_, records[i].id, &value); - records[i].score = GRN_FLOAT_VALUE(&value); - } - GRN_OBJ_FIN(ctx_, &value); - return GRN_SUCCESS; -} - -grn_rc ColumnNode::evaluate(const Record *records, size_t num_records, - void *results) { - if (num_records == 0) { - return GRN_SUCCESS; - } - if (dimension() == 0) { - return evaluate_scalar(records, num_records, results); - } else { - return evaluate_vector(records, num_records, results); - } -} - -#define GRN_TS_EVALUATE_SCALAR_CASE_BLOCK(type, ts_type)\ - case GRN_DB_ ## type: {\ - GRN_ ## type ## _INIT(&value, 0);\ - for (size_t i = 0; i < num_records; ++i) {\ - GRN_BULK_REWIND(&value);\ - grn_obj_get_value(ctx_, column_, records[i].id, &value);\ - if (ctx_->rc != GRN_SUCCESS) {\ - break;\ - }\ - static_cast<grn_ts_ ## ts_type *>(results)[i] =\ - GRN_ ## type ## _VALUE(&value);\ - }\ - break;\ - } -grn_rc ColumnNode::evaluate_scalar(const Record *records, size_t num_records, - void *results) { - grn_obj value; - switch (data_type()) { - GRN_TS_EVALUATE_SCALAR_CASE_BLOCK(BOOL, bool) - GRN_TS_EVALUATE_SCALAR_CASE_BLOCK(INT8, int) - GRN_TS_EVALUATE_SCALAR_CASE_BLOCK(INT16, int) - GRN_TS_EVALUATE_SCALAR_CASE_BLOCK(INT32, int) - GRN_TS_EVALUATE_SCALAR_CASE_BLOCK(INT64, int) - GRN_TS_EVALUATE_SCALAR_CASE_BLOCK(UINT8, int) - GRN_TS_EVALUATE_SCALAR_CASE_BLOCK(UINT16, int) - GRN_TS_EVALUATE_SCALAR_CASE_BLOCK(UINT32, int) - GRN_TS_EVALUATE_SCALAR_CASE_BLOCK(UINT64, int) - GRN_TS_EVALUATE_SCALAR_CASE_BLOCK(FLOAT, float) - GRN_TS_EVALUATE_SCALAR_CASE_BLOCK(TIME, time) - case GRN_DB_SHORT_TEXT: - case GRN_DB_TEXT: - case GRN_DB_LONG_TEXT: { - return evaluate_scalar_text(records, num_records, results); - } - case GRN_DB_TOKYO_GEO_POINT: - case GRN_DB_WGS84_GEO_POINT: { - if (data_type() == GRN_DB_TOKYO_GEO_POINT) { - GRN_TOKYO_GEO_POINT_INIT(&value, 0); - } else { - GRN_WGS84_GEO_POINT_INIT(&value, 0); - } - for (size_t i = 0; i < num_records; ++i) { - GRN_BULK_REWIND(&value); - grn_obj_get_value(ctx_, column_, records[i].id, &value); - if (ctx_->rc != GRN_SUCCESS) { - break; - } - grn_ts_geo_point *ptr = &static_cast<grn_ts_geo_point *>(results)[i]; - GRN_GEO_POINT_VALUE(&value, ptr->latitude, ptr->longitude); - } - break; - } - default: { - return GRN_UNKNOWN_ERROR; - } - } - GRN_OBJ_FIN(ctx_, &value); - if (ctx_->rc != GRN_SUCCESS) { - return ctx_->rc; - } - return GRN_SUCCESS; -} -#undef GRN_TS_EVALUATE_CASE_BLOCK - -grn_rc ColumnNode::evaluate_scalar_text(const Record *records, - size_t num_records, void *results) { - if (!buf_) { - buf_ = grn_obj_open(ctx_, GRN_BULK, 0, GRN_DB_TEXT); - if (!buf_) { - if (ctx_->rc != GRN_SUCCESS) { - return ctx_->rc; - } - return GRN_UNKNOWN_ERROR; - } - } - GRN_BULK_REWIND(buf_); - grn_ts_text *values = static_cast<grn_ts_text *>(results); - size_t offset = 0; - for (size_t i = 0; i < num_records; ++i) { - grn_obj_get_value(ctx_, column_, records[i].id, buf_); - if (ctx_->rc != GRN_SUCCESS) { - return ctx_->rc; - } - size_t size = GRN_TEXT_LEN(buf_); - values[i].size = size - offset; - offset = size; - } - const char *ptr = GRN_TEXT_VALUE(buf_); - for (size_t i = 0; i < num_records; ++i) { - values[i].ptr = ptr; - ptr += values[i].size; - } - return GRN_SUCCESS; -} - -#define GRN_TS_EVALUATE_VECTOR_CASE_BLOCK(type, ts_type)\ - case GRN_DB_ ## type: {\ - if (!buf_) {\ - buf_ = grn_obj_open(ctx_, GRN_UVECTOR, 0, GRN_DB_ ## type);\ - if (!buf_) {\ - if (ctx_->rc != GRN_SUCCESS) {\ - return ctx_->rc;\ - }\ - return GRN_UNKNOWN_ERROR;\ - }\ - }\ - GRN_BULK_REWIND(buf_);\ - grn_ts_vector *vectors = static_cast<grn_ts_vector *>(results);\ - size_t offset = 0;\ - for (size_t i = 0; i < num_records; i++) {\ - grn_obj_get_value(ctx_, column_, records[i].id, buf_);\ - if (ctx_->rc != GRN_SUCCESS) {\ - return ctx_->rc;\ - }\ - size_t size = grn_vector_size(ctx_, buf_);\ - vectors[i].size = size - offset;\ - offset = size;\ - }\ - grn_ts_ ## ts_type *ptr =\ - reinterpret_cast<grn_ts_ ## ts_type *>(GRN_BULK_HEAD(buf_));\ - for (size_t i = 0; i < num_records; i++) {\ - vectors[i].ptr = ptr;\ - ptr += vectors[i].size;\ - }\ - return GRN_SUCCESS;\ - } -grn_rc ColumnNode::evaluate_vector(const Record *records, size_t num_records, - void *results) { - switch (data_type()) { - case GRN_DB_INT8: - case GRN_DB_INT16: - case GRN_DB_INT32: - case GRN_DB_UINT8: - case GRN_DB_UINT16: - case GRN_DB_UINT32: { - return evaluate_vector_int(records, num_records, results); - } - GRN_TS_EVALUATE_VECTOR_CASE_BLOCK(BOOL, bool) - GRN_TS_EVALUATE_VECTOR_CASE_BLOCK(INT64, int) - GRN_TS_EVALUATE_VECTOR_CASE_BLOCK(UINT64, int) - GRN_TS_EVALUATE_VECTOR_CASE_BLOCK(FLOAT, float) - GRN_TS_EVALUATE_VECTOR_CASE_BLOCK(TIME, float) - case GRN_DB_SHORT_TEXT: - case GRN_DB_TEXT: - case GRN_DB_LONG_TEXT: { - return evaluate_vector_text(records, num_records, results); - } - case GRN_DB_TOKYO_GEO_POINT: - case GRN_DB_WGS84_GEO_POINT: { - if (!buf_) { - buf_ = grn_obj_open(ctx_, GRN_UVECTOR, 0, data_type()); - if (!buf_) { - if (ctx_->rc != GRN_SUCCESS) { - return ctx_->rc; - } - return GRN_UNKNOWN_ERROR; - } - } - GRN_BULK_REWIND(buf_); - grn_ts_vector *vectors = static_cast<grn_ts_vector *>(results); - size_t offset = 0; - for (size_t i = 0; i < num_records; i++) { - grn_obj_get_value(ctx_, column_, records[i].id, buf_); - if (ctx_->rc != GRN_SUCCESS) { - return ctx_->rc; - } - size_t size = grn_vector_size(ctx_, buf_); - vectors[i].size = size - offset; - offset = size; - } - grn_ts_geo_point *ptr = - reinterpret_cast<grn_ts_geo_point *>(GRN_BULK_HEAD(buf_)); - for (size_t i = 0; i < num_records; i++) { - vectors[i].ptr = ptr; - ptr += vectors[i].size; - } - return GRN_SUCCESS; - } - default: { - return GRN_UNKNOWN_ERROR; - } - } -} - -#define GRN_TS_EVALUATE_VECTOR_INT_CASE_BLOCK(type)\ - case GRN_DB_ ## type: {\ - if (!deep_buf_) {\ - deep_buf_ = grn_obj_open(ctx_, GRN_UVECTOR, 0, GRN_DB_ ## type);\ - if (!deep_buf_) {\ - if (ctx_->rc != GRN_SUCCESS) {\ - return ctx_->rc;\ - }\ - return GRN_UNKNOWN_ERROR;\ - }\ - }\ - GRN_BULK_REWIND(deep_buf_);\ - grn_ts_vector *vectors = static_cast<grn_ts_vector *>(results);\ - size_t offset = 0;\ - for (size_t i = 0; i < num_records; i++) {\ - grn_obj_get_value(ctx_, column_, records[i].id, deep_buf_);\ - if (ctx_->rc != GRN_SUCCESS) {\ - return ctx_->rc;\ - }\ - size_t size = grn_vector_size(ctx_, deep_buf_);\ - vectors[i].size = size - offset;\ - offset = size;\ - }\ - grn_rc rc = grn_bulk_resize(ctx_, buf_, sizeof(grn_ts_int) * offset);\ - if (rc != GRN_SUCCESS) {\ - return rc;\ - }\ - grn_ts_int *ptr = reinterpret_cast<grn_ts_int *>(GRN_BULK_HEAD(buf_));\ - for (size_t i = 0; i < offset; ++i) {\ - ptr[i] = GRN_ ## type ## _VALUE_AT(deep_buf_, i);\ - }\ - for (size_t i = 0; i < num_records; i++) {\ - vectors[i].ptr = ptr;\ - ptr += vectors[i].size;\ - }\ - return GRN_SUCCESS;\ - } -grn_rc ColumnNode::evaluate_vector_int(const Record *records, - size_t num_records, void *results) { - if (!buf_) { - buf_ = grn_obj_open(ctx_, GRN_UVECTOR, 0, GRN_DB_INT64); - if (!buf_) { - if (ctx_->rc != GRN_SUCCESS) { - return ctx_->rc; - } - return GRN_UNKNOWN_ERROR; - } - } - GRN_BULK_REWIND(buf_); - switch (data_type()) { - GRN_TS_EVALUATE_VECTOR_INT_CASE_BLOCK(INT8) - GRN_TS_EVALUATE_VECTOR_INT_CASE_BLOCK(INT16) - GRN_TS_EVALUATE_VECTOR_INT_CASE_BLOCK(INT32) - GRN_TS_EVALUATE_VECTOR_INT_CASE_BLOCK(UINT8) - GRN_TS_EVALUATE_VECTOR_INT_CASE_BLOCK(UINT16) - GRN_TS_EVALUATE_VECTOR_INT_CASE_BLOCK(UINT32) - default: { - return GRN_UNKNOWN_ERROR; - } - } -} -#undef GRN_TS_EVALUATE_VECTOR_INT_CASE_BLOCK - -grn_rc ColumnNode::evaluate_vector_text(const Record *records, - size_t num_records, void *results) { - if (!deep_buf_) { - deep_buf_ = grn_obj_open(ctx_, GRN_VECTOR, 0, GRN_DB_TEXT); - if (!deep_buf_) { - if (ctx_->rc != GRN_SUCCESS) { - return ctx_->rc; - } - return GRN_UNKNOWN_ERROR; - } - } - GRN_BULK_REWIND(deep_buf_); - grn_ts_vector *vectors = static_cast<grn_ts_vector *>(results); - size_t offset = 0; - for (size_t i = 0; i < num_records; ++i) { - grn_obj_get_value(ctx_, column_, records[i].id, deep_buf_); - if (ctx_->rc != GRN_SUCCESS) { - return ctx_->rc; - } - size_t size = grn_vector_size(ctx_, deep_buf_); - vectors[i].size = size - offset; - offset = size; - } - if (!buf_) { - buf_ = grn_obj_open(ctx_, GRN_BULK, 0, GRN_DB_TEXT); - if (!buf_) { - if (ctx_->rc != GRN_SUCCESS) { - return ctx_->rc; - } - return GRN_UNKNOWN_ERROR; - } - } - grn_rc rc = grn_bulk_resize(ctx_, buf_, sizeof(grn_ts_text) * offset); - if (rc != GRN_SUCCESS) { - return rc; - } - grn_ts_text *texts = reinterpret_cast<grn_ts_text *>(GRN_BULK_HEAD(buf_)); - offset = 0; - for (size_t i = 0; i < num_records; ++i) { - for (size_t j = 0; j < vectors[i].size; ++j) { - texts[offset + j].size = grn_vector_get_element( - ctx_, deep_buf_, offset + j, &texts[offset + j].ptr, NULL, NULL); - } - vectors[i].ptr = &texts[offset]; - offset += vectors[i].size; - } - return GRN_SUCCESS; -} - -// -- OperatorNode -- - -class OperatorNode : public ExpressionNode { - public: - OperatorNode() : ExpressionNode() {} - virtual ~OperatorNode() {} - - ExpressionNodeType type() const { - return GRN_TS_OPERATOR_NODE; - } -}; - -template <DataKind KIND> struct KindTraits; - -template <> struct KindTraits<GRN_TS_BOOL> { - typedef grn_ts_bool Type; - - static grn_ts_bool equal(Type lhs, Type rhs) { - return lhs == rhs; - } - static grn_ts_bool not_equal(Type lhs, Type rhs) { - return lhs != rhs; - } -}; - -template <> struct KindTraits<GRN_TS_INT> { - typedef grn_ts_int Type; - - static grn_ts_bool equal(Type lhs, Type rhs) { - return lhs == rhs; - } - static grn_ts_bool not_equal(Type lhs, Type rhs) { - return lhs != rhs; - } -}; - -template <> struct KindTraits<GRN_TS_FLOAT> { - typedef grn_ts_float Type; - - static grn_ts_bool equal(Type lhs, Type rhs) { - return (lhs <= rhs) && (lhs >= rhs); - } - static grn_ts_bool not_equal(Type lhs, Type rhs) { - return (lhs < rhs) || (lhs > rhs); - } -}; - -template <> struct KindTraits<GRN_TS_TIME> { - typedef grn_ts_time Type; - - static grn_ts_bool equal(Type lhs, Type rhs) { - return lhs == rhs; - } - static grn_ts_bool not_equal(Type lhs, Type rhs) { - return lhs != rhs; - } -}; - -template <> struct KindTraits<GRN_TS_TEXT> { - typedef grn_ts_text Type; - - static grn_ts_bool equal(Type lhs, Type rhs) { - return (lhs.size == rhs.size) && !memcmp(lhs.ptr, rhs.ptr, lhs.size); - } - static grn_ts_bool not_equal(Type lhs, Type rhs) { - return (lhs.size != rhs.size) || memcmp(lhs.ptr, rhs.ptr, lhs.size); - } -}; - -template <> struct KindTraits<GRN_TS_GEO_POINT> { - typedef grn_ts_geo_point Type; - - static grn_ts_bool equal(Type lhs, Type rhs) { - return (lhs.latitude == rhs.latitude) && (lhs.longitude == rhs.longitude); - } - static grn_ts_bool not_equal(Type lhs, Type rhs) { - return (lhs.latitude != rhs.latitude) || (lhs.longitude != rhs.longitude); - } -}; - -template <DataKind KIND> -grn_rc operator_node_evaluate_arg(const Record *records, size_t num_records, - ExpressionNode *arg, - std::vector<char> *arg_values) { - typedef KindTraits<KIND> Traits; - - size_t old_size = arg_values->size() / sizeof(typename Traits::Type); - if (old_size < num_records) try { - arg_values->resize(sizeof(typename Traits::Type) * num_records); - } catch (const std::bad_alloc &) { - return GRN_NO_MEMORY_AVAILABLE; - } - return arg->evaluate(records, num_records, &*arg_values->begin()); -} - -grn_rc operator_node_fill_arg_values(const Record *records, size_t num_records, - ExpressionNode *arg, - std::vector<char> *arg_values) { - size_t value_size = 0; - switch (arg->data_kind()) { - case GRN_TS_BOOL: { - value_size = sizeof(grn_ts_bool); - break; - } - case GRN_TS_INT: { - value_size = sizeof(grn_ts_int); - break; - } - case GRN_TS_FLOAT: { - value_size = sizeof(grn_ts_float); - break; - } - case GRN_TS_TIME: { - value_size = sizeof(grn_ts_time); - break; - } - case GRN_TS_TEXT: { - value_size = sizeof(grn_ts_text); - break; - } - case GRN_TS_GEO_POINT: { - value_size = sizeof(grn_ts_geo_point); - break; - } - default: { - return GRN_INVALID_ARGUMENT; - } - } - size_t old_size = arg_values->size() / value_size; - if (old_size < num_records) try { - arg_values->resize(value_size * num_records); - } catch (const std::bad_alloc &) { - return GRN_NO_MEMORY_AVAILABLE; - } - return arg->evaluate(records, num_records, &*arg_values->begin()); -} - -//// --- UnaryNode --- - -//template <typename T, typename U> -//class UnaryNode : public OperatorNode<T> { -// public: -// explicit UnaryNode(ExpressionNode *arg) -// : OperatorNode<T>(), arg_(static_cast<TypedNode<U> *>(arg)), -// arg_values_() {} -// virtual ~UnaryNode() { -// delete arg_; -// } - -// protected: -// TypedNode<U> *arg_; -// std::vector<U> arg_values_; - -// grn_rc fill_arg_values(const Record *records, size_t num_records) { -// return operator_node_fill_arg_values( -// records, num_records, arg_, &arg_values_); -// } -//}; - -//// --- BinaryNode --- - -//template <typename T, typename U, typename V> -//class BinaryNode : public OperatorNode<T> { -// public: -// BinaryNode(ExpressionNode *arg1, ExpressionNode *arg2) -// : OperatorNode<T>(), -// arg1_(static_cast<TypedNode<U> *>(arg1)), -// arg2_(static_cast<TypedNode<V> *>(arg2)), -// arg1_values_(), arg2_values_() {} -// virtual ~BinaryNode() { -// delete arg1_; -// delete arg2_; -// } - -// protected: -// TypedNode<U> *arg1_; -// TypedNode<V> *arg2_; -// std::vector<U> arg1_values_; -// std::vector<V> arg2_values_; - -// grn_rc fill_arg1_values(const Record *records, size_t num_records) { -// return operator_node_fill_arg_values( -// records, num_records, arg1_, &arg1_values_); -// } -// grn_rc fill_arg2_values(const Record *records, size_t num_records) { -// return operator_node_fill_arg_values( -// records, num_records, arg2_, &arg2_values_); -// } -//}; - -// ---- LogicalNotNode ---- - -class LogicalNotNode : public OperatorNode { - public: - ~LogicalNotNode() { - delete arg_; - } - - static grn_rc open(ExpressionNode *arg, ExpressionNode **node) { - LogicalNotNode *new_node = new (std::nothrow) LogicalNotNode(arg); - if (!new_node) { - return GRN_NO_MEMORY_AVAILABLE; - } - *node = new_node; - return GRN_SUCCESS; - } - - DataKind data_kind() const { - return GRN_TS_BOOL; - } - DataType data_type() const { - return GRN_DB_BOOL; - } - grn_obj *ref_table() const { - return NULL; - } - int dimension() const { - return 0; - } - - grn_rc filter(Record *input, size_t input_size, - Record *output, size_t *output_size); - - grn_rc evaluate(const Record *records, size_t num_records, void *results); - - private: - ExpressionNode *arg_; - std::vector<Record> temp_records_; - - explicit LogicalNotNode(ExpressionNode *arg) - : OperatorNode(), arg_(arg), temp_records_() {} -}; - -grn_rc LogicalNotNode::filter(Record *input, size_t input_size, - Record *output, size_t *output_size) { - if (temp_records_.size() <= input_size) { - try { - temp_records_.resize(input_size + 1); - temp_records_[input_size].id = GRN_ID_NIL; - } catch (const std::bad_alloc &) { - return GRN_NO_MEMORY_AVAILABLE; - } - } - size_t temp_size; - grn_rc rc = - arg_->filter(input, input_size, &*temp_records_.begin(), &temp_size); - if (rc != GRN_SUCCESS) { - return rc; - } - if (temp_size == 0) { - if (input != output) { - for (size_t i = 0; i < input_size; ++i) { - output[i] = input[i]; - } - } - *output_size = input_size; - return GRN_SUCCESS; - } else if (temp_size == input_size) { - *output_size = 0; - return GRN_SUCCESS; - } - - size_t count = 0; - for (size_t i = 0; i < input_size; ++i) { - if (input[i].id != temp_records_[i - count].id) { - output[count] = input[i]; - ++count; - } - } - *output_size = count; - return GRN_SUCCESS; -} - -grn_rc LogicalNotNode::evaluate(const Record *records, size_t num_records, - void *results) { - grn_rc rc = arg_->evaluate(records, num_records, results); - if (rc == GRN_SUCCESS) { - for (size_t i = 0; i < num_records; ++i) { - ((grn_ts_bool *)results)[i] = !((grn_ts_bool *)results)[i]; - } - } - return rc; -} - -// ---- LogicalAndNode ---- - -class LogicalAndNode : public OperatorNode { - public: - ~LogicalAndNode() {} - - static grn_rc open(ExpressionNode *arg1, ExpressionNode *arg2, - ExpressionNode **node); - - DataKind data_kind() const { - return GRN_TS_BOOL; - } - DataType data_type() const { - return GRN_DB_BOOL; - } - grn_obj *ref_table() const { - return NULL; - } - int dimension() const { - return 0; - } - - grn_rc filter(Record *input, size_t input_size, - Record *output, size_t *output_size); - grn_rc evaluate(const Record *records, size_t num_records, void *results); - - private: - ExpressionNode *arg1_; - ExpressionNode *arg2_; - std::vector<grn_ts_bool> arg_values_; - std::vector<Record> temp_records_; - - LogicalAndNode(ExpressionNode *arg1, ExpressionNode *arg2) - : OperatorNode(), arg1_(arg1), arg2_(arg2), arg_values_(), - temp_records_() {} -}; - -grn_rc LogicalAndNode::open(ExpressionNode *arg1, ExpressionNode *arg2, - ExpressionNode **node) { - LogicalAndNode *new_node = new (std::nothrow) LogicalAndNode(arg1, arg2); - if (!new_node) { - return GRN_NO_MEMORY_AVAILABLE; - } - *node = new_node; - return GRN_SUCCESS; -} - -grn_rc LogicalAndNode::filter(Record *input, size_t input_size, - Record *output, size_t *output_size) { - grn_rc rc = arg1_->filter(input, input_size, output, output_size); - if (rc == GRN_SUCCESS) { - rc = arg2_->filter(output, *output_size, output, output_size); - } - return rc; -} - -grn_rc LogicalAndNode::evaluate(const Record *records, size_t num_records, - void *results) { - // Evaluate "arg1" for all the records. - // Then, evaluate "arg2" for non-false records. - grn_rc rc = arg1_->evaluate(records, num_records, results); - if (rc != GRN_SUCCESS) { - return rc; - } - if (temp_records_.size() < num_records) try { - temp_records_.resize(num_records); - } catch (const std::bad_alloc &) { - return GRN_NO_MEMORY_AVAILABLE; - } - size_t count = 0; - for (size_t i = 0; i < num_records; ++i) { - if (((grn_ts_bool *)results)[i]) { - temp_records_[count] = records[i]; - ++count; - } - } - if (count == 0) { - // Nothing to do. - return GRN_SUCCESS; - } - - size_t old_size = arg_values_.size() / sizeof(grn_ts_bool); - if (old_size < num_records) try { - arg_values_.resize(sizeof(grn_ts_bool) * num_records); - } catch (const std::bad_alloc &) { - return GRN_NO_MEMORY_AVAILABLE; - } - rc = arg2_->evaluate(&*temp_records_.begin(), count, &*arg_values_.begin()); - if (rc != GRN_SUCCESS) { - return rc; - } - - // Merge the evaluation results. - count = 0; - for (size_t i = 0; i < num_records; ++i) { - if (((grn_ts_bool *)results)[i]) { - ((grn_ts_bool *)results)[i] = arg_values_[count]; - ++count; - } - } - return GRN_SUCCESS; -} - -// ---- LogicalOrNode ---- - -class LogicalOrNode : public OperatorNode { - public: - ~LogicalOrNode() {} - - static grn_rc open(ExpressionNode *arg1, ExpressionNode *arg2, - ExpressionNode **node); - - DataKind data_kind() const { - return GRN_TS_BOOL; - } - DataType data_type() const { - return GRN_DB_BOOL; - } - grn_obj *ref_table() const { - return NULL; - } - int dimension() const { - return 0; - } - - grn_rc filter(Record *input, size_t input_size, - Record *output, size_t *output_size); - grn_rc evaluate(const Record *records, size_t num_records, void *results); - - private: - ExpressionNode *arg1_; - ExpressionNode *arg2_; - std::vector<grn_ts_bool> arg1_values_; - std::vector<grn_ts_bool> arg2_values_; - std::vector<Record> temp_records_; - - LogicalOrNode(ExpressionNode *arg1, ExpressionNode *arg2) - : OperatorNode(), arg1_(arg1), arg2_(arg2), arg1_values_(), - arg2_values_(), temp_records_() {} - - grn_rc fill_arg_values(ExpressionNode *arg, - const Record *records, size_t num_records, - std::vector<grn_ts_bool> *arg_values); -}; - -grn_rc LogicalOrNode::open(ExpressionNode *arg1, ExpressionNode *arg2, - ExpressionNode **node) { - LogicalOrNode *new_node = new (std::nothrow) LogicalOrNode(arg1, arg2); - if (!new_node) { - return GRN_NO_MEMORY_AVAILABLE; - } - *node = new_node; - return GRN_SUCCESS; -} - -grn_rc LogicalOrNode::filter(Record *input, size_t input_size, - Record *output, size_t *output_size) { - // Evaluate "arg1" for all the records. - // Then, evaluate "arg2" for false records. - grn_rc rc = fill_arg_values(arg1_, input, input_size, &arg1_values_); - if (rc != GRN_SUCCESS) { - return rc; - } - if (temp_records_.size() < input_size) try { - temp_records_.resize(input_size); - } catch (const std::bad_alloc &) { - return GRN_NO_MEMORY_AVAILABLE; - } - size_t count = 0; - for (size_t i = 0; i < input_size; ++i) { - if (!arg1_values_[i]) { - temp_records_[count] = input[i]; - ++count; - } - } - if (count == 0) { - if (input != output) { - for (size_t i = 0; i < input_size; ++i) { - output[i] = input[i]; - } - } - *output_size = input_size; - return GRN_SUCCESS; - } - rc = fill_arg_values(arg2_, &*temp_records_.begin(), count, &arg2_values_); - if (rc != GRN_SUCCESS) { - return rc; - } - - // Merge the evaluation results. - count = 0; - size_t output_count = 0; - for (size_t i = 0; i < input_size; ++i) { - if (arg1_values_[i]) { - output[output_count] = input[i]; - ++output_count; - } else { - if (arg2_values_[count]) { - output[output_count] = input[i]; - ++output_count; - } - ++count; - } - } - *output_size = output_count; - return GRN_SUCCESS; -} - -grn_rc LogicalOrNode::evaluate(const Record *records, size_t num_records, - void *results) { - // Evaluate "arg1" for all the records. - // Then, evaluate "arg2" for false records. - grn_rc rc = arg1_->evaluate(records, num_records, results); - if (rc != GRN_SUCCESS) { - return rc; - } - if (temp_records_.size() < num_records) try { - temp_records_.resize(num_records); - } catch (const std::bad_alloc &) { - return GRN_NO_MEMORY_AVAILABLE; - } - size_t count = 0; - for (size_t i = 0; i < num_records; ++i) { - if (!static_cast<grn_ts_bool *>(results)[i]) { - temp_records_[count] = records[i]; - ++count; - } - } - if (count == 0) { - // Nothing to do. - return GRN_SUCCESS; - } - rc = fill_arg_values(arg2_, &*temp_records_.begin(), count, &arg2_values_); - if (rc != GRN_SUCCESS) { - return rc; - } - - // Merge the evaluation results. - count = 0; - for (size_t i = 0; i < num_records; ++i) { - if (!static_cast<grn_ts_bool *>(results)[i]) { - static_cast<grn_ts_bool *>(results)[i] = arg2_values_[count]; - ++count; - } - } - return GRN_SUCCESS; -} - -grn_rc LogicalOrNode::fill_arg_values(ExpressionNode *arg, - const Record *records, - size_t num_records, - std::vector<grn_ts_bool> *arg_values) { - size_t old_size = arg_values->size() / sizeof(grn_ts_bool); - if (old_size < num_records) try { - arg_values->resize(sizeof(grn_ts_bool) * num_records); - } catch (const std::bad_alloc &) { - return GRN_NO_MEMORY_AVAILABLE; - } - return arg->evaluate(records, num_records, &*arg_values->begin()); -} - -// ---- Comparer ---- - -template <OperatorType OPERATOR, DataKind KIND> struct Comparer; - -template <> struct Comparer<GRN_TS_EQUAL, GRN_TS_BOOL> { - grn_bool operator()(grn_ts_bool lhs, grn_ts_bool rhs) const { - return lhs == rhs; - } -}; -template <> struct Comparer<GRN_TS_EQUAL, GRN_TS_INT> { - grn_bool operator()(grn_ts_int lhs, grn_ts_int rhs) const { - return lhs == rhs; - } -}; -template <> struct Comparer<GRN_TS_EQUAL, GRN_TS_FLOAT> { - grn_bool operator()(grn_ts_float lhs, grn_ts_float rhs) const { - return (lhs <= rhs) && (lhs >= rhs); - } -}; -template <> struct Comparer<GRN_TS_EQUAL, GRN_TS_TIME> { - grn_bool operator()(grn_ts_time lhs, grn_ts_time rhs) const { - return lhs == rhs; - } -}; -template <> struct Comparer<GRN_TS_EQUAL, GRN_TS_TEXT> { - grn_bool operator()(grn_ts_text lhs, grn_ts_text rhs) const { - return (lhs.size == rhs.size) && !std::memcmp(lhs.ptr, rhs.ptr, lhs.size); - } -}; -template <> struct Comparer<GRN_TS_EQUAL, GRN_TS_GEO_POINT> { - grn_bool operator()(grn_ts_geo_point lhs, grn_ts_geo_point rhs) const { - return (lhs.latitude == rhs.latitude) && (lhs.longitude == rhs.longitude); - } -}; - -template <> struct Comparer<GRN_TS_NOT_EQUAL, GRN_TS_BOOL> { - grn_bool operator()(grn_ts_bool lhs, grn_ts_bool rhs) const { - return lhs != rhs; - } -}; -template <> struct Comparer<GRN_TS_NOT_EQUAL, GRN_TS_INT> { - grn_bool operator()(grn_ts_int lhs, grn_ts_int rhs) const { - return lhs != rhs; - } -}; -template <> struct Comparer<GRN_TS_NOT_EQUAL, GRN_TS_FLOAT> { - grn_bool operator()(grn_ts_float lhs, grn_ts_float rhs) const { - return (lhs < rhs) || (lhs > rhs); - } -}; -template <> struct Comparer<GRN_TS_NOT_EQUAL, GRN_TS_TIME> { - grn_bool operator()(grn_ts_time lhs, grn_ts_time rhs) const { - return lhs != rhs; - } -}; -template <> struct Comparer<GRN_TS_NOT_EQUAL, GRN_TS_TEXT> { - grn_bool operator()(grn_ts_text lhs, grn_ts_text rhs) const { - return (lhs.size != rhs.size) || !!std::memcmp(lhs.ptr, rhs.ptr, lhs.size); - } -}; -template <> struct Comparer<GRN_TS_NOT_EQUAL, GRN_TS_GEO_POINT> { - grn_bool operator()(grn_ts_geo_point lhs, grn_ts_geo_point rhs) const { - return (lhs.latitude != rhs.latitude) || (lhs.longitude != rhs.longitude); - } -}; - -template <> struct Comparer<GRN_TS_LESS, GRN_TS_INT> { - grn_bool operator()(grn_ts_int lhs, grn_ts_int rhs) const { - return lhs < rhs; - } -}; -template <> struct Comparer<GRN_TS_LESS, GRN_TS_FLOAT> { - grn_bool operator()(grn_ts_float lhs, grn_ts_float rhs) const { - return lhs < rhs; - } -}; -template <> struct Comparer<GRN_TS_LESS, GRN_TS_TIME> { - grn_bool operator()(grn_ts_time lhs, grn_ts_time rhs) const { - return lhs < rhs; - } -}; -template <> struct Comparer<GRN_TS_LESS, GRN_TS_TEXT> { - grn_bool operator()(grn_ts_text lhs, grn_ts_text rhs) const { - size_t min_size = (lhs.size < rhs.size) ? lhs.size : rhs.size; - int result = std::memcmp(lhs.ptr, rhs.ptr, min_size); - return !result ? (lhs.size < rhs.size) : (result < 0); - } -}; - -template <> struct Comparer<GRN_TS_LESS_EQUAL, GRN_TS_INT> { - grn_bool operator()(grn_ts_int lhs, grn_ts_int rhs) const { - return lhs <= rhs; - } -}; -template <> struct Comparer<GRN_TS_LESS_EQUAL, GRN_TS_FLOAT> { - grn_bool operator()(grn_ts_float lhs, grn_ts_float rhs) const { - return lhs <= rhs; - } -}; -template <> struct Comparer<GRN_TS_LESS_EQUAL, GRN_TS_TIME> { - grn_bool operator()(grn_ts_time lhs, grn_ts_time rhs) const { - return lhs <= rhs; - } -}; -template <> struct Comparer<GRN_TS_LESS_EQUAL, GRN_TS_TEXT> { - grn_bool operator()(grn_ts_text lhs, grn_ts_text rhs) const { - size_t min_size = (lhs.size < rhs.size) ? lhs.size : rhs.size; - int result = std::memcmp(lhs.ptr, rhs.ptr, min_size); - return !result ? (lhs.size <= rhs.size) : (result <= 0); - } -}; - -template <> struct Comparer<GRN_TS_GREATER, GRN_TS_INT> { - grn_bool operator()(grn_ts_int lhs, grn_ts_int rhs) const { - return lhs > rhs; - } -}; -template <> struct Comparer<GRN_TS_GREATER, GRN_TS_FLOAT> { - grn_bool operator()(grn_ts_float lhs, grn_ts_float rhs) const { - return lhs > rhs; - } -}; -template <> struct Comparer<GRN_TS_GREATER, GRN_TS_TIME> { - grn_bool operator()(grn_ts_time lhs, grn_ts_time rhs) const { - return lhs > rhs; - } -}; -template <> struct Comparer<GRN_TS_GREATER, GRN_TS_TEXT> { - grn_bool operator()(grn_ts_text lhs, grn_ts_text rhs) const { - size_t min_size = (lhs.size < rhs.size) ? lhs.size : rhs.size; - int result = std::memcmp(lhs.ptr, rhs.ptr, min_size); - return !result ? (lhs.size > rhs.size) : (result > 0); - } -}; - -template <> struct Comparer<GRN_TS_GREATER_EQUAL, GRN_TS_INT> { - grn_bool operator()(grn_ts_int lhs, grn_ts_int rhs) const { - return lhs >= rhs; - } -}; -template <> struct Comparer<GRN_TS_GREATER_EQUAL, GRN_TS_FLOAT> { - grn_bool operator()(grn_ts_float lhs, grn_ts_float rhs) const { - return lhs >= rhs; - } -}; -template <> struct Comparer<GRN_TS_GREATER_EQUAL, GRN_TS_TIME> { - grn_bool operator()(grn_ts_time lhs, grn_ts_time rhs) const { - return lhs >= rhs; - } -}; -template <> struct Comparer<GRN_TS_GREATER_EQUAL, GRN_TS_TEXT> { - grn_bool operator()(grn_ts_text lhs, grn_ts_text rhs) const { - size_t min_size = (lhs.size < rhs.size) ? lhs.size : rhs.size; - int result = std::memcmp(lhs.ptr, rhs.ptr, min_size); - return !result ? (lhs.size >= rhs.size) : (result >= 0); - } -}; - -// -- ComparerNode -- - -class ComparerNode : public ExpressionNode { - public: - ~ComparerNode() {} - - static grn_rc open(OperatorType operator_type, - ExpressionNode *arg1, ExpressionNode *arg2, - ExpressionNode **node); - - ExpressionNodeType type() const { - return GRN_TS_OPERATOR_NODE; - } - DataKind data_kind() const { - return GRN_TS_BOOL; - } - DataType data_type() const { - return GRN_DB_BOOL; - } - grn_obj *ref_table() const { - return NULL; - } - int dimension() const { - return 0; - } - - grn_rc filter(Record *input, size_t input_size, - Record *output, size_t *output_size); - grn_rc evaluate(const Record *records, size_t num_records, void *results); - - private: - OperatorType operator_type_; - ExpressionNode *arg1_; - ExpressionNode *arg2_; - std::vector<char> arg1_values_; - std::vector<char> arg2_values_; - - ComparerNode(OperatorType operator_type, - ExpressionNode *arg1, ExpressionNode *arg2) - : ExpressionNode(), operator_type_(operator_type), - arg1_(arg1), arg2_(arg2), arg1_values_(), arg2_values_() {} - - grn_rc fill_args(const Record *input, size_t input_size); - - template <OperatorType OPERATOR> - grn_rc filter_eq(Record *input, size_t input_size, - Record *output, size_t *output_size); - template <OperatorType OPERATOR> - grn_rc filter_cmp(Record *input, size_t input_size, - Record *output, size_t *output_size); - template <OperatorType OPERATOR, DataKind KIND> - grn_rc _filter(Record *input, size_t input_size, - Record *output, size_t *output_size); - - template <OperatorType OPERATOR> - grn_rc evaluate_eq(const Record *records, size_t num_records, void *results); - template <OperatorType OPERATOR> - grn_rc evaluate_cmp(const Record *records, size_t num_records, void *results); - template <OperatorType OPERATOR, DataKind KIND> - grn_rc _evaluate(const Record *records, size_t num_records, void *results); -}; - -grn_rc ComparerNode::open(OperatorType operator_type, - ExpressionNode *arg1, ExpressionNode *arg2, - ExpressionNode **node) { - if (arg1->data_kind() != arg2->data_kind()) { - return GRN_INVALID_ARGUMENT; - } - switch (operator_type) { - case GRN_TS_EQUAL: - case GRN_TS_NOT_EQUAL: { - break; - } - case GRN_TS_LESS: - case GRN_TS_LESS_EQUAL: - case GRN_TS_GREATER: - case GRN_TS_GREATER_EQUAL: { - switch (arg1->data_kind()) { - case GRN_TS_INT: - case GRN_TS_FLOAT: - case GRN_TS_TIME: - case GRN_TS_TEXT: { - break; - } - default: { - return GRN_INVALID_ARGUMENT; - } - } - break; - } - default: { - return GRN_INVALID_ARGUMENT; - } - } - ComparerNode *new_node = new (std::nothrow) ComparerNode(operator_type, - arg1, arg2); - if (!new_node) { - return GRN_NO_MEMORY_AVAILABLE; - } - *node = new_node; - return GRN_SUCCESS; -} - -grn_rc ComparerNode::filter(Record *input, size_t input_size, - Record *output, size_t *output_size) { - grn_rc rc = fill_args(input, input_size); - if (rc != GRN_SUCCESS) { - return rc; - } - switch (operator_type_) { - case GRN_TS_EQUAL: { - return filter_eq<GRN_TS_EQUAL>(input, input_size, output, output_size); - } - case GRN_TS_NOT_EQUAL: { - return filter_eq<GRN_TS_NOT_EQUAL>(input, input_size, - output, output_size); - } - case GRN_TS_LESS: { - return filter_cmp<GRN_TS_LESS>(input, input_size, output, output_size); - } - case GRN_TS_LESS_EQUAL: { - return filter_cmp<GRN_TS_LESS_EQUAL>(input, input_size, - output, output_size); - } - case GRN_TS_GREATER: { - return filter_cmp<GRN_TS_GREATER>(input, input_size, - output, output_size); - } - case GRN_TS_GREATER_EQUAL: { - return filter_cmp<GRN_TS_GREATER_EQUAL>(input, input_size, - output, output_size); - } - default: { - return GRN_INVALID_ARGUMENT; - } - } -} - -grn_rc ComparerNode::evaluate(const Record *records, - size_t num_records, void *results) { - grn_rc rc = fill_args(records, num_records); - if (rc != GRN_SUCCESS) { - return rc; - } - switch (operator_type_) { - case GRN_TS_EQUAL: { - return evaluate_eq<GRN_TS_EQUAL>(records, num_records, results); - } - case GRN_TS_NOT_EQUAL: { - return evaluate_eq<GRN_TS_NOT_EQUAL>(records, num_records, results); - } - case GRN_TS_LESS: { - return evaluate_cmp<GRN_TS_LESS>(records, num_records, results); - } - case GRN_TS_LESS_EQUAL: { - return evaluate_cmp<GRN_TS_LESS_EQUAL>(records, num_records, results); - } - case GRN_TS_GREATER: { - return evaluate_cmp<GRN_TS_GREATER>(records, num_records, results); - } - case GRN_TS_GREATER_EQUAL: { - return evaluate_cmp<GRN_TS_GREATER_EQUAL>(records, num_records, results); - } - default: { - return GRN_INVALID_ARGUMENT; - } - } -} - -grn_rc ComparerNode::fill_args(const Record *input, size_t input_size) { - grn_rc rc = operator_node_fill_arg_values(input, input_size, - arg1_, &arg1_values_); - if (rc != GRN_SUCCESS) { - return rc; - } - rc = operator_node_fill_arg_values(input, input_size, - arg2_, &arg2_values_); - if (rc != GRN_SUCCESS) { - return rc; - } - return GRN_SUCCESS; -} - -template <OperatorType OPERATOR> -grn_rc ComparerNode::filter_eq(Record *input, size_t input_size, - Record *output, size_t *output_size) { - switch (arg1_->data_kind()) { - case GRN_TS_BOOL: { - return _filter<OPERATOR, GRN_TS_BOOL>(input, input_size, - output, output_size); - } - case GRN_TS_INT: { - return _filter<OPERATOR, GRN_TS_INT>(input, input_size, - output, output_size); - } - case GRN_TS_FLOAT: { - return _filter<OPERATOR, GRN_TS_FLOAT>(input, input_size, - output, output_size); - } - case GRN_TS_TIME: { - return _filter<OPERATOR, GRN_TS_TIME>(input, input_size, - output, output_size); - } - case GRN_TS_TEXT: { - return _filter<OPERATOR, GRN_TS_TEXT>(input, input_size, - output, output_size); - } - case GRN_TS_GEO_POINT: { - return _filter<OPERATOR, GRN_TS_GEO_POINT>(input, input_size, - output, output_size); - } - default: { - return GRN_OPERATION_NOT_SUPPORTED; - } - } -} - -template <OperatorType OPERATOR> -grn_rc ComparerNode::filter_cmp(Record *input, size_t input_size, - Record *output, size_t *output_size) { - switch (arg1_->data_kind()) { - case GRN_TS_INT: { - return _filter<OPERATOR, GRN_TS_INT>(input, input_size, - output, output_size); - } - case GRN_TS_FLOAT: { - return _filter<OPERATOR, GRN_TS_FLOAT>(input, input_size, - output, output_size); - } - case GRN_TS_TIME: { - return _filter<OPERATOR, GRN_TS_TIME>(input, input_size, - output, output_size); - } - case GRN_TS_TEXT: { - return _filter<OPERATOR, GRN_TS_TEXT>(input, input_size, - output, output_size); - } - default: { - return GRN_OPERATION_NOT_SUPPORTED; - } - } -} - -template <OperatorType OPERATOR, DataKind KIND> -grn_rc ComparerNode::_filter(Record *input, size_t input_size, - Record *output, size_t *output_size) { - typedef KindTraits<KIND> Traits; - typedef typename Traits::Type Type; - Type *input1 = reinterpret_cast<Type *>(&*arg1_values_.begin()); - Type *input2 = reinterpret_cast<Type *>(&*arg2_values_.begin()); - size_t count = 0; - for (size_t i = 0; i < input_size; ++i) { - if (Comparer<OPERATOR, KIND>()(input1[i], input2[i])) { - output[count] = input[i]; - ++count; - } - } - *output_size = count; - return GRN_SUCCESS; -} - -template <OperatorType OPERATOR> -grn_rc ComparerNode::evaluate_eq(const Record *records, size_t num_records, - void *results) { - switch (arg1_->data_kind()) { - case GRN_TS_BOOL: { - return _evaluate<OPERATOR, GRN_TS_BOOL>(records, num_records, results); - } - case GRN_TS_INT: { - return _evaluate<OPERATOR, GRN_TS_INT>(records, num_records, results); - } - case GRN_TS_FLOAT: { - return _evaluate<OPERATOR, GRN_TS_FLOAT>(records, num_records, results); - } - case GRN_TS_TIME: { - return _evaluate<OPERATOR, GRN_TS_TIME>(records, num_records, results); - } - case GRN_TS_TEXT: { - return _evaluate<OPERATOR, GRN_TS_TEXT>(records, num_records, results); - } - case GRN_TS_GEO_POINT: { - return _evaluate<OPERATOR, GRN_TS_GEO_POINT>(records, num_records, - results); - } - default: { - return GRN_OPERATION_NOT_SUPPORTED; - } - } -} - -template <OperatorType OPERATOR> -grn_rc ComparerNode::evaluate_cmp(const Record *records, size_t num_records, - void *results) { - switch (arg1_->data_kind()) { - case GRN_TS_INT: { - return _evaluate<OPERATOR, GRN_TS_INT>(records, num_records, results); - } - case GRN_TS_FLOAT: { - return _evaluate<OPERATOR, GRN_TS_FLOAT>(records, num_records, results); - } - case GRN_TS_TIME: { - return _evaluate<OPERATOR, GRN_TS_TIME>(records, num_records, results); - } - case GRN_TS_TEXT: { - return _evaluate<OPERATOR, GRN_TS_TEXT>(records, num_records, results); - } - default: { - return GRN_OPERATION_NOT_SUPPORTED; - } - } -} - -template <OperatorType OPERATOR, DataKind KIND> -grn_rc ComparerNode::_evaluate(const Record *records, size_t num_records, - void *results) { - typedef KindTraits<KIND> Traits; - typedef typename Traits::Type Type; - Type *input1 = reinterpret_cast<Type *>(&*arg1_values_.begin()); - Type *input2 = reinterpret_cast<Type *>(&*arg2_values_.begin()); - grn_ts_bool *output = static_cast<grn_ts_bool *>(results); - for (size_t i = 0; i < num_records; ++i) { - output[i] = Comparer<OPERATOR, KIND>()(input1[i], input2[i]); - } - return GRN_SUCCESS; -} - -// -- ExpressionToken -- - -enum ExpressionTokenType { - DUMMY_TOKEN, - CONSTANT_TOKEN, - NAME_TOKEN, - UNARY_OPERATOR_TOKEN, - BINARY_OPERATOR_TOKEN, - DEREFERENCE_TOKEN, - BRACKET_TOKEN -}; - -enum ExpressionBracketType { - LEFT_ROUND_BRACKET, - RIGHT_ROUND_BRACKET, - LEFT_SQUARE_BRACKET, - RIGHT_SQUARE_BRACKET -}; - -// TODO: std::string should not be used. -class ExpressionToken { - public: - ExpressionToken() : string_(), type_(DUMMY_TOKEN), dummy_(0), priority_(0) {} - ExpressionToken(const std::string &string, ExpressionTokenType token_type) - : string_(string), type_(token_type), dummy_(0), priority_(0) {} - ExpressionToken(const std::string &string, - ExpressionBracketType bracket_type) - : string_(string), type_(BRACKET_TOKEN), bracket_type_(bracket_type), - priority_(0) {} - ExpressionToken(const std::string &string, OperatorType operator_type) - : string_(string), type_(get_operator_token_type(operator_type)), - operator_type_(operator_type), - priority_(get_operator_priority(operator_type)) {} - - const std::string &string() const { - return string_; - } - ExpressionTokenType type() const { - return type_; - } - ExpressionBracketType bracket_type() const { - return bracket_type_; - } - OperatorType operator_type() const { - return operator_type_; - } - int priority() const { - return priority_; - } - - private: - std::string string_; - ExpressionTokenType type_; - union { - int dummy_; - ExpressionBracketType bracket_type_; - OperatorType operator_type_; - }; - int priority_; - - static ExpressionTokenType get_operator_token_type( - OperatorType operator_type); - static int get_operator_priority(OperatorType operator_type); -}; - -ExpressionTokenType ExpressionToken::get_operator_token_type( - OperatorType operator_type) { - switch (operator_type) { - case GRN_TS_LOGICAL_NOT: { - return UNARY_OPERATOR_TOKEN; - } - case GRN_TS_LOGICAL_AND: - case GRN_TS_LOGICAL_OR: - case GRN_TS_EQUAL: - case GRN_TS_NOT_EQUAL: - case GRN_TS_LESS: - case GRN_TS_LESS_EQUAL: - case GRN_TS_GREATER: - case GRN_TS_GREATER_EQUAL: { - return BINARY_OPERATOR_TOKEN; - } - default: { - // TODO: ERROR_TOKEN or something should be used...? - // Or, default should be removed? - return DUMMY_TOKEN; - } - } -} - -int ExpressionToken::get_operator_priority( - OperatorType operator_type) { - switch (operator_type) { - case GRN_TS_LOGICAL_NOT: { -// case GRN_OP_BITWISE_NOT: -// case GRN_OP_POSITIVE: -// case GRN_OP_NEGATIVE: -// case GRN_OP_TO_INT: -// case GRN_OP_TO_FLOAT: { - return 3; - } - case GRN_TS_LOGICAL_AND: { - return 13; - } - case GRN_TS_LOGICAL_OR: { - return 14; - } - case GRN_TS_EQUAL: - case GRN_TS_NOT_EQUAL: { - return 9; - } - case GRN_TS_LESS: - case GRN_TS_LESS_EQUAL: - case GRN_TS_GREATER: - case GRN_TS_GREATER_EQUAL: { - return 8; - } -// case GRN_OP_BITWISE_AND: { -// return 10; -// } -// case GRN_OP_BITWISE_OR: { -// return 12; -// } -// case GRN_OP_BITWISE_XOR: { -// return 11; -// } -// case GRN_OP_PLUS: -// case GRN_OP_MINUS: { -// return 6; -// } -// case GRN_OP_MULTIPLICATION: -// case GRN_OP_DIVISION: -// case GRN_OP_MODULUS: { -// return 5; -// } -// case GRN_OP_STARTS_WITH: -// case GRN_OP_ENDS_WITH: -// case GRN_OP_CONTAINS: { -// return 7; -// } -// case GRN_OP_SUBSCRIPT: { -// return 2; -// } - default: { - return 100; - } - } -} - -// -- ExpressionParser -- - -class ExpressionParser { - public: - static grn_rc parse(grn_ctx *ctx, grn_obj *table, - const char *query, size_t query_size, Expression **expression); - - private: - grn_ctx *ctx_; - grn_obj *table_; - std::vector<ExpressionToken> tokens_; - std::vector<ExpressionToken> stack_; - Expression *expression_; - - ExpressionParser(grn_ctx *ctx, grn_obj *table) - : ctx_(ctx), table_(table), tokens_(), stack_(), expression_(NULL) {} - ~ExpressionParser() { - delete expression_; - } - - grn_rc tokenize(const char *query, size_t query_size); - grn_rc compose(); - grn_rc push_token(const ExpressionToken &token); -}; - -grn_rc ExpressionParser::parse(grn_ctx *ctx, grn_obj *table, - const char *query, size_t query_size, Expression **expression) { - ExpressionParser *parser = new (std::nothrow) ExpressionParser(ctx, table); - if (!parser) { - return GRN_NO_MEMORY_AVAILABLE; - } - grn_rc rc = parser->tokenize(query, query_size); - if (rc == GRN_SUCCESS) { - rc = parser->compose(); - if (rc == GRN_SUCCESS) { - *expression = parser->expression_; - parser->expression_ = NULL; - } - } - delete parser; - return rc; -} - -grn_rc ExpressionParser::tokenize(const char *query, size_t query_size) { - const char *rest = query; - size_t rest_size = query_size; - while (rest_size != 0) { - // Ignore white-space characters. - size_t pos; - for (pos = 0; pos < rest_size; ++pos) { - if (!std::isspace(static_cast<uint8_t>(rest[pos]))) { - break; - } - } - rest += pos; - rest_size -= pos; - switch (rest[0]) { - case '!': { -// if ((rest_size >= 2) && (rest[1] == '=')) { -// tokens_.push_back(ExpressionToken("!=", GRN_TS_NOT_EQUAL)); -// rest += 2; -// rest_size -= 2; -// } else { - tokens_.push_back(ExpressionToken("!", GRN_TS_LOGICAL_NOT)); - ++rest; - --rest_size; -// } - break; - } -//// case '~': { -//// tokens_.push_back(ExpressionToken("~", GRN_OP_BITWISE_NOT)); -//// rest = rest.substring(1); -//// break; -//// } - case '=': { - if ((rest_size >= 2) && (rest[1] == '=')) { - tokens_.push_back(ExpressionToken("==", GRN_TS_EQUAL)); - rest += 2; - rest_size -= 2; - } else { - return GRN_INVALID_ARGUMENT; - } - break; - } - case '<': { - if ((rest_size >= 2) && (rest[1] == '=')) { - tokens_.push_back(ExpressionToken("<=", GRN_TS_LESS_EQUAL)); - rest += 2; - rest_size -= 2; - } else { - tokens_.push_back(ExpressionToken("<", GRN_TS_LESS)); - ++rest; - --rest_size; - } - break; - } - case '>': { - if ((rest_size >= 2) && (rest[1] == '=')) { - tokens_.push_back(ExpressionToken(">=", GRN_TS_GREATER_EQUAL)); - rest += 2; - rest_size -= 2; - } else { - tokens_.push_back(ExpressionToken(">", GRN_TS_GREATER)); - ++rest; - --rest_size; - } - break; - } - case '&': { - if ((rest_size >= 2) && (rest[1] == '&')) { - tokens_.push_back(ExpressionToken("&&", GRN_TS_LOGICAL_AND)); - rest += 2; - rest_size -= 2; - } else { -// tokens_.push_back(ExpressionToken("&", GRN_OP_BITWISE_AND)); -// ++rest; -// --rest_size; - return GRN_INVALID_ARGUMENT; - } - break; - } - case '|': { - if ((rest_size >= 2) && (rest[1] == '|')) { - tokens_.push_back(ExpressionToken("||", GRN_TS_LOGICAL_OR)); - rest += 2; - rest_size -= 2; - } else { -// tokens_.push_back(ExpressionToken("|", GRN_OP_BITWISE_OR)); -// ++rest; -// --rest_size; - return GRN_INVALID_ARGUMENT; - } - break; - } -// case '^': { -// tokens_.push_back(ExpressionToken("^", GRN_OP_BITWISE_XOR)); -// rest = rest.substring(1); -// break; -// } -// case '+': { -// tokens_.push_back(ExpressionToken("+", GRN_OP_PLUS)); -// rest = rest.substring(1); -// break; -// } -// case '-': { -// tokens_.push_back(ExpressionToken("-", GRN_OP_MINUS)); -// rest = rest.substring(1); -// break; -// } -// case '*': { -// tokens_.push_back(ExpressionToken("*", GRN_OP_MULTIPLICATION)); -// rest = rest.substring(1); -// break; -// } -// case '/': { -// tokens_.push_back(ExpressionToken("/", GRN_OP_DIVISION)); -// rest = rest.substring(1); -// break; -// } -// case '%': { -// tokens_.push_back(ExpressionToken("%", GRN_OP_MODULUS)); -// rest = rest.substring(1); -// break; -// } -// case '@': { -// if ((rest_size >= 2) && (rest[1] == '^')) { -// tokens_.push_back(ExpressionToken("@^", GRN_OP_STARTS_WITH)); -// rest = rest.substring(2); -// } else if ((rest_size >= 2) && (rest[1] == '$')) { -// tokens_.push_back(ExpressionToken("@$", GRN_OP_ENDS_WITH)); -// rest = rest.substring(2); -// } else { -// tokens_.push_back(ExpressionToken("@", GRN_OP_CONTAINS)); -// rest = rest.substring(1); -// } -// break; -// } -// case '.': { -// tokens_.push_back(ExpressionToken(".", DEREFERENCE_TOKEN)); -// rest = rest.substring(1); -// break; -// } - case '(': { - tokens_.push_back(ExpressionToken("(", LEFT_ROUND_BRACKET)); - ++rest; - --rest_size; - break; - } - case ')': { - tokens_.push_back(ExpressionToken(")", RIGHT_ROUND_BRACKET)); - ++rest; - --rest_size; - break; - } -// case '[': { -// tokens_.push_back(ExpressionToken("[", LEFT_SQUARE_BRACKET)); -// rest = rest.substring(1); -// break; -// } -// case ']': { -// tokens_.push_back(ExpressionToken("]", RIGHT_SQUARE_BRACKET)); -// rest = rest.substring(1); -// break; -// } - case '"': { - for (pos = 1; pos < rest_size; ++pos) { - if (rest[pos] == '\\') { - if (pos == rest_size) { - break; - } - ++pos; - } else if (rest[pos] == '"') { - break; - } - } - if (pos == rest_size) { - return GRN_INVALID_ARGUMENT; - } - tokens_.push_back( - ExpressionToken(std::string(rest + 1, pos - 1), CONSTANT_TOKEN)); - rest += pos + 1; - rest_size -= pos + 1; - break; - } - case '0' ... '9': { - // TODO: Improve this. - for (pos = 1; pos < rest_size; ++pos) { - if (!std::isdigit(static_cast<uint8_t>(rest[pos]))) { - break; - } - } - tokens_.push_back( - ExpressionToken(std::string(rest, pos), CONSTANT_TOKEN)); - rest += pos; - rest_size -= pos; - break; - } - case '_': - case 'A' ... 'Z': - case 'a' ... 'z': { - // TODO: Improve this. - for (pos = 1; pos < rest_size; ++pos) { - if ((rest[pos] != '_') && (!std::isalnum(rest[pos]))) { - break; - } - } - std::string token(rest, pos); - if ((token == "true") || (token == "false")) { - tokens_.push_back(ExpressionToken(token, CONSTANT_TOKEN)); - } else { - tokens_.push_back(ExpressionToken(token, NAME_TOKEN)); - } - rest += pos; - rest_size -= pos; - break; - } - default: { - return GRN_INVALID_ARGUMENT; - } - } - } - return GRN_SUCCESS; -} - -grn_rc ExpressionParser::compose() { - if (tokens_.size() == 0) { - return GRN_INVALID_ARGUMENT; - } - expression_ = new (std::nothrow) Expression(ctx_, table_); - grn_rc rc = push_token(ExpressionToken("(", LEFT_ROUND_BRACKET)); - if (rc == GRN_SUCCESS) { - for (size_t i = 0; i < tokens_.size(); ++i) { - rc = push_token(tokens_[i]); - if (rc != GRN_SUCCESS) { - break; - } - } - if (rc == GRN_SUCCESS) { - rc = push_token(ExpressionToken(")", RIGHT_ROUND_BRACKET)); - } - } - return rc; -} - -grn_rc ExpressionParser::push_token(const ExpressionToken &token) { - grn_rc rc = GRN_SUCCESS; - switch (token.type()) { - case DUMMY_TOKEN: { - if ((stack_.size() != 0) && (stack_.back().type() == DUMMY_TOKEN)) { - return GRN_INVALID_ARGUMENT; - } - stack_.push_back(token); - break; - } - case CONSTANT_TOKEN: { - grn_obj *obj; - const std::string string = token.string(); - if (std::isdigit(static_cast<uint8_t>(string[0]))) { - if (string.find_first_of('.') == string.npos) { - obj = grn_obj_open(ctx_, GRN_BULK, 0, GRN_DB_INT64); - if (obj) { - GRN_INT64_SET(ctx_, obj, strtoll(string.c_str(), NULL, 10)); - } - } else { - obj = grn_obj_open(ctx_, GRN_BULK, 0, GRN_DB_FLOAT); - if (obj) { - GRN_FLOAT_SET(ctx_, obj, strtod(string.c_str(), NULL)); - } - } - } else if (string == "true") { - obj = grn_obj_open(ctx_, GRN_BULK, 0, GRN_DB_BOOL); - if (obj) { - GRN_BOOL_SET(ctx_, obj, GRN_TRUE); - } - } else if (string == "false") { - obj = grn_obj_open(ctx_, GRN_BULK, 0, GRN_DB_BOOL); - if (obj) { - GRN_BOOL_SET(ctx_, obj, GRN_FALSE); - } - } else { - obj = grn_obj_open(ctx_, GRN_BULK, 0, GRN_DB_TEXT); - if (obj) { - GRN_TEXT_SET(ctx_, obj, string.data(), string.size()); - } - } - if (!obj) { - if (ctx_->rc != GRN_SUCCESS) { - return ctx_->rc; - } - return GRN_UNKNOWN_ERROR; - } - rc = push_token(ExpressionToken(string, DUMMY_TOKEN)); - if (rc == GRN_SUCCESS) { - rc = expression_->push_object(obj); - } - if (rc != GRN_SUCCESS) { - grn_obj_close(ctx_, obj); - } - break; - } - case NAME_TOKEN: { - rc = push_token(ExpressionToken(token.string(), DUMMY_TOKEN)); - if (rc == GRN_SUCCESS) { - grn_obj *column = grn_obj_column( - ctx_, table_, token.string().data(), token.string().size()); - rc = expression_->push_object(column); - } - break; - } - case UNARY_OPERATOR_TOKEN: { - if ((stack_.size() != 0) && (stack_.back().type() == DUMMY_TOKEN)) { - // A unary operator must not follow an operand. - return GRN_INVALID_ARGUMENT; - } - stack_.push_back(token); - break; - } - case BINARY_OPERATOR_TOKEN: { - if ((stack_.size() == 0) || (stack_.back().type() != DUMMY_TOKEN)) { - // A binary operator must follow an operand. - return GRN_INVALID_ARGUMENT; - } - // Apply previous operators if those are prior to the new operator. - while (stack_.size() >= 2) { - ExpressionToken operator_token = stack_[stack_.size() - 2]; -// if (operator_token.type() == DEREFERENCE_TOKEN) { -// expression_->end_subexpression(); -// stack_.pop_back(); -// stack_.pop_back(); -// push_token(ExpressionToken("", DUMMY_TOKEN)); -// } else if (operator_token.type() == UNARY_OPERATOR_TOKEN) { - if (operator_token.type() == UNARY_OPERATOR_TOKEN) { - rc = expression_->push_operator(operator_token.operator_type()); - if (rc == GRN_SUCCESS) { - stack_.pop_back(); - stack_.pop_back(); - rc = push_token(ExpressionToken("", DUMMY_TOKEN)); - } - } else if ((operator_token.type() == BINARY_OPERATOR_TOKEN) && - (operator_token.priority() <= token.priority())) { - rc = expression_->push_operator(operator_token.operator_type()); - if (rc == GRN_SUCCESS) { - stack_.pop_back(); - stack_.pop_back(); - stack_.pop_back(); - rc = push_token(ExpressionToken("", DUMMY_TOKEN)); - } - } else { - break; - } - if (rc != GRN_SUCCESS) { - return rc; - } - } - stack_.push_back(token); - break; - } -// case DEREFERENCE_TOKEN: { -// builder_->begin_subexpression(); -// stack_.pop_back(); -// stack_.push_back(token); -// break; -// } - case BRACKET_TOKEN: { - if (token.bracket_type() == LEFT_ROUND_BRACKET) { - // A left round bracket must not follow a dummy. - if ((stack_.size() != 0) && (stack_.back().type() == DUMMY_TOKEN)) { - return GRN_INVALID_ARGUMENT; - } - stack_.push_back(token); - } else if (token.bracket_type() == RIGHT_ROUND_BRACKET) { - // A right round bracket must follow a dummy. - // A left round bracket must exist before a right round bracket. - if ((stack_.size() < 2) || (stack_.back().type() != DUMMY_TOKEN)) { - return GRN_INVALID_ARGUMENT; - } - // Apply operators in brackets. - while (stack_.size() >= 2) { - ExpressionToken operator_token = stack_[stack_.size() - 2]; -// if (operator_token.type() == DEREFERENCE_TOKEN) { -// rc = expression_->end_subexpression(); -// if (rc == GRN_SUCCESS) { -// stack_.pop_back(); -// stack_.pop_back(); -// rc = push_token(ExpressionToken("", DUMMY_TOKEN)); -// } -// } else if (operator_token.type() == UNARY_OPERATOR_TOKEN) { - if (operator_token.type() == UNARY_OPERATOR_TOKEN) { - rc = expression_->push_operator(operator_token.operator_type()); - if (rc == GRN_SUCCESS) { - stack_.pop_back(); - stack_.pop_back(); - rc = push_token(ExpressionToken("", DUMMY_TOKEN)); - } - } else if (operator_token.type() == BINARY_OPERATOR_TOKEN) { - rc = expression_->push_operator(operator_token.operator_type()); - if (rc == GRN_SUCCESS) { - stack_.pop_back(); - stack_.pop_back(); - stack_.pop_back(); - rc = push_token(ExpressionToken("", DUMMY_TOKEN)); - } - } else { - break; - } - if (rc != GRN_SUCCESS) { - return rc; - } - } - if ((stack_.size() < 2) || - (stack_[stack_.size() - 2].type() != BRACKET_TOKEN) || - (stack_[stack_.size() - 2].bracket_type() != LEFT_ROUND_BRACKET)) { - return GRN_INVALID_ARGUMENT; - } - stack_[stack_.size() - 2] = stack_.back(); - stack_.pop_back(); -// } else if (token.bracket_type() == LEFT_SQUARE_BRACKET) { -// // A left square bracket must follow a dummy. -// if ((stack_.size() == 0) || (stack_.back().type() != DUMMY_TOKEN)) { -// return GRN_INVALID_ARGUMENT; -// } -// stack_.push_back(token); -// } else if (token.bracket_type() == RIGHT_SQUARE_BRACKET) { -// // A right round bracket must follow a dummy. -// // A left round bracket must exist before a right round bracket. -// if ((stack_.size() < 2) || (stack_.back().type() != DUMMY_TOKEN)) { -// return GRN_INVALID_ARGUMENT; -// } -// // Apply operators in bracket. -// while (stack_.size() >= 2) { -// ExpressionToken operator_token = stack_[stack_.size() - 2]; -// if (operator_token.type() == DEREFERENCE_TOKEN) { -// builder_->end_subexpression(); -// stack_.pop_back(); -// stack_.pop_back(); -// push_token(ExpressionToken("", DUMMY_TOKEN)); -// } else if (operator_token.type() == UNARY_OPERATOR_TOKEN) { -// builder_->push_operator(operator_token.operator_type()); -// stack_.pop_back(); -// stack_.pop_back(); -// push_token(ExpressionToken("", DUMMY_TOKEN)); -// } else if (operator_token.type() == BINARY_OPERATOR_TOKEN) { -// builder_->push_operator(operator_token.operator_type()); -// stack_.pop_back(); -// stack_.pop_back(); -// stack_.pop_back(); -// push_token(ExpressionToken("", DUMMY_TOKEN)); -// } else { -// break; -// } -// } -// if ((stack_.size() < 2) || -// (stack_[stack_.size() - 2].type() != BRACKET_TOKEN) || -// (stack_[stack_.size() - 2].bracket_type() != LEFT_SQUARE_BRACKET)) { -// return GRN_INVALID_ARGUMENT; -// } -// stack_.pop_back(); -// stack_.pop_back(); -// builder_->push_operator(GRNXX_SUBSCRIPT); - } else { - return GRN_INVALID_ARGUMENT; - } - break; - } - default: { - return GRN_INVALID_ARGUMENT; - } - } - return rc; -} - -// -- Expression -- - -Expression::Expression(grn_ctx *ctx, grn_obj *table) - : ctx_(ctx), table_(table), type_(GRN_TS_INCOMPLETE), - output_type_(GRN_DB_VOID), stack_() {} - -Expression::~Expression() { - for (size_t i = 0; i < stack_.size(); ++i) { - delete stack_[i]; - } -} - -grn_rc Expression::open( - grn_ctx *ctx, grn_obj *table, Expression **expression) { - if (!ctx || !grn_obj_is_table(ctx, table) || !expression) { - return GRN_INVALID_ARGUMENT; - } - Expression *new_expression = new (std::nothrow) Expression(ctx, table); - if (!new_expression) { - return GRN_NO_MEMORY_AVAILABLE; - } - *expression = new_expression; - return GRN_SUCCESS; -} - -grn_rc Expression::parse(grn_ctx *ctx, grn_obj *table, - const char *query, size_t query_size, Expression **expression) { - if (!ctx || !grn_obj_is_table(ctx, table) || - !query || (query_size == 0) || !expression) { - return GRN_INVALID_ARGUMENT; - } - return ExpressionParser::parse(ctx, table, query, query_size, expression); -} - -DataKind Expression::data_kind() const { - ExpressionNode *root = this->root(); - return root ? root->data_kind() : GRN_TS_VOID; -} - -DataType Expression::data_type() const { - ExpressionNode *root = this->root(); - return root ? root->data_type() : GRN_ID_NIL; -} - -DataType Expression::output_type() const { - return output_type_; -} - -int Expression::dimension() const { - ExpressionNode *root = this->root(); - return root ? root->dimension() : 0; -} - -grn_rc Expression::push_object(grn_obj *obj) { - if (!obj) { - return GRN_INVALID_ARGUMENT; - } - grn_rc rc = GRN_UNKNOWN_ERROR; - switch (obj->header.type) { - case GRN_BULK: - case GRN_UVECTOR: - case GRN_VECTOR: { - rc = push_constant_object(obj); - break; - } - case GRN_ACCESSOR: - case GRN_COLUMN_FIX_SIZE: - case GRN_COLUMN_VAR_SIZE: { - rc = push_column_object(obj); - break; - } - default: { - return GRN_INVALID_ARGUMENT; - } - } - if (rc == GRN_SUCCESS) { - update_type(); - } - return rc; -} - -grn_rc Expression::push_operator(OperatorType operator_type) { - grn_rc rc = GRN_UNKNOWN_ERROR; - ExpressionNode *node; - switch (operator_type) { - case GRN_TS_LOGICAL_NOT: { - if (stack_.size() < 1) { - return GRN_INVALID_FORMAT; - } - ExpressionNode *arg = stack_[stack_.size() - 1]; - rc = create_unary_node(operator_type, arg, &node); - if (rc == GRN_SUCCESS) { - stack_.resize(stack_.size() - 1); - } - break; - } - case GRN_TS_LOGICAL_AND: - case GRN_TS_LOGICAL_OR: - case GRN_TS_EQUAL: - case GRN_TS_NOT_EQUAL: - case GRN_TS_LESS: - case GRN_TS_LESS_EQUAL: - case GRN_TS_GREATER: - case GRN_TS_GREATER_EQUAL: { - if (stack_.size() < 2) { - return GRN_INVALID_FORMAT; - } - ExpressionNode *arg1 = stack_[stack_.size() - 2]; - ExpressionNode *arg2 = stack_[stack_.size() - 1]; - rc = create_binary_node(operator_type, arg1, arg2, &node); - if (rc == GRN_SUCCESS) { - stack_.resize(stack_.size() - 2); - } - break; - } - default: { - return GRN_INVALID_ARGUMENT; - } - } - if (rc == GRN_SUCCESS) { - stack_.push_back(node); - update_type(); - } - return rc; -} - -grn_rc Expression::filter( - Record *input, size_t input_size, - Record *output, size_t *output_size) { - if ((!input && (input_size != 0)) || - ((output > input) && (output < (input + input_size))) || !output_size) { - return GRN_INVALID_ARGUMENT; - } - ExpressionNode *root = this->root(); - if (!root) { - return GRN_UNKNOWN_ERROR; - } - if (!output) { - output = input; - } - size_t total_output_size = 0; - while (input_size > 0) { - size_t batch_input_size = GRN_TS_MAX_BATCH_SIZE; - if (input_size < batch_input_size) { - batch_input_size = input_size; - } - size_t batch_output_size; - grn_rc rc = root->filter( - input, batch_input_size, output, &batch_output_size); - if (rc != GRN_SUCCESS) { - return rc; - } - input += batch_input_size; - input_size -= batch_input_size; - output += batch_output_size; - total_output_size += batch_output_size; - } - *output_size = total_output_size; - return GRN_SUCCESS; -} - -grn_rc Expression::adjust(Record *records, size_t num_records) { - if (!records && (num_records != 0)) { - return GRN_INVALID_ARGUMENT; - } - ExpressionNode *root = this->root(); - if (!root) { - return GRN_UNKNOWN_ERROR; - } - while (num_records > 0) { - size_t batch_size = GRN_TS_MAX_BATCH_SIZE; - if (num_records < batch_size) { - batch_size = num_records; - } - grn_rc rc = root->adjust(records, batch_size); - if (rc != GRN_SUCCESS) { - return rc; - } - records += batch_size; - num_records -= batch_size; - } - return GRN_SUCCESS; -} - -grn_rc Expression::evaluate(const Record *records, size_t num_records, - void *results) { - if ((!records || !results) && (num_records != 0)) { - return GRN_INVALID_ARGUMENT; - } - ExpressionNode *root = this->root(); - if (!root) { - return GRN_UNKNOWN_ERROR; - } - // FIXME: Records should be processed per block. - // However, the contents of old blocks will be lost. - return root->evaluate(records, num_records, results); -} - -ExpressionNode *Expression::root() const { - if (stack_.size() != 1) { - return NULL; - } - return stack_.front(); -} - -void Expression::update_type() { - ExpressionNode *root = this->root(); - if (!root) { - type_ = GRN_TS_INCOMPLETE; - } else { - switch (root->type()) { - case GRN_TS_ID_NODE: { - type_ = GRN_TS_ID; - break; - } - case GRN_TS_SCORE_NODE: { - type_ = GRN_TS_SCORE; - break; - } - case GRN_TS_CONSTANT_NODE: { - type_ = GRN_TS_CONSTANT; - break; - } - case GRN_TS_COLUMN_NODE: - case GRN_TS_OPERATOR_NODE: { - type_ = GRN_TS_VARIABLE; - break; - } - default: { - type_ = GRN_TS_INCOMPLETE; - break; - } - } - output_type_ = data_type(); - } -} - -grn_rc Expression::push_constant_object(grn_obj *obj) { - ExpressionNode *node; - grn_rc rc = ConstantNode::open(ctx_, obj, &node); - if (rc == GRN_SUCCESS) try { - stack_.push_back(node); - } catch (const std::bad_alloc &) { - delete node; - return GRN_NO_MEMORY_AVAILABLE; - } - return rc; -} - -grn_rc Expression::push_column_object(grn_obj *obj) { - if ((obj->header.type == GRN_COLUMN_FIX_SIZE) || - (obj->header.type == GRN_COLUMN_VAR_SIZE)) { - grn_obj *owner_table = grn_column_table(ctx_, obj); - if (owner_table != table_) { - return GRN_INVALID_ARGUMENT; - } - } - ExpressionNode *node; - grn_rc rc = ColumnNode::open(ctx_, obj, &node); - if (rc == GRN_SUCCESS) try { - stack_.push_back(node); - } catch (const std::bad_alloc &) { - delete node; - return GRN_NO_MEMORY_AVAILABLE; - } - return rc; -} - -grn_rc Expression::create_unary_node(OperatorType operator_type, - ExpressionNode *arg, ExpressionNode **node) { - grn_rc rc = GRN_SUCCESS; - switch (operator_type) { - case GRN_TS_LOGICAL_NOT: { - if (arg->data_kind() != GRN_TS_BOOL) { - return GRN_UNKNOWN_ERROR; - } - rc = LogicalNotNode::open(arg, node); - break; - } - default: { - return GRN_INVALID_ARGUMENT; - } - } - return rc; -} - -grn_rc Expression::create_binary_node(OperatorType operator_type, - ExpressionNode *arg1, ExpressionNode *arg2, ExpressionNode **node) { - switch (operator_type) { - case GRN_TS_LOGICAL_AND: { - if ((arg1->data_kind() != GRN_TS_BOOL) || - (arg1->data_kind() != GRN_TS_BOOL)) { - return GRN_INVALID_FORMAT; - } - return LogicalAndNode::open(arg1, arg2, node); - } - case GRN_TS_LOGICAL_OR: { - if ((arg1->data_kind() != GRN_TS_BOOL) || - (arg1->data_kind() != GRN_TS_BOOL)) { - return GRN_INVALID_FORMAT; - } - return LogicalOrNode::open(arg1, arg2, node); - } -// case GRN_TS_EQUAL: { -// if (arg1->data_kind() != arg2->data_kind()) { -// return GRN_INVALID_FORMAT; -// } -// return EqualNode::open(arg1, arg2, node); -// } - case GRN_TS_EQUAL: - case GRN_TS_NOT_EQUAL: - case GRN_TS_LESS: - case GRN_TS_LESS_EQUAL: - case GRN_TS_GREATER: - case GRN_TS_GREATER_EQUAL: { - return ComparerNode::open(operator_type, arg1, arg2, node); - } - default: { - return GRN_INVALID_ARGUMENT; - } - } -} - -} // namespace ts -} // namespace grn - -#ifdef __cplusplus -extern "C" { -#endif - -static grn_rc -grn_ts_select_filter(grn_ctx *ctx, grn_obj *table, - const char *filter, size_t filter_size, - int offset, int limit, - std::vector<grn_ts_record> *records, - size_t *num_hits) { - if (offset < 0) { - offset = 0; - } - if (limit < 0) { - limit = std::numeric_limits<int>::max(); - } - grn::ts::Cursor *cursor; - grn_rc rc = grn::ts::Cursor::open_table_cursor(ctx, table, &cursor); - if (rc == GRN_SUCCESS) { - grn::ts::Expression *expression; - rc = grn::ts::Expression::parse( - ctx, table, filter, filter_size, &expression); - if (rc == GRN_SUCCESS) { - size_t count = 0; - for ( ; ; ) { - size_t records_offset = records->size(); - try { - records->resize(records->size() + GRN_TS_MAX_BATCH_SIZE); - } catch (const std::bad_alloc &) { - rc = GRN_NO_MEMORY_AVAILABLE; - break; - } - size_t batch_size; - rc = cursor->read(&(*records)[records_offset], - GRN_TS_MAX_BATCH_SIZE, &batch_size); - if (rc != GRN_SUCCESS) { - break; - } - if (batch_size == 0) { - records->resize(records_offset); - break; - } - rc = expression->filter(&(*records)[records_offset], batch_size, - NULL, &batch_size); - if (rc != GRN_SUCCESS) { - break; - } - count += batch_size; - if (offset > 0) { - if (offset >= batch_size) { - offset -= batch_size; - batch_size = 0; - } else { - std::memcpy(&(*records)[0], &(*records)[offset], - sizeof(grn_ts_record) * (batch_size - offset)); - batch_size -= offset; - offset = 0; - } - } - if (limit >= batch_size) { - limit -= batch_size; - } else { - batch_size = limit; - limit = 0; - } - records->resize(records_offset + batch_size); - } - delete expression; - *num_hits = count; - } - delete cursor; - } - return rc; -} - -static grn_rc -grn_ts_select_output(grn_ctx *ctx, grn_obj *table, - const char *output_columns, size_t output_columns_size, - const grn_ts_record *records, size_t num_records, - size_t num_hits) { - grn_rc rc = GRN_SUCCESS; - std::vector<std::string> names; - std::vector<grn::ts::Expression *> expressions; - - const char *rest = output_columns; - size_t rest_size = output_columns_size; - while (rest_size != 0) { - size_t pos; - for (pos = 0; pos < rest_size; ++pos) { - if ((rest[pos] != ',') && - !std::isspace(static_cast<unsigned char>(rest[pos]))) { - break; - } - } - if (pos >= rest_size) { - break; - } - rest += pos; - rest_size -= pos; - for (pos = 0; pos < rest_size; ++pos) { - if ((rest[pos] == ',') || - std::isspace(static_cast<unsigned char>(rest[pos]))) { - break; - } - } - // TODO: Error handling. - std::string name(rest, pos); - if (name == "*") { - grn_hash *columns; - if ((columns = grn_hash_create(ctx, NULL, sizeof(grn_id), 0, - GRN_OBJ_TABLE_HASH_KEY|GRN_HASH_TINY))) { - if (grn_table_columns(ctx, table, "", 0, (grn_obj *)columns)) { - grn_id *key; - GRN_HASH_EACH(ctx, columns, id, &key, NULL, NULL, { - grn_obj *column = grn_ctx_at(ctx, *key); - if (column) { - char name_buf[1024]; - int name_size = grn_column_name( - ctx, column, name_buf, sizeof(name_buf)); - grn::ts::Expression *expression; - grn_rc r = grn::ts::Expression::open(ctx, table, &expression); - if (r == GRN_SUCCESS) { - r = expression->push_object(column); - if (r == GRN_SUCCESS) { - names.push_back(std::string(name_buf, name_size)); - expressions.push_back(expression); - } - } - } - }); - } - grn_hash_close(ctx, columns); - } - } else { - grn::ts::Expression *expression; - grn_rc r = grn::ts::Expression::parse( - ctx, table, rest, pos, &expression); - if (r == GRN_SUCCESS) { - names.push_back(name); - expressions.push_back(expression); - } - } - if (pos >= rest_size) { - break; - } - rest += pos + 1; - rest_size -= pos + 1; - } - - GRN_OUTPUT_ARRAY_OPEN("RESULT", 1); - GRN_OUTPUT_ARRAY_OPEN("RESULTSET", 2 + num_records); - GRN_OUTPUT_ARRAY_OPEN("NHITS", 1); - grn_text_ulltoa(ctx, ctx->impl->outbuf, num_hits); - GRN_OUTPUT_ARRAY_CLOSE(); // NHITS. - GRN_OUTPUT_ARRAY_OPEN("COLUMNS", expressions.size()); - for (size_t i = 0; i < expressions.size(); ++i) { - GRN_OUTPUT_ARRAY_OPEN("COLUMN", 2); - GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, '"'); - GRN_TEXT_PUT(ctx, ctx->impl->outbuf, names[i].data(), names[i].size()); - GRN_TEXT_PUT(ctx, ctx->impl->outbuf, "\",\"", 3); - switch (expressions[i]->output_type()) { - case GRN_DB_BOOL: { - GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "Bool"); - break; - } - case GRN_DB_INT8: { - GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "Int8"); - break; - } - case GRN_DB_INT16: { - GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "Int16"); - break; - } - case GRN_DB_INT32: { - GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "Int32"); - break; - } - case GRN_DB_INT64: { - GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "Int64"); - break; - } - case GRN_DB_UINT8: { - GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "UInt8"); - break; - } - case GRN_DB_UINT16: { - GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "UInt16"); - break; - } - case GRN_DB_UINT32: { - GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "UInt32"); - break; - } - case GRN_DB_UINT64: { - GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "UInt64"); - break; - } - case GRN_DB_FLOAT: { - GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "Float"); - break; - } - case GRN_DB_TIME: { - GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "Time"); - break; - } - case GRN_DB_SHORT_TEXT: { - GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "ShortText"); - break; - } - case GRN_DB_TEXT: { - GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "Text"); - break; - } - case GRN_DB_LONG_TEXT: { - GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "LongText"); - break; - } - case GRN_DB_TOKYO_GEO_POINT: { - GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "TokyoGeoPoint"); - break; - } - case GRN_DB_WGS84_GEO_POINT: { - GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "WGS84GeoPoint"); - break; - } - default: { - grn_obj *obj = grn_ctx_at(ctx, expressions[i]->output_type()); - if (obj && grn_obj_is_table(ctx, obj)) { - char name[GRN_TABLE_MAX_KEY_SIZE]; - int len = grn_obj_name(ctx, obj, name, sizeof(name)); - GRN_TEXT_PUT(ctx, ctx->impl->outbuf, name, len); - grn_obj_unlink(ctx, obj); - } - break; - } - } - GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, '"'); - GRN_OUTPUT_ARRAY_CLOSE(); - } - GRN_OUTPUT_ARRAY_CLOSE(); // COLUMNS. - if (num_records != 0) { - size_t count = 0; - std::vector<std::vector<char> > bufs(expressions.size()); - while (count < num_records) { - size_t batch_size = GRN_TS_MAX_BATCH_SIZE; - if (batch_size > (num_records - count)) { - batch_size = num_records - count; - } - for (size_t i = 0; i < expressions.size(); ++i) { - if (expressions[i]->dimension() == 0) { - switch (expressions[i]->data_kind()) { - case GRN_TS_BOOL: { - bufs[i].resize(sizeof(grn_ts_bool) * batch_size); - expressions[i]->evaluate(records + count, batch_size, - (grn::ts::Bool *)&bufs[i][0]); - break; - } - case GRN_TS_INT: { - bufs[i].resize(sizeof(grn_ts_int) * batch_size); - expressions[i]->evaluate(records + count, batch_size, - (grn::ts::Int *)&bufs[i][0]); - break; - } - case GRN_TS_FLOAT: { - bufs[i].resize(sizeof(grn_ts_float) * batch_size); - expressions[i]->evaluate(records + count, batch_size, - (grn::ts::Float *)&bufs[i][0]); - break; - } - case GRN_TS_TIME: { - bufs[i].resize(sizeof(grn_ts_time) * batch_size); - expressions[i]->evaluate(records + count, batch_size, - (grn::ts::Time *)&bufs[i][0]); - break; - } - case GRN_TS_TEXT: { - bufs[i].resize(sizeof(grn_ts_text) * batch_size); - expressions[i]->evaluate(records + count, batch_size, - (grn::ts::Text *)&bufs[i][0]); - break; - } - case GRN_TS_GEO_POINT: { - bufs[i].resize(sizeof(grn_ts_geo_point) * batch_size); - expressions[i]->evaluate(records + count, batch_size, - (grn::ts::GeoPoint *)&bufs[i][0]); - break; - } - default: { - break; - } - } - } else { - switch (expressions[i]->data_kind()) { - case GRN_TS_BOOL: { - bufs[i].resize(sizeof(grn_ts_vector) * batch_size); - expressions[i]->evaluate(records + count, batch_size, - (grn_ts_vector *)&bufs[i][0]); - break; - } - case GRN_TS_INT: { - bufs[i].resize(sizeof(grn_ts_vector) * batch_size); - expressions[i]->evaluate(records + count, batch_size, - (grn_ts_vector *)&bufs[i][0]); - break; - } - case GRN_TS_FLOAT: { - bufs[i].resize(sizeof(grn_ts_vector) * batch_size); - expressions[i]->evaluate(records + count, batch_size, - (grn_ts_vector *)&bufs[i][0]); - break; - } - case GRN_TS_TIME: { - bufs[i].resize(sizeof(grn_ts_vector) * batch_size); - expressions[i]->evaluate(records + count, batch_size, - (grn_ts_vector *)&bufs[i][0]); - break; - } - case GRN_TS_TEXT: { - bufs[i].resize(sizeof(grn_ts_vector) * batch_size); - expressions[i]->evaluate(records + count, batch_size, - (grn_ts_vector *)&bufs[i][0]); - break; - } - case GRN_TS_GEO_POINT: { - bufs[i].resize(sizeof(grn_ts_vector) * batch_size); - expressions[i]->evaluate(records + count, batch_size, - (grn_ts_vector *)&bufs[i][0]); - break; - } - default: { - break; - } - } - } - } - for (size_t i = 0; i < batch_size; ++i) { - GRN_OUTPUT_ARRAY_OPEN("HIT", expressions.size()); - for (size_t j = 0; j < expressions.size(); ++j) { - if (j != 0) { - GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ','); - } - if (expressions[j]->dimension() == 0) { - switch (expressions[j]->data_kind()) { - case GRN_TS_BOOL: { - if (((grn_ts_bool *)&bufs[j][0])[i]) { - GRN_TEXT_PUT(ctx, ctx->impl->outbuf, "true", 4); - } else { - GRN_TEXT_PUT(ctx, ctx->impl->outbuf, "false", 5); - } - break; - } - case GRN_TS_INT: { - grn_text_lltoa(ctx, ctx->impl->outbuf, - ((grn_ts_int *)&bufs[j][0])[i]); - break; - } - case GRN_TS_FLOAT: { - grn_text_ftoa(ctx, ctx->impl->outbuf, - ((grn_ts_float *)&bufs[j][0])[i]); - break; - } - case GRN_TS_TIME: { - grn_text_ftoa(ctx, ctx->impl->outbuf, - ((grn_ts_time *)&bufs[j][0])[i] * 0.000001); - break; - } - case GRN_TS_TEXT: { - grn_ts_text text = ((grn_ts_text *)&bufs[j][0])[i]; - grn_text_esc(ctx, ctx->impl->outbuf, text.ptr, text.size); - break; - } - case GRN_TS_GEO_POINT: { - grn_ts_geo_point geo_point = - ((grn_ts_geo_point *)&bufs[j][0])[i]; - GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, '"'); - grn_text_itoa(ctx, ctx->impl->outbuf, geo_point.latitude); - GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, 'x'); - grn_text_itoa(ctx, ctx->impl->outbuf, geo_point.longitude); - GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, '"'); - break; - } - default: { - break; - } - } - } else { - grn_ts_vector vector = - reinterpret_cast<grn_ts_vector *>(&bufs[j][0])[i]; - switch (expressions[j]->data_kind()) { - case GRN_TS_BOOL: { - const grn_ts_bool *ptr = - static_cast<const grn_ts_bool *>(vector.ptr); - GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, '['); - for (size_t k = 0; k < vector.size; ++k) { - if (k != 0) { - GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ','); - } - if (ptr[k]) { - GRN_TEXT_PUT(ctx, ctx->impl->outbuf, "true", 4); - } else { - GRN_TEXT_PUT(ctx, ctx->impl->outbuf, "false", 5); - } - } - GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ']'); - break; - } - case GRN_TS_INT: { - const grn_ts_int *ptr = - static_cast<const grn_ts_int *>(vector.ptr); - GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, '['); - for (size_t k = 0; k < vector.size; ++k) { - if (k != 0) { - GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ','); - } - grn_text_lltoa(ctx, ctx->impl->outbuf, ptr[k]); - } - GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ']'); - break; - } - case GRN_TS_FLOAT: { - const grn_ts_float *ptr = - static_cast<const grn_ts_float *>(vector.ptr); - GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, '['); - for (size_t k = 0; k < vector.size; ++k) { - if (k != 0) { - GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ','); - } - grn_text_ftoa(ctx, ctx->impl->outbuf, ptr[k]); - } - GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ']'); - break; - } - case GRN_TS_TIME: { - const grn_ts_time *ptr = - static_cast<const grn_ts_time *>(vector.ptr); - GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, '['); - for (size_t k = 0; k < vector.size; ++k) { - if (k != 0) { - GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ','); - } - grn_text_ftoa(ctx, ctx->impl->outbuf, ptr[k] * 0.000001); - } - GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ']'); - break; - } - case GRN_TS_TEXT: { - const grn_ts_text *ptr = - static_cast<const grn_ts_text *>(vector.ptr); - GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, '['); - for (size_t k = 0; k < vector.size; ++k) { - if (k != 0) { - GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ','); - } - grn_text_esc(ctx, ctx->impl->outbuf, ptr[k].ptr, ptr[k].size); - } - GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ']'); - break; - } - case GRN_TS_GEO_POINT: { - const grn_ts_geo_point *ptr = - static_cast<const grn_ts_geo_point *>(vector.ptr); - GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, '['); - for (size_t k = 0; k < vector.size; ++k) { - if (k != 0) { - GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ','); - } - GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, '"'); - grn_text_itoa(ctx, ctx->impl->outbuf, ptr[k].latitude); - GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, 'x'); - grn_text_itoa(ctx, ctx->impl->outbuf, ptr[k].longitude); - GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, '"'); - } - GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ']'); - break; - } - default: { - break; - } - } - } - } - GRN_OUTPUT_ARRAY_CLOSE(); // HITS. - } - count += batch_size; - } - } - GRN_OUTPUT_ARRAY_CLOSE(); // RESULTSET. - GRN_OUTPUT_ARRAY_CLOSE(); // RESET. - for (size_t i = 0; i < expressions.size(); ++i) { - delete expressions[i]; - } - return rc; -} - -grn_rc -grn_ts_select(grn_ctx *ctx, grn_obj *table, - const char *filter, size_t filter_size, - const char *output_columns, size_t output_columns_size, - int offset, int limit) { - if (!ctx || !grn_obj_is_table(ctx, table) || - (!filter && (filter_size != 0)) || - (!output_columns && (output_columns_size != 0))) { - return GRN_INVALID_ARGUMENT; - } - std::vector<grn_ts_record> records; - size_t num_hits; - grn_rc rc = grn_ts_select_filter(ctx, table, filter, filter_size, - offset, limit, &records, &num_hits); - if (rc == GRN_SUCCESS) { - rc = grn_ts_select_output(ctx, table, output_columns, output_columns_size, - &*records.begin(), records.size(), num_hits); - } - return rc; -} - -#ifdef __cplusplus -} -#endif - -#endif // GRN_WITH_TS