[Groonga-commit] groonga/groonga at 4478eab [master] grn_ts: move definitions of grn_ts_expr into lib/ts/ts_expr

Back to archive index

susumu.yata null+****@clear*****
Mon Nov 9 14:12:30 JST 2015


susumu.yata	2015-11-09 14:12:30 +0900 (Mon, 09 Nov 2015)

  New Revision: 4478eab3cf6ae2c2e78f293e47ab88ff34c3df48
  https://github.com/groonga/groonga/commit/4478eab3cf6ae2c2e78f293e47ab88ff34c3df48

  Message:
    grn_ts: move definitions of grn_ts_expr into lib/ts/ts_expr

  Copied files:
    lib/ts/ts_expr.c
      (from lib/ts.c)
    lib/ts/ts_expr.h
      (from lib/grn_ts.h)
  Modified files:
    lib/grn_ts.h
    lib/ts.c
    lib/ts/sources.am

  Modified: lib/grn_ts.h (+33 -281)
===================================================================
--- lib/grn_ts.h    2015-11-09 13:36:05 +0900 (c815433)
+++ lib/grn_ts.h    2015-11-09 14:12:30 +0900 (184ed38)
@@ -20,7 +20,6 @@
 #define GRN_TS_H
 
 #include <stddef.h>
-#include <stdint.h>
 
 #include "grn.h"
 
@@ -29,343 +28,96 @@ extern "C" {
 #endif
 
 /*-------------------------------------------------------------
- * 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             = 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 {
-  /* Invalid operator. */
-  GRN_TS_OP_NOP,
-
-  /* Unary operators. */
-  GRN_TS_OP_LOGICAL_NOT,    /* !X */
-  GRN_TS_OP_BITWISE_NOT,    /* ~X */
-  GRN_TS_OP_POSITIVE,       /* +X */
-  GRN_TS_OP_NEGATIVE,       /* -X */
-
-  /* Binary operators. */
-  GRN_TS_OP_LOGICAL_AND,            /* X && Y  */
-  GRN_TS_OP_LOGICAL_OR,             /* X || Y  */
-  GRN_TS_OP_LOGICAL_SUB,            /* X &! Y  */
-  GRN_TS_OP_BITWISE_AND,            /* X & Y   */
-  GRN_TS_OP_BITWISE_OR,             /* X | Y   */
-  GRN_TS_OP_BITWISE_XOR,            /* X ^ Y   */
-  GRN_TS_OP_EQUAL,                  /* X == Y  */
-  GRN_TS_OP_NOT_EQUAL,              /* X != Y  */
-  GRN_TS_OP_LESS,                   /* X < Y   */
-  GRN_TS_OP_LESS_EQUAL,             /* X <= Y  */
-  GRN_TS_OP_GREATER,                /* X > Y   */
-  GRN_TS_OP_GREATER_EQUAL,          /* X >= Y  */
-  GRN_TS_OP_SHIFT_ARITHMETIC_LEFT,  /* X << Y  */
-  GRN_TS_OP_SHIFT_ARITHMETIC_RIGHT, /* X >> Y  */
-  GRN_TS_OP_SHIFT_LOGICAL_LEFT,     /* X <<< Y */
-  GRN_TS_OP_SHIFT_LOGICAL_RIGHT,    /* X >>> Y */
-  GRN_TS_OP_PLUS,                   /* X + Y   */
-  GRN_TS_OP_MINUS,                  /* X - Y   */
-  GRN_TS_OP_MULTIPLICATION,         /* X * Y   */
-  GRN_TS_OP_DIVISION,               /* X / Y   */
-  GRN_TS_OP_MODULUS                 /* X % Y   */
-} grn_ts_op_type;
-
-typedef enum {
-  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_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_BRIDGE_NODE  /* Associated with a bridge to a subexpression. */
-} grn_ts_expr_node_type;
-
-/*-------------------------------------------------------------
  * Built-in data types.
  */
 
-/* ID (_id), score (_score), and record types. */
+/* ID (_id). */
 typedef grn_id grn_ts_id;
+
+/* Score (_score). */
 typedef float grn_ts_score;
+
+/* Record (_id, _score). */
 typedef struct {
   grn_ts_id id;
   grn_ts_score score;
 } grn_ts_record;
 
 /* Built-in scalar data types. */
+
+/* Bool. */
 typedef grn_bool grn_ts_bool;
+
+/* Int. */
 typedef int64_t grn_ts_int;
+
+/* Float. */
 typedef double grn_ts_float;
+
+/* Time. */
 typedef int64_t grn_ts_time;
+
+/* Text. */
 typedef struct {
   const char *ptr;
   size_t size;
 } grn_ts_text;
+
+/* GeoPoint. */
 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;
+
+/* Ref. */
 typedef grn_ts_record grn_ts_ref;
 
 /* Built-in vector data types. */
+
+/* BoolVector. */
 typedef struct {
   const grn_ts_bool *ptr;
   size_t size;
 } grn_ts_bool_vector;
+
+/* IntVector. */
 typedef struct {
   const grn_ts_int *ptr;
   size_t size;
 } grn_ts_int_vector;
+
+/* FloatVector. */
 typedef struct {
   const grn_ts_float *ptr;
   size_t size;
 } grn_ts_float_vector;
+
+/* TimeVector. */
 typedef struct {
   const grn_ts_time *ptr;
   size_t size;
 } grn_ts_time_vector;
+
+/* TextVector. */
 typedef struct {
   const grn_ts_text *ptr;
   size_t size;
 } grn_ts_text_vector;
+
+/* GeoPointVector. */
 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;
+
+/* RefVector. */
 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 *src_table;  /* The source table of a bridge (no ref. count). */
-  grn_obj *dest_table; /* The destination table of a bridge. */
-  size_t stack_depth;  /* The stack depth (position) of a bridge. */
-} grn_ts_expr_bridge;
-
-typedef struct {
-  grn_obj *table;              /* Associated table. */
-  grn_obj *curr_table;         /* Current table (no ref. count). */
-  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_bridge *bridges; /* Bridges to subexpressions. */
-  size_t n_bridges;            /* Number of bridges (subexpression depth). */
-  size_t max_n_bridges;        /* Max. number (capacity) of bridges. */
-} 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_ptr, 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() parses a string and pushes the result. */
-grn_rc grn_ts_expr_push(grn_ctx *ctx, grn_ts_expr *expr,
-                        const char *str_ptr, size_t str_size);
-
-/* grn_ts_expr_push_name() pushes a named object. */
-grn_rc grn_ts_expr_push_name(grn_ctx *ctx, grn_ts_expr *expr,
-                             const char *name_ptr, size_t name_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_op() pushes an operator. */
-grn_rc grn_ts_expr_push_op(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_ts_expr_begin_subexpr() begins a subexpression. */
-grn_rc grn_ts_expr_begin_subexpr(grn_ctx *ctx, grn_ts_expr *expr);
-
-/* grn_ts_expr_end_subexpr() ends a subexpression. */
-grn_rc grn_ts_expr_end_subexpr(grn_ctx *ctx, grn_ts_expr *expr);
-
-/* 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.
  */
 

  Modified: lib/ts.c (+10 -6946)
===================================================================
--- lib/ts.c    2015-11-09 13:36:05 +0900 (5410343)
+++ lib/ts.c    2015-11-09 14:12:30 +0900 (2d73b94)
@@ -20,22 +20,11 @@
 
 #include "grn_ts.h"
 
-#include <ctype.h>
-#include <math.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "grn_ctx_impl.h"
-#include "grn_dat.h"
-#include "grn_db.h"
-#include "grn_geo.h"
-#include "grn_hash.h"
 #include "grn_output.h"
-#include "grn_pat.h"
-#include "grn_store.h"
 #include "grn_str.h"
 
 #include "ts/ts_buf.h"
+#include "ts/ts_expr.h"
 #include "ts/ts_log.h"
 #include "ts/ts_str.h"
 
@@ -45,202 +34,6 @@
 
 enum { GRN_TS_BATCH_SIZE = 1024 };
 
-/*-------------------------------------------------------------
- * Built-in data kinds.
- */
-
-typedef union {
-  grn_ts_bool as_bool;
-  grn_ts_int as_int;
-  grn_ts_float as_float;
-  grn_ts_time as_time;
-  grn_ts_text as_text;
-  grn_ts_geo_point as_geo_point;
-  grn_ts_ref as_ref;
-  grn_ts_bool_vector as_bool_vector;
-  grn_ts_int_vector as_int_vector;
-  grn_ts_float_vector as_float_vector;
-  grn_ts_time_vector as_time_vector;
-  grn_ts_text_vector as_text_vector;
-  grn_ts_geo_point_vector as_geo_point_vector;
-  grn_ts_ref_vector as_ref_vector;
-} grn_ts_any;
-
-/* grn_ts_bool_is_valid() returns whether a value is valid or not. */
-inline static grn_ts_bool
-grn_ts_bool_is_valid(grn_ts_bool value) {
-  return GRN_TRUE;
-}
-
-/* grn_ts_int_is_valid() returns whether a value is valid or not. */
-inline static grn_ts_bool
-grn_ts_int_is_valid(grn_ts_int value) {
-  return GRN_TRUE;
-}
-
-/* grn_ts_float_is_valid() returns whether a value is valid or not. */
-inline static grn_ts_bool
-grn_ts_float_is_valid(grn_ts_float value) {
-  return !isnan(value);
-}
-
-/* grn_ts_time_is_valid() returns whether a value is valid or not. */
-inline static grn_ts_bool
-grn_ts_time_is_valid(grn_ts_time value) {
-  return GRN_TRUE;
-}
-
-/* grn_ts_text_is_valid() returns whether a value is valid or not. */
-inline static grn_ts_bool
-grn_ts_text_is_valid(grn_ts_text value) {
-  return value.ptr || !value.size;
-}
-
-/* grn_ts_geo_point_is_valid() returns whether a value is valid or not. */
-inline static grn_ts_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_ts_bool
-grn_ts_bool_vector_is_valid(grn_ts_bool_vector value) {
-  GRN_TS_VECTOR_IS_VALID(bool)
-}
-
-/* grn_ts_int_vector_is_valid() returns whether a value is valid or not. */
-inline static grn_ts_bool
-grn_ts_int_vector_is_valid(grn_ts_int_vector value) {
-  GRN_TS_VECTOR_IS_VALID(int)
-}
-
-/* grn_ts_float_vector_is_valid() returns whether a value is valid or not. */
-inline static grn_ts_bool
-grn_ts_float_vector_is_valid(grn_ts_float_vector value) {
-  GRN_TS_VECTOR_IS_VALID(float)
-}
-
-/* grn_ts_time_vector_is_valid() returns whether a value is valid or not. */
-inline static grn_ts_bool
-grn_ts_time_vector_is_valid(grn_ts_time_vector value) {
-  GRN_TS_VECTOR_IS_VALID(time)
-}
-
-/* grn_ts_text_vector_is_valid() returns whether a value is valid or not. */
-inline static grn_ts_bool
-grn_ts_text_vector_is_valid(grn_ts_text_vector value) {
-  GRN_TS_VECTOR_IS_VALID(text)
-}
-
-/*
- * grn_ts_geo_point_vector_is_valid() returns whether a value is valid or not.
- */
-inline static grn_ts_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_bool_output() outputs a value. */
 static grn_rc
 grn_ts_bool_output(grn_ctx *ctx, grn_ts_bool value) {
@@ -353,6756 +146,27 @@ grn_ts_geo_point_vector_output(grn_ctx *ctx, grn_ts_geo_point_vector value) {
 }
 #undef GRN_TS_VECTOR_OUTPUT
 
-/* 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;
-    }
-    case GRN_TS_REF: {
-      /*
-       * grn_ts_data_kind does not have enough information to get a correct
-       * table ID.
-       */
-      return GRN_DB_VOID;
-    }
-    default: {
-      return GRN_DB_VOID;
-    }
-  }
-}
-
-/*-------------------------------------------------------------
- * Operators.
- */
-
-/* Operator precedence. */
-typedef int grn_ts_op_precedence;
-
-/* grn_ts_op_get_n_args() returns the number of arguments. */
-static size_t
-grn_ts_op_get_n_args(grn_ts_op_type op_type) {
-  switch (op_type) {
-    case GRN_TS_OP_LOGICAL_NOT: /* !X */
-    case GRN_TS_OP_BITWISE_NOT: /* ~X */
-    case GRN_TS_OP_POSITIVE:    /* +X */
-    case GRN_TS_OP_NEGATIVE: {  /* -X */
-      return 1;
-    }
-    case GRN_TS_OP_LOGICAL_AND:            /* X && Y  */
-    case GRN_TS_OP_LOGICAL_OR:             /* X || Y  */
-    case GRN_TS_OP_LOGICAL_SUB:            /* X &! Y  */
-    case GRN_TS_OP_BITWISE_AND:            /* X & Y   */
-    case GRN_TS_OP_BITWISE_OR:             /* X | Y   */
-    case GRN_TS_OP_BITWISE_XOR:            /* X ^ Y   */
-    case GRN_TS_OP_EQUAL:                  /* X == Y  */
-    case GRN_TS_OP_NOT_EQUAL:              /* X != Y  */
-    case GRN_TS_OP_LESS:                   /* X < Y   */
-    case GRN_TS_OP_LESS_EQUAL:             /* X <= Y  */
-    case GRN_TS_OP_GREATER:                /* X > Y   */
-    case GRN_TS_OP_GREATER_EQUAL:          /* X >= Y  */
-    case GRN_TS_OP_SHIFT_ARITHMETIC_LEFT:  /* X << Y  */
-    case GRN_TS_OP_SHIFT_ARITHMETIC_RIGHT: /* X >> Y  */
-    case GRN_TS_OP_SHIFT_LOGICAL_LEFT:     /* X <<< Y */
-    case GRN_TS_OP_SHIFT_LOGICAL_RIGHT:    /* X >>> Y */
-    case GRN_TS_OP_PLUS:                   /* X + Y   */
-    case GRN_TS_OP_MINUS:                  /* X - Y   */
-    case GRN_TS_OP_MULTIPLICATION:         /* X * Y   */
-    case GRN_TS_OP_DIVISION:               /* X / Y   */
-    case GRN_TS_OP_MODULUS: {              /* X % Y   */
-      return 2;
-    }
-    default: {
-      return 0;
-    }
-  }
-}
-
-/*
- * grn_ts_op_get_precedence() returns the precedence.
- * A prior operator has a higher precedence.
- */
-static grn_ts_op_precedence
-grn_ts_op_get_precedence(grn_ts_op_type op_type) {
-  switch (op_type) {
-    case GRN_TS_OP_LOGICAL_NOT:
-    case GRN_TS_OP_BITWISE_NOT:
-    case GRN_TS_OP_POSITIVE:
-    case GRN_TS_OP_NEGATIVE: {
-      return 14;
-    }
-    case GRN_TS_OP_LOGICAL_AND: {
-      return 5;
-    }
-    case GRN_TS_OP_LOGICAL_OR: {
-      return 3;
-    }
-    case GRN_TS_OP_LOGICAL_SUB: {
-      return 4;
-    }
-    case GRN_TS_OP_BITWISE_AND: {
-      return 8;
-    }
-    case GRN_TS_OP_BITWISE_OR: {
-      return 6;
-    }
-    case GRN_TS_OP_BITWISE_XOR: {
-      return 7;
-    }
-    case GRN_TS_OP_EQUAL:
-    case GRN_TS_OP_NOT_EQUAL: {
-      return 9;
-    }
-    case GRN_TS_OP_LESS:
-    case GRN_TS_OP_LESS_EQUAL:
-    case GRN_TS_OP_GREATER:
-    case GRN_TS_OP_GREATER_EQUAL: {
-      return 10;
-    }
-    case GRN_TS_OP_SHIFT_ARITHMETIC_LEFT:
-    case GRN_TS_OP_SHIFT_ARITHMETIC_RIGHT:
-    case GRN_TS_OP_SHIFT_LOGICAL_LEFT:
-    case GRN_TS_OP_SHIFT_LOGICAL_RIGHT: {
-      return 11;
-    }
-    case GRN_TS_OP_PLUS:
-    case GRN_TS_OP_MINUS: {
-      return 12;
-    }
-    case GRN_TS_OP_MULTIPLICATION:
-    case GRN_TS_OP_DIVISION:
-    case GRN_TS_OP_MODULUS: {
-      return 13;
+/* grn_ts_table_has_key() returns whether or not a table has _key. */
+static grn_ts_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 0;
+      return GRN_FALSE;
     }
   }
 }
 
-/* FIXME: The following implementation assumes that NaN values don't appear. */
-
-/* grn_ts_op_logical_not_bool() returns !arg. */
-inline static grn_ts_bool
-grn_ts_op_logical_not_bool(grn_ts_bool arg) {
-  return !arg;
-}
-
-/* grn_ts_op_bitwise_not_bool() returns ~arg. */
-inline static grn_ts_bool
-grn_ts_op_bitwise_not_bool(grn_ts_bool arg) {
-  return !arg;
-}
-
-/* grn_ts_op_bitwise_not_int() returns ~arg. */
-inline static grn_ts_int
-grn_ts_op_bitwise_not_int(grn_ts_int arg) {
-  return ~arg;
-}
-
-/* grn_ts_op_positive_int() returns +arg. */
-inline static grn_ts_int
-grn_ts_op_positive_int(grn_ts_int arg) {
-  return arg;
-}
-
-/* grn_ts_op_positive_float() returns +arg. */
-inline static grn_ts_float
-grn_ts_op_positive_float(grn_ts_float arg) {
-  return arg;
-}
-
-/* grn_ts_op_negative_int() returns -arg. */
-inline static grn_ts_int
-grn_ts_op_negative_int(grn_ts_int arg) {
-  return -arg;
-}
-
-/* grn_ts_op_negative_float() returns -arg. */
-inline static grn_ts_float
-grn_ts_op_negative_float(grn_ts_float arg) {
-  return -arg;
-}
-
-/* grn_ts_op_bitwise_and_bool() returns lhs & rhs. */
-inline static grn_ts_bool
-grn_ts_op_bitwise_and_bool(grn_ts_bool lhs, grn_ts_bool rhs) {
-  return lhs & rhs;
-}
-
-/* grn_ts_op_bitwise_and_int() returns lhs & rhs. */
-inline static grn_ts_int
-grn_ts_op_bitwise_and_int(grn_ts_int lhs, grn_ts_int rhs) {
-  return lhs & rhs;
-}
-
-/* grn_ts_op_bitwise_or_bool() returns lhs | rhs. */
-inline static grn_ts_bool
-grn_ts_op_bitwise_or_bool(grn_ts_bool lhs, grn_ts_bool rhs) {
-  return lhs | rhs;
-}
-
-/* grn_ts_op_bitwise_or_int() returns lhs | rhs. */
-inline static grn_ts_int
-grn_ts_op_bitwise_or_int(grn_ts_int lhs, grn_ts_int rhs) {
-  return lhs | rhs;
-}
-
-/* grn_ts_op_bitwise_xor_bool() returns lhs ^ rhs. */
-inline static grn_ts_bool
-grn_ts_op_bitwise_xor_bool(grn_ts_bool lhs, grn_ts_bool rhs) {
-  return lhs ^ rhs;
-}
-
-/* grn_ts_op_bitwise_xor_int() returns lhs ^ rhs. */
-inline static grn_ts_int
-grn_ts_op_bitwise_xor_int(grn_ts_int lhs, grn_ts_int rhs) {
-  return lhs ^ rhs;
-}
-
-/* grn_ts_op_equal_bool() returns lhs == rhs. */
-inline static grn_ts_bool
-grn_ts_op_equal_bool(grn_ts_bool lhs, grn_ts_bool rhs) {
-  return lhs == rhs;
-}
-
-/* grn_ts_op_equal_int() returns lhs == rhs. */
-inline static grn_ts_bool
-grn_ts_op_equal_int(grn_ts_int lhs, grn_ts_int rhs) {
-  return lhs == rhs;
-}
-
-/* grn_ts_op_equal_float() returns lhs == rhs. */
-inline static grn_ts_bool
-grn_ts_op_equal_float(grn_ts_float lhs, grn_ts_float rhs) {
-  /* To suppress warnings, "lhs == rhs" is not used. */
-  return (lhs <= rhs) && (lhs >= rhs);
-}
-
-/* grn_ts_op_equal_time() returns lhs == rhs. */
-inline static grn_ts_bool
-grn_ts_op_equal_time(grn_ts_time lhs, grn_ts_time rhs) {
-  return lhs == rhs;
-}
-
-/* grn_ts_op_equal_text() returns lhs == rhs. */
-inline static grn_ts_bool
-grn_ts_op_equal_text(grn_ts_text lhs, grn_ts_text rhs) {
-  return (lhs.size == rhs.size) && !memcmp(lhs.ptr, rhs.ptr, lhs.size);
-}
-
-/* grn_ts_op_equal_geo_point() returns lhs == rhs. */
-inline static grn_ts_bool
-grn_ts_op_equal_geo_point(grn_ts_geo_point lhs, grn_ts_geo_point rhs) {
-  return (lhs.latitude == rhs.latitude) && (lhs.longitude == rhs.longitude);
-}
-
-/* grn_ts_op_equal_ref() returns lhs == rhs. */
-inline static grn_ts_bool
-grn_ts_op_equal_ref(grn_ts_ref lhs, grn_ts_ref rhs) {
-  /* Ignore scores. */
-  return lhs.id == rhs.id;
-}
-
-#define GRN_TS_OP_EQUAL_VECTOR(kind)\
-  size_t i;\
-  if (lhs.size != rhs.size) {\
-    return GRN_FALSE;\
-  }\
-  for (i = 0; i < lhs.size; i++) {\
-    if (!grn_ts_op_equal_ ## kind(lhs.ptr[i], rhs.ptr[i])) {\
-      return GRN_FALSE;\
-    }\
-  }\
-  return GRN_TRUE;
-/* grn_ts_op_equal_bool_vector() returns lhs == rhs. */
-inline static grn_ts_bool
-grn_ts_op_equal_bool_vector(grn_ts_bool_vector lhs, grn_ts_bool_vector rhs) {
-  GRN_TS_OP_EQUAL_VECTOR(bool)
-}
-
-/* grn_ts_op_equal_int_vector() returns lhs == rhs. */
-inline static grn_ts_bool
-grn_ts_op_equal_int_vector(grn_ts_int_vector lhs, grn_ts_int_vector rhs) {
-  GRN_TS_OP_EQUAL_VECTOR(int)
-}
-
-/* grn_ts_op_equal_float_vector() returns lhs == rhs. */
-inline static grn_ts_bool
-grn_ts_op_equal_float_vector(grn_ts_float_vector lhs,
-                             grn_ts_float_vector rhs) {
-  GRN_TS_OP_EQUAL_VECTOR(float)
-}
-
-/* grn_ts_op_equal_time_vector() returns lhs == rhs. */
-inline static grn_ts_bool
-grn_ts_op_equal_time_vector(grn_ts_time_vector lhs, grn_ts_time_vector rhs) {
-  GRN_TS_OP_EQUAL_VECTOR(time)
-}
-
-/* grn_ts_op_equal_text_vector() returns lhs == rhs. */
-inline static grn_ts_bool
-grn_ts_op_equal_text_vector(grn_ts_text_vector lhs, grn_ts_text_vector rhs) {
-  GRN_TS_OP_EQUAL_VECTOR(text)
-}
-
-/* grn_ts_op_equal_geo_point_vector() returns lhs == rhs. */
-inline static grn_ts_bool
-grn_ts_op_equal_geo_point_vector(grn_ts_geo_point_vector lhs,
-                                 grn_ts_geo_point_vector rhs) {
-  GRN_TS_OP_EQUAL_VECTOR(geo_point)
-}
-
-/* grn_ts_op_equal_ref_vector() returns lhs == rhs. */
-inline static grn_ts_bool
-grn_ts_op_equal_ref_vector(grn_ts_ref_vector lhs, grn_ts_ref_vector rhs) {
-  GRN_TS_OP_EQUAL_VECTOR(ref)
-}
-#undef GRN_TS_OP_EQUAL_VECTOR
-
-/* grn_ts_op_not_equal_bool() returns lhs != rhs. */
-inline static grn_ts_bool
-grn_ts_op_not_equal_bool(grn_ts_bool lhs, grn_ts_bool rhs) {
-  return lhs != rhs;
-}
-
-/* grn_ts_op_not_equal_int() returns lhs != rhs. */
-inline static grn_ts_bool
-grn_ts_op_not_equal_int(grn_ts_int lhs, grn_ts_int rhs) {
-  return lhs != rhs;
-}
-
-/* grn_ts_op_not_equal_float() returns lhs != rhs. */
-inline static grn_ts_bool
-grn_ts_op_not_equal_float(grn_ts_float lhs, grn_ts_float rhs) {
-  /* To suppress warnings, "lhs != rhs" is not used. */
-  return (lhs < rhs) || (lhs > rhs);
-}
-
-/* grn_ts_op_not_equal_time() returns lhs != rhs. */
-inline static grn_ts_bool
-grn_ts_op_not_equal_time(grn_ts_time lhs, grn_ts_time rhs) {
-  return lhs != rhs;
-}
-
-/* grn_ts_op_not_equal_text() returns lhs != rhs. */
-inline static grn_ts_bool
-grn_ts_op_not_equal_text(grn_ts_text lhs, grn_ts_text rhs) {
-  return (lhs.size != rhs.size) || memcmp(lhs.ptr, rhs.ptr, lhs.size);
-}
-
-/* grn_ts_op_not_equal_geo_point() returns lhs != rhs. */
-inline static grn_ts_bool
-grn_ts_op_not_equal_geo_point(grn_ts_geo_point lhs, grn_ts_geo_point rhs) {
-  return (lhs.latitude != rhs.latitude) || (lhs.longitude != rhs.longitude);
-}
-
-/* grn_ts_op_not_equal_ref() returns lhs != rhs. */
-inline static grn_ts_bool
-grn_ts_op_not_equal_ref(grn_ts_ref lhs, grn_ts_ref rhs) {
-  /* Ignore scores. */
-  return lhs.id != rhs.id;
-}
-
-#define GRN_TS_OP_NOT_EQUAL_VECTOR(kind)\
-  size_t i;\
-  if (lhs.size != rhs.size) {\
-    return GRN_TRUE;\
-  }\
-  for (i = 0; i < lhs.size; i++) {\
-    if (grn_ts_op_not_equal_ ## kind(lhs.ptr[i], rhs.ptr[i])) {\
-      return GRN_TRUE;\
-    }\
-  }\
-  return GRN_FALSE;
-/* grn_ts_op_not_equal_bool_vector() returns lhs != rhs. */
-inline static grn_ts_bool
-grn_ts_op_not_equal_bool_vector(grn_ts_bool_vector lhs,
-                                grn_ts_bool_vector rhs) {
-  GRN_TS_OP_NOT_EQUAL_VECTOR(bool)
-}
-
-/* grn_ts_op_not_equal_int_vector() returns lhs != rhs. */
-inline static grn_ts_bool
-grn_ts_op_not_equal_int_vector(grn_ts_int_vector lhs, grn_ts_int_vector rhs) {
-  GRN_TS_OP_NOT_EQUAL_VECTOR(int)
-}
-
-/* grn_ts_op_not_equal_float_vector() returns lhs != rhs. */
-inline static grn_ts_bool
-grn_ts_op_not_equal_float_vector(grn_ts_float_vector lhs,
-                             grn_ts_float_vector rhs) {
-  GRN_TS_OP_NOT_EQUAL_VECTOR(float)
-}
-
-/* grn_ts_op_not_equal_time_vector() returns lhs != rhs. */
-inline static grn_ts_bool
-grn_ts_op_not_equal_time_vector(grn_ts_time_vector lhs,
-                                grn_ts_time_vector rhs) {
-  GRN_TS_OP_NOT_EQUAL_VECTOR(time)
-}
-
-/* grn_ts_op_not_equal_text_vector() returns lhs != rhs. */
-inline static grn_ts_bool
-grn_ts_op_not_equal_text_vector(grn_ts_text_vector lhs,
-                                grn_ts_text_vector rhs) {
-  GRN_TS_OP_NOT_EQUAL_VECTOR(text)
-}
-
-/* grn_ts_op_not_equal_geo_point_vector() returns lhs != rhs. */
-inline static grn_ts_bool
-grn_ts_op_not_equal_geo_point_vector(grn_ts_geo_point_vector lhs,
-                                 grn_ts_geo_point_vector rhs) {
-  GRN_TS_OP_NOT_EQUAL_VECTOR(geo_point)
-}
-
-/* grn_ts_op_not_equal_ref_vector() returns lhs != rhs. */
-inline static grn_ts_bool
-grn_ts_op_not_equal_ref_vector(grn_ts_ref_vector lhs, grn_ts_ref_vector rhs) {
-  GRN_TS_OP_NOT_EQUAL_VECTOR(ref)
-}
-#undef GRN_TS_OP_NOT_EQUAL_VECTOR
-
-/* grn_ts_op_less_int() returns lhs < rhs. */
-inline static grn_ts_bool
-grn_ts_op_less_int(grn_ts_int lhs, grn_ts_int rhs) {
-  return lhs < rhs;
-}
-
-/* grn_ts_op_less_float() returns lhs < rhs. */
-inline static grn_ts_bool
-grn_ts_op_less_float(grn_ts_float lhs, grn_ts_float rhs) {
-  return lhs < rhs;
-}
-
-/* grn_ts_op_less_time() returns lhs < rhs. */
-inline static grn_ts_bool
-grn_ts_op_less_time(grn_ts_time lhs, grn_ts_time rhs) {
-  return lhs < rhs;
-}
-
-/* grn_ts_op_less_text() returns lhs < rhs. */
-inline static grn_ts_bool
-grn_ts_op_less_text(grn_ts_text lhs, grn_ts_text rhs) {
-  size_t min_size = (lhs.size < rhs.size) ? lhs.size : rhs.size;
-  int cmp = memcmp(lhs.ptr, rhs.ptr, min_size);
-  return cmp ? (cmp < 0) : (lhs.size < rhs.size);
-}
-
-#define GRN_TS_OP_LESS_VECTOR(kind)\
-  size_t i, min_size = (lhs.size < rhs.size) ? lhs.size : rhs.size;\
-  for (i = 0; i < min_size; i++) {\
-    if (grn_ts_op_not_equal_ ## kind(lhs.ptr[i], rhs.ptr[i])) {\
-      if (grn_ts_op_less_ ## kind(lhs.ptr[i], rhs.ptr[i])) {\
-        return GRN_TRUE;\
-      }\
-    }\
-  }\
-  return lhs.size < rhs.size;
-/* grn_ts_op_less_int_vector() returns lhs < rhs. */
-inline static grn_ts_bool
-grn_ts_op_less_int_vector(grn_ts_int_vector lhs, grn_ts_int_vector rhs) {
-  GRN_TS_OP_LESS_VECTOR(int)
-}
-
-/* grn_ts_op_less_float_vector() returns lhs < rhs. */
-inline static grn_ts_bool
-grn_ts_op_less_float_vector(grn_ts_float_vector lhs, grn_ts_float_vector rhs) {
-  GRN_TS_OP_LESS_VECTOR(float)
-}
-
-/* grn_ts_op_less_time_vector() returns lhs < rhs. */
-inline static grn_ts_bool
-grn_ts_op_less_time_vector(grn_ts_time_vector lhs, grn_ts_time_vector rhs) {
-  GRN_TS_OP_LESS_VECTOR(time)
-}
-
-/* grn_ts_op_less_text_vector() returns lhs < rhs. */
-inline static grn_ts_bool
-grn_ts_op_less_text_vector(grn_ts_text_vector lhs, grn_ts_text_vector rhs) {
-  GRN_TS_OP_LESS_VECTOR(text)
-}
-#undef GRN_TS_OP_LESS_VECTOR
-
-/* grn_ts_op_less_equal_int() returns lhs <= rhs. */
-inline static grn_ts_bool
-grn_ts_op_less_equal_int(grn_ts_int lhs, grn_ts_int rhs) {
-  return lhs <= rhs;
-}
-
-/* grn_ts_op_less_equal_float() returns lhs <= rhs. */
-inline static grn_ts_bool
-grn_ts_op_less_equal_float(grn_ts_float lhs, grn_ts_float rhs) {
-  return lhs <= rhs;
-}
-
-/* grn_ts_op_less_equal_time() returns lhs <= rhs. */
-inline static grn_ts_bool
-grn_ts_op_less_equal_time(grn_ts_time lhs, grn_ts_time rhs) {
-  return lhs <= rhs;
-}
-
-/* grn_ts_op_less_equal_text() returns lhs <= rhs. */
-inline static grn_ts_bool
-grn_ts_op_less_equal_text(grn_ts_text lhs, grn_ts_text rhs) {
-  size_t min_size = (lhs.size < rhs.size) ? lhs.size : rhs.size;
-  int cmp = memcmp(lhs.ptr, rhs.ptr, min_size);
-  return cmp ? (cmp < 0) : (lhs.size <= rhs.size);
-}
-
-#define GRN_TS_OP_LESS_EQUAL_VECTOR(kind)\
-  size_t i, min_size = (lhs.size < rhs.size) ? lhs.size : rhs.size;\
-  for (i = 0; i < min_size; i++) {\
-    if (grn_ts_op_not_equal_ ## kind(lhs.ptr[i], rhs.ptr[i])) {\
-      if (grn_ts_op_less_ ## kind(lhs.ptr[i], rhs.ptr[i])) {\
-        return GRN_TRUE;\
-      }\
-    }\
-  }\
-  return lhs.size <= rhs.size;
-/* grn_ts_op_less_equal_int_vector() returns lhs <= rhs. */
-inline static grn_ts_bool
-grn_ts_op_less_equal_int_vector(grn_ts_int_vector lhs, grn_ts_int_vector rhs) {
-  GRN_TS_OP_LESS_EQUAL_VECTOR(int)
-}
-
-/* grn_ts_op_less_equal_float_vector() returns lhs <= rhs. */
-inline static grn_ts_bool
-grn_ts_op_less_equal_float_vector(grn_ts_float_vector lhs,
-                                  grn_ts_float_vector rhs) {
-  GRN_TS_OP_LESS_EQUAL_VECTOR(float)
-}
-
-/* grn_ts_op_less_equal_time_vector() returns lhs <= rhs. */
-inline static grn_ts_bool
-grn_ts_op_less_equal_time_vector(grn_ts_time_vector lhs,
-                                 grn_ts_time_vector rhs) {
-  GRN_TS_OP_LESS_EQUAL_VECTOR(time)
-}
-
-/* grn_ts_op_less_equal_text_vector() returns lhs <= rhs. */
-inline static grn_ts_bool
-grn_ts_op_less_equal_text_vector(grn_ts_text_vector lhs,
-                                 grn_ts_text_vector rhs) {
-  GRN_TS_OP_LESS_EQUAL_VECTOR(text)
-}
-#undef GRN_TS_OP_LESS_EQUAL_VECTOR
-
-/* grn_ts_op_greater_int() returns lhs > rhs. */
-inline static grn_ts_bool
-grn_ts_op_greater_int(grn_ts_int lhs, grn_ts_int rhs) {
-  return lhs > rhs;
-}
-
-/* grn_ts_op_greater_float() returns lhs > rhs. */
-inline static grn_ts_bool
-grn_ts_op_greater_float(grn_ts_float lhs, grn_ts_float rhs) {
-  return lhs > rhs;
-}
-
-/* grn_ts_op_greater_time() returns lhs > rhs. */
-inline static grn_ts_bool
-grn_ts_op_greater_time(grn_ts_time lhs, grn_ts_time rhs) {
-  return lhs > rhs;
-}
-
-/* grn_ts_op_greater_text() returns lhs > rhs. */
-inline static grn_ts_bool
-grn_ts_op_greater_text(grn_ts_text lhs, grn_ts_text rhs) {
-  size_t min_size = (lhs.size < rhs.size) ? lhs.size : rhs.size;
-  int cmp = memcmp(lhs.ptr, rhs.ptr, min_size);
-  return cmp ? (cmp > 0) : (lhs.size > rhs.size);
-}
-
-#define GRN_TS_OP_GREATER_VECTOR(kind)\
-  size_t i, min_size = (lhs.size < rhs.size) ? lhs.size : rhs.size;\
-  for (i = 0; i < min_size; i++) {\
-    if (grn_ts_op_not_equal_ ## kind(lhs.ptr[i], rhs.ptr[i])) {\
-      if (grn_ts_op_greater_ ## kind(lhs.ptr[i], rhs.ptr[i])) {\
-        return GRN_TRUE;\
-      }\
-    }\
-  }\
-  return lhs.size > rhs.size;
-/* grn_ts_op_greater_int_vector() returns lhs > rhs. */
-inline static grn_ts_bool
-grn_ts_op_greater_int_vector(grn_ts_int_vector lhs, grn_ts_int_vector rhs) {
-  GRN_TS_OP_GREATER_VECTOR(int)
-}
-
-/* grn_ts_op_greater_float_vector() returns lhs > rhs. */
-inline static grn_ts_bool
-grn_ts_op_greater_float_vector(grn_ts_float_vector lhs,
-                               grn_ts_float_vector rhs) {
-  GRN_TS_OP_GREATER_VECTOR(float)
-}
-
-/* grn_ts_op_greater_time_vector() returns lhs > rhs. */
-inline static grn_ts_bool
-grn_ts_op_greater_time_vector(grn_ts_time_vector lhs, grn_ts_time_vector rhs) {
-  GRN_TS_OP_GREATER_VECTOR(time)
-}
-
-/* grn_ts_op_greater_text_vector() returns lhs > rhs. */
-inline static grn_ts_bool
-grn_ts_op_greater_text_vector(grn_ts_text_vector lhs, grn_ts_text_vector rhs) {
-  GRN_TS_OP_GREATER_VECTOR(text)
-}
-#undef GRN_TS_OP_GREATER_VECTOR
-
-/* grn_ts_op_greater_equal_int() returns lhs >= rhs. */
-inline static grn_ts_bool
-grn_ts_op_greater_equal_int(grn_ts_int lhs, grn_ts_int rhs) {
-  return lhs >= rhs;
-}
-
-/* grn_ts_op_greater_equal_float() returns lhs >= rhs. */
-inline static grn_ts_bool
-grn_ts_op_greater_equal_float(grn_ts_float lhs, grn_ts_float rhs) {
-  return lhs >= rhs;
-}
-
-/* grn_ts_op_greater_equal_time() returns lhs >= rhs. */
-inline static grn_ts_bool
-grn_ts_op_greater_equal_time(grn_ts_time lhs, grn_ts_time rhs) {
-  return lhs >= rhs;
-}
-
-/* grn_ts_op_greater_equal_text() returns lhs >= rhs. */
-inline static grn_ts_bool
-grn_ts_op_greater_equal_text(grn_ts_text lhs, grn_ts_text rhs) {
-  size_t min_size = (lhs.size < rhs.size) ? lhs.size : rhs.size;
-  int cmp = memcmp(lhs.ptr, rhs.ptr, min_size);
-  return cmp ? (cmp > 0) : (lhs.size >= rhs.size);
-}
-
-#define GRN_TS_OP_GREATER_EQUAL_VECTOR(kind)\
-  size_t i, min_size = (lhs.size < rhs.size) ? lhs.size : rhs.size;\
-  for (i = 0; i < min_size; i++) {\
-    if (grn_ts_op_not_equal_ ## kind(lhs.ptr[i], rhs.ptr[i])) {\
-      if (grn_ts_op_greater_ ## kind(lhs.ptr[i], rhs.ptr[i])) {\
-        return GRN_TRUE;\
-      }\
-    }\
-  }\
-  return lhs.size >= rhs.size;
-/* grn_ts_op_greater_equal_int_vector() returns lhs >= rhs. */
-inline static grn_ts_bool
-grn_ts_op_greater_equal_int_vector(grn_ts_int_vector lhs,
-                                   grn_ts_int_vector rhs) {
-  GRN_TS_OP_GREATER_EQUAL_VECTOR(int)
-}
-
-/* grn_ts_op_greater_equal_float_vector() returns lhs >= rhs. */
-inline static grn_ts_bool
-grn_ts_op_greater_equal_float_vector(grn_ts_float_vector lhs,
-                                     grn_ts_float_vector rhs) {
-  GRN_TS_OP_GREATER_EQUAL_VECTOR(float)
-}
-
-/* grn_ts_op_greater_equal_time_vector() returns lhs >= rhs. */
-inline static grn_ts_bool
-grn_ts_op_greater_equal_time_vector(grn_ts_time_vector lhs,
-                                    grn_ts_time_vector rhs) {
-  GRN_TS_OP_GREATER_EQUAL_VECTOR(time)
-}
-
-/* grn_ts_op_greater_equal_text_vector() returns lhs >= rhs. */
-inline static grn_ts_bool
-grn_ts_op_greater_equal_text_vector(grn_ts_text_vector lhs,
-                                    grn_ts_text_vector rhs) {
-  GRN_TS_OP_GREATER_EQUAL_VECTOR(text)
-}
-#undef GRN_TS_OP_GREATER_EQUAL_VECTOR
-
-/* grn_ts_op_shift_arithmetic_left() returns lhs << rhs. */
-inline static grn_ts_int
-grn_ts_op_shift_arithmetic_left(grn_ts_int lhs, grn_ts_int rhs) {
-  return lhs << rhs;
-}
-
-/* grn_ts_op_shift_arithmetic_right() returns lhs << rhs. */
-inline static grn_ts_int
-grn_ts_op_shift_arithmetic_right(grn_ts_int lhs, grn_ts_int rhs) {
-  return lhs >> rhs;
-}
-
-/* grn_ts_op_shift_logical_left() returns lhs << rhs. */
-inline static grn_ts_int
-grn_ts_op_shift_logical_left(grn_ts_int lhs, grn_ts_int rhs) {
-  return lhs << rhs;
-}
-
-/* grn_ts_op_shift_logical_right() returns lhs << rhs. */
-inline static grn_ts_int
-grn_ts_op_shift_logical_right(grn_ts_int lhs, grn_ts_int rhs) {
-  return (uint64_t)lhs >> rhs;
-}
-
-/* grn_ts_op_plus_int() returns lhs + rhs. */
-inline static grn_ts_int
-grn_ts_op_plus_int(grn_ts_int lhs, grn_ts_int rhs) {
-  return lhs + rhs;
-}
-
-/* grn_ts_op_plus_float() returns lhs + rhs. */
-inline static grn_ts_float
-grn_ts_op_plus_float(grn_ts_float lhs, grn_ts_float rhs) {
-  return lhs + rhs;
-}
-
-/* grn_ts_op_plus_time_int() returns lhs + rhs (Time + Int = Time). */
-inline static grn_ts_time
-grn_ts_op_plus_time_int(grn_ts_time lhs, grn_ts_int rhs) {
-  return lhs + (rhs * 1000000);
-}
-
-/* grn_ts_op_plus_time_float() returns lhs + rhs (Time + Float = Time). */
-inline static grn_ts_time
-grn_ts_op_plus_time_float(grn_ts_time lhs, grn_ts_float rhs) {
-  return lhs + (grn_ts_int)(rhs * 1000000.0);
-}
-
-/* grn_ts_op_minus_int() returns lhs - rhs. */
-inline static grn_ts_int
-grn_ts_op_minus_int(grn_ts_int lhs, grn_ts_int rhs) {
-  return lhs - rhs;
-}
-
-/* grn_ts_op_minus_float() returns lhs - rhs. */
-inline static grn_ts_float
-grn_ts_op_minus_float(grn_ts_float lhs, grn_ts_float rhs) {
-  return lhs - rhs;
-}
-
-/* grn_ts_op_minus_time_time() returns lhs - rhs (Time - Time = Float). */
-inline static grn_ts_float
-grn_ts_op_minus_time_time(grn_ts_time lhs, grn_ts_time rhs) {
-  return (lhs - rhs) * 0.000001;
-}
-
-/* grn_ts_op_minus_time_int() returns lhs - rhs (Time - Int = Time). */
-inline static grn_ts_time
-grn_ts_op_minus_time_int(grn_ts_time lhs, grn_ts_int rhs) {
-  return lhs - (rhs * 1000000);
-}
-
-/* grn_ts_op_minus_time_float() returns lhs - rhs (Time - Float = Time). */
-inline static grn_ts_time
-grn_ts_op_minus_time_float(grn_ts_time lhs, grn_ts_float rhs) {
-  return lhs - (grn_ts_int)(rhs * 1000000.0);
-}
-
-/* grn_ts_op_multiplication_int() returns lhs * rhs. */
-inline static grn_ts_int
-grn_ts_op_multiplication_int(grn_ts_int lhs, grn_ts_int rhs) {
-  return lhs * rhs;
-}
-
-/* grn_ts_op_multiplication_float() returns lhs * rhs. */
-inline static grn_ts_float
-grn_ts_op_multiplication_float(grn_ts_float lhs, grn_ts_float rhs) {
-  return lhs * rhs;
-}
-
-/*
- * grn_ts_op_division_int() returns lhs / rhs.
- *
- * This function causes a critical error in the following cases:
- * - rhs == 0
- * - (lhs == INT64_MIN) && (rhs == -1)
- */
-inline static grn_ts_int
-grn_ts_op_division_int(grn_ts_int lhs, grn_ts_int rhs) {
-  return lhs / rhs;
-}
-
-/* grn_ts_op_division_float() returns lhs / rhs. */
-inline static grn_ts_float
-grn_ts_op_division_float(grn_ts_float lhs, grn_ts_float rhs) {
-  return lhs / rhs;
-}
-
-/*
- * grn_ts_op_modulus_int() returns lhs % rhs.
- *
- * This function causes a critical error in the following cases:
- * - rhs == 0
- * - (lhs == INT64_MIN) && (rhs == -1)
- */
-inline static grn_ts_int
-grn_ts_op_modulus_int(grn_ts_int lhs, grn_ts_int rhs) {
-  return lhs % rhs;
-}
-
-/* grn_ts_op_modulus_float() returns lhs % rhs. */
-inline static grn_ts_float
-grn_ts_op_modulus_float(grn_ts_float lhs, grn_ts_float rhs) {
-  return fmod(lhs, rhs);
-}
-
-/*-------------------------------------------------------------
- * Groonga objects.
- */
-
-/* grn_ts_obj_increment_ref_count() increments an object reference count. */
-static grn_rc
-grn_ts_obj_increment_ref_count(grn_ctx *ctx, grn_obj *obj) {
-  grn_id id = grn_obj_id(ctx, obj);
-  grn_obj *obj_clone = grn_ctx_at(ctx, id);
-  if (!obj_clone) {
-    GRN_TS_ERR_RETURN(GRN_UNKNOWN_ERROR, "grn_ctx_at failed: %d", id);
-  }
-  if (obj_clone != obj) {
-    grn_obj_unlink(ctx, obj_clone);
-    GRN_TS_ERR_RETURN(GRN_UNKNOWN_ERROR, "wrong object: %p != %p",
-                      obj, obj_clone);
-  }
-  return GRN_SUCCESS;
-}
-
 /* grn_ts_obj_is_table() returns whether or not an object is a table. */
 static grn_ts_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 or not an object is a column. */
-static grn_ts_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_ja_get_value() gets a value from ja and writes it to buf. Note the a
- * value is appended to the end of buf.
- */
-static grn_rc
-grn_ts_ja_get_value(grn_ctx *ctx, grn_ja *ja, grn_ts_id id,
-                    grn_ts_buf *buf, size_t *value_size) {
-  grn_rc rc;
-  uint32_t size;
-  grn_io_win iw;
-  char *ptr = (char *)grn_ja_ref(ctx, ja, id, &iw, &size);
-  if (!ptr) {
-    if (value_size) {
-      *value_size = 0;
-    }
-    return GRN_SUCCESS;
-  }
-  rc = grn_ts_buf_write(ctx, buf, ptr, size);
-  grn_ja_unref(ctx, &iw);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  if (value_size) {
-    *value_size = size;
-  }
-  return GRN_SUCCESS;
-}
-
-#define GRN_TS_TABLE_GET_KEY(type)\
-  uint32_t key_size;\
-  const void *key_ptr = _grn_ ## type ## _key(ctx, type, id, &key_size);\
-  if (!key_ptr) {\
-    GRN_TS_ERR_RETURN(GRN_UNKNOWN_ERROR, "_grn_" #type "_key failed: %u", id);\
-  }\
-/* grn_ts_hash_get_bool_key() gets a reference to a key (_key). */
-static grn_rc
-grn_ts_hash_get_bool_key(grn_ctx *ctx, grn_hash *hash, grn_ts_id id,
-                         grn_ts_bool *key) {
-  GRN_TS_TABLE_GET_KEY(hash)
-  *key = *(const grn_ts_bool *)key_ptr;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_hash_get_int8_key() gets a reference to a key (_key). */
-static grn_rc
-grn_ts_hash_get_int8_key(grn_ctx *ctx, grn_hash *hash, grn_ts_id id,
-                         grn_ts_int *key) {
-  GRN_TS_TABLE_GET_KEY(hash)
-  *key = *(const int8_t *)key_ptr;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_hash_get_int16_key() gets a reference to a key (_key). */
-static grn_rc
-grn_ts_hash_get_int16_key(grn_ctx *ctx, grn_hash *hash, grn_ts_id id,
-                          grn_ts_int *key) {
-  GRN_TS_TABLE_GET_KEY(hash)
-  *key = *(const int16_t *)key_ptr;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_hash_get_int32_key() gets a reference to a key (_key). */
-static grn_rc
-grn_ts_hash_get_int32_key(grn_ctx *ctx, grn_hash *hash, grn_ts_id id,
-                          grn_ts_int *key) {
-  GRN_TS_TABLE_GET_KEY(hash)
-  *key = *(const int32_t *)key_ptr;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_hash_get_int64_key() gets a reference to a key (_key). */
-static grn_rc
-grn_ts_hash_get_int64_key(grn_ctx *ctx, grn_hash *hash, grn_ts_id id,
-                          grn_ts_int *key) {
-  GRN_TS_TABLE_GET_KEY(hash)
-  *key = *(const int64_t *)key_ptr;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_hash_get_uint8_key() gets a reference to a key (_key). */
-static grn_rc
-grn_ts_hash_get_uint8_key(grn_ctx *ctx, grn_hash *hash, grn_ts_id id,
-                          grn_ts_int *key) {
-  GRN_TS_TABLE_GET_KEY(hash)
-  *key = *(const uint8_t *)key_ptr;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_hash_get_uint16_key() gets a reference to a key (_key). */
-static grn_rc
-grn_ts_hash_get_uint16_key(grn_ctx *ctx, grn_hash *hash, grn_ts_id id,
-                           grn_ts_int *key) {
-  GRN_TS_TABLE_GET_KEY(hash)
-  *key = *(const uint16_t *)key_ptr;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_hash_get_uint32_key() gets a reference to a key (_key). */
-static grn_rc
-grn_ts_hash_get_uint32_key(grn_ctx *ctx, grn_hash *hash, grn_ts_id id,
-                           grn_ts_int *key) {
-  GRN_TS_TABLE_GET_KEY(hash)
-  *key = *(const uint32_t *)key_ptr;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_hash_get_uint64_key() gets a reference to a key (_key). */
-static grn_rc
-grn_ts_hash_get_uint64_key(grn_ctx *ctx, grn_hash *hash, grn_ts_id id,
-                           grn_ts_int *key) {
-  GRN_TS_TABLE_GET_KEY(hash)
-  *key = (grn_ts_int)*(const uint64_t *)key_ptr;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_hash_get_float_key() gets a reference to a key (_key). */
-static grn_rc
-grn_ts_hash_get_float_key(grn_ctx *ctx, grn_hash *hash, grn_ts_id id,
-                          grn_ts_float *key) {
-  GRN_TS_TABLE_GET_KEY(hash)
-  *key = *(const grn_ts_float *)key_ptr;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_hash_get_time_key() gets a reference to a key (_key). */
-static grn_rc
-grn_ts_hash_get_time_key(grn_ctx *ctx, grn_hash *hash, grn_ts_id id,
-                         grn_ts_time *key) {
-  GRN_TS_TABLE_GET_KEY(hash)
-  *key = *(const grn_ts_time *)key_ptr;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_hash_get_geo_point_key() gets a reference to a key (_key). */
-static grn_rc
-grn_ts_hash_get_geo_point_key(grn_ctx *ctx, grn_hash *hash, grn_ts_id id,
-                              grn_ts_geo_point *key) {
-  GRN_TS_TABLE_GET_KEY(hash)
-  *key = *(const grn_ts_geo_point *)key_ptr;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_hash_get_text_key() gets a reference to a key (_key). */
-static grn_rc
-grn_ts_hash_get_text_key(grn_ctx *ctx, grn_hash *hash, grn_ts_id id,
-                         grn_ts_text *key) {
-  GRN_TS_TABLE_GET_KEY(hash)
-  key->ptr = key_ptr;
-  key->size = key_size;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_hash_get_ref_key() gets a reference to a key (_key). */
-static grn_rc
-grn_ts_hash_get_ref_key(grn_ctx *ctx, grn_hash *hash, grn_ts_id id,
-                        grn_ts_ref *key) {
-  GRN_TS_TABLE_GET_KEY(hash)
-  key->id = *(const grn_ts_id *)key_ptr;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_pat_get_bool_key() gets a reference to a key (_key). */
-static grn_rc
-grn_ts_pat_get_bool_key(grn_ctx *ctx, grn_pat *pat, grn_ts_id id,
-                        grn_ts_bool *key) {
-  GRN_TS_TABLE_GET_KEY(pat)
-  *key = *(const grn_ts_bool *)key_ptr;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_pat_get_int8_key() gets a reference to a key (_key). */
-static grn_rc
-grn_ts_pat_get_int8_key(grn_ctx *ctx, grn_pat *pat, grn_ts_id id,
-                        grn_ts_int *key) {
-  int8_t tmp;
-  GRN_TS_TABLE_GET_KEY(pat)
-  grn_ntohi(&tmp, key_ptr, sizeof(tmp));
-  *key = tmp;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_pat_get_int16_key() gets a reference to a key (_key). */
-static grn_rc
-grn_ts_pat_get_int16_key(grn_ctx *ctx, grn_pat *pat, grn_ts_id id,
-                         grn_ts_int *key) {
-  int16_t tmp;
-  GRN_TS_TABLE_GET_KEY(pat)
-  grn_ntohi(&tmp, key_ptr, sizeof(tmp));
-  *key = tmp;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_pat_get_int32_key() gets a reference to a key (_key). */
-static grn_rc
-grn_ts_pat_get_int32_key(grn_ctx *ctx, grn_pat *pat, grn_ts_id id,
-                         grn_ts_int *key) {
-  int32_t tmp;
-  GRN_TS_TABLE_GET_KEY(pat)
-  grn_ntohi(&tmp, key_ptr, sizeof(tmp));
-  *key = tmp;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_pat_get_int64_key() gets a reference to a key (_key). */
-static grn_rc
-grn_ts_pat_get_int64_key(grn_ctx *ctx, grn_pat *pat, grn_ts_id id,
-                         grn_ts_int *key) {
-  GRN_TS_TABLE_GET_KEY(pat)
-  grn_ntohi(key, key_ptr, sizeof(grn_ts_int));
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_pat_get_uint8_key() gets a reference to a key (_key). */
-static grn_rc
-grn_ts_pat_get_uint8_key(grn_ctx *ctx, grn_pat *pat, grn_ts_id id,
-                         grn_ts_int *key) {
-  GRN_TS_TABLE_GET_KEY(pat)
-  *key = *(const uint8_t *)key_ptr;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_pat_get_uint16_key() gets a reference to a key (_key). */
-static grn_rc
-grn_ts_pat_get_uint16_key(grn_ctx *ctx, grn_pat *pat, grn_ts_id id,
-                          grn_ts_int *key) {
-  uint16_t tmp;
-  GRN_TS_TABLE_GET_KEY(pat)
-  grn_ntoh(&tmp, key_ptr, sizeof(tmp));
-  *key = tmp;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_pat_get_uint32_key() gets a reference to a key (_key). */
-static grn_rc
-grn_ts_pat_get_uint32_key(grn_ctx *ctx, grn_pat *pat, grn_ts_id id,
-                          grn_ts_int *key) {
-  uint32_t tmp;
-  GRN_TS_TABLE_GET_KEY(pat)
-  grn_ntoh(&tmp, key_ptr, sizeof(tmp));
-  *key = tmp;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_pat_get_uint64_key() gets a reference to a key (_key). */
-static grn_rc
-grn_ts_pat_get_uint64_key(grn_ctx *ctx, grn_pat *pat, grn_ts_id id,
-                          grn_ts_int *key) {
-  GRN_TS_TABLE_GET_KEY(pat)
-  grn_ntoh(key, key_ptr, sizeof(grn_ts_int));
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_pat_get_float_key() gets a reference to a key (_key). */
-static grn_rc
-grn_ts_pat_get_float_key(grn_ctx *ctx, grn_pat *pat, grn_ts_id id,
-                         grn_ts_float *key) {
-  int64_t tmp;
-  GRN_TS_TABLE_GET_KEY(pat)
-  grn_ntoh(&tmp, key_ptr, sizeof(tmp));
-  tmp ^= (((tmp ^ ((int64_t)1 << 63)) >> 63) | ((int64_t)1 << 63));
-  *(int64_t *)key = tmp;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_pat_get_time_key() gets a reference to a key (_key). */
-static grn_rc
-grn_ts_pat_get_time_key(grn_ctx *ctx, grn_pat *pat, grn_ts_id id,
-                        grn_ts_time *key) {
-  GRN_TS_TABLE_GET_KEY(pat)
-  grn_ntohi(key, key_ptr, sizeof(grn_ts_time));
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_pat_get_geo_point_key() gets a reference to a key (_key). */
-static grn_rc
-grn_ts_pat_get_geo_point_key(grn_ctx *ctx, grn_pat *pat, grn_ts_id id,
-                             grn_ts_geo_point *key) {
-  GRN_TS_TABLE_GET_KEY(pat)
-  grn_ntog(key, key_ptr, sizeof(grn_ts_geo_point));
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_pat_get_text_key() gets a reference to a key (_key). */
-static grn_rc
-grn_ts_pat_get_text_key(grn_ctx *ctx, grn_pat *pat, grn_ts_id id,
-                        grn_ts_text *key) {
-  GRN_TS_TABLE_GET_KEY(pat)
-  key->ptr = key_ptr;
-  key->size = key_size;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_pat_get_ref_key() gets a reference to a key (_key). */
-static grn_rc
-grn_ts_pat_get_ref_key(grn_ctx *ctx, grn_pat *pat, grn_ts_id id,
-                       grn_ts_ref *key) {
-  GRN_TS_TABLE_GET_KEY(pat)
-  grn_ntoh(&key->id, key_ptr, sizeof(key->id));
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_dat_get_text_key() gets a reference to a key (_key). */
-static grn_rc
-grn_ts_dat_get_text_key(grn_ctx *ctx, grn_dat *dat, grn_ts_id id,
-                        grn_ts_text *key) {
-  GRN_TS_TABLE_GET_KEY(dat)
-  key->ptr = key_ptr;
-  key->size = key_size;
-  return GRN_SUCCESS;
-}
-#undef GRN_TS_TABLE_GET_KEY
-
-/* grn_ts_table_has_key() returns whether or not a table has _key. */
-static grn_ts_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 or not a table has _value. */
-static grn_ts_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() gets a reference to a value (_value). On failure,
- * this function returns NULL.
- */
-static const void *
-grn_ts_table_get_value(grn_ctx *ctx, grn_obj *table, grn_ts_id id) {
-  switch (table->header.type) {
-    case GRN_TABLE_HASH_KEY: {
-      uint32_t size;
-      return grn_hash_get_value_(ctx, (grn_hash *)table, id, &size);
-    }
-    case GRN_TABLE_PAT_KEY: {
-      uint32_t size;
-      return grn_pat_get_value_(ctx, (grn_pat *)table, id, &size);
-    }
-    /* GRN_TABLE_DAT_KEY does not support _value. */
-    case GRN_TABLE_NO_KEY: {
-      return _grn_array_get_value(ctx, (grn_array *)table, id);
-    }
-    default: {
-      return NULL;
-    }
-  }
-}
-
-/*-------------------------------------------------------------
- * grn_ts_expr_id_node.
- */
-
-typedef struct {
-  GRN_TS_EXPR_NODE_COMMON_MEMBERS
-} grn_ts_expr_id_node;
-
-/* grn_ts_expr_id_node_init() initializes a node. */
-static void
-grn_ts_expr_id_node_init(grn_ctx *ctx, grn_ts_expr_id_node *node) {
-  memset(node, 0, sizeof(*node));
-  node->type = GRN_TS_EXPR_ID_NODE;
-  node->data_kind = GRN_TS_INT;
-  node->data_type = GRN_DB_UINT32;
-}
-
-/* grn_ts_expr_id_node_fin() finalizes a node. */
-static void
-grn_ts_expr_id_node_fin(grn_ctx *ctx, grn_ts_expr_id_node *node) {
-  /* Nothing to do. */
-}
-
-/* grn_ts_expr_id_node_open() creates a node associated with IDs (_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) {
-    GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE, "GRN_MALLOCN failed: %zu x 1",
-                      sizeof(grn_ts_expr_id_node));
-  }
-  grn_ts_expr_id_node_init(ctx, new_node);
-  *node = (grn_ts_expr_node *)new_node;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_expr_id_node_close() destroys a node. */
-static void
-grn_ts_expr_id_node_close(grn_ctx *ctx, grn_ts_expr_id_node *node) {
-  grn_ts_expr_id_node_fin(ctx, node);
-  GRN_FREE(node);
-}
-
-/* grn_ts_expr_id_node_evaluate() outputs IDs. */
-static grn_rc
-grn_ts_expr_id_node_evaluate(grn_ctx *ctx, grn_ts_expr_id_node *node,
-                             const grn_ts_record *in, size_t n_in, void *out) {
-  size_t i;
-  grn_ts_int *out_ptr = (grn_ts_int *)out;
-  for (i = 0; i < n_in; i++) {
-    out_ptr[i] = (grn_ts_int)in[i].id;
-  }
-  return GRN_SUCCESS;
-}
-
-/*-------------------------------------------------------------
- * grn_ts_expr_score_node.
- */
-
-typedef struct {
-  GRN_TS_EXPR_NODE_COMMON_MEMBERS
-} grn_ts_expr_score_node;
-
-/* grn_ts_expr_score_node_init() initializes a node. */
-static void
-grn_ts_expr_score_node_init(grn_ctx *ctx, grn_ts_expr_score_node *node) {
-  memset(node, 0, sizeof(*node));
-  node->type = GRN_TS_EXPR_SCORE_NODE;
-  node->data_kind = GRN_TS_FLOAT;
-  node->data_type = GRN_DB_FLOAT;
-}
-
-/* grn_ts_expr_score_node_fin() finalizes a node. */
-static void
-grn_ts_expr_score_node_fin(grn_ctx *ctx, grn_ts_expr_score_node *node) {
-  /* Nothing to do. */
-}
-
-/*
- * grn_ts_expr_score_node_open() creates a node associated with scores
- * (_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) {
-    GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE, "GRN_MALLOCN failed: %zu x 1",
-                      sizeof(grn_ts_expr_score_node));
-  }
-  grn_ts_expr_score_node_init(ctx, new_node);
-  *node = (grn_ts_expr_node *)new_node;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_expr_score_node_close() destroys a node. */
-static void
-grn_ts_expr_score_node_close(grn_ctx *ctx, grn_ts_expr_score_node *node) {
-  grn_ts_expr_score_node_fin(ctx, node);
-  GRN_FREE(node);
-}
-
-/* grn_ts_expr_score_node_evaluate() outputs scores. */
-static grn_rc
-grn_ts_expr_score_node_evaluate(grn_ctx *ctx, grn_ts_expr_score_node *node,
-                                const grn_ts_record *in, size_t n_in,
-                                void *out) {
-  size_t i;
-  grn_ts_float *out_ptr = (grn_ts_float *)out;
-  for (i = 0; i < n_in; i++) {
-    out_ptr[i] = (grn_ts_float)in[i].score;
-  }
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_expr_score_node_adjust() does nothing. */
-static grn_rc
-grn_ts_expr_score_node_adjust(grn_ctx *ctx, grn_ts_expr_score_node *node,
-                              grn_ts_record *io, size_t n_io) {
-  /* Nothing to do. */
-  return GRN_SUCCESS;
-}
-
-/*-------------------------------------------------------------
- * grn_ts_expr_key_node.
- */
-
-typedef struct {
-  GRN_TS_EXPR_NODE_COMMON_MEMBERS
-  grn_obj *table;
-  grn_ts_buf buf;
-} grn_ts_expr_key_node;
-
-/* grn_ts_expr_key_node_init() initializes a node. */
-static void
-grn_ts_expr_key_node_init(grn_ctx *ctx, grn_ts_expr_key_node *node) {
-  memset(node, 0, sizeof(*node));
-  node->type = GRN_TS_EXPR_KEY_NODE;
-  node->table = NULL;
-  grn_ts_buf_init(ctx, &node->buf);
-}
-
-/* grn_ts_expr_key_node_fin() finalizes a node. */
-static void
-grn_ts_expr_key_node_fin(grn_ctx *ctx, grn_ts_expr_key_node *node) {
-  grn_ts_buf_fin(ctx, &node->buf);
-  if (node->table) {
-    grn_obj_unlink(ctx, node->table);
-  }
-}
-
-/* grn_ts_expr_key_node_open() creates a node associated with keys (_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)) {
-    GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "the table has no _key");
-  }
-  new_node = GRN_MALLOCN(grn_ts_expr_key_node, 1);
-  if (!new_node) {
-    GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE, "GRN_MALLOCN failed: %zu x 1",
-                      sizeof(grn_ts_expr_key_node));
-  }
-  grn_ts_expr_key_node_init(ctx, new_node);
-  rc = grn_ts_obj_increment_ref_count(ctx, table);
-  if (rc != GRN_SUCCESS) {
-    grn_ts_expr_key_node_fin(ctx, new_node);
-    GRN_FREE(new_node);
-    return rc;
-  }
-  new_node->data_kind = grn_ts_data_type_to_kind(table->header.domain);
-  new_node->data_type = table->header.domain;
-  new_node->table = table;
-  *node = (grn_ts_expr_node *)new_node;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_expr_key_node_close() destroys a node. */
-static void
-grn_ts_expr_key_node_close(grn_ctx *ctx, grn_ts_expr_key_node *node) {
-  grn_ts_expr_key_node_fin(ctx, node);
-  GRN_FREE(node);
-}
-
-#define GRN_TS_EXPR_KEY_NODE_EVALUATE_CASE(table, KIND, kind)\
-  case GRN_TS_ ## KIND: {\
-    grn_ts_ ## kind *out_ptr = (grn_ts_ ## kind *)out;\
-    for (i = 0; i < n_in; i++) {\
-      rc = grn_ts_ ## table ## _get_ ## kind ## _key(ctx, table, in[i].id,\
-                                                     &out_ptr[i]);\
-      if (rc != GRN_SUCCESS) {\
-        out_ptr[i] = grn_ts_ ## kind ## _zero();\
-      }\
-    }\
-    return GRN_SUCCESS;\
-  }
-#define GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(table, TYPE, type)\
-  case GRN_DB_ ## TYPE: {\
-    grn_ts_int *out_ptr = (grn_ts_int *)out;\
-    for (i = 0; i < n_in; i++) {\
-      rc = grn_ts_ ## table ## _get_ ## type ## _key(ctx, table, in[i].id,\
-                                                     &out_ptr[i]);\
-      if (rc != GRN_SUCCESS) {\
-        out_ptr[i] = grn_ts_int_zero();\
-      }\
-    }\
-    return GRN_SUCCESS;\
-  }
-#define GRN_TS_EXPR_KEY_NODE_EVALUATE_TEXT_CASE(table)\
-  case GRN_TS_TEXT: {\
-    char *buf_ptr;\
-    grn_ts_text *out_ptr = (grn_ts_text *)out;\
-    node->buf.pos = 0;\
-    for (i = 0; i < n_in; i++) {\
-      grn_ts_text key;\
-      rc = grn_ts_ ## table ## _get_text_key(ctx, table, in[i].id, &key);\
-      if (rc != GRN_SUCCESS) {\
-        key = grn_ts_text_zero();\
-      }\
-      rc = grn_ts_buf_write(ctx, &node->buf, key.ptr, key.size);\
-      if (rc != GRN_SUCCESS) {\
-        return rc;\
-      }\
-      out_ptr[i].size = key.size;\
-    }\
-    buf_ptr = (char *)node->buf.ptr;\
-    for (i = 0; i < n_in; i++) {\
-      out_ptr[i].ptr = buf_ptr;\
-      buf_ptr += out_ptr[i].size;\
-    }\
-    return GRN_SUCCESS;\
-  }
-#define GRN_TS_EXPR_KEY_NODE_EVALUATE_REF_CASE(table)\
-  case GRN_TS_REF: {\
-    grn_ts_ref *out_ptr = (grn_ts_ref *)out;\
-    for (i = 0; i < n_in; i++) {\
-      rc = grn_ts_ ## table ## _get_ref_key(ctx, table, in[i].id,\
-                                            &out_ptr[i]);\
-      if (rc != GRN_SUCCESS) {\
-        out_ptr[i] = grn_ts_ref_zero();\
-      }\
-      out_ptr[i].score = in[i].score;\
-    }\
-    return GRN_SUCCESS;\
-  }
-/* grn_ts_expr_key_node_evaluate() outputs keys. */
-static grn_rc
-grn_ts_expr_key_node_evaluate(grn_ctx *ctx, grn_ts_expr_key_node *node,
-                              const grn_ts_record *in, size_t n_in,
-                              void *out) {
-  size_t i;
-  grn_rc rc;
-  switch (node->table->header.type) {
-    case GRN_TABLE_HASH_KEY: {
-      grn_hash *hash = (grn_hash *)node->table;
-      switch (node->data_kind) {
-        GRN_TS_EXPR_KEY_NODE_EVALUATE_CASE(hash, BOOL, bool)
-        case GRN_TS_INT: {
-          switch (node->data_type) {
-            GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(hash, INT8, int8)
-            GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(hash, INT16, int16)
-            GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(hash, INT32, int32)
-            GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(hash, INT64, int64)
-            GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(hash, UINT8, uint8)
-            GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(hash, UINT16, uint16)
-            GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(hash, UINT32, uint32)
-            GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(hash, UINT64, uint64)
-          }
-        }
-        GRN_TS_EXPR_KEY_NODE_EVALUATE_CASE(hash, FLOAT, float)
-        GRN_TS_EXPR_KEY_NODE_EVALUATE_CASE(hash, TIME, time)
-        GRN_TS_EXPR_KEY_NODE_EVALUATE_TEXT_CASE(hash)
-        GRN_TS_EXPR_KEY_NODE_EVALUATE_CASE(hash, GEO_POINT, geo_point)
-        GRN_TS_EXPR_KEY_NODE_EVALUATE_REF_CASE(hash)
-        default: {
-          GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",
-                            node->data_kind);
-        }
-      }
-    }
-    case GRN_TABLE_PAT_KEY: {
-      grn_pat *pat = (grn_pat *)node->table;
-      switch (node->data_kind) {
-        GRN_TS_EXPR_KEY_NODE_EVALUATE_CASE(pat, BOOL, bool)
-        case GRN_TS_INT: {
-          switch (node->data_type) {
-            GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(pat, INT8, int8)
-            GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(pat, INT16, int16)
-            GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(pat, INT32, int32)
-            GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(pat, INT64, int64)
-            GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(pat, UINT8, uint8)
-            GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(pat, UINT16, uint16)
-            GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(pat, UINT32, uint32)
-            GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(pat, UINT64, uint64)
-          }
-        }
-        GRN_TS_EXPR_KEY_NODE_EVALUATE_CASE(pat, FLOAT, float)
-        GRN_TS_EXPR_KEY_NODE_EVALUATE_CASE(pat, TIME, time)
-        GRN_TS_EXPR_KEY_NODE_EVALUATE_TEXT_CASE(pat)
-        GRN_TS_EXPR_KEY_NODE_EVALUATE_CASE(pat, GEO_POINT, geo_point)
-        GRN_TS_EXPR_KEY_NODE_EVALUATE_REF_CASE(pat)
-        default: {
-          GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",
-                            node->data_kind);
-        }
-      }
-    }
-    case GRN_TABLE_DAT_KEY: {
-      grn_dat *dat = (grn_dat *)node->table;
-      switch (node->data_kind) {
-        GRN_TS_EXPR_KEY_NODE_EVALUATE_TEXT_CASE(dat)
-        /* GRN_TABLE_DAT_KEY supports only Text. */
-        default: {
-          GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",
-                            node->data_kind);
-        }
-      }
-    }
-    /* GRN_TABLE_NO_KEY doesn't support _key. */
-    default: {
-      GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid table type: %d",
-                        node->table->header.type);
-    }
-  }
-}
-#undef GRN_TS_EXPR_KEY_NODE_EVALUATE_REF_CASE
-#undef GRN_TS_EXPR_KEY_NODE_EVALUATE_TEXT_CASE
-#undef GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE
-#undef GRN_TS_EXPR_KEY_NODE_EVALUATE_CASE
-
-/* grn_ts_expr_key_node_filter() filters records. */
-static grn_rc
-grn_ts_expr_key_node_filter(grn_ctx *ctx, grn_ts_expr_key_node *node,
-                            grn_ts_record *in, size_t n_in,
-                            grn_ts_record *out, size_t *n_out) {
-  size_t i, count;
-  grn_ts_bool key;
-  switch (node->table->header.type) {
-    case GRN_TABLE_HASH_KEY: {
-      grn_hash *hash = (grn_hash *)node->table;
-      for (i = 0, count = 0; i < n_in; i++) {
-        grn_rc rc = grn_ts_hash_get_bool_key(ctx, hash, in[i].id, &key);
-        if (rc != GRN_SUCCESS) {
-          key = grn_ts_bool_zero();
-        }
-        if (key) {
-          out[count++] = in[i];
-        }
-      }
-      *n_out = count;
-      return GRN_SUCCESS;
-    }
-    case GRN_TABLE_PAT_KEY: {
-      grn_pat *pat = (grn_pat *)node->table;
-      for (i = 0, count = 0; i < n_in; i++) {
-        grn_rc rc = grn_ts_pat_get_bool_key(ctx, pat, in[i].id, &key);
-        if (rc != GRN_SUCCESS) {
-          key = grn_ts_bool_zero();
-        }
-        if (key) {
-          out[count++] = in[i];
-        }
-      }
-      *n_out = count;
-      return GRN_SUCCESS;
-    }
-    /* GRN_TABLE_DAT_KEY and GRN_TABLE_NO_KEY don't support a Bool key. */
-    default: {
-      GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid table type: %d",
-                        node->table->header.type);
-    }
-  }
-}
-
-/* grn_ts_expr_key_node_adjust() updates scores. */
-static grn_rc
-grn_ts_expr_key_node_adjust(grn_ctx *ctx, grn_ts_expr_key_node *node,
-                            grn_ts_record *io, size_t n_io) {
-  size_t i;
-  grn_ts_float key;
-  switch (node->table->header.type) {
-    case GRN_TABLE_HASH_KEY: {
-      grn_hash *hash = (grn_hash *)node->table;
-      for (i = 0; i < n_io; i++) {
-        grn_rc rc = grn_ts_hash_get_float_key(ctx, hash, io[i].id, &key);
-        if (rc != GRN_SUCCESS) {
-          key = grn_ts_float_zero();
-        }
-        io[i].score = (grn_ts_score)key;
-      }
-      return GRN_SUCCESS;
-    }
-    case GRN_TABLE_PAT_KEY: {
-      grn_pat *pat = (grn_pat *)node->table;
-      for (i = 0; i < n_io; i++) {
-        grn_rc rc = grn_ts_pat_get_float_key(ctx, pat, io[i].id, &key);
-        if (rc != GRN_SUCCESS) {
-          key = grn_ts_float_zero();
-        }
-        io[i].score = (grn_ts_score)key;
-      }
-      return GRN_SUCCESS;
-    }
-    /* GRN_TABLE_DAT_KEY and GRN_TABLE_NO_KEY don't support a Float key. */
-    default: {
-      GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid table type: %d",
-                        node->table->header.type);
-    }
-  }
-}
-
-/*-------------------------------------------------------------
- * grn_ts_expr_value_node.
- */
-
-typedef struct {
-  GRN_TS_EXPR_NODE_COMMON_MEMBERS
-  grn_obj *table;
-} grn_ts_expr_value_node;
-
-/* grn_ts_expr_value_node_init() initializes a node. */
-static void
-grn_ts_expr_value_node_init(grn_ctx *ctx, grn_ts_expr_value_node *node) {
-  memset(node, 0, sizeof(*node));
-  node->type = GRN_TS_EXPR_VALUE_NODE;
-  node->table = NULL;
-}
-
-/* grn_ts_expr_value_node_fin() finalizes a node. */
-static void
-grn_ts_expr_value_node_fin(grn_ctx *ctx, grn_ts_expr_value_node *node) {
-  if (node->table) {
-    grn_obj_unlink(ctx, node->table);
-  }
-}
-
-/*
- * grn_ts_expr_value_node_open() creates a node associated with values
- * (_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)) {
-    GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "table has no _value");
-  }
-  new_node = GRN_MALLOCN(grn_ts_expr_value_node, 1);
-  if (!new_node) {
-    GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE, "GRN_MALLOCN failed: %zu x 1",
-                      sizeof(grn_ts_expr_value_node));
-  }
-  grn_ts_expr_value_node_init(ctx, new_node);
-  rc = grn_ts_obj_increment_ref_count(ctx, table);
-  if (rc != GRN_SUCCESS) {
-    GRN_FREE(new_node);
-    return rc;
-  }
-  new_node->data_kind = grn_ts_data_type_to_kind(DB_OBJ(table)->range);
-  new_node->data_type = DB_OBJ(table)->range;
-  new_node->table = table;
-  *node = (grn_ts_expr_node *)new_node;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_expr_value_node_close() destroys a node. */
-static void
-grn_ts_expr_value_node_close(grn_ctx *ctx, grn_ts_expr_value_node *node) {
-  grn_ts_expr_value_node_fin(ctx, node);
-  GRN_FREE(node);
-}
-
-#define GRN_TS_EXPR_VALUE_NODE_EVALUATE_CASE(KIND, kind)\
-  case GRN_TS_ ## KIND: {\
-    size_t i;\
-    grn_ts_ ## kind *out_ptr = (grn_ts_ ## kind *)out;\
-    for (i = 0; i < n_in; i++) {\
-      const void *ptr = grn_ts_table_get_value(ctx, node->table, in[i].id);\
-      if (ptr) {\
-        out_ptr[i] = *(const grn_ts_ ## kind *)ptr;\
-      } else {\
-        out_ptr[i] = grn_ts_ ## kind ## _zero();\
-      }\
-    }\
-    return GRN_SUCCESS;\
-  }
-#define GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE(TYPE, type)\
-  case GRN_DB_ ## TYPE: {\
-    size_t i;\
-    grn_ts_int *out_ptr = (grn_ts_int *)out;\
-    for (i = 0; i < n_in; i++) {\
-      const void *ptr = grn_ts_table_get_value(ctx, node->table, in[i].id);\
-      if (ptr) {\
-        out_ptr[i] = (grn_ts_int)*(const type ## _t *)ptr;\
-      } else {\
-        out_ptr[i] = grn_ts_int_zero();\
-      }\
-    }\
-    return GRN_SUCCESS;\
-  }
-/* grn_ts_expr_value_node_evaluate() outputs values. */
-static grn_rc
-grn_ts_expr_value_node_evaluate(grn_ctx *ctx, grn_ts_expr_value_node *node,
-                                const grn_ts_record *in, size_t n_in,
-                                void *out) {
-  switch (node->data_kind) {
-    GRN_TS_EXPR_VALUE_NODE_EVALUATE_CASE(BOOL, bool)
-    case GRN_TS_INT: {
-      switch (node->data_type) {
-        GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE(INT8, int8)
-        GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE(INT16, int16)
-        GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE(INT32, int32)
-        GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE(INT64, int64)
-        GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE(UINT8, uint8)
-        GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE(UINT16, uint16)
-        GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE(UINT32, uint32)
-        GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE(UINT64, uint64)
-        default: {
-          GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data type: %d",
-                            node->data_type);
-        }
-      }
-    }
-    GRN_TS_EXPR_VALUE_NODE_EVALUATE_CASE(FLOAT, float)
-    GRN_TS_EXPR_VALUE_NODE_EVALUATE_CASE(TIME, time)
-    GRN_TS_EXPR_VALUE_NODE_EVALUATE_CASE(GEO_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++) {
-        const void *ptr = grn_ts_table_get_value(ctx, node->table, in[i].id);
-        if (ptr) {
-          out_ptr[i].id = *(const grn_ts_id *)ptr;
-          out_ptr[i].score = in[i].score;
-        } else {
-          out_ptr[i] = grn_ts_ref_zero();
-        }
-      }
-      return GRN_SUCCESS;
-    }
-    default: {
-      GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",
-                        node->data_kind);
-    }
-  }
-}
-#undef GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE
-#undef GRN_TS_EXPR_VALUE_NODE_EVALUATE_CASE
-
-/* grn_ts_expr_value_node_filter() filters records. */
-static grn_rc
-grn_ts_expr_value_node_filter(grn_ctx *ctx, grn_ts_expr_value_node *node,
-                              grn_ts_record *in, size_t n_in,
-                              grn_ts_record *out, size_t *n_out) {
-  size_t i, count = 0;
-  for (i = 0; i < n_in; i++) {
-    const void *ptr = grn_ts_table_get_value(ctx, node->table, in[i].id);
-    if (ptr && *(const grn_ts_bool *)ptr) {
-      out[count++] = in[i];
-    }
-  }
-  *n_out = count;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_expr_value_node_adjust() updates scores. */
-static grn_rc
-grn_ts_expr_value_node_adjust(grn_ctx *ctx, grn_ts_expr_value_node *node,
-                              grn_ts_record *io, size_t n_io) {
-  size_t i;
-  for (i = 0; i < n_io; i++) {
-    const void *ptr = grn_ts_table_get_value(ctx, node->table, io[i].id);
-    if (ptr) {
-      io[i].score = (grn_ts_score)*(const grn_ts_float *)ptr;
-    }
-  }
-  return GRN_SUCCESS;
-}
-
-/*-------------------------------------------------------------
- * grn_ts_expr_const_node.
- */
-
-typedef struct {
-  GRN_TS_EXPR_NODE_COMMON_MEMBERS
-  grn_ts_any content;
-  grn_ts_buf text_buf;
-  grn_ts_buf vector_buf;
-} grn_ts_expr_const_node;
-
-/* grn_ts_expr_const_node_init() initializes a node. */
-static void
-grn_ts_expr_const_node_init(grn_ctx *ctx, grn_ts_expr_const_node *node) {
-  memset(node, 0, sizeof(*node));
-  node->type = GRN_TS_EXPR_CONST_NODE;
-  grn_ts_buf_init(ctx, &node->text_buf);
-  grn_ts_buf_init(ctx, &node->vector_buf);
-}
-
-/* grn_ts_expr_const_node_fin() finalizes a node. */
-static void
-grn_ts_expr_const_node_fin(grn_ctx *ctx, grn_ts_expr_const_node *node) {
-  grn_ts_buf_fin(ctx, &node->vector_buf);
-  grn_ts_buf_fin(ctx, &node->text_buf);
-}
-
-#define GRN_TS_EXPR_CONST_NODE_SET_SCALAR_CASE(KIND, kind)\
-  case GRN_TS_ ## KIND: {\
-    node->content.as_ ## kind = *(const grn_ts_ ## kind *)value;\
-    return GRN_SUCCESS;\
-  }
-/* grn_ts_expr_const_node_set_scalar() sets a scalar value. */
-static grn_rc
-grn_ts_expr_const_node_set_scalar(grn_ctx *ctx, grn_ts_expr_const_node *node,
-                                  const void *value) {
-  switch (node->data_kind) {
-    GRN_TS_EXPR_CONST_NODE_SET_SCALAR_CASE(BOOL, bool)
-    GRN_TS_EXPR_CONST_NODE_SET_SCALAR_CASE(INT, int)
-    GRN_TS_EXPR_CONST_NODE_SET_SCALAR_CASE(FLOAT, float)
-    GRN_TS_EXPR_CONST_NODE_SET_SCALAR_CASE(TIME, time)
-    case GRN_TS_TEXT: {
-      grn_ts_text text_value = *(const grn_ts_text *)value;
-      grn_rc rc = grn_ts_buf_write(ctx, &node->text_buf,
-                                   text_value.ptr, text_value.size);
-      if (rc != GRN_SUCCESS) {
-        return rc;
-      }
-      node->content.as_text.ptr = (const char *)node->text_buf.ptr;
-      node->content.as_text.size = text_value.size;
-      return GRN_SUCCESS;
-    }
-    GRN_TS_EXPR_CONST_NODE_SET_SCALAR_CASE(GEO_POINT, geo_point)
-    default: {
-      GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",
-                        node->data_kind);
-    }
-  }
-}
-#undef GRN_TS_EXPR_CONST_NODE_SET_SCALAR_CASE
-
-#define GRN_TS_EXPR_CONST_NODE_SET_VECTOR_CASE(KIND, kind)\
-  case GRN_TS_ ## KIND ## _VECTOR: {\
-    grn_rc rc;\
-    size_t n_bytes;\
-    const grn_ts_ ## kind *buf_ptr;\
-    grn_ts_ ## kind ## _vector vector;\
-    vector = *(const grn_ts_ ## kind ## _vector *)value;\
-    n_bytes = sizeof(grn_ts_ ## kind) * vector.size;\
-    rc = grn_ts_buf_write(ctx, &node->vector_buf, vector.ptr, n_bytes);\
-    if (rc != GRN_SUCCESS) {\
-      return rc;\
-    }\
-    buf_ptr = (const grn_ts_ ## kind *)node->vector_buf.ptr;\
-    node->content.as_ ## kind ## _vector.ptr = buf_ptr;\
-    node->content.as_ ## kind ## _vector.size = vector.size;\
-    return GRN_SUCCESS;\
-  }
-/* grn_ts_expr_const_node_set_vector() sets a vector value. */
-static grn_rc
-grn_ts_expr_const_node_set_vector(grn_ctx *ctx, grn_ts_expr_const_node *node,
-                                  const void *value) {
-  switch (node->data_kind) {
-    GRN_TS_EXPR_CONST_NODE_SET_VECTOR_CASE(BOOL, bool)
-    GRN_TS_EXPR_CONST_NODE_SET_VECTOR_CASE(INT, int)
-    GRN_TS_EXPR_CONST_NODE_SET_VECTOR_CASE(FLOAT, float)
-    GRN_TS_EXPR_CONST_NODE_SET_VECTOR_CASE(TIME, time)
-    case GRN_TS_TEXT_VECTOR: {
-      grn_rc rc;
-      size_t i, n_bytes, offset, total_size;
-      grn_ts_text_vector vector = *(const grn_ts_text_vector *)value;
-      grn_ts_text *vector_buf;
-      char *text_buf;
-      n_bytes = sizeof(grn_ts_text) * vector.size;
-      rc = grn_ts_buf_resize(ctx, &node->vector_buf, n_bytes);
-      if (rc != GRN_SUCCESS) {
-        return rc;
-      }
-      vector_buf = (grn_ts_text *)node->vector_buf.ptr;
-      total_size = 0;
-      for (i = 0; i < vector.size; i++) {
-        total_size += vector.ptr[i].size;
-      }
-      rc = grn_ts_buf_resize(ctx, &node->text_buf, total_size);
-      if (rc != GRN_SUCCESS) {
-        return rc;
-      }
-      text_buf = (char *)node->text_buf.ptr;
-      offset = 0;
-      for (i = 0; i < vector.size; i++) {
-        grn_memcpy(text_buf + offset, vector.ptr[i].ptr, vector.ptr[i].size);
-        vector_buf[i].ptr = text_buf + offset;
-        vector_buf[i].size = vector.ptr[i].size;
-        offset += vector.ptr[i].size;
-      }
-      node->content.as_text_vector.ptr = vector_buf;
-      node->content.as_text_vector.size = vector.size;
-      return GRN_SUCCESS;
-    }
-    GRN_TS_EXPR_CONST_NODE_SET_VECTOR_CASE(GEO_POINT, geo_point)
-    default: {
-      GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",
-                        node->data_kind);
-    }
-  }
-}
-#undef GRN_TS_EXPR_CONST_NODE_SET_VECTOR_CASE
-
-/* 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_ts_expr_const_node *new_node = GRN_MALLOCN(grn_ts_expr_const_node, 1);
-  if (!new_node) {
-    GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE, "GRN_MALLOCN failed: %zu x 1",
-                      sizeof(grn_ts_expr_const_node));
-  }
-  grn_ts_expr_const_node_init(ctx, new_node);
-  new_node->data_kind = kind;
-  new_node->data_type = grn_ts_data_kind_to_type(kind);
-  if (kind & GRN_TS_VECTOR_FLAG) {
-    rc = grn_ts_expr_const_node_set_vector(ctx, new_node, value);
-  } else {
-    rc = grn_ts_expr_const_node_set_scalar(ctx, new_node, value);
-  }
-  if (rc != GRN_SUCCESS) {
-    grn_ts_expr_const_node_fin(ctx, new_node);
-    GRN_FREE(new_node);
-    return rc;
-  }
-  *node = (grn_ts_expr_node *)new_node;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_expr_const_node_close() destroys a node. */
-static void
-grn_ts_expr_const_node_close(grn_ctx *ctx, grn_ts_expr_const_node *node) {
-  grn_ts_expr_const_node_fin(ctx, node);
-  GRN_FREE(node);
-}
-
-#define GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE(KIND, kind)\
-  case GRN_TS_ ## KIND: {\
-    size_t i;\
-    grn_ts_ ## kind *out_ptr = (grn_ts_ ## kind *)out;\
-    for (i = 0; i < n_in; i++) {\
-      out_ptr[i] = node->content.as_ ## kind;\
-    }\
-    return GRN_SUCCESS;\
-  }
-#define GRN_TS_EXPR_CONST_NODE_EVALUATE_VECTOR_CASE(KIND, kind)\
-  GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE(KIND ## _VECTOR, kind ## _vector)
-/* grn_ts_expr_const_node_evaluate() outputs the stored const. */
-static grn_rc
-grn_ts_expr_const_node_evaluate(grn_ctx *ctx, grn_ts_expr_const_node *node,
-                                const grn_ts_record *in, size_t n_in,
-                                void *out) {
-  switch (node->data_kind) {
-    GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE(BOOL, bool)
-    GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE(INT, int)
-    GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE(FLOAT, float)
-    GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE(TIME, time)
-    GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE(TEXT, text)
-    GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE(GEO_POINT, geo_point)
-    GRN_TS_EXPR_CONST_NODE_EVALUATE_VECTOR_CASE(BOOL, bool)
-    GRN_TS_EXPR_CONST_NODE_EVALUATE_VECTOR_CASE(INT, int)
-    GRN_TS_EXPR_CONST_NODE_EVALUATE_VECTOR_CASE(FLOAT, float)
-    GRN_TS_EXPR_CONST_NODE_EVALUATE_VECTOR_CASE(TIME, time)
-    GRN_TS_EXPR_CONST_NODE_EVALUATE_VECTOR_CASE(TEXT, text)
-    GRN_TS_EXPR_CONST_NODE_EVALUATE_VECTOR_CASE(GEO_POINT, geo_point)
-    default: {
-      GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",
-                        node->data_kind);
-    }
-  }
-}
-#undef GRN_TS_EXPR_CONST_NODE_EVALUATE_VECTOR_CASE
-#undef GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE
-
-/* grn_ts_expr_const_node_filter() filters records. */
-static grn_rc
-grn_ts_expr_const_node_filter(grn_ctx *ctx, grn_ts_expr_const_node *node,
-                              grn_ts_record *in, size_t n_in,
-                              grn_ts_record *out, size_t *n_out) {
-  if (node->content.as_bool) {
-    /* All the records pass through the filter. */
-    if (in != out) {
-      size_t i;
-      for (i = 0; i < n_in; i++) {
-        out[i] = in[i];
-      }
-    }
-    *n_out = n_in;
-  } else {
-    /* All the records are discarded. */
-    *n_out = 0;
-  }
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_expr_const_node_adjust() updates scores. */
-static grn_rc
-grn_ts_expr_const_node_adjust(grn_ctx *ctx, grn_ts_expr_const_node *node,
-                              grn_ts_record *io, size_t n_io) {
-  size_t i;
-  grn_ts_score score = (grn_ts_score)node->content.as_float;
-  for (i = 0; i < n_io; i++) {
-    io[i].score = score;
-  }
-  return GRN_SUCCESS;
-}
-
-/*-------------------------------------------------------------
- * grn_ts_expr_column_node.
- */
-
-typedef struct {
-  GRN_TS_EXPR_NODE_COMMON_MEMBERS
-  grn_obj *column;
-  grn_ts_buf buf;
-  grn_ts_buf body_buf;
-} grn_ts_expr_column_node;
-
-/* grn_ts_expr_column_node_init() initializes a node. */
-static void
-grn_ts_expr_column_node_init(grn_ctx *ctx, grn_ts_expr_column_node *node) {
-  memset(node, 0, sizeof(*node));
-  node->type = GRN_TS_EXPR_COLUMN_NODE;
-  node->column = NULL;
-  grn_ts_buf_init(ctx, &node->buf);
-  grn_ts_buf_init(ctx, &node->body_buf);
-}
-
-/* grn_ts_expr_column_node_fin() finalizes a node. */
-static void
-grn_ts_expr_column_node_fin(grn_ctx *ctx, grn_ts_expr_column_node *node) {
-  grn_ts_buf_fin(ctx, &node->body_buf);
-  grn_ts_buf_fin(ctx, &node->buf);
-  if (node->column) {
-    grn_obj_unlink(ctx, node->column);
-  }
-}
-
-#define GRN_TS_EXPR_COLUMN_NODE_OPEN_CASE(TYPE)\
-  case GRN_DB_ ## TYPE: {\
-    GRN_ ## TYPE ## _INIT(&new_node->buf, GRN_OBJ_VECTOR);\
-    break;\
-  }
-/* grn_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) {
-    GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE, "GRN_MALLOCN failed: %zu x 1",
-                      sizeof(grn_ts_expr_column_node));
-  }
-  grn_ts_expr_column_node_init(ctx, new_node);
-  new_node->data_kind = grn_ts_data_type_to_kind(DB_OBJ(column)->range);
-  if (column->header.type == GRN_COLUMN_VAR_SIZE) {
-    grn_obj_flags type = column->header.flags & GRN_OBJ_COLUMN_TYPE_MASK;
-    if (type == GRN_OBJ_COLUMN_VECTOR) {
-      new_node->data_kind |= GRN_TS_VECTOR_FLAG;
-    }
-  }
-  new_node->data_type = DB_OBJ(column)->range;
-  rc = grn_ts_obj_increment_ref_count(ctx, column);
-  if (rc != GRN_SUCCESS) {
-    grn_ts_expr_column_node_fin(ctx, new_node);
-    GRN_FREE(new_node);
-    return rc;
-  }
-  new_node->column = column;
-  *node = (grn_ts_expr_node *)new_node;
-  return GRN_SUCCESS;
-}
-#undef GRN_TS_EXPR_COLUMN_NODE_OPEN_CASE
-
-/* grn_ts_expr_column_node_close() destroys a node. */
-static void
-grn_ts_expr_column_node_close(grn_ctx *ctx, grn_ts_expr_column_node *node) {
-  grn_ts_expr_column_node_fin(ctx, node);
-  GRN_FREE(node);
-}
-
-#define GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_CASE(KIND, kind)\
-  case GRN_TS_ ## KIND: {\
-    size_t i;\
-    grn_ts_ ## kind *out_ptr = (grn_ts_ ## kind *)out;\
-    grn_ra *ra = (grn_ra *)node->column;\
-    grn_ra_cache cache;\
-    GRN_RA_CACHE_INIT(ra, &cache);\
-    for (i = 0; i < n_in; i++) {\
-      grn_ts_ ## kind *ptr = NULL;\
-      if (in[i].id) {\
-        ptr = (grn_ts_ ## kind *)grn_ra_ref_cache(ctx, ra, in[i].id, &cache);\
-      }\
-      out_ptr[i] = ptr ? *ptr : grn_ts_ ## kind ## _zero();\
-    }\
-    GRN_RA_CACHE_FIN(ra, &cache);\
-    return GRN_SUCCESS;\
-  }
-#define GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_INT_CASE(TYPE, type)\
-  case GRN_DB_ ## TYPE: {\
-    size_t i;\
-    grn_ts_int *out_ptr = (grn_ts_int *)out;\
-    grn_ra *ra = (grn_ra *)node->column;\
-    grn_ra_cache cache;\
-    GRN_RA_CACHE_INIT(ra, &cache);\
-    for (i = 0; i < n_in; i++) {\
-      type ## _t *ptr = NULL;\
-      if (in[i].id) {\
-        ptr = (type ## _t *)grn_ra_ref_cache(ctx, ra, in[i].id, &cache);\
-      }\
-      out_ptr[i] = ptr ? (grn_ts_int)*ptr : grn_ts_int_zero();\
-    }\
-    GRN_RA_CACHE_FIN(ra, &cache);\
-    return GRN_SUCCESS;\
-  }
-/* grn_ts_expr_column_node_evaluate_scalar() outputs scalar column values. */
-static grn_rc
-grn_ts_expr_column_node_evaluate_scalar(grn_ctx *ctx,
-                                        grn_ts_expr_column_node *node,
-                                        const grn_ts_record *in, size_t n_in,
-                                        void *out) {
-  switch (node->data_kind) {
-    GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_CASE(BOOL, bool)
-    case GRN_TS_INT: {
-      switch (node->data_type) {
-        GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_INT_CASE(INT8, int8)
-        GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_INT_CASE(INT16, int16)
-        GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_INT_CASE(INT32, int32)
-        GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_INT_CASE(INT64, int64)
-        GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_INT_CASE(UINT8, uint8)
-        GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_INT_CASE(UINT16, uint16)
-        GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_INT_CASE(UINT32, uint32)
-        /* The behavior is undefined if a value is greater than 2^63 - 1. */
-        GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_INT_CASE(UINT64, uint64)
-        default: {
-          GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data type: %d",
-                            node->data_type);
-        }
-      }
-    }
-    GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_CASE(FLOAT, float)
-    GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_CASE(TIME, time)
-    case GRN_TS_TEXT: {
-      size_t i, size;
-      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. */
-      node->buf.pos = 0;
-      for (i = 0; i < n_in; i++) {
-        grn_rc rc = grn_ts_ja_get_value(ctx, ja, in[i].id, &node->buf, &size);
-        out_ptr[i].size = (rc == GRN_SUCCESS) ? size : 0;
-      }
-      buf_ptr = (char *)node->buf.ptr;
-      for (i = 0; i < n_in; i++) {
-        out_ptr[i].ptr = buf_ptr;
-        buf_ptr += out_ptr[i].size;
-      }
-      return GRN_SUCCESS;
-    }
-    GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_CASE(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: {
-      GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",
-                        node->data_kind);
-    }
-  }
-}
-#undef GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_INT_CASE
-#undef GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_CASE
-
-/*
- * grn_ts_expr_column_node_evaluate_text_vector() outputs text vector column
- * values.
- */
-static grn_rc
-grn_ts_expr_column_node_evaluate_text_vector(grn_ctx *ctx,
-                                             grn_ts_expr_column_node *node,
-                                             const grn_ts_record *in,
-                                             size_t n_in, void *out) {
-  grn_rc rc;
-  char *buf_ptr;
-  size_t i, j, n_bytes, n_values, total_n_bytes = 0, total_n_values = 0;
-  grn_ts_text *text_ptr;
-  grn_ts_text_vector *out_ptr = (grn_ts_text_vector *)out;
-  /* Read encoded values into node->body_buf and get the size of each value. */
-  node->body_buf.pos = 0;
-  for (i = 0; i < n_in; i++) {
-    char *ptr;
-    rc = grn_ts_ja_get_value(ctx, (grn_ja *)node->column, in[i].id,
-                             &node->body_buf, &n_bytes);
-    if (rc == GRN_SUCCESS) {
-      ptr = (char *)node->body_buf.ptr + total_n_bytes;
-      GRN_B_DEC(n_values, ptr);
-    } else {
-      n_bytes = 0;
-      n_values = 0;
-    }
-    grn_memcpy(&out_ptr[i].ptr, &n_bytes, sizeof(n_bytes));
-    out_ptr[i].size = n_values;
-    total_n_bytes += n_bytes;
-    total_n_values += n_values;
-  }
-  /* Resize node->buf. */
-  n_bytes = sizeof(grn_ts_text) * total_n_values;
-  rc = grn_ts_buf_reserve(ctx, &node->buf, n_bytes);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  /* Decode values and compose the result. */
-  buf_ptr = (char *)node->body_buf.ptr;
-  text_ptr = (grn_ts_text *)node->buf.ptr;
-  for (i = 0; i < n_in; i++) {
-    char *ptr = buf_ptr;
-    grn_memcpy(&n_bytes, &out_ptr[i].ptr, sizeof(n_bytes));
-    buf_ptr += n_bytes;
-    GRN_B_DEC(n_values, ptr);
-    out_ptr[i].ptr = text_ptr;
-    for (j = 0; j < out_ptr[i].size; j++) {
-      GRN_B_DEC(text_ptr[j].size, ptr);
-    }
-    for (j = 0; j < out_ptr[i].size; j++) {
-      text_ptr[j].ptr = ptr;
-      ptr += text_ptr[j].size;
-    }
-    text_ptr += out_ptr[i].size;
-  }
-  return GRN_SUCCESS;
-}
-
-/*
- * grn_ts_expr_column_node_evaluate_ref_vector() outputs ref vector column
- * values.
- */
-static grn_rc
-grn_ts_expr_column_node_evaluate_ref_vector(grn_ctx *ctx,
-                                             grn_ts_expr_column_node *node,
-                                             const grn_ts_record *in,
-                                             size_t n_in, void *out) {
-  grn_rc rc;
-  size_t i, j, n_bytes, offset = 0;
-  grn_ts_id *buf_ptr;
-  grn_ts_ref *ref_ptr;
-  grn_ts_ref_vector *out_ptr = (grn_ts_ref_vector *)out;
-  /* Read column values into node->body_buf and get the size of each value. */
-  node->body_buf.pos = 0;
-  for (i = 0; i < n_in; i++) {
-    size_t size;
-    rc = grn_ts_ja_get_value(ctx, (grn_ja *)node->column, in[i].id,
-                             &node->body_buf, &size);
-    if (rc == GRN_SUCCESS) {
-      out_ptr[i].size = size / sizeof(grn_ts_id);
-      offset += out_ptr[i].size;
-    } else {
-      out_ptr[i].size = 0;
-    }
-  }
-  /* Resize node->buf. */
-  n_bytes = sizeof(grn_ts_ref) * offset;
-  rc = grn_ts_buf_reserve(ctx, &node->buf, n_bytes);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  /* Compose the result. */
-  buf_ptr = (grn_ts_id *)node->body_buf.ptr;
-  ref_ptr = (grn_ts_ref *)node->buf.ptr;
-  for (i = 0; i < n_in; i++) {
-    out_ptr[i].ptr = ref_ptr;
-    for (j = 0; j < out_ptr[i].size; j++, buf_ptr++, ref_ptr++) {
-      ref_ptr->id = *buf_ptr;
-      ref_ptr->score = in[i].score;
-    }
-  }
-  return GRN_SUCCESS;
-}
-
-#define GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_CASE(KIND, kind)\
-  case GRN_TS_ ## KIND ## _VECTOR: {\
-    size_t i;\
-    grn_ts_ ## kind *buf_ptr;\
-    grn_ts_ ## kind ## _vector *out_ptr = (grn_ts_ ## kind ## _vector *)out;\
-    /* Read column values into node->buf and save the size of each value. */\
-    node->buf.pos = 0;\
-    for (i = 0; i < n_in; i++) {\
-      size_t n_bytes;\
-      grn_rc rc = grn_ts_ja_get_value(ctx, (grn_ja *)node->column, in[i].id,\
-                                      &node->buf, &n_bytes);\
-      if (rc == GRN_SUCCESS) {\
-        out_ptr[i].size = n_bytes / sizeof(grn_ts_ ## kind);\
-      } else {\
-        out_ptr[i].size = 0;\
-      }\
-    }\
-    buf_ptr = (grn_ts_ ## kind *)node->buf.ptr;\
-    for (i = 0; i < n_in; i++) {\
-      out_ptr[i].ptr = buf_ptr;\
-      buf_ptr += out_ptr[i].size;\
-    }\
-    return GRN_SUCCESS;\
-  }
-#define GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_INT_CASE(TYPE, type)\
-  case GRN_DB_ ## TYPE: {\
-    size_t i, j;\
-    grn_ts_int *buf_ptr;\
-    grn_ts_int_vector *out_ptr = (grn_ts_int_vector *)out;\
-    /*
-     * Read column values into body_buf and typecast the values to grn_ts_int.
-     * Then, store the grn_ts_int values into node->buf and save the size of
-     * each value.
-     */\
-    node->buf.pos = 0;\
-    for (i = 0; i < n_in; i++) {\
-      grn_rc rc;\
-      size_t n_bytes, new_n_bytes;\
-      node->body_buf.pos = 0;\
-      rc = grn_ts_ja_get_value(ctx, (grn_ja *)node->column, in[i].id,\
-                               &node->body_buf, &n_bytes);\
-      if (rc == GRN_SUCCESS) {\
-        out_ptr[i].size = n_bytes / sizeof(type ## _t);\
-      } else {\
-        out_ptr[i].size = 0;\
-      }\
-      new_n_bytes = node->buf.pos + (sizeof(grn_ts_int) * out_ptr[i].size);\
-      rc = grn_ts_buf_reserve(ctx, &node->buf, new_n_bytes);\
-      if (rc == GRN_SUCCESS) {\
-        type ## _t *src_ptr = (type ## _t *)node->body_buf.ptr;\
-        grn_ts_int *dest_ptr;\
-        dest_ptr = (grn_ts_int *)((char *)node->buf.ptr + node->buf.pos);\
-        for (j = 0; j < out_ptr[i].size; j++) {\
-          dest_ptr[j] = (grn_ts_int)src_ptr[j];\
-        }\
-        node->buf.pos = new_n_bytes;\
-      } else {\
-        out_ptr[i].size = 0;\
-      }\
-    }\
-    buf_ptr = (grn_ts_int *)node->buf.ptr;\
-    for (i = 0; i < n_in; i++) {\
-      out_ptr[i].ptr = buf_ptr;\
-      buf_ptr += out_ptr[i].size;\
-    }\
-    return GRN_SUCCESS;\
-  }
-/* grn_ts_expr_column_node_evaluate_vector() outputs vector column values. */
-static grn_rc
-grn_ts_expr_column_node_evaluate_vector(grn_ctx *ctx,
-                                        grn_ts_expr_column_node *node,
-                                        const grn_ts_record *in, size_t n_in,
-                                        void *out) {
-  switch (node->data_kind) {
-    GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_CASE(BOOL, bool)
-    case GRN_TS_INT_VECTOR: {
-      switch (node->data_type) {
-        GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_INT_CASE(INT8, int8)
-        GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_INT_CASE(INT16, int16)
-        GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_INT_CASE(INT32, int32)
-        GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_INT_CASE(INT64, int64)
-        GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_INT_CASE(UINT8, uint8)
-        GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_INT_CASE(UINT16, uint16)
-        GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_INT_CASE(UINT32, uint32)
-        /* The behavior is undefined if a value is greater than 2^63 - 1. */
-        GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_INT_CASE(UINT64, uint64)
-        default: {
-          GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data type: %d",
-                            node->data_type);
-        }
-      }
-    }
-    GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_CASE(FLOAT, float)
-    GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_CASE(TIME, time)
-    case GRN_TS_TEXT_VECTOR: {
-      return grn_ts_expr_column_node_evaluate_text_vector(ctx, node, in, n_in,
-                                                          out);
-    }
-    GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_CASE(GEO_POINT, geo_point)
-    case GRN_TS_REF_VECTOR: {
-      return grn_ts_expr_column_node_evaluate_ref_vector(ctx, node, in, n_in,
-                                                         out);
-    }
-    default: {
-      GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",
-                        node->data_kind);
-    }
-  }
-}
-#undef GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_INT_CASE
-#undef GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_CASE
-
-/* grn_ts_expr_column_node_evaluate() outputs column values. */
-static grn_rc
-grn_ts_expr_column_node_evaluate(grn_ctx *ctx, grn_ts_expr_column_node *node,
-                                 const grn_ts_record *in, size_t n_in,
-                                 void *out) {
-  if (node->data_kind & GRN_TS_VECTOR_FLAG) {
-    return grn_ts_expr_column_node_evaluate_vector(ctx, node, in, n_in, out);
-  } else {
-    return grn_ts_expr_column_node_evaluate_scalar(ctx, node, in, n_in, out);
-  }
-}
-
-/* grn_ts_expr_column_node_filter() filters records. */
-static grn_rc
-grn_ts_expr_column_node_filter(grn_ctx *ctx, grn_ts_expr_column_node *node,
-                               grn_ts_record *in, size_t n_in,
-                               grn_ts_record *out, size_t *n_out) {
-  size_t i, count = 0;
-  grn_ra *ra = (grn_ra *)node->column;
-  grn_ra_cache cache;
-  GRN_RA_CACHE_INIT(ra, &cache);
-  for (i = 0; i < n_in; i++) {
-    grn_ts_bool *ptr = NULL;
-    if (in[i].id) {
-      ptr = grn_ra_ref_cache(ctx, ra, in[i].id, &cache);
-    }
-    if (ptr && *ptr) {
-      out[count++] = in[i];
-    }
-  }
-  GRN_RA_CACHE_FIN(ra, &cache);
-  *n_out = count;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_expr_column_node_adjust() updates scores. */
-static grn_rc
-grn_ts_expr_column_node_adjust(grn_ctx *ctx, grn_ts_expr_column_node *node,
-                               grn_ts_record *io, size_t n_io) {
-  size_t i;
-  grn_ra *ra = (grn_ra *)node->column;
-  grn_ra_cache cache;
-  GRN_RA_CACHE_INIT(ra, &cache);
-  for (i = 0; i < n_io; i++) {
-    grn_ts_float *ptr = NULL;
-    if (io[i].id) {
-      ptr = grn_ra_ref_cache(ctx, ra, io[i].id, &cache);
-    }
-    if (ptr) {
-      io[i].score = (grn_ts_score)*ptr;
-    }
-  }
-  GRN_RA_CACHE_FIN(ra, &cache);
-  return GRN_SUCCESS;
-}
-
-/*-------------------------------------------------------------
- * grn_ts_expr_op_node.
- */
-
-enum {
-  GRN_TS_EXPR_OP_NODE_MAX_N_ARGS = 3,
-  GRN_TS_EXPR_OP_NODE_N_BUFS = 3
-};
-
-/* Forward declarations. */
-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);
-static grn_rc grn_ts_expr_node_evaluate_to_buf(grn_ctx *ctx,
-                                               grn_ts_expr_node *node,
-                                               const grn_ts_record *in,
-                                               size_t n_in,
-                                               grn_ts_buf *out);
-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);
-static grn_rc grn_ts_expr_node_adjust(grn_ctx *ctx, grn_ts_expr_node *node,
-                                      grn_ts_record *io, size_t n_io);
-
-typedef struct {
-  GRN_TS_EXPR_NODE_COMMON_MEMBERS
-  grn_ts_op_type op_type;
-  grn_ts_expr_node *args[GRN_TS_EXPR_OP_NODE_MAX_N_ARGS];
-  size_t n_args;
-  grn_ts_buf bufs[GRN_TS_EXPR_OP_NODE_N_BUFS];
-} grn_ts_expr_op_node;
-
-/* grn_ts_expr_op_node_init() initializes a node. */
-static void
-grn_ts_expr_op_node_init(grn_ctx *ctx, grn_ts_expr_op_node *node) {
-  size_t i;
-  memset(node, 0, sizeof(*node));
-  node->type = GRN_TS_EXPR_OP_NODE;
-  for (i = 0; i < GRN_TS_EXPR_OP_NODE_MAX_N_ARGS; i++) {
-    node->args[i] = NULL;
-  }
-  for (i = 0; i < GRN_TS_EXPR_OP_NODE_N_BUFS; i++) {
-    grn_ts_buf_init(ctx, &node->bufs[i]);
-  }
-}
-
-/* grn_ts_expr_op_node_fin() finalizes a node. */
-static void
-grn_ts_expr_op_node_fin(grn_ctx *ctx, grn_ts_expr_op_node *node) {
-  size_t i;
-  for (i = 0; i < GRN_TS_EXPR_OP_NODE_N_BUFS; i++) {
-    grn_ts_buf_fin(ctx, &node->bufs[i]);
-  }
-}
-
-/*
- * grn_ts_op_plus_check_args() checks arguments. Note that arguments are
- * rearranged in some cases.
- */
-static grn_rc
-grn_ts_op_plus_check_args(grn_ctx *ctx, grn_ts_expr_op_node *node) {
-  switch (node->args[0]->data_kind) {
-    case GRN_TS_INT: {
-      switch (node->args[1]->data_kind) {
-        case GRN_TS_INT: {
-          /* Int + Int = Int. */
-          node->data_kind = GRN_TS_INT;
-          node->data_type = GRN_DB_INT64;
-          return GRN_SUCCESS;
-        }
-        case GRN_TS_TIME: {
-          /* Int + Time = Time + Int = Time. */
-          grn_ts_expr_node *tmp = node->args[0];
-          node->args[0] = node->args[1];
-          node->args[1] = tmp;
-          node->data_kind = GRN_TS_TIME;
-          node->data_type = GRN_DB_TIME;
-          return GRN_SUCCESS;
-        }
-        default: {
-          GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d",
-                            node->args[1]->data_kind);
-        }
-      }
-    }
-    case GRN_TS_FLOAT: {
-      switch (node->args[1]->data_kind) {
-        case GRN_TS_FLOAT: {
-          /* Float + Float = Float. */
-          node->data_kind = GRN_TS_FLOAT;
-          node->data_type = GRN_DB_FLOAT;
-          return GRN_SUCCESS;
-        }
-        case GRN_TS_TIME: {
-          /* Float + Time = Time + Float = Time. */
-          grn_ts_expr_node *tmp = node->args[0];
-          node->args[0] = node->args[1];
-          node->args[1] = tmp;
-          node->data_kind = GRN_TS_TIME;
-          node->data_type = GRN_DB_TIME;
-          return GRN_SUCCESS;
-        }
-        default: {
-          GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d",
-                            node->args[1]->data_kind);
-        }
-      }
-    }
-    case GRN_TS_TIME: {
-      switch (node->args[1]->data_kind) {
-        case GRN_TS_INT:
-        case GRN_TS_FLOAT: {
-          /* Time + Int or Float = Time. */
-          node->data_kind = GRN_TS_TIME;
-          node->data_type = GRN_DB_TIME;
-          return GRN_SUCCESS;
-        }
-        default: {
-          GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d",
-                            node->args[1]->data_kind);
-        }
-      }
-    }
-    default: {
-      GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d",
-                        node->args[0]->data_kind);
-    }
-  }
-}
-
-/* grn_ts_op_minus_check_args() checks arguments. */
-static grn_rc
-grn_ts_op_minus_check_args(grn_ctx *ctx, grn_ts_expr_op_node *node) {
-  switch (node->args[0]->data_kind) {
-    case GRN_TS_INT: {
-      if (node->args[1]->data_kind != GRN_TS_INT) {
-        GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d",
-                          node->args[1]->data_kind);
-      }
-      /* Int - Int = Int. */
-      node->data_kind = GRN_TS_INT;
-      node->data_type = GRN_DB_INT64;
-      return GRN_SUCCESS;
-    }
-    case GRN_TS_FLOAT: {
-      if (node->args[1]->data_kind != GRN_TS_FLOAT) {
-        GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d",
-                          node->args[1]->data_kind);
-      }
-      /* Float - Float = Float. */
-      node->data_kind = GRN_TS_FLOAT;
-      node->data_type = GRN_DB_FLOAT;
-      return GRN_SUCCESS;
-    }
-    case GRN_TS_TIME: {
-      switch (node->args[1]->data_kind) {
-        case GRN_TS_INT:
-        case GRN_TS_FLOAT: {
-          /* Time - Int or Float = Time. */
-          node->data_kind = GRN_TS_TIME;
-          node->data_type = GRN_DB_TIME;
-          return GRN_SUCCESS;
-        }
-        case GRN_TS_TIME: {
-          /* Time - Time = Float. */
-          node->data_kind = GRN_TS_FLOAT;
-          node->data_type = GRN_DB_FLOAT;
-          return GRN_SUCCESS;
-        }
-        default: {
-          GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d",
-                            node->args[1]->data_kind);
-        }
-      }
-    }
-    default: {
-      GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d",
-                        node->args[0]->data_kind);
-    }
-  }
-}
-
-/*
- * grn_ts_expr_op_node_check_args() checks the combination of an operator and
- * its arguments.
- */
-static grn_rc
-grn_ts_expr_op_node_check_args(grn_ctx *ctx, grn_ts_expr_op_node *node) {
-  switch (node->op_type) {
-    case GRN_TS_OP_LOGICAL_NOT: {
-      if (node->args[0]->data_kind != GRN_TS_BOOL) {
-        GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d",
-                          node->args[0]->data_kind);
-      }
-      node->data_kind = GRN_TS_BOOL;
-      node->data_type = GRN_DB_BOOL;
-      return GRN_SUCCESS;
-    }
-    case GRN_TS_OP_BITWISE_NOT: {
-      switch (node->args[0]->data_kind) {
-        case GRN_TS_BOOL:
-        case GRN_TS_INT: {
-          node->data_kind = node->args[0]->data_kind;
-          node->data_type = grn_ts_data_kind_to_type(node->data_kind);
-          return GRN_SUCCESS;
-        }
-        default: {
-          GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d",
-                            node->args[0]->data_kind);
-        }
-      }
-    }
-    case GRN_TS_OP_POSITIVE:
-    case GRN_TS_OP_NEGATIVE: {
-      if ((node->args[0]->data_kind != GRN_TS_INT) &&
-          (node->args[0]->data_kind != GRN_TS_FLOAT)) {
-        GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d",
-                          node->args[0]->data_kind);
-      }
-      node->data_kind = node->args[0]->data_kind;
-      node->data_type = grn_ts_data_kind_to_type(node->data_kind);
-      return GRN_SUCCESS;
-    }
-    case GRN_TS_OP_LOGICAL_AND:
-    case GRN_TS_OP_LOGICAL_OR:
-    case GRN_TS_OP_LOGICAL_SUB: {
-      if ((node->args[0]->data_kind != GRN_TS_BOOL) ||
-          (node->args[1]->data_kind != GRN_TS_BOOL)) {
-        GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d, %d",
-                          node->args[0]->data_kind, node->args[1]->data_kind);
-      }
-      node->data_kind = GRN_TS_BOOL;
-      node->data_type = GRN_DB_BOOL;
-      return GRN_SUCCESS;
-    }
-    case GRN_TS_OP_BITWISE_AND:
-    case GRN_TS_OP_BITWISE_OR:
-    case GRN_TS_OP_BITWISE_XOR: {
-      if (node->args[0]->data_kind != node->args[1]->data_kind) {
-        GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "data kind conflict: %d != %d",
-                          node->args[0]->data_kind, node->args[1]->data_kind);
-      }
-      switch (node->args[0]->data_kind) {
-        case GRN_TS_BOOL:
-        case GRN_TS_INT: {
-          node->data_kind = node->args[0]->data_kind;
-          node->data_type = grn_ts_data_kind_to_type(node->data_kind);
-          return GRN_SUCCESS;
-        }
-        default: {
-          GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d",
-                            node->args[0]->data_kind);
-        }
-      }
-      node->data_kind = GRN_TS_BOOL;
-      node->data_type = GRN_DB_BOOL;
-      return GRN_SUCCESS;
-    }
-    case GRN_TS_OP_EQUAL:
-    case GRN_TS_OP_NOT_EQUAL: {
-      grn_ts_data_kind scalar_data_kind;
-      if (node->args[0]->data_kind != node->args[1]->data_kind) {
-        GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "data kind conflict: %d != %d",
-                          node->args[0]->data_kind, node->args[1]->data_kind);
-      }
-      scalar_data_kind = node->args[0]->data_kind & ~GRN_TS_VECTOR_FLAG;
-      if (((scalar_data_kind == GRN_TS_REF) ||
-           (scalar_data_kind == GRN_TS_GEO_POINT)) &&
-          (node->args[0]->data_type != node->args[1]->data_type)) {
-        GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "data type conflict: %d != %d",
-                          node->args[0]->data_type, node->args[1]->data_type);
-      }
-      node->data_kind = GRN_TS_BOOL;
-      node->data_type = GRN_DB_BOOL;
-      return GRN_SUCCESS;
-    }
-    case GRN_TS_OP_LESS:
-    case GRN_TS_OP_LESS_EQUAL:
-    case GRN_TS_OP_GREATER:
-    case GRN_TS_OP_GREATER_EQUAL: {
-      if (node->args[0]->data_kind != node->args[1]->data_kind) {
-        GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "data kind conflict: %d != %d",
-                          node->args[0]->data_kind, node->args[1]->data_kind);
-      }
-      switch (node->args[0]->data_kind) {
-        case GRN_TS_INT:
-        case GRN_TS_FLOAT:
-        case GRN_TS_TIME:
-        case GRN_TS_TEXT:
-        case GRN_TS_INT_VECTOR:
-        case GRN_TS_FLOAT_VECTOR:
-        case GRN_TS_TIME_VECTOR:
-        case GRN_TS_TEXT_VECTOR: {
-          node->data_kind = GRN_TS_BOOL;
-          node->data_type = GRN_DB_BOOL;
-          return GRN_SUCCESS;
-        }
-        default: {
-          GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d",
-                            node->args[0]->data_kind);
-        }
-      }
-      case GRN_TS_OP_SHIFT_ARITHMETIC_LEFT:
-      case GRN_TS_OP_SHIFT_ARITHMETIC_RIGHT:
-      case GRN_TS_OP_SHIFT_LOGICAL_LEFT:
-      case GRN_TS_OP_SHIFT_LOGICAL_RIGHT: {
-        if ((node->args[0]->data_kind != GRN_TS_INT) ||
-            (node->args[1]->data_kind != GRN_TS_INT)) {
-          GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d, %d",
-                            node->args[0]->data_kind,
-                            node->args[1]->data_kind);
-        }
-        node->data_kind = GRN_TS_INT;
-        node->data_type = GRN_DB_INT64;
-        return GRN_SUCCESS;
-      }
-      case GRN_TS_OP_PLUS: {
-        return grn_ts_op_plus_check_args(ctx, node);
-      }
-      case GRN_TS_OP_MINUS: {
-        return grn_ts_op_minus_check_args(ctx, node);
-      }
-      case GRN_TS_OP_MULTIPLICATION:
-      case GRN_TS_OP_DIVISION:
-      case GRN_TS_OP_MODULUS: {
-        if (node->args[0]->data_kind != node->args[1]->data_kind) {
-          GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT,
-                            "data kind conflict: %d != %d",
-                            node->args[0]->data_kind,
-                            node->args[1]->data_kind);
-        }
-        switch (node->args[0]->data_kind) {
-          case GRN_TS_INT:
-          case GRN_TS_FLOAT: {
-            node->data_kind = node->args[0]->data_kind;
-            node->data_type = grn_ts_data_kind_to_type(node->data_kind);
-            return GRN_SUCCESS;
-          }
-          default: {
-            GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d",
-                              node->args[0]->data_kind);
-          }
-        }
-      }
-    }
-    default: {
-      GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid operator: %d",
-                        node->op_type);
-    }
-  }
-}
-
-/* grn_ts_expr_op_node_open() creates a node associated with an operator. */
-static grn_rc
-grn_ts_expr_op_node_open(grn_ctx *ctx, grn_ts_op_type op_type,
-                         grn_ts_expr_node **args, size_t n_args,
-                         grn_ts_expr_node **node) {
-  size_t i;
-  grn_rc rc;
-  grn_ts_expr_op_node *new_node = GRN_MALLOCN(grn_ts_expr_op_node, 1);
-  if (!new_node) {
-    GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE, "GRN_MALLOCN failed: %zu x 1",
-                      sizeof(grn_ts_expr_op_node));
-  }
-  grn_ts_expr_op_node_init(ctx, new_node);
-  new_node->op_type = op_type;
-  for (i = 0; i < n_args; i++) {
-    new_node->args[i] = args[i];
-  }
-  new_node->n_args = n_args;
-
-  /* Check arguments. */
-  rc = grn_ts_expr_op_node_check_args(ctx, new_node);
-  if (rc == GRN_SUCCESS) {
-    if (new_node->data_kind == GRN_TS_VOID) {
-      GRN_TS_ERR(GRN_OBJECT_CORRUPT, "invalid data kind: %d", GRN_TS_VOID);
-      rc = ctx->rc;
-    } else if (new_node->data_type == GRN_DB_VOID) {
-      GRN_TS_ERR(GRN_OBJECT_CORRUPT, "invalid data type: %d", GRN_DB_VOID);
-      rc = ctx->rc;
-    }
-  }
-  if (rc != GRN_SUCCESS) {
-    grn_ts_expr_op_node_fin(ctx, new_node);
-    GRN_FREE(new_node);
-    return rc;
-  }
-  *node = (grn_ts_expr_node *)new_node;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_expr_op_node_close() destroys a node. */
-static void
-grn_ts_expr_op_node_close(grn_ctx *ctx, grn_ts_expr_op_node *node) {
-  grn_ts_expr_op_node_fin(ctx, node);
-  GRN_FREE(node);
-}
-
-/* grn_ts_op_logical_not_evaluate() evaluates an operator. */
-static grn_rc
-grn_ts_op_logical_not_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
-                               const grn_ts_record *in, size_t n_in,
-                               void *out) {
-  size_t i;
-  grn_ts_bool *out_ptr = (grn_ts_bool *)out;
-  grn_rc rc = grn_ts_expr_node_evaluate(ctx, node->args[0], in, n_in, out);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  for (i = 0; i < n_in; i++) {
-    out_ptr[i] = grn_ts_op_logical_not_bool(out_ptr[i]);
-  }
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_op_bitwise_not_evaluate() evaluates an operator. */
-static grn_rc
-grn_ts_op_bitwise_not_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
-                               const grn_ts_record *in, size_t n_in,
-                               void *out) {
-  size_t i;
-  grn_rc rc = grn_ts_expr_node_evaluate(ctx, node->args[0], in, n_in, out);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  switch (node->data_kind) {
-    case GRN_TS_BOOL: {
-      grn_ts_bool *out_ptr = (grn_ts_bool *)out;
-      for (i = 0; i < n_in; i++) {
-        out_ptr[i] = grn_ts_op_bitwise_not_bool(out_ptr[i]);
-      }
-      return GRN_SUCCESS;
-    }
-    case GRN_TS_INT: {
-      grn_ts_int *out_ptr = (grn_ts_int *)out;
-      for (i = 0; i < n_in; i++) {
-        out_ptr[i] = grn_ts_op_bitwise_not_int(out_ptr[i]);
-      }
-      return GRN_SUCCESS;
-    }
-    default: {
-      GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",
-                        node->data_kind);
-    }
-  }
-}
-
-#define GRN_TS_OP_SIGN_EVALUATE_CASE(type, KIND, kind) \
-  case GRN_TS_ ## KIND: {\
-    grn_ts_ ## kind *out_ptr = (grn_ts_ ## kind *)out;\
-    for (i = 0; i < n_in; i++) {\
-      out_ptr[i] = grn_ts_op_ ## type ## _ ## kind(out_ptr[i]);\
-    }\
-    return GRN_SUCCESS;\
-  }
-#define GRN_TS_OP_SIGN_EVALUATE(type) \
-  size_t i;\
-  grn_rc rc = grn_ts_expr_node_evaluate(ctx, node->args[0], in, n_in, out);\
-  if (rc != GRN_SUCCESS) {\
-    return rc;\
-  }\
-  switch (node->data_kind) {\
-    GRN_TS_OP_SIGN_EVALUATE_CASE(type, INT, int)\
-    GRN_TS_OP_SIGN_EVALUATE_CASE(type, FLOAT, float)\
-    default: {\
-      GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",\
-                        node->data_kind);\
-    }\
-  }
-/* grn_ts_op_positive_evaluate() evaluates an operator. */
-static grn_rc
-grn_ts_op_positive_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
-                            const grn_ts_record *in, size_t n_in, void *out) {
-  GRN_TS_OP_SIGN_EVALUATE(positive)
-}
-
-/* grn_ts_op_negative_evaluate() evaluates an operator. */
-static grn_rc
-grn_ts_op_negative_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
-                            const grn_ts_record *in, size_t n_in, void *out) {
-  GRN_TS_OP_SIGN_EVALUATE(negative)
-}
-#undef GRN_TS_OP_SIGN_EVALUATE
-#undef GRN_TS_OP_SIGN_EVALUATE_CASE
-
-/* grn_ts_op_logical_and_evaluate() evaluates an operator. */
-static grn_rc
-grn_ts_op_logical_and_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
-                               const grn_ts_record *in, size_t n_in,
-                               void *out) {
-  size_t i, j, count;
-  grn_rc rc;
-  grn_ts_bool *buf_ptrs[2], *out_ptr = (grn_ts_bool *)out;
-  grn_ts_buf *tmp_in_buf = &node->bufs[2];
-  grn_ts_record *tmp_in;
-
-  /* Evaluate the 1st argument. */
-  rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[0], in, n_in,
-                                        &node->bufs[0]);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  buf_ptrs[0] = (grn_ts_bool *)node->bufs[0].ptr;
-
-  /* Create a list of true records. */
-  rc = grn_ts_buf_reserve(ctx, tmp_in_buf, sizeof(grn_ts_record) * n_in);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  tmp_in = (grn_ts_record *)tmp_in_buf->ptr;
-  count = 0;
-  for (i = 0; i < n_in; i++) {
-    if (buf_ptrs[0][i]) {
-      tmp_in[count++] = in[i];
-    }
-  }
-
-  /* Evaluate the 2nd argument. */
-  rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[1], tmp_in, count,
-                                        &node->bufs[1]);
-  buf_ptrs[1] = (grn_ts_bool *)node->bufs[1].ptr;
-
-  /* Merge the results. */
-  count = 0;
-  for (i = 0, j = 0; i < n_in; i++) {
-    out_ptr[count++] = buf_ptrs[0][i] && buf_ptrs[1][j++];
-  }
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_op_logical_or_evaluate() evaluates an operator. */
-static grn_rc
-grn_ts_op_logical_or_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
-                               const grn_ts_record *in, size_t n_in,
-                               void *out) {
-  size_t i, j, count;
-  grn_rc rc;
-  grn_ts_bool *buf_ptrs[2], *out_ptr = (grn_ts_bool *)out;
-  grn_ts_buf *tmp_in_buf = &node->bufs[2];
-  grn_ts_record *tmp_in;
-
-  /* Evaluate the 1st argument. */
-  rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[0], in, n_in,
-                                        &node->bufs[0]);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  buf_ptrs[0] = (grn_ts_bool *)node->bufs[0].ptr;
-
-  /* Create a list of false records. */
-  rc = grn_ts_buf_reserve(ctx, tmp_in_buf, sizeof(grn_ts_record) * n_in);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  tmp_in = (grn_ts_record *)tmp_in_buf->ptr;
-  count = 0;
-  for (i = 0; i < n_in; i++) {
-    if (!buf_ptrs[0][i]) {
-      tmp_in[count++] = in[i];
-    }
-  }
-
-  /* Evaluate the 2nd argument. */
-  rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[1], tmp_in, count,
-                                        &node->bufs[1]);
-  buf_ptrs[1] = (grn_ts_bool *)node->bufs[1].ptr;
-
-  /* Merge the results. */
-  count = 0;
-  for (i = 0, j = 0; i < n_in; i++) {
-    out_ptr[count++] = buf_ptrs[0][i] || buf_ptrs[1][j++];
-  }
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_op_logical_sub_evaluate() evaluates an operator. */
-static grn_rc
-grn_ts_op_logical_sub_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
-                               const grn_ts_record *in, size_t n_in,
-                               void *out) {
-  size_t i, j, count;
-  grn_rc rc;
-  grn_ts_bool *buf_ptrs[2], *out_ptr = (grn_ts_bool *)out;
-  grn_ts_buf *tmp_in_buf = &node->bufs[2];
-  grn_ts_record *tmp_in;
-
-  /* Evaluate the 1st argument. */
-  rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[0], in, n_in,
-                                        &node->bufs[0]);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  buf_ptrs[0] = (grn_ts_bool *)node->bufs[0].ptr;
-
-  /* Create a list of true records. */
-  rc = grn_ts_buf_reserve(ctx, tmp_in_buf, sizeof(grn_ts_record) * n_in);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  tmp_in = (grn_ts_record *)tmp_in_buf->ptr;
-  count = 0;
-  for (i = 0; i < n_in; i++) {
-    if (buf_ptrs[0][i]) {
-      tmp_in[count++] = in[i];
-    }
-  }
-
-  /* Evaluate the 2nd argument. */
-  rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[1], tmp_in, count,
-                                        &node->bufs[1]);
-  buf_ptrs[1] = (grn_ts_bool *)node->bufs[1].ptr;
-
-  /* Merge the results. */
-  count = 0;
-  for (i = 0, j = 0; i < n_in; i++) {
-    out_ptr[count++] = buf_ptrs[0][i] &&
-                       grn_ts_op_logical_not_bool(buf_ptrs[1][j++]);
-  }
-  return GRN_SUCCESS;
-}
-
-#define GRN_TS_OP_BITWISE_EVALUATE_CASE(type, KIND, kind)\
-  case GRN_TS_ ## KIND: {\
-    /*
-     * Use the output buffer to put evaluation results of the 1st argument,
-     * because the data kind is same.
-     */\
-    size_t i;\
-    grn_rc rc;\
-    grn_ts_ ## kind *out_ptr = (grn_ts_ ## kind *)out;\
-    rc = grn_ts_expr_node_evaluate(ctx, node->args[0], in, n_in, out);\
-    if (rc == GRN_SUCCESS) {\
-      rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[1],\
-                                            in, n_in, &node->bufs[0]);\
-      if (rc == GRN_SUCCESS) {\
-        grn_ts_ ## kind *buf_ptr = (grn_ts_ ## kind *)node->bufs[0].ptr;\
-        for (i = 0; i < n_in; i++) {\
-          out_ptr[i] = grn_ts_op_bitwise_ ## type ## _ ## kind(out_ptr[i],\
-                                                               buf_ptr[i]);\
-        }\
-      }\
-    }\
-    return rc;\
-  }
-/* grn_ts_op_bitwise_and_evaluate() evaluates an operator. */
-static grn_rc
-grn_ts_op_bitwise_and_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
-                               const grn_ts_record *in, size_t n_in,
-                               void *out) {
-  switch (node->args[0]->data_kind) {
-    GRN_TS_OP_BITWISE_EVALUATE_CASE(and, BOOL, bool)
-    GRN_TS_OP_BITWISE_EVALUATE_CASE(and, INT, int)
-    default: {
-      GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",
-                        node->args[0]->data_kind);
-    }
-  }
-}
-
-/* grn_ts_op_bitwise_or_evaluate() evaluates an operator. */
-static grn_rc
-grn_ts_op_bitwise_or_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
-                              const grn_ts_record *in, size_t n_in,
-                              void *out) {
-  switch (node->args[0]->data_kind) {
-    GRN_TS_OP_BITWISE_EVALUATE_CASE(or, BOOL, bool)
-    GRN_TS_OP_BITWISE_EVALUATE_CASE(or, INT, int)
-    default: {
-      GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",
-                        node->args[0]->data_kind);
-    }
-  }
-}
-
-/* grn_ts_op_bitwise_xor_evaluate() evaluates an operator. */
-static grn_rc
-grn_ts_op_bitwise_xor_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
-                               const grn_ts_record *in, size_t n_in,
-                               void *out) {
-  switch (node->args[0]->data_kind) {
-    GRN_TS_OP_BITWISE_EVALUATE_CASE(xor, BOOL, bool)
-    GRN_TS_OP_BITWISE_EVALUATE_CASE(xor, INT, int)
-    default: {
-      GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",
-                        node->args[0]->data_kind);
-    }
-  }
-}
-#undef GRN_TS_OP_BITWISE_EVALUATE_CASE
-
-#define GRN_TS_OP_CHK_EVALUATE_CASE(type, KIND, kind)\
-  case GRN_TS_ ## KIND: {\
-    grn_ts_ ## kind *buf_ptrs[] = {\
-      (grn_ts_ ## kind *)node->bufs[0].ptr,\
-      (grn_ts_ ## kind *)node->bufs[1].ptr\
-    };\
-    for (i = 0; i < n_in; i++) {\
-      out_ptr[i] = grn_ts_op_ ## type ## _ ## kind(buf_ptrs[0][i],\
-                                                   buf_ptrs[1][i]);\
-    }\
-    return GRN_SUCCESS;\
-  }
-#define GRN_TS_OP_CHK_EVALUATE_VECTOR_CASE(type, KIND, kind)\
-  GRN_TS_OP_CHK_EVALUATE_CASE(type, KIND ## _VECTOR, kind ## _vector)
-#define GRN_TS_OP_CHK_EVALUATE(type)\
-  size_t i;\
-  grn_rc rc;\
-  grn_ts_bool *out_ptr = (grn_ts_bool *)out;\
-  if (node->args[0]->data_kind == GRN_TS_BOOL) {\
-    /*
-     * Use the output buffer to put evaluation results of the 1st argument,
-     * because the data kind is same.
-     */\
-    rc = grn_ts_expr_node_evaluate(ctx, node->args[0], in, n_in, out);\
-    if (rc == GRN_SUCCESS) {\
-      grn_ts_buf *buf = &node->bufs[0];\
-      rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[1],\
-                                            in, n_in, buf);\
-      if (rc == GRN_SUCCESS) {\
-        grn_ts_bool *buf_ptr = (grn_ts_bool *)buf->ptr;\
-        for (i = 0; i < n_in; i++) {\
-          out_ptr[i] = grn_ts_op_ ## type ## _bool(out_ptr[i], buf_ptr[i]);\
-        }\
-      }\
-    }\
-    return rc;\
-  }\
-  for (i = 0; i < 2; i++) {\
-    rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[i], in, n_in,\
-                                          &node->bufs[i]);\
-    if (rc != GRN_SUCCESS) {\
-      return rc;\
-    }\
-  }\
-  switch (node->args[0]->data_kind) {\
-    GRN_TS_OP_CHK_EVALUATE_CASE(type, INT, int)\
-    GRN_TS_OP_CHK_EVALUATE_CASE(type, FLOAT, float)\
-    GRN_TS_OP_CHK_EVALUATE_CASE(type, TIME, time)\
-    GRN_TS_OP_CHK_EVALUATE_CASE(type, TEXT, text)\
-    GRN_TS_OP_CHK_EVALUATE_CASE(type, GEO_POINT, geo_point)\
-    GRN_TS_OP_CHK_EVALUATE_CASE(type, REF, ref)\
-    GRN_TS_OP_CHK_EVALUATE_VECTOR_CASE(type, BOOL, bool)\
-    GRN_TS_OP_CHK_EVALUATE_VECTOR_CASE(type, INT, int)\
-    GRN_TS_OP_CHK_EVALUATE_VECTOR_CASE(type, FLOAT, float)\
-    GRN_TS_OP_CHK_EVALUATE_VECTOR_CASE(type, TIME, time)\
-    GRN_TS_OP_CHK_EVALUATE_VECTOR_CASE(type, TEXT, text)\
-    GRN_TS_OP_CHK_EVALUATE_VECTOR_CASE(type, GEO_POINT, geo_point)\
-    GRN_TS_OP_CHK_EVALUATE_VECTOR_CASE(type, REF, ref)\
-    default: {\
-      GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",\
-                        node->args[0]->data_kind);\
-    }\
-  }
-/* grn_ts_op_equal_evaluate() evaluates an operator. */
-static grn_rc
-grn_ts_op_equal_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
-                         const grn_ts_record *in, size_t n_in, void *out) {
-  GRN_TS_OP_CHK_EVALUATE(equal)
-}
-
-/* grn_ts_op_not_equal_evaluate() evaluates an operator. */
-static grn_rc
-grn_ts_op_not_equal_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
-                             const grn_ts_record *in, size_t n_in, void *out) {
-  GRN_TS_OP_CHK_EVALUATE(not_equal)
-}
-#undef GRN_TS_OP_CHK_EVALUATE
-#undef GRN_TS_OP_CHK_EVALUATE_VECTOR_CASE
-#undef GRN_TS_OP_CHK_EVALUATE_CASE
-
-#define GRN_TS_OP_CMP_EVALUATE_CASE(type, KIND, kind)\
-  case GRN_TS_ ## KIND: {\
-    grn_ts_ ## kind *buf_ptrs[] = {\
-      (grn_ts_ ## kind *)node->bufs[0].ptr,\
-      (grn_ts_ ## kind *)node->bufs[1].ptr\
-    };\
-    for (i = 0; i < n_in; i++) {\
-      out_ptr[i] = grn_ts_op_ ## type ## _ ## kind(buf_ptrs[0][i],\
-                                                   buf_ptrs[1][i]);\
-    }\
-    return GRN_SUCCESS;\
-  }
-#define GRN_TS_OP_CMP_EVALUATE_VECTOR_CASE(type, KIND, kind)\
-  GRN_TS_OP_CMP_EVALUATE_CASE(type, KIND ## _VECTOR, kind ## _vector)
-#define GRN_TS_OP_CMP_EVALUATE(type)\
-  size_t i;\
-  grn_rc rc;\
-  grn_ts_bool *out_ptr = (grn_ts_bool *)out;\
-  for (i = 0; i < 2; i++) {\
-    rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[i], in, n_in,\
-                                          &node->bufs[i]);\
-    if (rc != GRN_SUCCESS) {\
-      return rc;\
-    }\
-  }\
-  switch (node->args[0]->data_kind) {\
-    GRN_TS_OP_CMP_EVALUATE_CASE(type, INT, int)\
-    GRN_TS_OP_CMP_EVALUATE_CASE(type, FLOAT, float)\
-    GRN_TS_OP_CMP_EVALUATE_CASE(type, TIME, time)\
-    GRN_TS_OP_CMP_EVALUATE_CASE(type, TEXT, text)\
-    GRN_TS_OP_CMP_EVALUATE_VECTOR_CASE(type, INT, int)\
-    GRN_TS_OP_CMP_EVALUATE_VECTOR_CASE(type, FLOAT, float)\
-    GRN_TS_OP_CMP_EVALUATE_VECTOR_CASE(type, TIME, time)\
-    GRN_TS_OP_CMP_EVALUATE_VECTOR_CASE(type, TEXT, text)\
-    default: {\
-      GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",\
-                        node->args[0]->data_kind);\
-    }\
-  }
-/* grn_ts_op_less_evaluate() evaluates an operator. */
-static grn_rc
-grn_ts_op_less_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
-                        const grn_ts_record *in, size_t n_in, void *out) {
-  GRN_TS_OP_CMP_EVALUATE(less)
-}
-
-/* grn_ts_op_less_equal_evaluate() evaluates an operator. */
-static grn_rc
-grn_ts_op_less_equal_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
-                              const grn_ts_record *in, size_t n_in,
-                              void *out) {
-  GRN_TS_OP_CMP_EVALUATE(less_equal)
-}
-
-/* grn_ts_op_greater_evaluate() evaluates an operator. */
-static grn_rc
-grn_ts_op_greater_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
-                           const grn_ts_record *in, size_t n_in, void *out) {
-  GRN_TS_OP_CMP_EVALUATE(greater)
-}
-
-/* grn_ts_op_greater_equal_evaluate() evaluates an operator. */
-static grn_rc
-grn_ts_op_greater_equal_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
-                                 const grn_ts_record *in, size_t n_in,
-                                 void *out) {
-  GRN_TS_OP_CMP_EVALUATE(greater_equal)
-}
-#undef GRN_TS_OP_CMP_EVALUATE
-#undef GRN_TS_OP_CMP_EVALUATE_VECTOR_CASE
-#undef GRN_TS_OP_CMP_EVALUATE_CASE
-
-#define GRN_TS_OP_SHIFT_EVALUATE(type)\
-  size_t i;\
-  grn_rc rc;\
-  grn_ts_int *out_ptr = (grn_ts_int *)out;\
-  rc = grn_ts_expr_node_evaluate(ctx, node->args[0], in, n_in, out);\
-  if (rc == GRN_SUCCESS) {\
-    rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[1],\
-                                          in, n_in, &node->bufs[0]);\
-    if (rc == GRN_SUCCESS) {\
-      grn_ts_int *buf_ptr = (grn_ts_int *)node->bufs[0].ptr;\
-      for (i = 0; i < n_in; i++) {\
-        out_ptr[i] = grn_ts_op_shift_ ## type(out_ptr[i], buf_ptr[i]);\
-      }\
-    }\
-  }\
-  return rc;
-/* grn_ts_op_shift_arithmetic_left_evaluate() evaluates an operator. */
-static grn_rc
-grn_ts_op_shift_arithmetic_left_evaluate(grn_ctx *ctx,
-                                         grn_ts_expr_op_node *node,
-                                         const grn_ts_record *in, size_t n_in,
-                                         void *out) {
-  GRN_TS_OP_SHIFT_EVALUATE(arithmetic_left)
-}
-
-/* grn_ts_op_shift_arithmetic_right_evaluate() evaluates an operator. */
-static grn_rc
-grn_ts_op_shift_arithmetic_right_evaluate(grn_ctx *ctx,
-                                          grn_ts_expr_op_node *node,
-                                          const grn_ts_record *in, size_t n_in,
-                                          void *out) {
-  GRN_TS_OP_SHIFT_EVALUATE(arithmetic_right)
-}
-
-/* grn_ts_op_shift_logical_left_evaluate() evaluates an operator. */
-static grn_rc
-grn_ts_op_shift_logical_left_evaluate(grn_ctx *ctx,
-                                      grn_ts_expr_op_node *node,
-                                      const grn_ts_record *in, size_t n_in,
-                                      void *out) {
-  GRN_TS_OP_SHIFT_EVALUATE(logical_left)
-}
-
-/* grn_ts_op_shift_logical_right_evaluate() evaluates an operator. */
-static grn_rc
-grn_ts_op_shift_logical_right_evaluate(grn_ctx *ctx,
-                                       grn_ts_expr_op_node *node,
-                                       const grn_ts_record *in, size_t n_in,
-                                       void *out) {
-  GRN_TS_OP_SHIFT_EVALUATE(logical_right)
-}
-#undef GRN_TS_OP_SHIFT_EVALUATE
-
-#define GRN_TS_OP_ARITH_EVALUATE_CASE(type, KIND, kind)\
-  case GRN_TS_ ## KIND: {\
-    /*
-     * Use the output buffer to put evaluation results of the 1st argument,
-     * because the data kind is same.
-     */\
-    size_t i;\
-    grn_rc rc;\
-    grn_ts_ ## kind *out_ptr = (grn_ts_ ## kind *)out;\
-    rc = grn_ts_expr_node_evaluate(ctx, node->args[0], in, n_in, out);\
-    if (rc == GRN_SUCCESS) {\
-      rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[1],\
-                                            in, n_in, &node->bufs[0]);\
-      if (rc == GRN_SUCCESS) {\
-        grn_ts_ ## kind *buf_ptr = (grn_ts_ ## kind *)node->bufs[0].ptr;\
-        for (i = 0; i < n_in; i++) {\
-          out_ptr[i] = grn_ts_op_ ## type ## _ ## kind(out_ptr[i],\
-                                                       buf_ptr[i]);\
-        }\
-      }\
-    }\
-    return rc;\
-  }
-#define GRN_TS_OP_ARITH_EVALUATE_TIME_CASE(type, KIND, lhs, rhs)\
-  case GRN_TS_ ## KIND: {\
-    /*
-     * Use the output buffer to put evaluation results of the 1st argument,
-     * because the data kind is same.
-     */\
-    size_t i;\
-    grn_rc rc;\
-    grn_ts_ ## lhs *out_ptr = (grn_ts_ ## lhs *)out;\
-    rc = grn_ts_expr_node_evaluate(ctx, node->args[0], in, n_in, out);\
-    if (rc == GRN_SUCCESS) {\
-      rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[1],\
-                                            in, n_in, &node->bufs[0]);\
-      if (rc == GRN_SUCCESS) {\
-        grn_ts_ ## rhs *buf_ptr = (grn_ts_ ## rhs *)node->bufs[0].ptr;\
-        for (i = 0; i < n_in; i++) {\
-          out_ptr[i] = grn_ts_op_ ## type ## _ ## lhs ## _ ## rhs(out_ptr[i],\
-                                                                  buf_ptr[i]);\
-        }\
-      }\
-    }\
-    return rc;\
-  }
-/* grn_ts_op_plus_evaluate() evaluates an operator. */
-static grn_rc
-grn_ts_op_plus_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
-                        const grn_ts_record *in, size_t n_in, void *out) {
-  switch (node->args[0]->data_kind) {
-    GRN_TS_OP_ARITH_EVALUATE_CASE(plus, INT, int)
-    GRN_TS_OP_ARITH_EVALUATE_CASE(plus, FLOAT, float)
-    case GRN_TS_TIME: {
-      switch (node->args[1]->data_kind) {
-        GRN_TS_OP_ARITH_EVALUATE_TIME_CASE(plus, INT, time, int)
-        GRN_TS_OP_ARITH_EVALUATE_TIME_CASE(plus, FLOAT, time, float)
-        default: {
-          GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "data kind conflict: %d, %d",
-                            node->args[0]->data_kind,
-                            node->args[1]->data_kind);
-        }
-      }
-    }
-    default: {
-      GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",
-                        node->args[0]->data_kind);
-    }
-  }
-}
-
-/* grn_ts_op_minus_evaluate() evaluates an operator. */
-static grn_rc
-grn_ts_op_minus_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
-                         const grn_ts_record *in, size_t n_in, void *out) {
-  switch (node->args[0]->data_kind) {
-    GRN_TS_OP_ARITH_EVALUATE_CASE(minus, INT, int)
-    GRN_TS_OP_ARITH_EVALUATE_CASE(minus, FLOAT, float)
-    case GRN_TS_TIME: {
-      switch (node->args[1]->data_kind) {
-        GRN_TS_OP_ARITH_EVALUATE_TIME_CASE(minus, INT, time, int)
-        GRN_TS_OP_ARITH_EVALUATE_TIME_CASE(minus, FLOAT, time, float)
-        case GRN_TS_TIME: {
-          size_t i;
-          grn_rc rc;
-          grn_ts_float *out_ptr = (grn_ts_float *)out;
-          grn_ts_time *buf_ptrs[2];
-          rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[0], in, n_in,
-                                                &node->bufs[0]);
-          if (rc != GRN_SUCCESS) {
-            return rc;
-          }
-          rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[1], in, n_in,
-                                                &node->bufs[1]);
-          if (rc != GRN_SUCCESS) {
-            return rc;
-          }
-          buf_ptrs[0] = (grn_ts_time *)node->bufs[0].ptr;
-          buf_ptrs[1] = (grn_ts_time *)node->bufs[1].ptr;
-          for (i = 0; i < n_in; i++) {
-            out_ptr[i] = grn_ts_op_minus_time_time(buf_ptrs[0][i],
-                                                   buf_ptrs[1][i]);
-          }
-          return GRN_SUCCESS;
-        }
-        default: {
-          GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "data kind conflict: %d, %d",
-                            node->args[0]->data_kind,
-                            node->args[1]->data_kind);
-        }
-      }
-    }
-    default: {
-      GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",
-                        node->args[0]->data_kind);
-    }
-  }
-}
-#undef GRN_TS_OP_ARITH_EVALUATE_TIME_CASE
-
-/* grn_ts_op_multiplication_evaluate() evaluates an operator. */
-static grn_rc
-grn_ts_op_multiplication_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
-                                  const grn_ts_record *in, size_t n_in,
-                                  void *out) {
-  switch (node->data_kind) {
-    GRN_TS_OP_ARITH_EVALUATE_CASE(multiplication, INT, int)
-    GRN_TS_OP_ARITH_EVALUATE_CASE(multiplication, FLOAT, float)
-    default: {
-      GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",
-                        node->data_kind);
-    }
-  }
-}
-
-/* grn_ts_op_division_evaluate() evaluates an operator. */
-static grn_rc
-grn_ts_op_division_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
-                            const grn_ts_record *in, size_t n_in, void *out) {
-  switch (node->data_kind) {
-    case GRN_TS_INT: {
-      /* Specialized to detect a critical error. */
-      size_t i;
-      grn_rc rc;
-      grn_ts_int *out_ptr = (grn_ts_int *)out;
-      rc = grn_ts_expr_node_evaluate(ctx, node->args[0], in, n_in, out);
-      if (rc == GRN_SUCCESS) {
-        rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[1],
-                                              in, n_in, &node->bufs[0]);
-        if (rc == GRN_SUCCESS) {
-          grn_ts_int *buf_ptr = (grn_ts_int *)node->bufs[0].ptr;
-          for (i = 0; i < n_in; i++) {
-            if (!buf_ptr[i]) {
-              GRN_TS_ERR(GRN_INVALID_ARGUMENT, "integer division by zero");
-              rc = ctx->rc;
-              break;
-            } else if ((out_ptr[i] == INT64_MIN) && (buf_ptr[i] == -1)) {
-              GRN_TS_ERR(GRN_INVALID_ARGUMENT, "integer division overflow");
-              rc = ctx->rc;
-              break;
-            }
-            out_ptr[i] = grn_ts_op_division_int(out_ptr[i], buf_ptr[i]);
-          }
-        }
-      }
-      return rc;
-    }
-    GRN_TS_OP_ARITH_EVALUATE_CASE(division, FLOAT, float)
-    default: {
-      GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",
-                        node->data_kind);
-    }
-  }
-}
-
-/* grn_ts_op_modulus_evaluate() evaluates an operator. */
-static grn_rc
-grn_ts_op_modulus_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
-                           const grn_ts_record *in, size_t n_in, void *out) {
-  switch (node->data_kind) {
-    case GRN_TS_INT: {
-      /* Specialized to detect a critical error. */
-      size_t i;
-      grn_rc rc;
-      grn_ts_int *out_ptr = (grn_ts_int *)out;
-      rc = grn_ts_expr_node_evaluate(ctx, node->args[0], in, n_in, out);
-      if (rc == GRN_SUCCESS) {
-        rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[1],
-                                              in, n_in, &node->bufs[0]);
-        if (rc == GRN_SUCCESS) {
-          grn_ts_int *buf_ptr = (grn_ts_int *)node->bufs[0].ptr;
-          for (i = 0; i < n_in; i++) {
-            if (!buf_ptr[i]) {
-              GRN_TS_ERR(GRN_INVALID_ARGUMENT, "integer division by zero");
-              rc = ctx->rc;
-              break;
-            } else if ((out_ptr[i] == INT64_MIN) && (buf_ptr[i] == -1)) {
-              GRN_TS_ERR(GRN_INVALID_ARGUMENT, "integer division overflow");
-              rc = ctx->rc;
-              break;
-            }
-            out_ptr[i] = grn_ts_op_modulus_int(out_ptr[i], buf_ptr[i]);
-          }
-        }
-      }
-      return rc;
-    }
-    GRN_TS_OP_ARITH_EVALUATE_CASE(modulus, FLOAT, float)
-    default: {
-      GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",
-                        node->data_kind);
-    }
-  }
-}
-#undef GRN_TS_OP_ARITH_EVALUATE_CASE
-
-/* grn_ts_expr_op_node_evaluate() evaluates an operator. */
-static grn_rc
-grn_ts_expr_op_node_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
-                             const grn_ts_record *in, size_t n_in,
-                             void *out) {
-  switch (node->op_type) {
-    case GRN_TS_OP_LOGICAL_NOT: {
-      return grn_ts_op_logical_not_evaluate(ctx, node, in, n_in, out);
-    }
-    case GRN_TS_OP_BITWISE_NOT: {
-      return grn_ts_op_bitwise_not_evaluate(ctx, node, in, n_in, out);
-    }
-    case GRN_TS_OP_POSITIVE: {
-      return grn_ts_op_positive_evaluate(ctx, node, in, n_in, out);
-    }
-    case GRN_TS_OP_NEGATIVE: {
-      return grn_ts_op_negative_evaluate(ctx, node, in, n_in, out);
-    }
-    case GRN_TS_OP_LOGICAL_AND: {
-      return grn_ts_op_logical_and_evaluate(ctx, node, in, n_in, out);
-    }
-    case GRN_TS_OP_LOGICAL_OR: {
-      return grn_ts_op_logical_or_evaluate(ctx, node, in, n_in, out);
-    }
-    case GRN_TS_OP_LOGICAL_SUB: {
-      return grn_ts_op_logical_sub_evaluate(ctx, node, in, n_in, out);
-    }
-    case GRN_TS_OP_BITWISE_AND: {
-      return grn_ts_op_bitwise_and_evaluate(ctx, node, in, n_in, out);
-    }
-    case GRN_TS_OP_BITWISE_OR: {
-      return grn_ts_op_bitwise_or_evaluate(ctx, node, in, n_in, out);
-    }
-    case GRN_TS_OP_BITWISE_XOR: {
-      return grn_ts_op_bitwise_xor_evaluate(ctx, node, in, n_in, out);
-    }
-    case GRN_TS_OP_EQUAL: {
-      return grn_ts_op_equal_evaluate(ctx, node, in, n_in, out);
-    }
-    case GRN_TS_OP_NOT_EQUAL: {
-      return grn_ts_op_not_equal_evaluate(ctx, node, in, n_in, out);
-    }
-    case GRN_TS_OP_LESS: {
-      return grn_ts_op_less_evaluate(ctx, node, in, n_in, out);
-    }
-    case GRN_TS_OP_LESS_EQUAL: {
-      return grn_ts_op_less_equal_evaluate(ctx, node, in, n_in, out);
-    }
-    case GRN_TS_OP_GREATER: {
-      return grn_ts_op_greater_evaluate(ctx, node, in, n_in, out);
-    }
-    case GRN_TS_OP_GREATER_EQUAL: {
-      return grn_ts_op_greater_equal_evaluate(ctx, node, in, n_in, out);
-    }
-    case GRN_TS_OP_SHIFT_ARITHMETIC_LEFT: {
-      return grn_ts_op_shift_arithmetic_left_evaluate(ctx, node, in, n_in, out);
-    }
-    case GRN_TS_OP_SHIFT_ARITHMETIC_RIGHT: {
-      return grn_ts_op_shift_arithmetic_right_evaluate(ctx, node, in, n_in, out);
-    }
-    case GRN_TS_OP_SHIFT_LOGICAL_LEFT: {
-      return grn_ts_op_shift_logical_left_evaluate(ctx, node, in, n_in, out);
-    }
-    case GRN_TS_OP_SHIFT_LOGICAL_RIGHT: {
-      return grn_ts_op_shift_logical_right_evaluate(ctx, node, in, n_in, out);
-    }
-    case GRN_TS_OP_PLUS: {
-      return grn_ts_op_plus_evaluate(ctx, node, in, n_in, out);
-    }
-    case GRN_TS_OP_MINUS: {
-      return grn_ts_op_minus_evaluate(ctx, node, in, n_in, out);
-    }
-    case GRN_TS_OP_MULTIPLICATION: {
-      return grn_ts_op_multiplication_evaluate(ctx, node, in, n_in, out);
-    }
-    case GRN_TS_OP_DIVISION: {
-      return grn_ts_op_division_evaluate(ctx, node, in, n_in, out);
-    }
-    case GRN_TS_OP_MODULUS: {
-      return grn_ts_op_modulus_evaluate(ctx, node, in, n_in, out);
-    }
-    // TODO: Add operators.
-    default: {
-      GRN_TS_ERR_RETURN(GRN_OPERATION_NOT_SUPPORTED,
-                        "operator not supported: %d", node->op_type);
-    }
-  }
-}
-
-/* grn_ts_op_logical_not_filter() filters records. */
-static grn_rc
-grn_ts_op_logical_not_filter(grn_ctx *ctx, grn_ts_expr_op_node *node,
-                             grn_ts_record *in, size_t n_in,
-                             grn_ts_record *out, size_t *n_out) {
-  size_t i, count;
-  grn_rc rc;
-  grn_ts_bool *buf_ptr;
-  rc = grn_ts_buf_reserve(ctx, &node->bufs[0], sizeof(grn_ts_bool) * n_in);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  buf_ptr = (grn_ts_bool *)node->bufs[0].ptr;
-  rc = grn_ts_expr_node_evaluate(ctx, node->args[0], in, n_in, buf_ptr);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  for (i = 0, count = 0; i < n_in; i++) {
-    if (grn_ts_op_logical_not_bool(buf_ptr[i])) {
-      out[count++] = in[i];
-    }
-  }
-  *n_out = count;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_op_bitwise_not_filter() filters records. */
-static grn_rc
-grn_ts_op_bitwise_not_filter(grn_ctx *ctx, grn_ts_expr_op_node *node,
-                             grn_ts_record *in, size_t n_in,
-                             grn_ts_record *out, size_t *n_out) {
-  size_t i, count;
-  grn_rc rc;
-  grn_ts_bool *buf_ptr;
-  rc = grn_ts_buf_reserve(ctx, &node->bufs[0], sizeof(grn_ts_bool) * n_in);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  buf_ptr = (grn_ts_bool *)node->bufs[0].ptr;
-  rc = grn_ts_expr_node_evaluate(ctx, node->args[0], in, n_in, buf_ptr);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  for (i = 0, count = 0; i < n_in; i++) {
-    if (grn_ts_op_bitwise_not_bool(buf_ptr[i])) {
-      out[count++] = in[i];
-    }
-  }
-  *n_out = count;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_op_logical_and_filter() filters records. */
-static grn_rc
-grn_ts_op_logical_and_filter(grn_ctx *ctx, grn_ts_expr_op_node *node,
-                             grn_ts_record *in, size_t n_in,
-                             grn_ts_record *out, size_t *n_out) {
-  grn_rc rc = grn_ts_expr_node_filter(ctx, node->args[0], in, n_in,
-                                      out, n_out);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  return grn_ts_expr_node_filter(ctx, node->args[1], out, *n_out, out, n_out);
-}
-
-/* grn_ts_op_logical_or_filter() filters records. */
-static grn_rc
-grn_ts_op_logical_or_filter(grn_ctx *ctx, grn_ts_expr_op_node *node,
-                            grn_ts_record *in, size_t n_in,
-                            grn_ts_record *out, size_t *n_out) {
-  size_t i, j, count;
-  grn_rc rc;
-  grn_ts_bool *buf_ptrs[2];
-  grn_ts_buf *tmp_in_buf = &node->bufs[2];
-  grn_ts_record *tmp_in;
-
-  /* Evaluate the 1st argument. */
-  rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[0], in, n_in,
-                                        &node->bufs[0]);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  buf_ptrs[0] = (grn_ts_bool *)node->bufs[0].ptr;
-
-  /* Create a list of false records. */
-  rc = grn_ts_buf_reserve(ctx, tmp_in_buf, sizeof(grn_ts_record) * n_in);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  tmp_in = (grn_ts_record *)tmp_in_buf->ptr;
-  count = 0;
-  for (i = 0; i < n_in; i++) {
-    if (!buf_ptrs[0][i]) {
-      tmp_in[count++] = in[i];
-    }
-  }
-
-  /* Evaluate the 2nd argument. */
-  rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[1], tmp_in, count,
-                                        &node->bufs[1]);
-  buf_ptrs[1] = (grn_ts_bool *)node->bufs[1].ptr;
-
-  /* Merge the results. */
-  count = 0;
-  for (i = 0, j = 0; i < n_in; i++) {
-    if (buf_ptrs[0][i] || buf_ptrs[1][j++]) {
-      out[count++] = in[i];
-    }
-  }
-  *n_out = count;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_op_logical_sub_filter() filters records. */
-static grn_rc
-grn_ts_op_logical_sub_filter(grn_ctx *ctx, grn_ts_expr_op_node *node,
-                             grn_ts_record *in, size_t n_in,
-                             grn_ts_record *out, size_t *n_out) {
-  size_t i, n, count;
-  grn_ts_bool *buf_ptr;
-  grn_rc rc = grn_ts_expr_node_filter(ctx, node->args[0], in, n_in, out, &n);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[1], out, n,
-                                        &node->bufs[0]);
-  buf_ptr = (grn_ts_bool *)node->bufs[0].ptr;
-  for (i = 0, count = 0; i < n; i++) {
-    if (grn_ts_op_logical_not_bool(buf_ptr[i])) {
-      out[count++] = out[i];
-    }
-  }
-  *n_out = count;
-  return GRN_SUCCESS;
-}
-
-#define GRN_TS_OP_BITWISE_FILTER(type)\
-  size_t i, count = 0;\
-  grn_ts_bool *buf_ptrs[2];\
-  for (i = 0; i < 2; i++) {\
-    grn_rc rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[i], in, n_in,\
-                                                 &node->bufs[i]);\
-    if (rc != GRN_SUCCESS) {\
-      return rc;\
-    }\
-    buf_ptrs[i] = (grn_ts_bool *)node->bufs[i].ptr;\
-  }\
-  for (i = 0; i < n_in; i++) {\
-    if (grn_ts_op_bitwise_ ## type ## _bool(buf_ptrs[0][i], buf_ptrs[1][i])) {\
-      out[count++] = in[i];\
-    }\
-  }\
-  *n_out = count;\
-  return GRN_SUCCESS;\
-/* grn_ts_op_bitwise_and_filter() filters records. */
-static grn_rc
-grn_ts_op_bitwise_and_filter(grn_ctx *ctx, grn_ts_expr_op_node *node,
-                             grn_ts_record *in, size_t n_in,
-                             grn_ts_record *out, size_t *n_out) {
-  GRN_TS_OP_BITWISE_FILTER(and);
-}
-
-/* grn_ts_op_bitwise_or_filter() filters records. */
-static grn_rc
-grn_ts_op_bitwise_or_filter(grn_ctx *ctx, grn_ts_expr_op_node *node,
-                            grn_ts_record *in, size_t n_in,
-                            grn_ts_record *out, size_t *n_out) {
-  GRN_TS_OP_BITWISE_FILTER(or);
-}
-
-/* grn_ts_op_bitwise_xor_filter() filters records. */
-static grn_rc
-grn_ts_op_bitwise_xor_filter(grn_ctx *ctx, grn_ts_expr_op_node *node,
-                             grn_ts_record *in, size_t n_in,
-                             grn_ts_record *out, size_t *n_out) {
-  GRN_TS_OP_BITWISE_FILTER(xor);
-}
-#undef GRN_TS_OP_BITWISE_FILTER_CASE
-
-#define GRN_TS_OP_CHK_FILTER_CASE(type, KIND, kind)\
-  case GRN_TS_ ## KIND: {\
-    grn_ts_ ## kind *buf_ptrs[] = {\
-      (grn_ts_ ## kind *)node->bufs[0].ptr,\
-      (grn_ts_ ## kind *)node->bufs[1].ptr\
-    };\
-    for (i = 0; i < n_in; i++) {\
-      if (grn_ts_op_ ## type ## _ ## kind(buf_ptrs[0][i], buf_ptrs[1][i])) {\
-        out[count++] = in[i];\
-      }\
-    }\
-    *n_out = count;\
-    return GRN_SUCCESS;\
-  }
-#define GRN_TS_OP_CHK_FILTER_VECTOR_CASE(type, KIND, kind)\
-  GRN_TS_OP_CHK_FILTER_CASE(type, KIND ## _VECTOR, kind ## _vector)
-#define GRN_TS_OP_CHK_FILTER(type)\
-  size_t i, count = 0;\
-  for (i = 0; i < 2; i++) {\
-    grn_rc rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[i], in, n_in,\
-                                                 &node->bufs[i]);\
-    if (rc != GRN_SUCCESS) {\
-      return rc;\
-    }\
-  }\
-  switch (node->args[0]->data_kind) {\
-    GRN_TS_OP_CHK_FILTER_CASE(type, BOOL, bool)\
-    GRN_TS_OP_CHK_FILTER_CASE(type, INT, int)\
-    GRN_TS_OP_CHK_FILTER_CASE(type, FLOAT, float)\
-    GRN_TS_OP_CHK_FILTER_CASE(type, TIME, time)\
-    GRN_TS_OP_CHK_FILTER_CASE(type, TEXT, text)\
-    GRN_TS_OP_CHK_FILTER_CASE(type, GEO_POINT, geo_point)\
-    GRN_TS_OP_CHK_FILTER_CASE(type, REF, ref)\
-    GRN_TS_OP_CHK_FILTER_VECTOR_CASE(type, BOOL, bool)\
-    GRN_TS_OP_CHK_FILTER_VECTOR_CASE(type, INT, int)\
-    GRN_TS_OP_CHK_FILTER_VECTOR_CASE(type, FLOAT, float)\
-    GRN_TS_OP_CHK_FILTER_VECTOR_CASE(type, TIME, time)\
-    GRN_TS_OP_CHK_FILTER_VECTOR_CASE(type, TEXT, text)\
-    GRN_TS_OP_CHK_FILTER_VECTOR_CASE(type, GEO_POINT, geo_point)\
-    GRN_TS_OP_CHK_FILTER_VECTOR_CASE(type, REF, ref)\
-    default: {\
-      GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",\
-                        node->args[0]->data_kind);\
-    }\
-  }
-/* grn_ts_op_equal_filter() filters records. */
-static grn_rc
-grn_ts_op_equal_filter(grn_ctx *ctx, grn_ts_expr_op_node *node,
-                       const grn_ts_record *in, size_t n_in,
-                       grn_ts_record *out, size_t *n_out) {
-  GRN_TS_OP_CHK_FILTER(equal)
-}
-
-/* grn_ts_op_not_equal_filter() filters records. */
-static grn_rc
-grn_ts_op_not_equal_filter(grn_ctx *ctx, grn_ts_expr_op_node *node,
-                           const grn_ts_record *in, size_t n_in,
-                           grn_ts_record *out, size_t *n_out) {
-  GRN_TS_OP_CHK_FILTER(not_equal)
-}
-#undef GRN_TS_OP_CHK_FILTER
-#undef GRN_TS_OP_CHK_FILTER_VECTOR_CASE
-#undef GRN_TS_OP_CHK_FILTER_CASE
-
-#define GRN_TS_OP_CMP_FILTER_CASE(type, KIND, kind)\
-  case GRN_TS_ ## KIND: {\
-    grn_ts_ ## kind *buf_ptrs[] = {\
-      (grn_ts_ ## kind *)node->bufs[0].ptr,\
-      (grn_ts_ ## kind *)node->bufs[1].ptr\
-    };\
-    for (i = 0; i < n_in; i++) {\
-      if (grn_ts_op_ ## type ## _ ## kind(buf_ptrs[0][i], buf_ptrs[1][i])) {\
-        out[count++] = in[i];\
-      }\
-    }\
-    *n_out = count;\
-    return GRN_SUCCESS;\
-  }
-#define GRN_TS_OP_CMP_FILTER_VECTOR_CASE(type, KIND, kind)\
-  GRN_TS_OP_CMP_FILTER_CASE(type, KIND ## _VECTOR, kind ## _vector)
-#define GRN_TS_OP_CMP_FILTER(type)\
-  size_t i, count = 0;\
-  for (i = 0; i < 2; i++) {\
-    grn_rc rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[i], in, n_in,\
-                                                 &node->bufs[i]);\
-    if (rc != GRN_SUCCESS) {\
-      return rc;\
-    }\
-  }\
-  switch (node->args[0]->data_kind) {\
-    GRN_TS_OP_CMP_FILTER_CASE(type, INT, int)\
-    GRN_TS_OP_CMP_FILTER_CASE(type, FLOAT, float)\
-    GRN_TS_OP_CMP_FILTER_CASE(type, TIME, time)\
-    GRN_TS_OP_CMP_FILTER_CASE(type, TEXT, text)\
-    GRN_TS_OP_CMP_FILTER_VECTOR_CASE(type, INT, int)\
-    GRN_TS_OP_CMP_FILTER_VECTOR_CASE(type, FLOAT, float)\
-    GRN_TS_OP_CMP_FILTER_VECTOR_CASE(type, TIME, time)\
-    GRN_TS_OP_CMP_FILTER_VECTOR_CASE(type, TEXT, text)\
-    default: {\
-      GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",\
-                        node->args[0]->data_kind);\
-    }\
-  }
-/* grn_ts_op_less_filter() filters records. */
-static grn_rc
-grn_ts_op_less_filter(grn_ctx *ctx, grn_ts_expr_op_node *node,
-                      const grn_ts_record *in, size_t n_in,
-                      grn_ts_record *out, size_t *n_out) {
-  GRN_TS_OP_CMP_FILTER(less)
-}
-
-/* grn_ts_op_less_equal_filter() filters records. */
-static grn_rc
-grn_ts_op_less_equal_filter(grn_ctx *ctx, grn_ts_expr_op_node *node,
-                            const grn_ts_record *in, size_t n_in,
-                            grn_ts_record *out, size_t *n_out) {
-  GRN_TS_OP_CMP_FILTER(less_equal)
-}
-
-/* grn_ts_op_greater_filter() filters records. */
-static grn_rc
-grn_ts_op_greater_filter(grn_ctx *ctx, grn_ts_expr_op_node *node,
-                         const grn_ts_record *in, size_t n_in,
-                         grn_ts_record *out, size_t *n_out) {
-  GRN_TS_OP_CMP_FILTER(greater)
-}
-
-/* grn_ts_op_greater_equal_filter() filters records. */
-static grn_rc
-grn_ts_op_greater_equal_filter(grn_ctx *ctx, grn_ts_expr_op_node *node,
-                               const grn_ts_record *in, size_t n_in,
-                               grn_ts_record *out, size_t *n_out) {
-  GRN_TS_OP_CMP_FILTER(greater_equal)
-}
-#undef GRN_TS_OP_CMP_FILTER
-#undef GRN_TS_OP_CMP_FILTER_VECTOR_CASE
-#undef GRN_TS_OP_CMP_FILTER_CASE
-
-/* grn_ts_expr_op_node_filter() filters records. */
-static grn_rc
-grn_ts_expr_op_node_filter(grn_ctx *ctx, grn_ts_expr_op_node *node,
-                           grn_ts_record *in, size_t n_in,
-                           grn_ts_record *out, size_t *n_out) {
-  switch (node->op_type) {
-    case GRN_TS_OP_LOGICAL_NOT: {
-      return grn_ts_op_logical_not_filter(ctx, node, in, n_in, out, n_out);
-    }
-    case GRN_TS_OP_BITWISE_NOT: {
-      return grn_ts_op_bitwise_not_filter(ctx, node, in, n_in, out, n_out);
-    }
-    case GRN_TS_OP_LOGICAL_AND: {
-      return grn_ts_op_logical_and_filter(ctx, node, in, n_in, out, n_out);
-    }
-    case GRN_TS_OP_LOGICAL_OR: {
-      return grn_ts_op_logical_or_filter(ctx, node, in, n_in, out, n_out);
-    }
-    case GRN_TS_OP_LOGICAL_SUB: {
-      return grn_ts_op_logical_sub_filter(ctx, node, in, n_in, out, n_out);
-    }
-    case GRN_TS_OP_BITWISE_AND: {
-      return grn_ts_op_bitwise_and_filter(ctx, node, in, n_in, out, n_out);
-    }
-    case GRN_TS_OP_BITWISE_OR: {
-      return grn_ts_op_bitwise_or_filter(ctx, node, in, n_in, out, n_out);
-    }
-    case GRN_TS_OP_BITWISE_XOR: {
-      return grn_ts_op_bitwise_xor_filter(ctx, node, in, n_in, out, n_out);
-    }
-    case GRN_TS_OP_EQUAL: {
-      return grn_ts_op_equal_filter(ctx, node, in, n_in, out, n_out);
-    }
-    case GRN_TS_OP_NOT_EQUAL: {
-      return grn_ts_op_not_equal_filter(ctx, node, in, n_in, out, n_out);
-    }
-    case GRN_TS_OP_LESS: {
-      return grn_ts_op_less_filter(ctx, node, in, n_in, out, n_out);
-    }
-    case GRN_TS_OP_LESS_EQUAL: {
-      return grn_ts_op_less_equal_filter(ctx, node, in, n_in, out, n_out);
-    }
-    case GRN_TS_OP_GREATER: {
-      return grn_ts_op_greater_filter(ctx, node, in, n_in, out, n_out);
-    }
-    case GRN_TS_OP_GREATER_EQUAL: {
-      return grn_ts_op_greater_equal_filter(ctx, node, in, n_in, out, n_out);
-    }
-    // TODO: Add operators.
-    default: {
-      GRN_TS_ERR_RETURN(GRN_OPERATION_NOT_SUPPORTED,
-                        "operator not supported: %d", node->op_type);
-    }
-  }
-}
-
-#define GRN_TS_OP_SIGN_ADJUST(type)\
-  size_t i, count = 0;\
-  grn_ts_float *buf_ptr;\
-  grn_rc rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[0], io, n_io,\
-                                               &node->bufs[0]);\
-  if (rc != GRN_SUCCESS) {\
-    return rc;\
-  }\
-  buf_ptr = (grn_ts_float *)node->bufs[0].ptr;\
-  for (i = 0; i < n_io; i++) {\
-    grn_ts_float result = grn_ts_op_ ## type ## _float(buf_ptr[i]);\
-    io[count++].score = (grn_ts_score)result;\
-  }\
-  return GRN_SUCCESS;
-/* grn_ts_op_positive_adjust() updates scores. */
-static grn_rc
-grn_ts_op_positive_adjust(grn_ctx *ctx, grn_ts_expr_op_node *node,
-                          grn_ts_record *io, size_t n_io) {
-  GRN_TS_OP_SIGN_ADJUST(positive)
-}
-
-/* grn_ts_op_negative_adjust() updates scores. */
-static grn_rc
-grn_ts_op_negative_adjust(grn_ctx *ctx, grn_ts_expr_op_node *node,
-                          grn_ts_record *io, size_t n_io) {
-  GRN_TS_OP_SIGN_ADJUST(negative)
-}
-#undef GRN_TS_OP_SIGN_ADJUST
-
-#define GRN_TS_OP_ARITH_ADJUST(type)\
-  size_t i, count = 0;\
-  grn_ts_float *buf_ptrs[2];\
-  for (i = 0; i < 2; i++) {\
-    grn_rc rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[i], io, n_io,\
-                                                 &node->bufs[i]);\
-    if (rc != GRN_SUCCESS) {\
-      return rc;\
-    }\
-  }\
-  buf_ptrs[0] = (grn_ts_float *)node->bufs[0].ptr;\
-  buf_ptrs[1] = (grn_ts_float *)node->bufs[1].ptr;\
-  for (i = 0; i < n_io; i++) {\
-    grn_ts_float result = grn_ts_op_ ## type ## _float(buf_ptrs[0][i],\
-                                                       buf_ptrs[1][i]);\
-    io[count++].score = (grn_ts_score)result;\
-  }\
-  return GRN_SUCCESS;
-/* grn_ts_op_plus_adjust() updates scores. */
-static grn_rc
-grn_ts_op_plus_adjust(grn_ctx *ctx, grn_ts_expr_op_node *node,
-                      grn_ts_record *io, size_t n_io) {
-  GRN_TS_OP_ARITH_ADJUST(plus)
-}
-
-/* grn_ts_op_minus_adjust() updates scores. */
-static grn_rc
-grn_ts_op_minus_adjust(grn_ctx *ctx, grn_ts_expr_op_node *node,
-                       grn_ts_record *io, size_t n_io) {
-  GRN_TS_OP_ARITH_ADJUST(minus)
-}
-
-/* grn_ts_op_multiplication_adjust() updates scores. */
-static grn_rc
-grn_ts_op_multiplication_adjust(grn_ctx *ctx, grn_ts_expr_op_node *node,
-                                grn_ts_record *io, size_t n_io) {
-  GRN_TS_OP_ARITH_ADJUST(multiplication)
-}
-
-/* grn_ts_op_division_adjust() updates scores. */
-static grn_rc
-grn_ts_op_division_adjust(grn_ctx *ctx, grn_ts_expr_op_node *node,
-                          grn_ts_record *io, size_t n_io) {
-  GRN_TS_OP_ARITH_ADJUST(division)
-}
-
-/* grn_ts_op_modulus_adjust() updates scores. */
-static grn_rc
-grn_ts_op_modulus_adjust(grn_ctx *ctx, grn_ts_expr_op_node *node,
-                         grn_ts_record *io, size_t n_io) {
-  GRN_TS_OP_ARITH_ADJUST(modulus)
-}
-#undef GRN_TS_OP_ARITH_ADJUST
-
-/* grn_ts_expr_op_node_adjust() updates scores. */
-static grn_rc
-grn_ts_expr_op_node_adjust(grn_ctx *ctx, grn_ts_expr_op_node *node,
-                           grn_ts_record *io, size_t n_io) {
-  switch (node->op_type) {
-    case GRN_TS_OP_POSITIVE: {
-      return grn_ts_op_positive_adjust(ctx, node, io, n_io);
-    }
-    case GRN_TS_OP_NEGATIVE: {
-      return grn_ts_op_negative_adjust(ctx, node, io, n_io);
-    }
-    case GRN_TS_OP_PLUS: {
-      return grn_ts_op_plus_adjust(ctx, node, io, n_io);
-    }
-    case GRN_TS_OP_MINUS: {
-      return grn_ts_op_minus_adjust(ctx, node, io, n_io);
-    }
-    case GRN_TS_OP_MULTIPLICATION: {
-      return grn_ts_op_multiplication_adjust(ctx, node, io, n_io);
-    }
-    case GRN_TS_OP_DIVISION: {
-      return grn_ts_op_division_adjust(ctx, node, io, n_io);
-    }
-    case GRN_TS_OP_MODULUS: {
-      return grn_ts_op_modulus_adjust(ctx, node, io, n_io);
-    }
-    // TODO: Add operators.
-    default: {
-      GRN_TS_ERR_RETURN(GRN_OPERATION_NOT_SUPPORTED,
-                        "operator not supported: %d", node->op_type);
-    }
-  }
-}
-
-/*-------------------------------------------------------------
- * grn_ts_expr_bridge_node.
- */
-
-enum { GRN_TS_EXPR_BRIDGE_NODE_N_BUFS = 2 };
-
-typedef struct {
-  GRN_TS_EXPR_NODE_COMMON_MEMBERS
-  grn_ts_expr_node *src;
-  grn_ts_expr_node *dest;
-  grn_ts_buf bufs[GRN_TS_EXPR_BRIDGE_NODE_N_BUFS];
-} grn_ts_expr_bridge_node;
-
-/* grn_ts_expr_bridge_node_init() initializes a node. */
-static void
-grn_ts_expr_bridge_node_init(grn_ctx *ctx, grn_ts_expr_bridge_node *node) {
-  size_t i;
-  memset(node, 0, sizeof(*node));
-  node->type = GRN_TS_EXPR_BRIDGE_NODE;
-  node->src = NULL;
-  node->dest = NULL;
-  for (i = 0; i < GRN_TS_EXPR_BRIDGE_NODE_N_BUFS; i++) {
-    grn_ts_buf_init(ctx, &node->bufs[i]);
-  }
-}
-
-/* grn_ts_expr_bridge_node_fin() finalizes a node. */
-static void
-grn_ts_expr_bridge_node_fin(grn_ctx *ctx, grn_ts_expr_bridge_node *node) {
-  size_t i;
-  for (i = 0; i < GRN_TS_EXPR_BRIDGE_NODE_N_BUFS; i++) {
-    grn_ts_buf_fin(ctx, &node->bufs[i]);
-  }
-}
-
-/* grn_ts_expr_bridge_node_open() creates a node associated with a bridge. */
-static grn_rc
-grn_ts_expr_bridge_node_open(grn_ctx *ctx, grn_ts_expr_node *src,
-                             grn_ts_expr_node *dest, grn_ts_expr_node **node) {
-  grn_ts_expr_bridge_node *new_node = GRN_MALLOCN(grn_ts_expr_bridge_node, 1);
-  if (!new_node) {
-    GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE, "GRN_MALLOCN failed: %zu x 1",
-                      sizeof(grn_ts_expr_bridge_node));
-  }
-  grn_ts_expr_bridge_node_init(ctx, new_node);
-  new_node->data_kind = dest->data_kind;
-  new_node->data_type = dest->data_type;
-  new_node->src = src;
-  new_node->dest = dest;
-  *node = (grn_ts_expr_node *)new_node;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_expr_bridge_node_close() destroys a node. */
-static void
-grn_ts_expr_bridge_node_close(grn_ctx *ctx, grn_ts_expr_bridge_node *node) {
-  grn_ts_expr_bridge_node_fin(ctx, node);
-  GRN_FREE(node);
-}
-
-/* grn_ts_expr_bridge_node_evaluate() evaluates a bridge. */
-static grn_rc
-grn_ts_expr_bridge_node_evaluate(grn_ctx *ctx, grn_ts_expr_bridge_node *node,
-                                 const grn_ts_record *in, size_t n_in,
-                                 void *out) {
-  grn_ts_record *tmp;
-  grn_rc rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->src, in, n_in,
-                                               &node->bufs[0]);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  tmp = (grn_ts_record *)node->bufs[0].ptr;
-  return grn_ts_expr_node_evaluate(ctx, node->dest, tmp, n_in, out);
-}
-
-/* grn_ts_expr_bridge_node_filter() filters records. */
-static grn_rc
-grn_ts_expr_bridge_node_filter(grn_ctx *ctx, grn_ts_expr_bridge_node *node,
-                               grn_ts_record *in, size_t n_in,
-                               grn_ts_record *out, size_t *n_out) {
-  size_t i, count;
-  grn_ts_bool *values;
-  grn_ts_record *tmp;
-  grn_rc rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->src, in, n_in,
-                                               &node->bufs[0]);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  tmp = (grn_ts_record *)node->bufs[0].ptr;
-  rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->dest, in, n_in,
-                                        &node->bufs[1]);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  values = (grn_ts_bool *)&node->bufs[1].ptr;
-  for (i = 0, count = 0; i < n_in; i++) {
-    if (values[i]) {
-      out[count++] = in[i];
-    }
-  }
-  *n_out = count;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_expr_bridge_node_adjust() updates scores. */
-static grn_rc
-grn_ts_expr_bridge_node_adjust(grn_ctx *ctx, grn_ts_expr_bridge_node *node,
-                               grn_ts_record *io, size_t n_io) {
-  size_t i;
-  grn_ts_record *tmp;
-  grn_rc rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->src, io, n_io,
-                                               &node->bufs[0]);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  tmp = (grn_ts_record *)node->bufs[0].ptr;
-  rc = grn_ts_expr_node_adjust(ctx, node->dest, tmp, n_io);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  for (i = 0; i < n_io; i++) {
-    io[i].score = tmp[i].score;
-  }
-  return GRN_SUCCESS;
-}
-
-/*-------------------------------------------------------------
- * grn_ts_expr_node.
- */
-
-#define GRN_TS_EXPR_NODE_CLOSE_CASE(TYPE, type)\
-  case GRN_TS_EXPR_ ## TYPE ## _NODE: {\
-    grn_ts_expr_ ## type ## _node *type ## _node;\
-    type ## _node = (grn_ts_expr_ ## type ## _node *)node;\
-    grn_ts_expr_ ## type ## _node_close(ctx, type ## _node);\
-    return;\
-  }
-/* grn_ts_expr_node_close() destroys a node. */
-static void
-grn_ts_expr_node_close(grn_ctx *ctx, grn_ts_expr_node *node) {
-  switch (node->type) {
-    GRN_TS_EXPR_NODE_CLOSE_CASE(ID, id)
-    GRN_TS_EXPR_NODE_CLOSE_CASE(SCORE, score)
-    GRN_TS_EXPR_NODE_CLOSE_CASE(KEY, key)
-    GRN_TS_EXPR_NODE_CLOSE_CASE(VALUE, value)
-    GRN_TS_EXPR_NODE_CLOSE_CASE(CONST, const)
-    GRN_TS_EXPR_NODE_CLOSE_CASE(COLUMN, column)
-    GRN_TS_EXPR_NODE_CLOSE_CASE(OP, op)
-    GRN_TS_EXPR_NODE_CLOSE_CASE(BRIDGE, bridge)
-  }
-}
-#undef GRN_TS_EXPR_NODE_CLOSE_CASE
-
-#define GRN_TS_EXPR_NODE_EVALUATE_CASE(TYPE, type)\
-  case GRN_TS_EXPR_ ## TYPE ## _NODE: {\
-    grn_ts_expr_ ## type ## _node *type ## _node;\
-    type ## _node = (grn_ts_expr_ ## type ## _node *)node;\
-    return grn_ts_expr_ ## type ## _node_evaluate(ctx, type ## _node,\
-                                                  in, n_in, out);\
-  }
-/* grn_ts_expr_node_evaluate() evaluates a subtree. */
-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(ID, id)
-    GRN_TS_EXPR_NODE_EVALUATE_CASE(SCORE, score)
-    GRN_TS_EXPR_NODE_EVALUATE_CASE(KEY, key)
-    GRN_TS_EXPR_NODE_EVALUATE_CASE(VALUE, value)
-    GRN_TS_EXPR_NODE_EVALUATE_CASE(CONST, const)
-    GRN_TS_EXPR_NODE_EVALUATE_CASE(COLUMN, column)
-    GRN_TS_EXPR_NODE_EVALUATE_CASE(OP, op)
-    GRN_TS_EXPR_NODE_EVALUATE_CASE(BRIDGE, bridge)
-    default: {
-      GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT,
-                        "invalid node type: %d", node->type);
-    }
-  }
-}
-#undef GRN_TS_EXPR_NODE_EVALUATE_CASE
-
-#define GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_CASE(KIND, kind)\
-  case GRN_TS_ ## KIND: {\
-    grn_rc rc = grn_ts_buf_reserve(ctx, out, sizeof(grn_ts_ ## kind) * n_in);\
-    if (rc != GRN_SUCCESS) {\
-      return rc;\
-    }\
-    return grn_ts_expr_node_evaluate(ctx, node, in, n_in, out->ptr);\
-  }
-#define GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_VECTOR_CASE(KIND, kind)\
-  GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_CASE(KIND ## _VECTOR, kind ## _vector)
-/* grn_ts_expr_node_evaluate_to_buf() evaluates a subtree. */
-static grn_rc
-grn_ts_expr_node_evaluate_to_buf(grn_ctx *ctx, grn_ts_expr_node *node,
-                                 const grn_ts_record *in, size_t n_in,
-                                 grn_ts_buf *out) {
-  switch (node->data_kind) {
-    GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_CASE(BOOL, bool)
-    GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_CASE(INT, int)
-    GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_CASE(FLOAT, float)
-    GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_CASE(TIME, time)
-    GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_CASE(TEXT, text)
-    GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_CASE(GEO_POINT, geo_point)
-    GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_CASE(REF, ref)
-    GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_VECTOR_CASE(BOOL, bool)
-    GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_VECTOR_CASE(INT, int)
-    GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_VECTOR_CASE(FLOAT, float)
-    GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_VECTOR_CASE(TIME, time)
-    GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_VECTOR_CASE(TEXT, text)
-    GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_VECTOR_CASE(GEO_POINT, geo_point)
-    GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_VECTOR_CASE(REF, ref)
-    default: {
-      GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT,
-                        "invalid data kind: %d", node->data_kind);
-    }
-  }
-}
-#undef GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_VECTOR_CASE
-#undef GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_CASE
-
-#define GRN_TS_EXPR_NODE_FILTER_CASE(TYPE, type)\
-  case GRN_TS_EXPR_ ## TYPE ## _NODE: {\
-    grn_ts_expr_ ## type ## _node *type ## _node;\
-    type ## _node = (grn_ts_expr_ ## type ## _node *)node;\
-    return grn_ts_expr_ ## type ## _node_filter(ctx, type ## _node,\
-                                                in, n_in, out, n_out);\
-  }
-/* grn_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) {
-    GRN_TS_ERR_RETURN(GRN_OPERATION_NOT_SUPPORTED,
-                      "invalid data kind: %d", node->data_kind);
-  }
-  switch (node->type) {
-    GRN_TS_EXPR_NODE_FILTER_CASE(KEY, key)
-    GRN_TS_EXPR_NODE_FILTER_CASE(VALUE, value)
-    GRN_TS_EXPR_NODE_FILTER_CASE(CONST, const)
-    GRN_TS_EXPR_NODE_FILTER_CASE(COLUMN, column)
-    GRN_TS_EXPR_NODE_FILTER_CASE(OP, op)
-    GRN_TS_EXPR_NODE_FILTER_CASE(BRIDGE, bridge)
-    default: {
-      GRN_TS_ERR_RETURN(GRN_OPERATION_NOT_SUPPORTED,
-                        "invalid node type: %d", node->type);
-    }
-  }
-}
-#undef GRN_TS_EXPR_NODE_FILTER_CASE
-
-#define GRN_TS_EXPR_NODE_ADJUST_CASE(TYPE, type)\
-  case GRN_TS_EXPR_ ## TYPE ## _NODE: {\
-    grn_ts_expr_ ## type ## _node *type ## _node;\
-    type ## _node = (grn_ts_expr_ ## type ## _node *)node;\
-    return grn_ts_expr_ ## type ## _node_adjust(ctx, type ## _node, io, n_io);\
-  }
-/* grn_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) {
-    GRN_TS_ERR_RETURN(GRN_OPERATION_NOT_SUPPORTED,
-                      "invalid data kind: %d", node->data_kind);
-  }
-  switch (node->type) {
-    GRN_TS_EXPR_NODE_ADJUST_CASE(SCORE, score)
-    GRN_TS_EXPR_NODE_ADJUST_CASE(KEY, key)
-    GRN_TS_EXPR_NODE_ADJUST_CASE(VALUE, value)
-    GRN_TS_EXPR_NODE_ADJUST_CASE(CONST, const)
-    GRN_TS_EXPR_NODE_ADJUST_CASE(COLUMN, column)
-    GRN_TS_EXPR_NODE_ADJUST_CASE(OP, op)
-    GRN_TS_EXPR_NODE_ADJUST_CASE(BRIDGE, bridge)
-    default: {
-      GRN_TS_ERR_RETURN(GRN_OPERATION_NOT_SUPPORTED,
-                        "invalid node type: %d", node->type);
-    }
-  }
-}
-#undef GRN_TS_EXPR_NODE_ADJUST_CASE
-
-/*-------------------------------------------------------------
- * grn_ts_expr_parser.
- */
-
-/*
- * FIXME: A grn_ts_expr_parser object is designed to parse one expression
- *        string. grn_ts_expr_parser_parse() should not be called more than
- *        once.
- */
-
-typedef enum {
-  GRN_TS_EXPR_DUMMY_TOKEN,  /* No extra data. */
-  GRN_TS_EXPR_START_TOKEN,  /* No extra data. */
-  GRN_TS_EXPR_END_TOKEN,    /* No extra data. */
-  GRN_TS_EXPR_CONST_TOKEN,  /* +data_kind, content and buf. */
-  GRN_TS_EXPR_NAME_TOKEN,   /* +name. */
-  GRN_TS_EXPR_OP_TOKEN,     /* +op_type. */
-  GRN_TS_EXPR_BRIDGE_TOKEN, /* No extra data. */
-  GRN_TS_EXPR_BRACKET_TOKEN /* No extra data. */
-} grn_ts_expr_token_type;
-
-#define GRN_TS_EXPR_TOKEN_COMMON_MEMBERS\
-  grn_ts_str src;              /* Source string. */\
-  grn_ts_expr_token_type type; /* Token type. */
-
-typedef struct {
-  GRN_TS_EXPR_TOKEN_COMMON_MEMBERS
-} grn_ts_expr_token;
-
-typedef grn_ts_expr_token grn_ts_expr_dummy_token;
-typedef grn_ts_expr_token grn_ts_expr_start_token;
-typedef grn_ts_expr_token grn_ts_expr_end_token;
-
-typedef struct {
-  GRN_TS_EXPR_TOKEN_COMMON_MEMBERS
-  grn_ts_data_kind data_kind; /* The data kind of the const. */
-  grn_ts_any content;         /* The const. */
-  grn_ts_buf buf;             /* Buffer for content.as_text. */
-} grn_ts_expr_const_token;
-
-typedef grn_ts_expr_token grn_ts_expr_name_token;
-
-typedef struct {
-  GRN_TS_EXPR_TOKEN_COMMON_MEMBERS
-  grn_ts_op_type op_type;     /* Operator type. */
-} grn_ts_expr_op_token;
-
-typedef grn_ts_expr_token grn_ts_expr_bridge_token;
-typedef grn_ts_expr_token grn_ts_expr_bracket_token;
-
-typedef struct {
-  grn_ts_expr *expr;                     /* Associated expression. */
-  grn_ts_buf str_buf;                    /* Buffer for a source string. */
-  grn_ts_expr_token **tokens;            /* Tokens. */
-  size_t n_tokens;                       /* Number of tokens. */
-  size_t max_n_tokens;                   /* Max. number of tokens. */
-  grn_ts_expr_dummy_token *dummy_tokens; /* Dummy tokens. */
-  size_t n_dummy_tokens;                 /* Number of dummy tokens. */
-  grn_ts_expr_token **stack;             /* Token stack. */
-  size_t stack_depth;                    /* Token stack's current depth. */
-} grn_ts_expr_parser;
-
-#define GRN_TS_EXPR_TOKEN_INIT(TYPE)\
-  memset(token, 0, sizeof(*token));\
-  token->type = GRN_TS_EXPR_ ## TYPE ## _TOKEN;\
-  token->src = src;
-/* grn_ts_expr_dummy_token_init() initializes a token. */
-static void
-grn_ts_expr_dummy_token_init(grn_ctx *ctx, grn_ts_expr_dummy_token *token,
-                             grn_ts_str src) {
-  GRN_TS_EXPR_TOKEN_INIT(DUMMY)
-}
-
-/* grn_ts_expr_start_token_init() initializes a token. */
-static void
-grn_ts_expr_start_token_init(grn_ctx *ctx, grn_ts_expr_start_token *token,
-                             grn_ts_str src) {
-  GRN_TS_EXPR_TOKEN_INIT(START)
-}
-
-/* grn_ts_expr_end_token_init() initializes a token. */
-static void
-grn_ts_expr_end_token_init(grn_ctx *ctx, grn_ts_expr_end_token *token,
-                           grn_ts_str src) {
-  GRN_TS_EXPR_TOKEN_INIT(END)
-}
-
-/* grn_ts_expr_const_token_init() initializes a token. */
-static void
-grn_ts_expr_const_token_init(grn_ctx *ctx, grn_ts_expr_const_token *token,
-                             grn_ts_str src) {
-  GRN_TS_EXPR_TOKEN_INIT(CONST);
-  grn_ts_buf_init(ctx, &token->buf);
-}
-
-/* grn_ts_expr_name_token_init() initializes a token. */
-static void
-grn_ts_expr_name_token_init(grn_ctx *ctx, grn_ts_expr_name_token *token,
-                            grn_ts_str src) {
-  GRN_TS_EXPR_TOKEN_INIT(NAME);
-}
-
-/* grn_ts_expr_op_token_init() initializes a token. */
-static void
-grn_ts_expr_op_token_init(grn_ctx *ctx, grn_ts_expr_op_token *token,
-                          grn_ts_str src) {
-  GRN_TS_EXPR_TOKEN_INIT(OP);
-}
-
-/* grn_ts_expr_bridge_token_init() initializes a token. */
-static void
-grn_ts_expr_bridge_token_init(grn_ctx *ctx, grn_ts_expr_bridge_token *token,
-                              grn_ts_str src) {
-  GRN_TS_EXPR_TOKEN_INIT(BRIDGE)
-}
-
-/* grn_ts_expr_bracket_token_init() initializes a token. */
-static void
-grn_ts_expr_bracket_token_init(grn_ctx *ctx, grn_ts_expr_bracket_token *token,
-                               grn_ts_str src) {
-  GRN_TS_EXPR_TOKEN_INIT(BRACKET)
-}
-#undef GRN_TS_EXPR_TOKEN_INIT
-
-/* grn_ts_expr_dummy_token_fin() finalizes a token. */
-static void
-grn_ts_expr_dummy_token_fin(grn_ctx *ctx, grn_ts_expr_dummy_token *token) {
-  /* Nothing to do. */
-}
-
-/* grn_ts_expr_start_token_fin() finalizes a token. */
-static void
-grn_ts_expr_start_token_fin(grn_ctx *ctx, grn_ts_expr_start_token *token) {
-  /* Nothing to do. */
-}
-
-/* grn_ts_expr_end_token_fin() finalizes a token. */
-static void
-grn_ts_expr_end_token_fin(grn_ctx *ctx, grn_ts_expr_end_token *token) {
-  /* Nothing to do. */
-}
-
-/* grn_ts_expr_const_token_fin() finalizes a token. */
-static void
-grn_ts_expr_const_token_fin(grn_ctx *ctx, grn_ts_expr_const_token *token) {
-  grn_ts_buf_fin(ctx, &token->buf);
-}
-
-/* grn_ts_expr_name_token_fin() finalizes a token. */
-static void
-grn_ts_expr_name_token_fin(grn_ctx *ctx, grn_ts_expr_name_token *token) {
-  /* Nothing to do. */
-}
-
-/* grn_ts_expr_op_token_fin() finalizes a token. */
-static void
-grn_ts_expr_op_token_fin(grn_ctx *ctx, grn_ts_expr_op_token *token) {
-  /* Nothing to do. */
-}
-
-/* grn_ts_expr_bridge_token_fin() finalizes a token. */
-static void
-grn_ts_expr_bridge_token_fin(grn_ctx *ctx, grn_ts_expr_bridge_token *token) {
-  /* Nothing to do. */
-}
-
-/* grn_ts_expr_bracket_token_fin() finalizes a token. */
-static void
-grn_ts_expr_bracket_token_fin(grn_ctx *ctx, grn_ts_expr_bracket_token *token) {
-  /* Nothing to do. */
-}
-
-#define GRN_TS_EXPR_TOKEN_OPEN(TYPE, type)\
-  grn_ts_expr_ ## type ## _token *new_token;\
-  new_token = GRN_MALLOCN(grn_ts_expr_ ## type ## _token, 1);\
-  if (!new_token) {\
-    GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE, "GRN_MALLOCN failed: %zu x 1",\
-                      sizeof(grn_ts_expr_ ## type ## _token));\
-  }\
-  grn_ts_expr_ ## type ## _token_init(ctx, new_token, src);\
-  *token = new_token;
-/* grn_ts_expr_dummy_token_open() creates a token. */
-/*
-static grn_rc
-grn_ts_expr_dummy_token_open(grn_ctx *ctx, grn_ts_str src,
-                             grn_ts_expr_dummy_token **token) {
-  GRN_TS_EXPR_TOKEN_OPEN(DUMMY, dummy)
-  return GRN_SUCCESS;
-}
-*/
-
-/* grn_ts_expr_start_token_open() creates a token. */
-static grn_rc
-grn_ts_expr_start_token_open(grn_ctx *ctx, grn_ts_str src,
-                             grn_ts_expr_start_token **token) {
-  GRN_TS_EXPR_TOKEN_OPEN(START, start)
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_expr_end_token_open() creates a token. */
-static grn_rc
-grn_ts_expr_end_token_open(grn_ctx *ctx, grn_ts_str src,
-                           grn_ts_expr_end_token **token) {
-  GRN_TS_EXPR_TOKEN_OPEN(END, end)
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_expr_const_token_open() creates a token. */
-static grn_rc
-grn_ts_expr_const_token_open(grn_ctx *ctx, grn_ts_str src,
-                             grn_ts_expr_const_token **token) {
-  GRN_TS_EXPR_TOKEN_OPEN(CONST, const)
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_expr_name_token_open() creates a token. */
-static grn_rc
-grn_ts_expr_name_token_open(grn_ctx *ctx, grn_ts_str src,
-                            grn_ts_expr_name_token **token) {
-  GRN_TS_EXPR_TOKEN_OPEN(NAME, name)
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_expr_op_token_open() creates a token. */
-static grn_rc
-grn_ts_expr_op_token_open(grn_ctx *ctx, grn_ts_str src, grn_ts_op_type op_type,
-                          grn_ts_expr_op_token **token) {
-  GRN_TS_EXPR_TOKEN_OPEN(OP, op)
-  new_token->op_type = op_type;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_expr_bridge_token_open() creates a token. */
-static grn_rc
-grn_ts_expr_bridge_token_open(grn_ctx *ctx, grn_ts_str src,
-                              grn_ts_expr_bridge_token **token) {
-  GRN_TS_EXPR_TOKEN_OPEN(BRIDGE, bridge)
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_expr_bracket_token_open() creates a token. */
-static grn_rc
-grn_ts_expr_bracket_token_open(grn_ctx *ctx, grn_ts_str src,
-                               grn_ts_expr_bracket_token **token) {
-  GRN_TS_EXPR_TOKEN_OPEN(BRACKET, bracket)
-  return GRN_SUCCESS;
-}
-#undef GRN_TS_EXPR_TOKEN_OPEN
-
-#define GRN_TS_EXPR_TOKEN_CLOSE_CASE(TYPE, type)\
-  case GRN_TS_EXPR_ ## TYPE ## _TOKEN: {\
-    grn_ts_expr_ ## type ## _token *type ## _token;\
-    type ## _token = (grn_ts_expr_ ## type ## _token *)token;\
-    grn_ts_expr_ ## type ## _token_fin(ctx, type ## _token);\
-    break;\
-  }
-/* grn_ts_expr_token_close() destroys a token. */
-static void
-grn_ts_expr_token_close(grn_ctx *ctx, grn_ts_expr_token *token) {
-  switch (token->type) {
-    GRN_TS_EXPR_TOKEN_CLOSE_CASE(DUMMY, dummy)
-    GRN_TS_EXPR_TOKEN_CLOSE_CASE(START, start)
-    GRN_TS_EXPR_TOKEN_CLOSE_CASE(END, end)
-    GRN_TS_EXPR_TOKEN_CLOSE_CASE(CONST, const)
-    GRN_TS_EXPR_TOKEN_CLOSE_CASE(NAME, name)
-    GRN_TS_EXPR_TOKEN_CLOSE_CASE(OP, op)
-    GRN_TS_EXPR_TOKEN_CLOSE_CASE(BRACKET, bracket)
-    GRN_TS_EXPR_TOKEN_CLOSE_CASE(BRIDGE, bridge)
-  }
-  GRN_FREE(token);
-}
-#undef GRN_TS_EXPR_TOKEN_CLOSE_CASE
-
-/* grn_ts_expr_parser_init() initializes a parser. */
-static void
-grn_ts_expr_parser_init(grn_ctx *ctx, grn_ts_expr *expr,
-                        grn_ts_expr_parser *parser) {
-  memset(parser, 0, sizeof(*parser));
-  parser->expr = expr;
-  grn_ts_buf_init(ctx, &parser->str_buf);
-  parser->tokens = NULL;
-  parser->dummy_tokens = NULL;
-  parser->stack = NULL;
-}
-
-/* grn_ts_expr_parser_fin() finalizes a parser. */
-static void
-grn_ts_expr_parser_fin(grn_ctx *ctx, grn_ts_expr_parser *parser) {
-  if (parser->stack) {
-    GRN_FREE(parser->stack);
-  }
-  if (parser->dummy_tokens) {
-    size_t i;
-    for (i = 0; i < parser->n_dummy_tokens; i++) {
-      grn_ts_expr_dummy_token_fin(ctx, &parser->dummy_tokens[i]);
-    }
-    GRN_FREE(parser->dummy_tokens);
-  }
-  if (parser->tokens) {
-    size_t i;
-    for (i = 0; i < parser->n_tokens; i++) {
-      grn_ts_expr_token_close(ctx, parser->tokens[i]);
-    }
-    GRN_FREE(parser->tokens);
-  }
-  grn_ts_buf_fin(ctx, &parser->str_buf);
-}
-
-/* grn_ts_expr_parser_open() creates a parser. */
-static grn_rc
-grn_ts_expr_parser_open(grn_ctx *ctx, grn_ts_expr *expr,
-                        grn_ts_expr_parser **parser) {
-  grn_ts_expr_parser *new_parser = GRN_MALLOCN(grn_ts_expr_parser, 1);
-  if (!new_parser) {
-    GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE, "GRN_MALLOCN failed: %zu x 1",
-                      sizeof(grn_ts_expr_parser));
-  }
-  grn_ts_expr_parser_init(ctx, expr, new_parser);
-  *parser = new_parser;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_expr_parser_close() destroys a parser. */
-static void
-grn_ts_expr_parser_close(grn_ctx *ctx, grn_ts_expr_parser *parser) {
-  grn_ts_expr_parser_fin(ctx, parser);
-  GRN_FREE(parser);
-}
-
-/* grn_ts_expr_parser_tokenize_start() creates the start token. */
-static grn_rc
-grn_ts_expr_parser_tokenize_start(grn_ctx *ctx, grn_ts_expr_parser *parser,
-                                  grn_ts_str str, grn_ts_expr_token **token) {
-  grn_ts_str token_str = { str.ptr, 0 };
-  grn_ts_expr_start_token *new_token;
-  grn_rc rc = grn_ts_expr_start_token_open(ctx, token_str, &new_token);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  *token = (grn_ts_expr_token *)new_token;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_expr_parser_tokenize_end() creates the end token. */
-static grn_rc
-grn_ts_expr_parser_tokenize_end(grn_ctx *ctx, grn_ts_expr_parser *parser,
-                                grn_ts_str str, grn_ts_expr_token **token) {
-  grn_ts_str token_str = { str.ptr, 0 };
-  grn_ts_expr_end_token *new_token;
-  grn_rc rc = grn_ts_expr_end_token_open(ctx, token_str, &new_token);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  *token = (grn_ts_expr_token *)new_token;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_expr_parser_tokenize_number() tokenizes an Int or Float literal. */
-static grn_rc
-grn_ts_expr_parser_tokenize_number(grn_ctx *ctx, grn_ts_expr_parser *parser,
-                                   grn_ts_str str, grn_ts_expr_token **token) {
-  char *end;
-  grn_rc rc;
-  grn_ts_int int_value;
-  grn_ts_str token_str;
-  grn_ts_expr_const_token *new_token;
-
-  int_value = strtol(str.ptr, &end, 0);
-  if ((end != str.ptr) && (*end != '.')) {
-    if (grn_ts_byte_is_name_char(*end)) {
-      GRN_TS_ERR_RETURN(GRN_INVALID_FORMAT,
-                        "unterminated Int literal: \"%.*s\"",
-                        (int)str.size, str.ptr);
-    }
-    token_str.ptr = str.ptr;
-    token_str.size = end - str.ptr;
-    rc = grn_ts_expr_const_token_open(ctx, token_str, &new_token);
-    if (rc != GRN_SUCCESS) {
-      return rc;
-    }
-    new_token->data_kind = GRN_TS_INT;
-    new_token->content.as_int = int_value;
-  } else {
-    grn_ts_float float_value = strtod(str.ptr, &end);
-    if (end == str.ptr) {
-      GRN_TS_ERR_RETURN(GRN_INVALID_FORMAT, "invalid number literal: \"%.*s\"",
-                        (int)str.size, str.ptr);
-    }
-    if (grn_ts_byte_is_name_char(*end)) {
-      GRN_TS_ERR_RETURN(GRN_INVALID_FORMAT,
-                        "unterminated Float literal: \"%.*s\"",
-                        (int)str.size, str.ptr);
-    }
-    token_str.ptr = str.ptr;
-    token_str.size = end - str.ptr;
-    rc = grn_ts_expr_const_token_open(ctx, token_str, &new_token);
-    if (rc != GRN_SUCCESS) {
-      return rc;
-    }
-    new_token->data_kind = GRN_TS_FLOAT;
-    new_token->content.as_float = float_value;
-  }
-  *token = (grn_ts_expr_token *)new_token;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_expr_parser_tokenize_text() tokenizes a Text literal. */
-static grn_rc
-grn_ts_expr_parser_tokenize_text(grn_ctx *ctx, grn_ts_expr_parser *parser,
-                                 grn_ts_str str, grn_ts_expr_token **token) {
-  size_t i, n_escapes = 0;
-  grn_rc rc;
-  grn_ts_str token_str;
-  grn_ts_expr_const_token *new_token;
-  for (i = 1; i < str.size; i++) {
-    if (str.ptr[i] == '\\') {
-      i++;
-      n_escapes++;
-    } else if (str.ptr[i] == '"') {
-      break;
-    }
-  }
-  if (i >= str.size) {
-    GRN_TS_ERR_RETURN(GRN_INVALID_FORMAT, "no closing double quote: \"%.*s\"",
-                      (int)str.size, str.ptr);
-  }
-  token_str.ptr = str.ptr;
-  token_str.size = i + 1;
-  rc = grn_ts_expr_const_token_open(ctx, token_str, &new_token);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  new_token->data_kind = GRN_TS_TEXT;
-  if (n_escapes) {
-    char *buf_ptr;
-    const char *str_ptr = str.ptr + 1;
-    size_t size = token_str.size - 2 - n_escapes;
-    rc = grn_ts_buf_resize(ctx, &new_token->buf, size);
-    if (rc != GRN_SUCCESS) {
-      grn_ts_expr_token_close(ctx, (grn_ts_expr_token *)new_token);
-      return rc;
-    }
-    buf_ptr = (char *)new_token->buf.ptr;
-    for (i = 0; i < size; i++) {
-      if (str_ptr[i] == '\\') {
-        str_ptr++;
-      }
-      buf_ptr[i] = str_ptr[i];
-    }
-    new_token->content.as_text.ptr = buf_ptr;
-    new_token->content.as_text.size = size;
-  } else {
-    new_token->content.as_text.ptr = token_str.ptr + 1;
-    new_token->content.as_text.size = token_str.size - 2;
-  }
-  *token = (grn_ts_expr_token *)new_token;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_expr_parser_tokenize_name() tokenizes a Bool literal or a name. */
-static grn_rc
-grn_ts_expr_parser_tokenize_name(grn_ctx *ctx, grn_ts_expr_parser *parser,
-                                 grn_ts_str str, grn_ts_expr_token **token) {
-  size_t i;
-  grn_ts_str token_str;
-  for (i = 1; i < str.size; i++) {
-    if (!grn_ts_byte_is_name_char(str.ptr[i])) {
-      break;
-    }
-  }
-  token_str.ptr = str.ptr;
-  token_str.size = i;
-
-  if (grn_ts_str_is_bool(token_str)) {
-    grn_ts_expr_const_token *new_token;
-    grn_rc rc = grn_ts_expr_const_token_open(ctx, token_str, &new_token);
-    if (rc != GRN_SUCCESS) {
-      return rc;
-    }
-    new_token->data_kind = GRN_TS_BOOL;
-    if (token_str.ptr[0] == 't') {
-      new_token->content.as_bool = GRN_TRUE;
-    } else {
-      new_token->content.as_bool = GRN_FALSE;
-    }
-    *token = (grn_ts_expr_token *)new_token;
-    return GRN_SUCCESS;
-  }
-  return grn_ts_expr_name_token_open(ctx, token_str, token);
-}
-
-/* grn_ts_expr_parser_tokenize_bridge() tokenizes a bridge. */
-static grn_rc
-grn_ts_expr_parser_tokenize_bridge(grn_ctx *ctx, grn_ts_expr_parser *parser,
-                                   grn_ts_str str, grn_ts_expr_token **token) {
-  grn_ts_str token_str = { str.ptr, 1 };
-  grn_ts_expr_bridge_token *new_token;
-  grn_rc rc = grn_ts_expr_bridge_token_open(ctx, token_str, &new_token);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  *token = (grn_ts_expr_token *)new_token;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_expr_parser_tokenize_bracket() tokenizes a bracket. */
-static grn_rc
-grn_ts_expr_parser_tokenize_bracket(grn_ctx *ctx, grn_ts_expr_parser *parser,
-                                    grn_ts_str str,
-                                    grn_ts_expr_token **token) {
-  grn_ts_str token_str = { str.ptr, 1 };
-  grn_ts_expr_bracket_token *new_token;
-  grn_rc rc = grn_ts_expr_bracket_token_open(ctx, token_str, &new_token);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  *token = (grn_ts_expr_token *)new_token;
-  return GRN_SUCCESS;
-}
-
-/*
- * grn_ts_expr_parsre_tokenize_sign() tokenizes an operator '+' or '-'.
- * Note that '+' and '-' have two roles each.
- * '+' is GRN_TS_OP_POSITIVE or GRN_TS_OP_PLUS.
- * '-' is GRN_TS_OP_NEGATIVE or GRN_TS_OP_MINUS.
- */
-static grn_rc
-grn_ts_expr_parser_tokenize_sign(grn_ctx *ctx, grn_ts_expr_parser *parser,
-                                 grn_ts_str str, grn_ts_expr_token **token) {
-  size_t n_args;
-  grn_rc rc;
-  grn_ts_op_type op_type;
-  grn_ts_str token_str = { str.ptr, 1 };
-  grn_ts_expr_token *prev_token = parser->tokens[parser->n_tokens - 1];
-  grn_ts_expr_op_token *new_token;
-  switch (prev_token->type) {
-    case GRN_TS_EXPR_START_TOKEN:
-    case GRN_TS_EXPR_OP_TOKEN: {
-      n_args = 1;
-      break;
-    }
-    case GRN_TS_EXPR_CONST_TOKEN:
-    case GRN_TS_EXPR_NAME_TOKEN: {
-      n_args = 2;
-      break;
-    }
-    case GRN_TS_EXPR_BRACKET_TOKEN: {
-      grn_ts_str bracket;
-      const grn_ts_expr_bracket_token *bracket_token;
-      bracket_token = (const grn_ts_expr_bracket_token *)prev_token;
-      bracket = bracket_token->src;
-      switch (bracket.ptr[0]) {
-        case '(': case '[': {
-          n_args = 1;
-          break;
-        }
-        case ')': case ']': {
-          n_args = 2;
-          break;
-        }
-        default: {
-          GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "undefined bracket: \"%.*s\"",
-                            (int)bracket.size, bracket.ptr);
-        }
-      }
-      break;
-    }
-    default: {
-      GRN_TS_ERR_RETURN(GRN_INVALID_FORMAT, "invalid token sequence: %d",
-                        prev_token->type);
-    }
-  }
-  if (token_str.ptr[0] == '+') {
-    op_type = (n_args == 1) ? GRN_TS_OP_POSITIVE : GRN_TS_OP_PLUS;
-  } else {
-    op_type = (n_args == 1) ? GRN_TS_OP_NEGATIVE : GRN_TS_OP_MINUS;
-  }
-  rc = grn_ts_expr_op_token_open(ctx, token_str, op_type, &new_token);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  *token = (grn_ts_expr_token *)new_token;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_expr_parser_tokenize_op() tokenizes an operator. */
-static grn_rc
-grn_ts_expr_parser_tokenize_op(grn_ctx *ctx, grn_ts_expr_parser *parser,
-                               grn_ts_str str, grn_ts_expr_token **token) {
-  grn_rc rc = GRN_SUCCESS;
-  grn_ts_str token_str = str;
-  grn_ts_op_type op_type;
-  grn_ts_expr_op_token *new_token;
-  switch (str.ptr[0]) {
-    case '+': case '-': {
-      return grn_ts_expr_parser_tokenize_sign(ctx, parser, str, token);
-    }
-    case '!': {
-      if ((str.size >= 2) && (str.ptr[1] == '=')) {
-        token_str.size = 2;
-        op_type = GRN_TS_OP_NOT_EQUAL;
-      } else {
-        token_str.size = 1;
-        op_type = GRN_TS_OP_LOGICAL_NOT;
-      }
-      rc = grn_ts_expr_op_token_open(ctx, token_str, op_type, &new_token);
-      break;
-    }
-#define GRN_TS_EXPR_PARSER_TOKENIZE_OP_CASE(label, TYPE_1, TYPE_2, TYPE_3,\
-                                            TYPE_EQUAL)\
-  case label: {\
-    if ((str.size >= 2) && (str.ptr[1] == '=')) {\
-      token_str.size = 2;\
-      op_type = GRN_TS_OP_ ## TYPE_EQUAL;\
-    } else if ((str.size >= 2) && (str.ptr[1] == label)) {\
-      if ((str.size >= 3) && (str.ptr[2] == label)) {\
-        token_str.size = 3;\
-        op_type = GRN_TS_OP_ ## TYPE_3;\
-      } else {\
-        token_str.size = 2;\
-        op_type = GRN_TS_OP_ ## TYPE_2;\
-      }\
-    } else {\
-      token_str.size = 1;\
-      op_type = GRN_TS_OP_ ## TYPE_1;\
-    }\
-    rc = grn_ts_expr_op_token_open(ctx, token_str, op_type, &new_token);\
-    break;\
-  }
-    GRN_TS_EXPR_PARSER_TOKENIZE_OP_CASE('<', LESS, SHIFT_ARITHMETIC_LEFT,
-                                        SHIFT_LOGICAL_LEFT, LESS_EQUAL)
-    GRN_TS_EXPR_PARSER_TOKENIZE_OP_CASE('>', GREATER, SHIFT_ARITHMETIC_RIGHT,
-                                        SHIFT_LOGICAL_RIGHT, GREATER_EQUAL)
-#undef GRN_TS_EXPR_PARSER_TOKENIZE_OP_CASE
-    case '&': {
-      if ((str.size >= 2) && (str.ptr[1] == '&')) {
-        token_str.size = 2;
-        op_type = GRN_TS_OP_LOGICAL_AND;
-      } else if ((str.size >= 2) && (str.ptr[1] == '&')) {
-        token_str.size = 2;
-        op_type = GRN_TS_OP_LOGICAL_SUB;
-      } else {
-        token_str.size = 1;
-        op_type = GRN_TS_OP_BITWISE_AND;
-      }
-      rc = grn_ts_expr_op_token_open(ctx, token_str, op_type, &new_token);
-      break;
-    }
-    case '|': {
-      if ((str.size >= 2) && (str.ptr[1] == '|')) {
-        token_str.size = 2;
-        op_type = GRN_TS_OP_LOGICAL_OR;
-      } else {
-        token_str.size = 1;
-        op_type = GRN_TS_OP_BITWISE_OR;
-      }
-      rc = grn_ts_expr_op_token_open(ctx, token_str, op_type, &new_token);
-      break;
-    }
-    case '=': {
-      if ((str.size < 2) || (str.ptr[1] != '=')) {
-        GRN_TS_ERR_RETURN(GRN_INVALID_FORMAT,
-                          "single equal not available: =\"%.*s\"",
-                          (int)str.size, str.ptr);
-      }
-      token_str.size = 2;
-      rc = grn_ts_expr_op_token_open(ctx, token_str, GRN_TS_OP_EQUAL,
-                                     &new_token);
-      break;
-    }
-#define GRN_TS_EXPR_PARSER_TOKENIZE_OP_CASE(label, TYPE)\
-  case label: {\
-    token_str.size = 1;\
-    rc = grn_ts_expr_op_token_open(ctx, token_str, GRN_TS_OP_ ## TYPE,\
-                                   &new_token);\
-    break;\
-  }
-    GRN_TS_EXPR_PARSER_TOKENIZE_OP_CASE('~', BITWISE_NOT)
-    GRN_TS_EXPR_PARSER_TOKENIZE_OP_CASE('^', BITWISE_XOR)
-    GRN_TS_EXPR_PARSER_TOKENIZE_OP_CASE('*', MULTIPLICATION)
-    GRN_TS_EXPR_PARSER_TOKENIZE_OP_CASE('/', DIVISION)
-    GRN_TS_EXPR_PARSER_TOKENIZE_OP_CASE('%', MODULUS)
-#undef GRN_TS_EXPR_PARSER_TOKENIZE_OP_CASE
-    default: {
-      GRN_TS_ERR_RETURN(GRN_INVALID_FORMAT, "invalid character: \"%.*s\"",
-                        (int)str.size, str.ptr);
-    }
-  }
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  *token = (grn_ts_expr_token *)new_token;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_expr_parser_tokenize_next() extracts the next token. */
-static grn_rc
-grn_ts_expr_parser_tokenize_next(grn_ctx *ctx, grn_ts_expr_parser *parser,
-                                 grn_ts_str str, grn_ts_expr_token **token) {
-  grn_ts_str rest;
-  if (!parser->n_tokens) {
-    return grn_ts_expr_parser_tokenize_start(ctx, parser, str, token);
-  }
-  rest = grn_ts_str_trim_left(str);
-  if (!rest.size) {
-    return grn_ts_expr_parser_tokenize_end(ctx, parser, rest, token);
-  }
-  if (grn_ts_str_has_number_prefix(rest)) {
-    return grn_ts_expr_parser_tokenize_number(ctx, parser, rest, token);
-  }
-  if (rest.ptr[0] == '"') {
-    return grn_ts_expr_parser_tokenize_text(ctx, parser, rest, token);
-  }
-  if (grn_ts_byte_is_name_char(rest.ptr[0])) {
-    return grn_ts_expr_parser_tokenize_name(ctx, parser, rest, token);
-  }
-  switch (rest.ptr[0]) {
-    case '(': case ')': case '[': case ']': {
-      return grn_ts_expr_parser_tokenize_bracket(ctx, parser, rest, token);
-    }
-    case '.': {
-      return grn_ts_expr_parser_tokenize_bridge(ctx, parser, rest, token);
-    }
-    default: {
-      return grn_ts_expr_parser_tokenize_op(ctx, parser, rest, token);
-    }
-  }
-}
-
-/*
- * grn_ts_expr_parser_reserve_tokens() extends a token buffer for a new token.
- */
-static grn_rc
-grn_ts_expr_parser_reserve_tokens(grn_ctx *ctx, grn_ts_expr_parser *parser) {
-  size_t i, n_bytes, new_max_n_tokens;
-  grn_ts_expr_token **new_tokens;
-  if (parser->n_tokens < parser->max_n_tokens) {
-    return GRN_SUCCESS;
-  }
-  new_max_n_tokens = parser->n_tokens * 2;
-  if (!new_max_n_tokens) {
-    new_max_n_tokens = 1;
-  }
-  n_bytes = sizeof(grn_ts_expr_token *) * new_max_n_tokens;
-  new_tokens = (grn_ts_expr_token **)GRN_REALLOC(parser->tokens, n_bytes);
-  if (!new_tokens) {
-    GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE, "GRN_REALLOC failed: %zu",
-                      n_bytes);
-  }
-  for (i = parser->n_tokens; i < new_max_n_tokens; i++) {
-    new_tokens[i] = NULL;
-  }
-  parser->tokens = new_tokens;
-  parser->max_n_tokens = new_max_n_tokens;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_expr_parser_tokenize() tokenizes a string. */
-static grn_rc
-grn_ts_expr_parser_tokenize(grn_ctx *ctx, grn_ts_expr_parser *parser,
-                            grn_ts_str str) {
-  grn_ts_str rest = str;
-  const char *end = str.ptr + str.size;
-  grn_ts_expr_token *token = NULL;
-  GRN_TS_DEBUG("str = \"%.*s\"", (int)str.size, str.ptr);
-  do {
-    grn_rc rc = grn_ts_expr_parser_reserve_tokens(ctx, parser);
-    if (rc != GRN_SUCCESS) {
-      return rc;
-    }
-    rc = grn_ts_expr_parser_tokenize_next(ctx, parser, rest, &token);
-    if (rc != GRN_SUCCESS) {
-      return rc;
-    }
-    if ((token->type != GRN_TS_EXPR_START_TOKEN) &&
-        (token->type != GRN_TS_EXPR_END_TOKEN)) {
-      GRN_TS_DEBUG("token = \"%.*s\"", (int)token->src.size, token->src.ptr);
-    }
-    parser->tokens[parser->n_tokens++] = token;
-    rest.ptr = token->src.ptr + token->src.size;
-    rest.size = end - rest.ptr;
-  } while (token->type != GRN_TS_EXPR_END_TOKEN);
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_expr_parser_push_const() pushes a token to an expression. */
-static grn_rc
-grn_ts_expr_parser_push_const(grn_ctx *ctx, grn_ts_expr_parser *parser,
-                              grn_ts_expr_const_token *token) {
-  switch (token->data_kind) {
-    case GRN_TS_BOOL: {
-      return grn_ts_expr_push_bool(ctx, parser->expr, token->content.as_bool);
-    }
-    case GRN_TS_INT: {
-      return grn_ts_expr_push_int(ctx, parser->expr, token->content.as_int);
-    }
-    case GRN_TS_FLOAT: {
-      return grn_ts_expr_push_float(ctx, parser->expr,
-                                    token->content.as_float);
-    }
-    case GRN_TS_TEXT: {
-      return grn_ts_expr_push_text(ctx, parser->expr, token->content.as_text);
-    }
-    default: {
-      GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",
-                        token->data_kind);
-    }
-  }
-}
-
-/* grn_ts_expr_parser_push_name() pushes a token to an expression. */
-static grn_rc
-grn_ts_expr_parser_push_name(grn_ctx *ctx, grn_ts_expr_parser *parser,
-                             grn_ts_expr_name_token *token) {
-  return grn_ts_expr_push_name(ctx, parser->expr,
-                               token->src.ptr, token->src.size);
-}
-
-/* grn_ts_expr_parser_push_op() pushes a token to an expression. */
-static grn_rc
-grn_ts_expr_parser_push_op(grn_ctx *ctx, grn_ts_expr_parser *parser,
-                           grn_ts_expr_op_token *token) {
-  return grn_ts_expr_push_op(ctx, parser->expr, token->op_type);
-}
-
-/*
- * grn_ts_expr_parser_apply_one() applies a bridge or prior operator.
- * If there is no target, this function returns GRN_END_OF_DATA.
- */
-// FIXME: Support a ternary operator.
-static grn_rc
-grn_ts_expr_parser_apply_one(grn_ctx *ctx, grn_ts_expr_parser *parser,
-                             grn_ts_op_precedence precedence_threshold) {
-  grn_rc rc;
-  grn_ts_str src;
-  grn_ts_expr_token **stack = parser->stack;
-  grn_ts_expr_dummy_token *dummy_token;
-  size_t n_args, depth = parser->stack_depth;
-  if (depth < 2) {
-    return GRN_END_OF_DATA;
-  }
-  if (stack[depth - 1]->type != GRN_TS_EXPR_DUMMY_TOKEN) {
-    GRN_TS_ERR_RETURN(GRN_INVALID_FORMAT, "argument must be dummy token");
-  }
-
-  /* Check the number of arguments. */
-  switch (stack[depth - 2]->type) {
-    case GRN_TS_EXPR_BRIDGE_TOKEN: {
-      rc = grn_ts_expr_end_subexpr(ctx, parser->expr);
-      if (rc != GRN_SUCCESS) {
-        return rc;
-      }
-      n_args = 2;
-      break;
-    }
-    case GRN_TS_EXPR_OP_TOKEN: {
-      grn_ts_expr_op_token *op_token;
-      grn_ts_op_precedence precedence;
-      op_token = (grn_ts_expr_op_token *)stack[depth - 2];
-      precedence = grn_ts_op_get_precedence(op_token->op_type);
-      if (precedence < precedence_threshold) {
-        return GRN_END_OF_DATA;
-      }
-      rc = grn_ts_expr_parser_push_op(ctx, parser, op_token);
-      if (rc != GRN_SUCCESS) {
-        return rc;
-      }
-      n_args = grn_ts_op_get_n_args(op_token->op_type);
-      break;
-    }
-    default: {
-      return GRN_END_OF_DATA;
-    }
-  }
-
-  /* Concatenate the source strings. */
-  switch (n_args) {
-    case 1: {
-      grn_ts_expr_token *arg = stack[depth - 1];
-      src.ptr = stack[depth - 2]->src.ptr;
-      src.size = (arg->src.ptr + arg->src.size) - src.ptr;
-      break;
-    }
-    case 2: {
-      grn_ts_expr_token *args[2] = { stack[depth - 3], stack[depth - 1] };
-      src.ptr = args[0]->src.ptr;
-      src.size = (args[1]->src.ptr + args[1]->src.size) - src.ptr;
-      break;
-    }
-    default: {
-      GRN_TS_ERR_RETURN(GRN_OPERATION_NOT_SUPPORTED,
-                        "invalid #arguments: %zu", n_args);
-    }
-  }
-
-  /* Replace the operator and argument tokens with a dummy token. */
-  dummy_token = &parser->dummy_tokens[parser->n_dummy_tokens++];
-  GRN_TS_DEBUG("dummy token: \"%.*s\"", (int)src.size, src.ptr);
-  grn_ts_expr_dummy_token_init(ctx, dummy_token, src);
-  depth -= n_args + 1;
-  stack[depth++] = dummy_token;
-  parser->stack_depth = depth;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_expr_parser_apply() applies bridges and prior operators. */
-static grn_rc
-grn_ts_expr_parser_apply(grn_ctx *ctx, grn_ts_expr_parser *parser,
-                         grn_ts_op_precedence precedence_threshold) {
-  for ( ; ; ) {
-    grn_rc rc = grn_ts_expr_parser_apply_one(ctx, parser,
-                                             precedence_threshold);
-    if (rc == GRN_END_OF_DATA) {
-      return GRN_SUCCESS;
-    } else if (rc != GRN_SUCCESS) {
-      return rc;
-    }
-  }
-}
-
-/* grn_ts_expr_parser_analyze_op() analyzes a token. */
-static grn_rc
-grn_ts_expr_parser_analyze_op(grn_ctx *ctx, grn_ts_expr_parser *parser,
-                              grn_ts_expr_op_token *token) {
-  size_t n_args = grn_ts_op_get_n_args(token->op_type);
-  grn_ts_expr_token *ex_token = parser->stack[parser->stack_depth - 1];
-  if (n_args == 1) {
-    if (ex_token->type == GRN_TS_EXPR_DUMMY_TOKEN) {
-      GRN_TS_ERR_RETURN(GRN_INVALID_FORMAT, "invalid token sequence");
-    }
-  } else if (n_args == 2) {
-    grn_ts_op_precedence precedence = grn_ts_op_get_precedence(token->op_type);
-    grn_rc rc = grn_ts_expr_parser_apply(ctx, parser, precedence);
-    if (rc != GRN_SUCCESS) {
-      return rc;
-    }
-  }
-  parser->stack[parser->stack_depth++] = (grn_ts_expr_token *)token;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_expr_parser_analyze_bridge() analyzes a token. */
-static grn_rc
-grn_ts_expr_parser_analyze_bridge(grn_ctx *ctx, grn_ts_expr_parser *parser,
-                                  grn_ts_expr_bridge_token *token) {
-  grn_rc rc = grn_ts_expr_begin_subexpr(ctx, parser->expr);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  parser->stack[parser->stack_depth++] = (grn_ts_expr_token *)token;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_expr_parser_analyze_bracket() analyzes a token. */
-static grn_rc
-grn_ts_expr_parser_analyze_bracket(grn_ctx *ctx, grn_ts_expr_parser *parser,
-                                   grn_ts_expr_bracket_token *token) {
-  grn_ts_expr_token *ex_token = parser->stack[parser->stack_depth - 1];
-  switch (token->src.ptr[0]) {
-    case '(': {
-      if (ex_token->type == GRN_TS_EXPR_DUMMY_TOKEN) {
-        GRN_TS_ERR_RETURN(GRN_INVALID_FORMAT, "invalid token sequence");
-      }
-      parser->stack[parser->stack_depth++] = (grn_ts_expr_token *)token;
-      return GRN_SUCCESS;
-    }
-    case '[': {
-      if (ex_token->type != GRN_TS_EXPR_DUMMY_TOKEN) {
-        GRN_TS_ERR_RETURN(GRN_INVALID_FORMAT, "invalid token sequence");
-      }
-      parser->stack[parser->stack_depth++] = (grn_ts_expr_token *)token;
-      return GRN_SUCCESS;
-    }
-    case ')': case ']': {
-      grn_ts_expr_token *ex_ex_token;
-      grn_rc rc = grn_ts_expr_parser_apply(ctx, parser, 0);
-      if (rc != GRN_SUCCESS) {
-        return rc;
-      }
-      if (parser->stack_depth < 2) {
-        GRN_TS_ERR_RETURN(GRN_INVALID_FORMAT, "invalid token sequence");
-      }
-      ex_ex_token = parser->stack[parser->stack_depth - 2];
-      if (ex_ex_token->type != GRN_TS_EXPR_BRACKET_TOKEN) {
-        GRN_TS_ERR_RETURN(GRN_INVALID_FORMAT, "invalid token sequence");
-      }
-      if (token->src.ptr[0] == ')') {
-        size_t depth = parser->stack_depth;
-        grn_ts_str src;
-        grn_ts_expr_dummy_token *dummy_token;
-        if (ex_ex_token->src.ptr[0] != '(') {
-          GRN_TS_ERR_RETURN(GRN_INVALID_FORMAT, "invalid token sequence");
-        }
-        src.ptr = ex_ex_token->src.ptr;
-        src.size = (token->src.ptr + token->src.size) - src.ptr;
-        dummy_token = &parser->dummy_tokens[parser->n_dummy_tokens++];
-        GRN_TS_DEBUG("dummy token: \"%.*s\"", (int)src.size, src.ptr);
-        grn_ts_expr_dummy_token_init(ctx, dummy_token, src);
-        parser->stack[depth - 2] = dummy_token;
-        parser->stack_depth--;
-        // TODO: Apply a function.
-      } else if (token->src.ptr[0] == ']') {
-        size_t depth = parser->stack_depth;
-        if (ex_ex_token->src.ptr[0] != '[') {
-          GRN_TS_ERR_RETURN(GRN_INVALID_FORMAT, "invalid token sequence");
-        }
-        parser->stack[depth - 2] = parser->stack[depth - 1];
-        parser->stack_depth--;
-        // TODO: Push a subscript operator.
-      }
-      return GRN_SUCCESS;
-    }
-    default: {
-      GRN_TS_ERR_RETURN(GRN_INVALID_FORMAT, "undefined bracket: \"%.*s\"",
-                        (int)token->src.size, token->src.ptr);
-    }
-  }
-}
-
-/* grn_ts_expr_parser_analyze_token() analyzes a token. */
-static grn_rc
-grn_ts_expr_parser_analyze_token(grn_ctx *ctx, grn_ts_expr_parser *parser,
-                                 grn_ts_expr_token *token) {
-  switch (token->type) {
-    case GRN_TS_EXPR_START_TOKEN: {
-      parser->stack[parser->stack_depth++] = token;
-      return GRN_SUCCESS;
-    }
-    case GRN_TS_EXPR_END_TOKEN: {
-      return grn_ts_expr_parser_apply(ctx, parser, 0);
-    }
-    case GRN_TS_EXPR_CONST_TOKEN: {
-      grn_ts_expr_const_token *const_token = (grn_ts_expr_const_token *)token;
-      grn_ts_expr_dummy_token *dummy_token;
-      grn_rc rc = grn_ts_expr_parser_push_const(ctx, parser, const_token);
-      if (rc != GRN_SUCCESS) {
-        return rc;
-      }
-      dummy_token = &parser->dummy_tokens[parser->n_dummy_tokens++];
-      grn_ts_expr_dummy_token_init(ctx, dummy_token, token->src);
-      parser->stack[parser->stack_depth++] = dummy_token;
-      return GRN_SUCCESS;
-    }
-    case GRN_TS_EXPR_NAME_TOKEN: {
-      grn_ts_expr_name_token *name_token = (grn_ts_expr_name_token *)token;
-      grn_ts_expr_dummy_token *dummy_token;
-      grn_rc rc = grn_ts_expr_parser_push_name(ctx, parser, name_token);
-      if (rc != GRN_SUCCESS) {
-        return rc;
-      }
-      dummy_token = &parser->dummy_tokens[parser->n_dummy_tokens++];
-      grn_ts_expr_dummy_token_init(ctx, dummy_token, token->src);
-      parser->stack[parser->stack_depth++] = dummy_token;
-      return GRN_SUCCESS;
-    }
-    case GRN_TS_EXPR_OP_TOKEN: {
-      grn_ts_expr_op_token *op_token = (grn_ts_expr_op_token *)token;
-      return grn_ts_expr_parser_analyze_op(ctx, parser, op_token);
-    }
-    case GRN_TS_EXPR_BRIDGE_TOKEN: {
-      grn_ts_expr_bridge_token *bridge_token;
-      bridge_token = (grn_ts_expr_bridge_token *)token;
-      return grn_ts_expr_parser_analyze_bridge(ctx, parser, bridge_token);
-    }
-    case GRN_TS_EXPR_BRACKET_TOKEN: {
-      grn_ts_expr_bracket_token *bracket_token;
-      bracket_token = (grn_ts_expr_bracket_token *)token;
-      return grn_ts_expr_parser_analyze_bracket(ctx, parser, bracket_token);
-    }
-    default: {
-      GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid token type: %d",
-                        token->type);
-    }
-  }
-}
-
-/* grn_ts_expr_parser_analyze() analyzes tokens. */
-static grn_rc
-grn_ts_expr_parser_analyze(grn_ctx *ctx, grn_ts_expr_parser *parser) {
-  size_t i;
-
-  /* Reserve temporary work spaces. */
-  parser->dummy_tokens = GRN_MALLOCN(grn_ts_expr_dummy_token,
-                                     parser->n_tokens);
-  if (!parser->dummy_tokens) {
-    GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE, "GRN_MALLOCN failed: %zu x %zu",
-                      sizeof(grn_ts_expr_dummy_token), parser->n_tokens);
-  }
-  parser->stack = GRN_MALLOCN(grn_ts_expr_token *, parser->n_tokens);
-  if (!parser->stack) {
-    GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE, "GRN_MALLOCN failed: %zu x %zu",
-                      sizeof(grn_ts_expr_token *), parser->n_tokens);
-  }
-
-  /* Analyze tokens. */
-  for (i = 0; i < parser->n_tokens; i++) {
-    grn_rc rc;
-    rc = grn_ts_expr_parser_analyze_token(ctx, parser, parser->tokens[i]);
-    if (rc != GRN_SUCCESS) {
-      return rc;
-    }
-  }
-  if (parser->stack_depth != 2) {
-    GRN_TS_ERR_RETURN(GRN_INVALID_FORMAT, "tokens left in stack: %zu",
-                      parser->stack_depth);
-  }
-  return GRN_SUCCESS;
-}
-
-/*
- * grn_ts_expr_parser_parse() parses a string and pushes nodes into an
- * expression.
- */
-static grn_rc
-grn_ts_expr_parser_parse(grn_ctx *ctx, grn_ts_expr_parser *parser,
-                         const char *str_ptr, size_t str_size) {
-  grn_rc rc;
-  grn_ts_str str;
-  rc = grn_ts_buf_reserve(ctx, &parser->str_buf, str_size + 1);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  grn_memcpy(parser->str_buf.ptr, str_ptr, str_size);
-  ((char *)parser->str_buf.ptr)[str_size] = '\0';
-  str.ptr = (const char *)parser->str_buf.ptr;
-  str.size = str_size;
-  rc = grn_ts_expr_parser_tokenize(ctx, parser, str);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  rc = grn_ts_expr_parser_analyze(ctx, parser);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  return GRN_SUCCESS;
-}
-
-/*-------------------------------------------------------------
- * grn_ts_expr_bridge.
- */
-
-/* grn_ts_expr_bridge_init() initializes a bridge. */
-static void
-grn_ts_expr_bridge_init(grn_ctx *ctx, grn_ts_expr_bridge *bridge) {
-  memset(bridge, 0, sizeof(*bridge));
-  bridge->src_table = NULL;
-  bridge->dest_table = NULL;
-}
-
-/* grn_ts_expr_bridge_fin() finalizes a bridge. */
-static void
-grn_ts_expr_bridge_fin(grn_ctx *ctx, grn_ts_expr_bridge *bridge) {
-  if (bridge->dest_table) {
-    grn_obj_unlink(ctx, bridge->dest_table);
-  }
-  /* Note: bridge->src_table does not increment a reference count. */
-}
-
-/*-------------------------------------------------------------
- * grn_ts_expr.
- */
-
-/* grn_ts_expr_init() initializes an expression. */
-static void
-grn_ts_expr_init(grn_ctx *ctx, grn_ts_expr *expr) {
-  memset(expr, 0, sizeof(*expr));
-  expr->table = NULL;
-  expr->curr_table = NULL;
-  expr->root = NULL;
-  expr->nodes = NULL;
-  expr->stack = NULL;
-  expr->bridges = NULL;
-}
-
-/* grn_ts_expr_fin() finalizes an expression. */
-static void
-grn_ts_expr_fin(grn_ctx *ctx, grn_ts_expr *expr) {
-  size_t i;
-  if (expr->bridges) {
-    for (i = 0; i < expr->n_bridges; i++) {
-      grn_ts_expr_bridge_fin(ctx, &expr->bridges[i]);
-    }
-    GRN_FREE(expr->bridges);
-  }
-  if (expr->stack) {
-    GRN_FREE(expr->stack);
-  }
-  if (expr->nodes) {
-    for (i = 0; i < expr->n_nodes; i++) {
-      if (expr->nodes[i]) {
-        grn_ts_expr_node_close(ctx, expr->nodes[i]);
-      }
-    }
-    GRN_FREE(expr->nodes);
-  }
-  /* Note: expr->curr_table does not increment a reference count. */
-  if (expr->table) {
-    grn_obj_unlink(ctx, expr->table);
-  }
-}
-
-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) {
-    return GRN_INVALID_ARGUMENT;
-  }
-  if (!table || !grn_ts_obj_is_table(ctx, table) || !expr) {
-    GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
-  }
-  new_expr = GRN_MALLOCN(grn_ts_expr, 1);
-  if (!new_expr) {
-    GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE, "GRN_MALLOCN failed: %zu x 1",
-                      sizeof(grn_ts_expr));
-  }
-  rc = grn_ts_obj_increment_ref_count(ctx, table);
-  if (rc != GRN_SUCCESS) {
-    GRN_FREE(new_expr);
-    return rc;
-  }
-  grn_ts_expr_init(ctx, new_expr);
-  new_expr->table = table;
-  new_expr->curr_table = table;
-  *expr = new_expr;
-  return GRN_SUCCESS;
-}
-
-grn_rc
-grn_ts_expr_parse(grn_ctx *ctx, grn_obj *table,
-                  const char *str_ptr, size_t str_size, grn_ts_expr **expr) {
-  grn_rc rc;
-  grn_ts_expr *new_expr;
-  if (!ctx) {
-    return GRN_INVALID_ARGUMENT;
-  }
-  if (!table || !grn_ts_obj_is_table(ctx, table) ||
-      (!str_ptr && str_size) || !expr) {
-    GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
-  }
-  rc = grn_ts_expr_open(ctx, table, &new_expr);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  rc = grn_ts_expr_push(ctx, new_expr, str_ptr, str_size);
-  if (rc == GRN_SUCCESS) {
-    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_rc
-grn_ts_expr_close(grn_ctx *ctx, grn_ts_expr *expr) {
-  if (!ctx || !expr) {
-    return GRN_INVALID_ARGUMENT;
-  }
-  grn_ts_expr_fin(ctx, expr);
-  GRN_FREE(expr);
-  return GRN_SUCCESS;
-}
-
-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) {
-    GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE, "GRN_REALLOC failed: %zu",
-                      n_bytes);
-  }
-  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;
-}
-
-#define GRN_TS_EXPR_OPEN_NODE(call)\
-  grn_rc rc = grn_ts_expr_reserve_nodes(ctx, expr);\
-  if (rc != GRN_SUCCESS) {\
-    return rc;\
-  }\
-  rc = call;\
-  if (rc != GRN_SUCCESS) {\
-    return rc;\
-  }\
-  expr->nodes[expr->n_nodes++] = *node;\
-  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_OPEN_NODE(grn_ts_expr_id_node_open(ctx, node))
-}
-
-/*
- * 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_OPEN_NODE(grn_ts_expr_score_node_open(ctx, node))
-}
-
-/*
- * 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_OPEN_NODE(grn_ts_expr_key_node_open(ctx, expr->curr_table, node))
-}
-
-/*
- * 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_OPEN_NODE(grn_ts_expr_value_node_open(ctx, expr->curr_table,
-                                                    node))
-}
-
-/*
- * 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_OPEN_NODE(grn_ts_expr_const_node_open(ctx, kind, value, node))
-}
-
-/*
- * grn_ts_expr_open_column_node() opens and registers a column node.
- * 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_OPEN_NODE(grn_ts_expr_column_node_open(ctx, column, node))
-}
-
-/*
- * grn_ts_expr_open_op_node() opens and registers an operator node.
- * Registered nodes will be closed in grn_ts_expr_fin().
- */
-static grn_rc
-grn_ts_expr_open_op_node(grn_ctx *ctx, grn_ts_expr *expr,
-                         grn_ts_op_type op_type, grn_ts_expr_node **args,
-                         size_t n_args, grn_ts_expr_node **node) {
-  GRN_TS_EXPR_OPEN_NODE(grn_ts_expr_op_node_open(ctx, op_type, args, n_args,
-                                                 node))
-}
-
-/*
- * grn_ts_expr_open_bridge_node() opens and registers a bridge node.
- * Registered nodes will be closed in grn_ts_expr_fin().
- */
-static grn_rc
-grn_ts_expr_open_bridge_node(grn_ctx *ctx, grn_ts_expr *expr,
-                             grn_ts_expr_node *src, grn_ts_expr_node *dest,
-                             grn_ts_expr_node **node) {
-  GRN_TS_EXPR_OPEN_NODE(grn_ts_expr_bridge_node_open(ctx, src, dest, node))
-}
-#undef GRN_TS_EXPR_OPEN_NODE
-
-/* grn_ts_expr_reserve_stack() extends a stack. */
-static grn_rc
-grn_ts_expr_reserve_stack(grn_ctx *ctx, grn_ts_expr *expr) {
-  size_t i, n_bytes, new_size;
-  grn_ts_expr_node **new_stack;
-  if (expr->stack_depth < expr->stack_size) {
-    return GRN_SUCCESS;
-  }
-  new_size = expr->stack_size ? (expr->stack_size * 2) : 1;
-  n_bytes = sizeof(grn_ts_expr_node *) * new_size;
-  new_stack = GRN_REALLOC(expr->stack, n_bytes);
-  if (!new_stack) {
-    GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE, "GRN_REALLOC failed: %zu",
-                      n_bytes);
-  }
-  for (i = expr->stack_size; i < new_size; i++) {
-    new_stack[i] = NULL;
-  }
-  expr->stack = new_stack;
-  expr->stack_size = new_size;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_expr_deref() dereferences a node. */
-static grn_rc
-grn_ts_expr_deref(grn_ctx *ctx, grn_ts_expr *expr,
-                  grn_ts_expr_node **node_ptr) {
-  grn_ts_expr_node *node = *node_ptr;
-  while (node->data_kind == GRN_TS_REF) {
-    grn_rc rc;
-    grn_ts_expr_node *key_node, *bridge_node;
-    grn_id table_id = node->data_type;
-    grn_obj *table = grn_ctx_at(ctx, table_id);
-    if (!table) {
-      return GRN_OBJECT_CORRUPT;
-    }
-    if (!grn_ts_obj_is_table(ctx, table)) {
-      grn_obj_unlink(ctx, table);
-      return GRN_OBJECT_CORRUPT;
-    }
-    rc = grn_ts_expr_key_node_open(ctx, table, &key_node);
-    grn_obj_unlink(ctx, table);
-    if (rc != GRN_SUCCESS) {
-      return rc;
-    }
-    rc = grn_ts_expr_bridge_node_open(ctx, node, key_node, &bridge_node);
-    if (rc != GRN_SUCCESS) {
-      return rc;
-    }
-    node = bridge_node;
-  }
-  *node_ptr = node;
-  return GRN_SUCCESS;
-}
-
-grn_rc
-grn_ts_expr_push(grn_ctx *ctx, grn_ts_expr *expr,
-                 const char *str_ptr, size_t str_size) {
-  grn_rc rc;
-  grn_ts_expr_parser *parser;
-  if (!ctx) {
-    return GRN_INVALID_ARGUMENT;
-  }
-  if (!expr || (expr->type != GRN_TS_EXPR_INCOMPLETE) ||
-      (!str_ptr && str_size)) {
-    GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
-  }
-  rc = grn_ts_expr_parser_open(ctx, expr, &parser);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  rc = grn_ts_expr_parser_parse(ctx, parser, str_ptr, str_size);
-  grn_ts_expr_parser_close(ctx, parser);
-  return rc;
-}
-
-grn_rc
-grn_ts_expr_push_name(grn_ctx *ctx, grn_ts_expr *expr,
-                     const char *name_ptr, size_t name_size) {
-  grn_obj *column;
-  grn_ts_str name = { name_ptr, name_size };
-  if (!ctx) {
-    return GRN_INVALID_ARGUMENT;
-  }
-  if (!expr || (expr->type != GRN_TS_EXPR_INCOMPLETE) ||
-      !grn_ts_str_is_name(name)) {
-    GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
-  }
-  if (grn_ts_str_is_id_name(name)) {
-    return grn_ts_expr_push_id(ctx, expr);
-  }
-  if (grn_ts_str_is_score_name(name)) {
-    return grn_ts_expr_push_score(ctx, expr);
-  }
-  if (grn_ts_str_is_key_name(name)) {
-    return grn_ts_expr_push_key(ctx, expr);
-  }
-  if (grn_ts_str_is_value_name(name)) {
-    return grn_ts_expr_push_value(ctx, expr);
-  }
-  /* grn_obj_column() returns a column or accessor. */
-  column = grn_obj_column(ctx, expr->curr_table, name.ptr, name.size);
-  if (!column) {
-    GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "object not found: \"%.*s\"",
-                      (int)name.size, name.ptr);
-  }
-  return grn_ts_expr_push_obj(ctx, expr, column);
-}
-
-#define GRN_TS_EXPR_PUSH_BULK_CASE(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(BOOL, bool)
-    GRN_TS_EXPR_PUSH_BULK_CASE(INT8, int)
-    GRN_TS_EXPR_PUSH_BULK_CASE(INT16, int)
-    GRN_TS_EXPR_PUSH_BULK_CASE(INT32, int)
-    GRN_TS_EXPR_PUSH_BULK_CASE(INT64, int)
-    GRN_TS_EXPR_PUSH_BULK_CASE(UINT8, int)
-    GRN_TS_EXPR_PUSH_BULK_CASE(UINT16, int)
-    GRN_TS_EXPR_PUSH_BULK_CASE(UINT32, int)
-    /* The behavior is undefined if a value is greater than 2^63 - 1. */
-    GRN_TS_EXPR_PUSH_BULK_CASE(UINT64, int)
-    GRN_TS_EXPR_PUSH_BULK_CASE(FLOAT, float)
-    GRN_TS_EXPR_PUSH_BULK_CASE(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: {
-      GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "not bulk");
-    }
-  }
-}
-#undef GRN_TS_EXPR_PUSH_BULK_CASE
-
-#define GRN_TS_EXPR_PUSH_UVECTOR_CASE(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_WITH_TYPECAST(TYPE, kind)\
-  case GRN_DB_ ## TYPE: {\
-    size_t i;\
-    grn_rc rc;\
-    grn_ts_ ## kind *buf;\
-    grn_ts_ ## kind ## _vector value = { NULL, grn_uvector_size(ctx, obj) };\
-    if (!value.size) {\
-      return grn_ts_expr_push_ ## kind ## _vector(ctx, expr, value);\
-    }\
-    buf = GRN_MALLOCN(grn_ts_ ## kind, value.size);\
-    if (!buf) {\
-      GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE,\
-                        "GRN_MALLOCN failed: %zu x 1",\
-                        sizeof(grn_ts_ ## kind));\
-    }\
-    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(BOOL, bool)
-    GRN_TS_EXPR_PUSH_UVECTOR_CASE_WITH_TYPECAST(INT8, int)
-    GRN_TS_EXPR_PUSH_UVECTOR_CASE_WITH_TYPECAST(INT16, int)
-    GRN_TS_EXPR_PUSH_UVECTOR_CASE_WITH_TYPECAST(INT32, int)
-    GRN_TS_EXPR_PUSH_UVECTOR_CASE(INT64, int)
-    GRN_TS_EXPR_PUSH_UVECTOR_CASE_WITH_TYPECAST(UINT8, int)
-    GRN_TS_EXPR_PUSH_UVECTOR_CASE_WITH_TYPECAST(UINT16, int)
-    GRN_TS_EXPR_PUSH_UVECTOR_CASE_WITH_TYPECAST(UINT32, int)
-    GRN_TS_EXPR_PUSH_UVECTOR_CASE(UINT64, int)
-    GRN_TS_EXPR_PUSH_UVECTOR_CASE(TIME, time)
-    GRN_TS_EXPR_PUSH_UVECTOR_CASE(TOKYO_GEO_POINT, tokyo_geo_point)
-    GRN_TS_EXPR_PUSH_UVECTOR_CASE(WGS84_GEO_POINT, wgs84_geo_point)
-    default: {
-      GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data type: %d",
-                        obj->header.domain);
-    }
-  }
-}
-#undef GRN_TS_EXPR_PUSH_UVECTOR_CASE_WITH_TYPECAST
-#undef GRN_TS_EXPR_PUSH_UVECTOR_CASE
-
-/* grn_ts_expr_push_vector() 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 *buf;
-      grn_ts_text_vector value = { NULL, grn_vector_size(ctx, obj) };
-      if (!value.size) {
-        return grn_ts_expr_push_text_vector(ctx, expr, value);
-      }
-      buf = GRN_MALLOCN(grn_ts_text, value.size);
-      if (!buf) {
-        GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE,
-                          "GRN_MALLOCN failed: %zu x %zu",
-                          sizeof(grn_ts_text), value.size);
-      }
-      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: {
-      GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data type: %d",
-                        obj->header.domain);
-    }
-  }
-}
-
-static grn_rc
-grn_ts_expr_push_single_accessor(grn_ctx *ctx, grn_ts_expr *expr,
-                                 grn_accessor *accessor) {
-  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: {
-      if (accessor->obj != expr->curr_table) {
-        GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "table conflict");
-      }
-      return grn_ts_expr_push_key(ctx, expr);
-    }
-    case GRN_ACCESSOR_GET_VALUE: {
-      if (accessor->obj != expr->curr_table) {
-        GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "table conflict");
-      }
-      return grn_ts_expr_push_value(ctx, expr);
-    }
-    case GRN_ACCESSOR_GET_COLUMN_VALUE: {
-      return grn_ts_expr_push_column(ctx, expr, accessor->obj);
-    }
-    default: {
-      GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid accessor action: %d",
-                        accessor->action);
-    }
-  }
-}
-
-static grn_rc
-grn_ts_expr_push_accessor(grn_ctx *ctx, grn_ts_expr *expr,
-                          grn_accessor *accessor) {
-  grn_rc rc = grn_ts_expr_push_single_accessor(ctx, expr, accessor);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  for (accessor = accessor->next; accessor; accessor = accessor->next) {
-    rc = grn_ts_expr_begin_subexpr(ctx, expr);
-    if (rc != GRN_SUCCESS) {
-      return rc;
-    }
-    rc = grn_ts_expr_push_single_accessor(ctx, expr, accessor);
-    if (rc != GRN_SUCCESS) {
-      return rc;
-    }
-    rc = grn_ts_expr_end_subexpr(ctx, expr);
-    if (rc != GRN_SUCCESS) {
-      return rc;
-    }
-  }
-  return GRN_SUCCESS;
-}
-
-grn_rc
-grn_ts_expr_push_obj(grn_ctx *ctx, grn_ts_expr *expr, grn_obj *obj) {
-  if (!ctx) {
-    return GRN_INVALID_ARGUMENT;
-  }
-  if (!expr || (expr->type != GRN_TS_EXPR_INCOMPLETE) || !obj) {
-    GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "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: {
-      GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid object type: %d",
-                        obj->header.type);
-    }
-  }
-}
-
-grn_rc
-grn_ts_expr_push_id(grn_ctx *ctx, grn_ts_expr *expr) {
-  grn_rc rc;
-  grn_ts_expr_node *node;
-  if (!ctx) {
-    return GRN_INVALID_ARGUMENT;
-  }
-  if (!expr || (expr->type != GRN_TS_EXPR_INCOMPLETE)) {
-    GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
-  }
-  rc = grn_ts_expr_reserve_stack(ctx, expr);
-  if (rc == GRN_SUCCESS) {
-    rc = grn_ts_expr_open_id_node(ctx, expr, &node);
-    if (rc == GRN_SUCCESS) {
-      expr->stack[expr->stack_depth++] = node;
-    }
-  }
-  return rc;
-}
-
-grn_rc
-grn_ts_expr_push_score(grn_ctx *ctx, grn_ts_expr *expr) {
-  grn_rc rc;
-  grn_ts_expr_node *node;
-  if (!ctx) {
-    return GRN_INVALID_ARGUMENT;
-  }
-  if (!expr || (expr->type != GRN_TS_EXPR_INCOMPLETE)) {
-    GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
-  }
-  rc = grn_ts_expr_reserve_stack(ctx, expr);
-  if (rc == GRN_SUCCESS) {
-    rc = grn_ts_expr_open_score_node(ctx, expr, &node);
-    if (rc == GRN_SUCCESS) {
-      expr->stack[expr->stack_depth++] = node;
-    }
-  }
-  return rc;
-}
-
-grn_rc
-grn_ts_expr_push_key(grn_ctx *ctx, grn_ts_expr *expr) {
-  grn_rc rc;
-  grn_ts_expr_node *node;
-  if (!ctx) {
-    return GRN_INVALID_ARGUMENT;
-  }
-  if (!expr || (expr->type != GRN_TS_EXPR_INCOMPLETE)) {
-    GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
-  }
-  rc = grn_ts_expr_reserve_stack(ctx, expr);
-  if (rc == GRN_SUCCESS) {
-    rc = grn_ts_expr_open_key_node(ctx, expr, &node);
-    if (rc == GRN_SUCCESS) {
-      expr->stack[expr->stack_depth++] = node;
-    }
-  }
-  return rc;
-}
-
-grn_rc
-grn_ts_expr_push_value(grn_ctx *ctx, grn_ts_expr *expr) {
-  grn_rc rc;
-  grn_ts_expr_node *node;
-  if (!ctx) {
-    return GRN_INVALID_ARGUMENT;
-  }
-  if (!expr || (expr->type != GRN_TS_EXPR_INCOMPLETE)) {
-    GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
-  }
-  rc = grn_ts_expr_reserve_stack(ctx, expr);
-  if (rc == GRN_SUCCESS) {
-    rc = grn_ts_expr_open_value_node(ctx, expr, &node);
-    if (rc == GRN_SUCCESS) {
-      expr->stack[expr->stack_depth++] = node;
-    }
-  }
-  return rc;
-}
-
-#define GRN_TS_EXPR_PUSH_CONST_CASE(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) {
-    return GRN_INVALID_ARGUMENT;
-  }
-  if (!expr || (expr->type != GRN_TS_EXPR_INCOMPLETE) || !value) {
-    GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
-  }
-  switch (kind) {
-    GRN_TS_EXPR_PUSH_CONST_CASE(BOOL, bool)
-    GRN_TS_EXPR_PUSH_CONST_CASE(INT, int)
-    GRN_TS_EXPR_PUSH_CONST_CASE(FLOAT, float)
-    GRN_TS_EXPR_PUSH_CONST_CASE(TIME, time)
-    GRN_TS_EXPR_PUSH_CONST_CASE(TEXT, text)
-    GRN_TS_EXPR_PUSH_CONST_CASE(GEO_POINT, geo_point)
-    GRN_TS_EXPR_PUSH_CONST_CASE(BOOL_VECTOR, bool_vector)
-    GRN_TS_EXPR_PUSH_CONST_CASE(INT_VECTOR, int_vector)
-    GRN_TS_EXPR_PUSH_CONST_CASE(FLOAT_VECTOR, float_vector)
-    GRN_TS_EXPR_PUSH_CONST_CASE(TIME_VECTOR, time_vector)
-    GRN_TS_EXPR_PUSH_CONST_CASE(TEXT_VECTOR, text_vector)
-    GRN_TS_EXPR_PUSH_CONST_CASE(GEO_POINT_VECTOR, geo_point_vector)
-    default: {
-      GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d", kind);
-    }
-  }
-}
-#undef GRN_TS_EXPR_PUSH_CONST_CASE
-
-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) {
-    return GRN_INVALID_ARGUMENT;
-  }
-  if (!expr || (expr->type != GRN_TS_EXPR_INCOMPLETE) ||
-      !column || !grn_ts_obj_is_column(ctx, column) ||
-      (DB_OBJ(expr->curr_table)->id != column->header.domain)) {
-    GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
-  }
-  rc = grn_ts_expr_reserve_stack(ctx, expr);
-  if (rc == GRN_SUCCESS) {
-    rc = grn_ts_expr_open_column_node(ctx, expr, column, &node);
-    if (rc == GRN_SUCCESS) {
-      expr->stack[expr->stack_depth++] = node;
-    }
-  }
-  return rc;
-}
-
-grn_rc
-grn_ts_expr_push_op(grn_ctx *ctx, grn_ts_expr *expr, grn_ts_op_type op_type) {
-  grn_rc rc;
-  grn_ts_expr_node **args, *node;
-  size_t i, n_args;
-  if (!ctx) {
-    return GRN_INVALID_ARGUMENT;
-  }
-  if (!expr || (expr->type != GRN_TS_EXPR_INCOMPLETE)) {
-    GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
-  }
-  n_args = grn_ts_op_get_n_args(op_type);
-  if (!n_args) {
-    GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid #arguments: %zu", n_args);
-  }
-  if (n_args > expr->stack_depth) {
-    GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid #arguments: %zu, %zu",
-                      n_args, expr->stack_depth);
-  }
-  /* Arguments are the top n_args nodes in the stack. */
-  args = &expr->stack[expr->stack_depth - n_args];
-  for (i = 0; i < n_args; i++) {
-    /*
-     * FIXME: Operators "==" and "!=" should compare arguments as references
-     *        if possible.
-     */
-    rc = grn_ts_expr_deref(ctx, expr, &args[i]);
-    if (rc != GRN_SUCCESS) {
-      return rc;
-    }
-  }
-  rc = grn_ts_expr_open_op_node(ctx, expr, op_type, args, n_args, &node);
-  if (rc == GRN_SUCCESS) {
-    expr->stack_depth -= n_args;
-    expr->stack[expr->stack_depth++] = node;
-  }
-  return rc;
-}
-
-#define GRN_TS_EXPR_PUSH_CONST(KIND, kind)\
-  grn_rc rc;\
-  grn_ts_expr_node *node;\
-  if (!ctx) {\
-    return GRN_INVALID_ARGUMENT;\
-  }\
-  if (!expr || (expr->type != GRN_TS_EXPR_INCOMPLETE) ||\
-      !grn_ts_ ## kind ## _is_valid(value)) {\
-    GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");\
-  }\
-  rc = grn_ts_expr_reserve_stack(ctx, expr);\
-  if (rc == GRN_SUCCESS) {\
-    rc = grn_ts_expr_open_const_node(ctx, expr, GRN_TS_ ## KIND,\
-                                     &value, &node);\
-    if (rc == GRN_SUCCESS) {\
-      expr->stack[expr->stack_depth++] = node;\
-    }\
-  }
-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 rc;
-}
-
-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 rc;
-}
-
-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 rc;
-}
-
-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 rc;
-}
-
-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 rc;
-}
-
-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 rc;
-}
-
-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 rc;
-}
-
-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 rc;
-}
-
-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 rc;
-}
-
-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 rc;
-}
-
-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 rc;
-}
-
-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 rc;
-}
-
-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 rc;
-}
-
-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 rc;
-}
-
-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 rc;
-}
-
-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 rc;
-}
-#undef GRN_TS_EXPR_PUSH_CONST
-
-/* grn_ts_expr_reserve_bridges() extends a bridge buffer for a new bridge. */
-static grn_rc
-grn_ts_expr_reserve_bridges(grn_ctx *ctx, grn_ts_expr *expr) {
-  size_t n_bytes, new_max_n_bridges;
-  grn_ts_expr_bridge *new_bridges;
-  if (expr->n_bridges < expr->max_n_bridges) {
-    return GRN_SUCCESS;
-  }
-  new_max_n_bridges = expr->n_bridges * 2;
-  if (!new_max_n_bridges) {
-    new_max_n_bridges = 1;
-  }
-  n_bytes = sizeof(grn_ts_expr_bridge) * new_max_n_bridges;
-  new_bridges = (grn_ts_expr_bridge *)GRN_REALLOC(expr->bridges, n_bytes);
-  if (!new_bridges) {
-    GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE, "GRN_REALLOC failed: %zu",
-                      n_bytes);
-  }
-  expr->bridges = new_bridges;
-  expr->max_n_bridges = new_max_n_bridges;
-  return GRN_SUCCESS;
-}
-
-grn_rc
-grn_ts_expr_begin_subexpr(grn_ctx *ctx, grn_ts_expr *expr) {
-  grn_rc rc;
-  grn_obj *obj;
-  grn_ts_expr_node *node;
-  grn_ts_expr_bridge *bridge;
-  if (!ctx) {
-    return GRN_INVALID_ARGUMENT;
-  }
-  if (!expr || (expr->type != GRN_TS_EXPR_INCOMPLETE) || !expr->stack_depth) {
-    GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
-  }
-
-  /* Check whehter or not the latest node refers to a table. */
-  node = expr->stack[expr->stack_depth - 1];
-  if ((node->data_kind & ~GRN_TS_VECTOR_FLAG) != GRN_TS_REF) {
-    GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d",
-                      node->data_kind);
-  }
-  obj = grn_ctx_at(ctx, node->data_type);
-  if (!obj) {
-    GRN_TS_ERR_RETURN(GRN_UNKNOWN_ERROR, "grn_ctx_at failed: %d",
-                      node->data_type);
-  }
-  if (!grn_ts_obj_is_table(ctx, obj)) {
-    grn_obj_unlink(ctx, obj);
-    GRN_TS_ERR_RETURN(GRN_UNKNOWN_ERROR, "not table: %d", node->data_type);
-  }
-
-  /* Creates a bridge to a subexpression. */
-  rc = grn_ts_expr_reserve_bridges(ctx, expr);
-  if (rc != GRN_SUCCESS) {
-    grn_obj_unlink(ctx, obj);
-    return rc;
-  }
-  bridge = &expr->bridges[expr->n_bridges++];
-  grn_ts_expr_bridge_init(ctx, bridge);
-  bridge->src_table = expr->curr_table;
-  bridge->dest_table = obj;
-  bridge->stack_depth = expr->stack_depth;
-  expr->curr_table = bridge->dest_table;
-  return GRN_SUCCESS;
-}
-
-grn_rc
-grn_ts_expr_end_subexpr(grn_ctx *ctx, grn_ts_expr *expr) {
-  grn_rc rc;
-  grn_ts_expr_node **args, *node;
-  grn_ts_expr_bridge *bridge;
-  if (!ctx || !expr || (expr->type != GRN_TS_EXPR_INCOMPLETE) ||
-      (expr->stack_depth < 2) || !expr->n_bridges) {
-    return GRN_INVALID_ARGUMENT;
-  }
-  /* Check whehter or not the subexpression is complete.*/
-  bridge = &expr->bridges[expr->n_bridges - 1];
-  if (expr->stack_depth != (bridge->stack_depth + 1)) {
-    return GRN_INVALID_ARGUMENT;
-  }
-  /* Creates a bridge node. */
-  args = &expr->stack[expr->stack_depth - 2];
-  rc = grn_ts_expr_open_bridge_node(ctx, expr, args[0], args[1], &node);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  /* Note: grn_ts_expr_reserve_stack() is not required. */
-  expr->stack_depth -= 2;
-  expr->stack[expr->stack_depth++] = node;
-  expr->curr_table = bridge->src_table;
-  grn_ts_expr_bridge_fin(ctx, bridge);
-  expr->n_bridges--;
-  return GRN_SUCCESS;
-}
-
-grn_rc
-grn_ts_expr_complete(grn_ctx *ctx, grn_ts_expr *expr) {
-  grn_rc rc;
-  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;
-  }
-  rc = grn_ts_expr_deref(ctx, expr, &expr->stack[0]);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  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:
-    case GRN_TS_EXPR_BRIDGE_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_ts_expr_evaluate_to_buf() evaluates an expression. */
-static grn_rc
-grn_ts_expr_evaluate_to_buf(grn_ctx *ctx, grn_ts_expr *expr,
-                            const grn_ts_record *in, size_t n_in,
-                            grn_ts_buf *out) {
-  if (!ctx || !expr || (expr->type == GRN_TS_EXPR_INCOMPLETE) ||
-      (expr->type == GRN_TS_EXPR_BROKEN) || (!in && n_in) || !out) {
-    return GRN_INVALID_ARGUMENT;
-  }
-  if (!n_in) {
-    return GRN_SUCCESS;
-  }
-  return grn_ts_expr_node_evaluate_to_buf(ctx, expr->root, in, n_in, out);
-}
-
-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);
-}
-
 /*-------------------------------------------------------------
  * grn_ts_writer.
  */

  Modified: lib/ts/sources.am (+2 -0)
===================================================================
--- lib/ts/sources.am    2015-11-09 13:36:05 +0900 (c51787a)
+++ lib/ts/sources.am    2015-11-09 14:12:30 +0900 (31ec497)
@@ -1,6 +1,8 @@
 libgrnts_la_SOURCES =				\
 	ts_buf.c				\
 	ts_buf.h				\
+	ts_expr.c				\
+	ts_expr.h				\
 	ts_log.h				\
 	ts_str.c				\
 	ts_str.h

  Copied: lib/ts/ts_expr.c (+12 -739) 91%
===================================================================
--- lib/ts.c    2015-11-09 13:36:05 +0900 (5410343)
+++ lib/ts/ts_expr.c    2015-11-09 14:12:30 +0900 (a2d5611)
@@ -16,34 +16,23 @@
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
 
-/* TS is an acronym for "Turbo Selector". */
+#include "ts_expr.h"
 
-#include "grn_ts.h"
-
-#include <ctype.h>
 #include <math.h>
 #include <stdlib.h>
 #include <string.h>
 
-#include "grn_ctx_impl.h"
-#include "grn_dat.h"
-#include "grn_db.h"
-#include "grn_geo.h"
-#include "grn_hash.h"
-#include "grn_output.h"
-#include "grn_pat.h"
-#include "grn_store.h"
-#include "grn_str.h"
-
-#include "ts/ts_buf.h"
-#include "ts/ts_log.h"
-#include "ts/ts_str.h"
-
-/*-------------------------------------------------------------
- * Miscellaneous.
- */
+#include "../grn_ctx_impl.h"
+#include "../grn_dat.h"
+#include "../grn_db.h"
+#include "../grn_geo.h"
+#include "../grn_hash.h"
+#include "../grn_pat.h"
+#include "../grn_store.h"
 
-enum { GRN_TS_BATCH_SIZE = 1024 };
+#include "ts_buf.h"
+#include "ts_log.h"
+#include "ts_str.h"
 
 /*-------------------------------------------------------------
  * Built-in data kinds.
@@ -241,118 +230,6 @@ grn_ts_ref_vector_zero(void) {
   return (grn_ts_ref_vector){ NULL, 0 };
 }
 
-/* grn_ts_bool_output() outputs a value. */
-static grn_rc
-grn_ts_bool_output(grn_ctx *ctx, grn_ts_bool value) {
-  if (value) {
-    return grn_bulk_write(ctx, ctx->impl->outbuf, "true", 4);
-  } else {
-    return grn_bulk_write(ctx, ctx->impl->outbuf, "false", 5);
-  }
-}
-
-/* grn_ts_int_output() outputs a value. */
-static grn_rc
-grn_ts_int_output(grn_ctx *ctx, grn_ts_int value) {
-  return grn_text_lltoa(ctx, ctx->impl->outbuf, value);
-}
-
-/* grn_ts_float_output() outputs a value. */
-static grn_rc
-grn_ts_float_output(grn_ctx *ctx, grn_ts_float value) {
-  return grn_text_ftoa(ctx, ctx->impl->outbuf, value);
-}
-
-/* grn_ts_time_output() outputs a value. */
-static grn_rc
-grn_ts_time_output(grn_ctx *ctx, grn_ts_time value) {
-  return grn_text_ftoa(ctx, ctx->impl->outbuf, value * 0.000001);
-}
-
-/* grn_ts_text_output() outputs a value. */
-static grn_rc
-grn_ts_text_output(grn_ctx *ctx, grn_ts_text value) {
-  return grn_text_esc(ctx, ctx->impl->outbuf, value.ptr, value.size);
-}
-
-/* grn_ts_geo_point_output() outputs a value. */
-static grn_rc
-grn_ts_geo_point_output(grn_ctx *ctx, grn_ts_geo_point value) {
-  grn_rc rc = grn_bulk_write(ctx, ctx->impl->outbuf, "\"", 1);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  rc = grn_text_itoa(ctx, ctx->impl->outbuf, value.latitude);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  rc = grn_bulk_write(ctx, ctx->impl->outbuf, "x", 1);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  rc = grn_text_itoa(ctx, ctx->impl->outbuf, value.longitude);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  return grn_bulk_write(ctx, ctx->impl->outbuf, "\"", 1);
-}
-
-#define GRN_TS_VECTOR_OUTPUT(kind)\
-  size_t i;\
-  grn_rc rc = grn_bulk_write(ctx, ctx->impl->outbuf, "[", 1);\
-  if (rc != GRN_SUCCESS) {\
-    return rc;\
-  }\
-  for (i = 0; i < value.size; ++i) {\
-    if (i) {\
-      rc = grn_bulk_write(ctx, ctx->impl->outbuf, ",", 1);\
-      if (rc != GRN_SUCCESS) {\
-        return rc;\
-      }\
-    }\
-    rc = grn_ts_ ## kind ## _output(ctx, value.ptr[i]);\
-    if (rc != GRN_SUCCESS) {\
-      return rc;\
-    }\
-  }\
-  return grn_bulk_write(ctx, ctx->impl->outbuf, "]", 1);
-/* grn_ts_bool_vector_output() outputs a value. */
-static grn_rc
-grn_ts_bool_vector_output(grn_ctx *ctx, grn_ts_bool_vector value) {
-  GRN_TS_VECTOR_OUTPUT(bool)
-}
-
-/* grn_ts_int_vector_output() outputs a value. */
-static grn_rc
-grn_ts_int_vector_output(grn_ctx *ctx, grn_ts_int_vector value) {
-  GRN_TS_VECTOR_OUTPUT(int)
-}
-
-/* grn_ts_float_vector_output() outputs a value. */
-static grn_rc
-grn_ts_float_vector_output(grn_ctx *ctx, grn_ts_float_vector value) {
-  GRN_TS_VECTOR_OUTPUT(float)
-}
-
-/* grn_ts_time_vector_output() outputs a value. */
-static grn_rc
-grn_ts_time_vector_output(grn_ctx *ctx, grn_ts_time_vector value) {
-  GRN_TS_VECTOR_OUTPUT(time)
-}
-
-/* grn_ts_text_vector_output() outputs a value. */
-static grn_rc
-grn_ts_text_vector_output(grn_ctx *ctx, grn_ts_text_vector value) {
-  GRN_TS_VECTOR_OUTPUT(text)
-}
-
-/* grn_ts_geo_point_vector_output() outputs a value. */
-static grn_rc
-grn_ts_geo_point_vector_output(grn_ctx *ctx, grn_ts_geo_point_vector value) {
-  GRN_TS_VECTOR_OUTPUT(geo_point)
-}
-#undef GRN_TS_VECTOR_OUTPUT
-
 /* 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) {
@@ -7046,8 +6923,7 @@ grn_ts_expr_complete(grn_ctx *ctx, grn_ts_expr *expr) {
   return GRN_SUCCESS;
 }
 
-/* grn_ts_expr_evaluate_to_buf() evaluates an expression. */
-static grn_rc
+grn_rc
 grn_ts_expr_evaluate_to_buf(grn_ctx *ctx, grn_ts_expr *expr,
                             const grn_ts_record *in, size_t n_in,
                             grn_ts_buf *out) {
@@ -7102,606 +6978,3 @@ grn_ts_expr_adjust(grn_ctx *ctx, grn_ts_expr *expr,
   }
   return grn_ts_expr_node_adjust(ctx, expr->root, io, n_io);
 }
-
-/*-------------------------------------------------------------
- * grn_ts_writer.
- */
-
-typedef struct {
-  grn_ts_expr **exprs;
-  size_t n_exprs;
-  size_t max_n_exprs;
-  grn_obj name_buf;
-  grn_ts_str *names;
-  grn_ts_buf *bufs;
-} grn_ts_writer;
-
-/* grn_ts_writer_init() initializes a writer. */
-static void
-grn_ts_writer_init(grn_ctx *ctx, grn_ts_writer *writer) {
-  memset(writer, 0, sizeof(*writer));
-  writer->exprs = NULL;
-  GRN_TEXT_INIT(&writer->name_buf, GRN_OBJ_VECTOR);
-  writer->names = NULL;
-  writer->bufs = NULL;
-}
-
-/* grn_ts_writer_fin() finalizes a writer. */
-static void
-grn_ts_writer_fin(grn_ctx *ctx, grn_ts_writer *writer) {
-  size_t i;
-  if (writer->bufs) {
-    for (i = 0; i < writer->n_exprs; i++) {
-      grn_ts_buf_fin(ctx, &writer->bufs[i]);
-    }
-    GRN_FREE(writer->bufs);
-  }
-  if (writer->names) {
-    GRN_FREE(writer->names);
-  }
-  GRN_OBJ_FIN(ctx, &writer->name_buf);
-  if (writer->exprs) {
-    for (i = 0; i < writer->n_exprs; i++) {
-      grn_ts_expr_close(ctx, writer->exprs[i]);
-    }
-    GRN_FREE(writer->exprs);
-  }
-}
-
-/*
- * grn_ts_writer_tokenize() extracts the first expression string.
- * If the input is empty, this function returns GRN_END_OF_DATA.
- */
-static grn_rc
-grn_ts_writer_tokenize(grn_ctx *ctx, grn_ts_writer *writer,
-                       grn_ts_str in, grn_ts_str *token, grn_ts_str *rest) {
-  size_t i;
-  char stack_top;
-  grn_rc rc = GRN_SUCCESS;
-  grn_ts_str str = in;
-  grn_ts_buf stack;
-
-  /* Find a non-empty token. */
-  grn_ts_buf_init(ctx, &stack);
-  for ( ; ; ) {
-    str = grn_ts_str_trim_left(str);
-    if (!str.size) {
-      rc = GRN_END_OF_DATA;
-      break;
-    }
-    for (i = 0; i < str.size; i++) {
-      if (stack.pos) {
-        if (str.ptr[i] == stack_top) {
-          if (--stack.pos) {
-            stack_top = ((char *)stack.ptr)[stack.pos - 1];
-          }
-          continue;
-        }
-        if (stack_top == '"') {
-          /* Skip the next byte of an escape character. */
-          if ((str.ptr[i] == '\\') && (i < (str.size - 1))) {
-            i++;
-          }
-          continue;
-        }
-      } else if (str.ptr[i] == ',') {
-        break;
-      }
-      switch (str.ptr[i]) {
-        case '(': {
-          stack_top = ')';
-          rc = grn_ts_buf_write(ctx, &stack, &stack_top, 1);
-          break;
-        }
-        case '[': {
-          stack_top = ']';
-          rc = grn_ts_buf_write(ctx, &stack, &stack_top, 1);
-          break;
-        }
-        case '{': {
-          stack_top = '}';
-          rc = grn_ts_buf_write(ctx, &stack, &stack_top, 1);
-          break;
-        }
-        case '"': {
-          stack_top = '"';
-          rc = grn_ts_buf_write(ctx, &stack, &stack_top, 1);
-          break;
-        }
-      }
-      if (rc != GRN_SUCCESS) {
-        break;
-      }
-    }
-    if (rc != GRN_SUCCESS) {
-      break;
-    }
-    if (i) {
-      /* Output the result. */
-      token->ptr = str.ptr;
-      token->size = i;
-      if (token->size == str.size) {
-        rest->ptr = str.ptr + str.size;
-        rest->size = 0;
-      } else {
-        rest->ptr = str.ptr + token->size + 1;
-        rest->size = str.size - token->size - 1;
-      }
-      break;
-    }
-    str.ptr++;
-    str.size--;
-  }
-  grn_ts_buf_fin(ctx, &stack);
-  return rc;
-}
-
-/* grn_ts_writer_expand() expands a wildcard. */
-static grn_rc
-grn_ts_writer_expand(grn_ctx *ctx, grn_ts_writer *writer,
-                     grn_obj *table, grn_ts_str str) {
-  grn_rc rc = GRN_SUCCESS;
-  grn_hash_cursor *cursor;
-  grn_hash *hash = grn_hash_create(ctx, NULL, sizeof(grn_ts_id), 0,
-                                   GRN_OBJ_TABLE_HASH_KEY | GRN_HASH_TINY);
-  if (!hash) {
-    return GRN_INVALID_ARGUMENT;
-  }
-  grn_table_columns(ctx, table, str.ptr, str.size - 1, (grn_obj *)hash);
-  if (ctx->rc != GRN_SUCCESS) {
-    return ctx->rc;
-  }
-  cursor = grn_hash_cursor_open(ctx, hash, NULL, 0, NULL, 0, 0, -1, 0);
-  if (!cursor) {
-    rc = GRN_INVALID_ARGUMENT;
-  } else {
-    while (grn_hash_cursor_next(ctx, cursor) != GRN_ID_NIL) {
-      char name_buf[GRN_TABLE_MAX_KEY_SIZE];
-      size_t name_size;
-      grn_obj *column;
-      grn_ts_id *column_id;
-      if (!grn_hash_cursor_get_key(ctx, cursor, (void **)&column_id)) {
-        rc = GRN_INVALID_ARGUMENT;
-        break;
-      }
-      column = grn_ctx_at(ctx, *column_id);
-      if (!column) {
-        rc = GRN_INVALID_ARGUMENT;
-        break;
-      }
-      name_size = grn_column_name(ctx, column, name_buf, sizeof(name_buf));
-      grn_obj_unlink(ctx, column);
-      rc = grn_vector_add_element(ctx, &writer->name_buf,
-                                  name_buf, name_size, 0, GRN_DB_TEXT);
-      if (rc != GRN_SUCCESS) {
-        break;
-      }
-    }
-    grn_hash_cursor_close(ctx, cursor);
-  }
-  grn_hash_close(ctx, hash);
-  return rc;
-}
-
-/* grn_ts_writer_parse() parses output expressions. */
-static grn_rc
-grn_ts_writer_parse(grn_ctx *ctx, grn_ts_writer *writer,
-                    grn_obj *table, grn_ts_str str) {
-  grn_rc rc;
-  grn_ts_str rest = str;
-  for ( ; ; ) {
-    grn_ts_str token = { NULL, 0 };
-    rc = grn_ts_writer_tokenize(ctx, writer, rest, &token, &rest);
-    if (rc != GRN_SUCCESS) {
-      return (rc == GRN_END_OF_DATA) ? GRN_SUCCESS : rc;
-    }
-    if ((token.ptr[token.size - 1] == '*') &&
-        grn_ts_str_is_name_prefix((grn_ts_str){ token.ptr, token.size - 1 })) {
-      rc = grn_ts_writer_expand(ctx, writer, table, token);
-      if (rc != GRN_SUCCESS) {
-        return rc;
-      }
-    } else if (grn_ts_str_is_key_name(token) &&
-               !grn_ts_table_has_key(ctx, table)) {
-      /*
-       * Skip _key if the table has no _key, because the default output_columns
-       * option contains _key.
-       */
-      GRN_TS_DEBUG("skip \"_key\" because the table has no _key");
-    } else {
-      rc = grn_vector_add_element(ctx, &writer->name_buf,
-                                  token.ptr, token.size, 0, GRN_DB_TEXT);
-      if (rc != GRN_SUCCESS) {
-        return rc;
-      }
-    }
-  }
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_writer_build() builds output expresions. */
-static grn_rc
-grn_ts_writer_build(grn_ctx *ctx, grn_ts_writer *writer, grn_obj *table) {
-  size_t i, n_names = grn_vector_size(ctx, &writer->name_buf);
-  if (!n_names) {
-    return GRN_SUCCESS;
-  }
-  writer->names = GRN_MALLOCN(grn_ts_str, n_names);
-  if (!writer->names) {
-    GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE, "GRN_MALLOCN failed: %zu x %zu",
-                      sizeof(grn_ts_str), n_names);
-  }
-  writer->exprs = GRN_MALLOCN(grn_ts_expr *, n_names);
-  if (!writer->exprs) {
-    GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE, "GRN_MALLOCN failed: %zu x %zu",
-                      sizeof(grn_ts_expr *), n_names);
-  }
-  for (i = 0; i < n_names; i++) {
-    grn_rc rc;
-    grn_ts_expr *new_expr;
-    const char *name_ptr;
-    size_t name_size = grn_vector_get_element(ctx, &writer->name_buf, i,
-                                              &name_ptr, NULL, NULL);
-    rc = grn_ts_expr_parse(ctx, table, name_ptr, name_size, &new_expr);
-    if (rc != GRN_SUCCESS) {
-      return rc;
-    }
-    writer->names[i].ptr = name_ptr;
-    writer->names[i].size = name_size;
-    writer->exprs[i] = new_expr;
-    writer->n_exprs++;
-  }
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_writer_open() creates a writer. */
-static grn_rc
-grn_ts_writer_open(grn_ctx *ctx, grn_obj *table, grn_ts_str str,
-                   grn_ts_writer **writer) {
-  grn_rc rc;
-  grn_ts_writer *new_writer = GRN_MALLOCN(grn_ts_writer, 1);
-  if (!new_writer) {
-    GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE, "GRN_MALLOCN failed: %zu x 1",
-                      sizeof(grn_ts_writer));
-  }
-  grn_ts_writer_init(ctx, new_writer);
-  rc = grn_ts_writer_parse(ctx, new_writer, table, str);
-  if (rc == GRN_SUCCESS) {
-    rc = grn_ts_writer_build(ctx, new_writer, table);
-  }
-  if (rc != GRN_SUCCESS) {
-    grn_ts_writer_fin(ctx, new_writer);
-    GRN_FREE(new_writer);
-    return rc;
-  }
-  *writer = new_writer;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_writer_close() destroys a writer. */
-static void
-grn_ts_writer_close(grn_ctx *ctx, grn_ts_writer *writer) {
-  grn_ts_writer_fin(ctx, writer);
-  GRN_FREE(writer);
-}
-
-/* TODO: Errors of output macros, such as GRN_TEXT_*(), are ignored. */
-
-#define GRN_TS_WRITER_OUTPUT_HEADER_CASE(TYPE, name)\
-  case GRN_DB_ ## TYPE: {\
-    GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, name);\
-    break;\
-  }
-/* grn_ts_writer_output_header() outputs names and data types. */
-static grn_rc
-grn_ts_writer_output_header(grn_ctx *ctx, grn_ts_writer *writer) {
-  grn_rc rc;
-  GRN_OUTPUT_ARRAY_OPEN("COLUMNS", writer->n_exprs);
-  for (size_t i = 0; i < writer->n_exprs; ++i) {
-    GRN_OUTPUT_ARRAY_OPEN("COLUMN", 2);
-    rc = grn_text_esc(ctx, ctx->impl->outbuf,
-                      writer->names[i].ptr, writer->names[i].size);
-    if (rc != GRN_SUCCESS) {
-      return rc;
-    }
-    GRN_TEXT_PUT(ctx, ctx->impl->outbuf, ",\"", 2);
-    switch (writer->exprs[i]->data_type) {
-      case GRN_DB_VOID: {
-        if (writer->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;
-      }
-      GRN_TS_WRITER_OUTPUT_HEADER_CASE(BOOL, "Bool")
-      GRN_TS_WRITER_OUTPUT_HEADER_CASE(INT8, "Int8")
-      GRN_TS_WRITER_OUTPUT_HEADER_CASE(INT16, "Int16")
-      GRN_TS_WRITER_OUTPUT_HEADER_CASE(INT32, "Int32")
-      GRN_TS_WRITER_OUTPUT_HEADER_CASE(INT64, "Int64")
-      GRN_TS_WRITER_OUTPUT_HEADER_CASE(UINT8, "UInt8")
-      GRN_TS_WRITER_OUTPUT_HEADER_CASE(UINT16, "UInt16")
-      GRN_TS_WRITER_OUTPUT_HEADER_CASE(UINT32, "UInt32")
-      GRN_TS_WRITER_OUTPUT_HEADER_CASE(UINT64, "UInt64")
-      GRN_TS_WRITER_OUTPUT_HEADER_CASE(FLOAT, "Float")
-      GRN_TS_WRITER_OUTPUT_HEADER_CASE(TIME, "Time")
-      GRN_TS_WRITER_OUTPUT_HEADER_CASE(SHORT_TEXT, "ShortText")
-      GRN_TS_WRITER_OUTPUT_HEADER_CASE(TEXT, "Text")
-      GRN_TS_WRITER_OUTPUT_HEADER_CASE(LONG_TEXT, "LongText")
-      GRN_TS_WRITER_OUTPUT_HEADER_CASE(TOKYO_GEO_POINT, "TokyoGeoPoint")
-      GRN_TS_WRITER_OUTPUT_HEADER_CASE(WGS84_GEO_POINT, "WGS84GeoPoint")
-      default: {
-        char name_buf[GRN_TABLE_MAX_KEY_SIZE];
-        size_t name_size;
-        grn_obj *obj = grn_ctx_at(ctx, writer->exprs[i]->data_type);
-        if (!obj) {
-          GRN_TS_ERR_RETURN(GRN_UNKNOWN_ERROR, "grn_ctx_at failed: %d",
-                            writer->exprs[i]->data_type);
-        }
-        if (!grn_ts_obj_is_table(ctx, obj)) {
-          grn_obj_unlink(ctx, obj);
-          GRN_TS_ERR_RETURN(GRN_UNKNOWN_ERROR, "not table: %d",
-                            writer->exprs[i]->data_type);
-        }
-        name_size = grn_obj_name(ctx, obj, name_buf, sizeof(name_buf));
-        GRN_TEXT_PUT(ctx, ctx->impl->outbuf, name_buf, name_size);
-        grn_obj_unlink(ctx, obj);
-        break;
-      }
-    }
-    GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, '"');
-    GRN_OUTPUT_ARRAY_CLOSE();
-  }
-  GRN_OUTPUT_ARRAY_CLOSE(); /* COLUMNS. */
-  return GRN_SUCCESS;
-}
-#undef GRN_TS_WRITER_OUTPUT_HEADER_CASE
-
-#define GRN_TS_WRITER_OUTPUT_BODY_CASE(KIND, kind)\
-  case GRN_TS_ ## KIND: {\
-    grn_ts_ ## kind *value = (grn_ts_ ## kind *)writer->bufs[j].ptr;\
-    grn_ts_ ## kind ## _output(ctx, value[i]);\
-    break;\
-  }
-#define GRN_TS_WRITER_OUTPUT_BODY_VECTOR_CASE(KIND, kind)\
-  GRN_TS_WRITER_OUTPUT_BODY_CASE(KIND ## _VECTOR, kind ## _vector)
-/*
- * grn_ts_writer_output_body() evaluates expressions and outputs the results.
- */
-static grn_rc
-grn_ts_writer_output_body(grn_ctx *ctx, grn_ts_writer *writer,
-                          const grn_ts_record *in, size_t n_in) {
-  size_t i, j, count = 0;
-  writer->bufs = GRN_MALLOCN(grn_ts_buf, writer->n_exprs);
-  if (!writer->bufs) {
-    GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE, "GRN_MALLOCN failed: %zu x %zu",
-                      sizeof(grn_ts_buf), writer->n_exprs);
-  }
-  for (i = 0; i < writer->n_exprs; i++) {
-    grn_ts_buf_init(ctx, &writer->bufs[i]);
-  }
-  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 < writer->n_exprs; ++i) {
-      grn_rc rc = grn_ts_expr_evaluate_to_buf(ctx, writer->exprs[i], in + count,
-                                              batch_size, &writer->bufs[i]);
-      if (rc != GRN_SUCCESS) {
-        return rc;
-      }
-    }
-    for (i = 0; i < batch_size; ++i) {
-      GRN_OUTPUT_ARRAY_OPEN("HIT", writer->n_exprs);
-      for (j = 0; j < writer->n_exprs; ++j) {
-        if (j) {
-          GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ',');
-        }
-        switch (writer->exprs[j]->data_kind) {
-          GRN_TS_WRITER_OUTPUT_BODY_CASE(BOOL, bool);
-          GRN_TS_WRITER_OUTPUT_BODY_CASE(INT, int);
-          GRN_TS_WRITER_OUTPUT_BODY_CASE(FLOAT, float);
-          GRN_TS_WRITER_OUTPUT_BODY_CASE(TIME, time);
-          GRN_TS_WRITER_OUTPUT_BODY_CASE(TEXT, text);
-          GRN_TS_WRITER_OUTPUT_BODY_CASE(GEO_POINT, geo_point);
-          GRN_TS_WRITER_OUTPUT_BODY_VECTOR_CASE(BOOL, bool);
-          GRN_TS_WRITER_OUTPUT_BODY_VECTOR_CASE(INT, int);
-          GRN_TS_WRITER_OUTPUT_BODY_VECTOR_CASE(FLOAT, float);
-          GRN_TS_WRITER_OUTPUT_BODY_VECTOR_CASE(TIME, time);
-          GRN_TS_WRITER_OUTPUT_BODY_VECTOR_CASE(TEXT, text);
-          GRN_TS_WRITER_OUTPUT_BODY_VECTOR_CASE(GEO_POINT, geo_point);
-          default: {
-            break;
-          }
-        }
-      }
-      GRN_OUTPUT_ARRAY_CLOSE(); /* HITS. */
-    }
-    count += batch_size;
-  }
-  return GRN_SUCCESS;
-}
-#undef GRN_TS_WRITER_OUTPUT_BODY_VECTOR_CASE
-#undef GRN_TS_WRITER_OUTPUT_BODY_CASE
-
-/* grn_ts_writer_output() outputs search results into the output buffer. */
-static grn_rc
-grn_ts_writer_output(grn_ctx *ctx, grn_ts_writer *writer,
-                     const grn_ts_record *in, size_t n_in, size_t n_hits) {
-  grn_rc rc;
-  GRN_OUTPUT_ARRAY_OPEN("RESULT", 1);
-  GRN_OUTPUT_ARRAY_OPEN("RESULTSET", 2 + n_in);
-  GRN_OUTPUT_ARRAY_OPEN("NHITS", 1);
-  rc = grn_text_ulltoa(ctx, ctx->impl->outbuf, n_hits);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  GRN_OUTPUT_ARRAY_CLOSE(); /* NHITS. */
-  rc = grn_ts_writer_output_header(ctx, writer);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  rc = grn_ts_writer_output_body(ctx, writer, in, n_in);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  GRN_OUTPUT_ARRAY_CLOSE(); /* RESULTSET. */
-  GRN_OUTPUT_ARRAY_CLOSE(); /* RESET. */
-  return GRN_SUCCESS;
-}
-
-/*-------------------------------------------------------------
- * 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, grn_ts_str str,
-                     size_t offset, size_t limit,
-                     grn_ts_record **out, size_t *n_out, size_t *n_hits) {
-  grn_rc 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.ptr, 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) {
-          GRN_TS_ERR(GRN_NO_MEMORY_AVAILABLE,
-                     "GRN_REALLOC failed: %zu", n_bytes);
-          rc = ctx->rc;
-          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);
-          grn_memmove(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;
-    }
-    /* Ignore a failure of destruction. */
-    grn_ts_expr_close(ctx, expr);
-  }
-  /* Ignore a failure of  destruction. */
-  grn_table_cursor_close(ctx, cursor);
-
-  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. */
-static grn_rc
-grn_ts_select_output(grn_ctx *ctx, grn_obj *table, grn_ts_str str,
-                     const grn_ts_record *in, size_t n_in, size_t n_hits) {
-  grn_ts_writer *writer;
-  grn_rc rc = grn_ts_writer_open(ctx, table, str, &writer);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  rc = grn_ts_writer_output(ctx, writer, in, n_in, n_hits);
-  grn_ts_writer_close(ctx, writer);
-  return rc;
-}
-
-grn_rc
-grn_ts_select(grn_ctx *ctx, grn_obj *table,
-              const char *filter_ptr, size_t filter_size,
-              const char *output_columns_ptr, size_t output_columns_size,
-              size_t offset, size_t limit) {
-  grn_rc rc;
-  grn_ts_str filter = { filter_ptr, filter_size };
-  grn_ts_str output_columns = { output_columns_ptr, output_columns_size };
-  grn_ts_record *records = NULL;
-  size_t n_records, n_hits;
-  if (!ctx || !table || !grn_ts_obj_is_table(ctx, table) ||
-      (!filter_ptr && filter_size) ||
-      (!output_columns_ptr && output_columns_size)) {
-    return GRN_INVALID_ARGUMENT;
-  }
-  rc = grn_ts_select_filter(ctx, table, filter, offset, limit,
-                            &records, &n_records, &n_hits);
-  if (rc == GRN_SUCCESS) {
-    rc = grn_ts_select_output(ctx, table, output_columns,
-                              records, n_records, n_hits);
-  }
-  if (records) {
-    GRN_FREE(records);
-  }
-  if (rc != GRN_SUCCESS) {
-    GRN_BULK_REWIND(ctx->impl->outbuf);
-    if ((ctx->rc == GRN_SUCCESS) || !ctx->errbuf[0]) {
-      ERR(rc, "error message is missing");
-    } else if (ctx->errlvl < GRN_LOG_ERROR) {
-      ctx->errlvl = GRN_LOG_ERROR;
-    }
-  }
-  return rc;
-}

  Copied: lib/ts/ts_expr.h (+10 -85) 85%
===================================================================
--- lib/grn_ts.h    2015-11-09 13:36:05 +0900 (c815433)
+++ lib/ts/ts_expr.h    2015-11-09 14:12:30 +0900 (9344fce)
@@ -16,13 +16,14 @@
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
 
-#ifndef GRN_TS_H
-#define GRN_TS_H
+#ifndef GRN_TS_EXPR_H
+#define GRN_TS_EXPR_H
 
-#include <stddef.h>
 #include <stdint.h>
 
-#include "grn.h"
+#include "../grn_ts.h"
+
+#include "ts_buf.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -111,64 +112,6 @@ typedef enum {
 } grn_ts_expr_node_type;
 
 /*-------------------------------------------------------------
- * Built-in data types.
- */
-
-/* ID (_id), score (_score), and record types. */
-typedef grn_id grn_ts_id;
-typedef float grn_ts_score;
-typedef struct {
-  grn_ts_id id;
-  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;
-typedef int64_t grn_ts_time;
-typedef struct {
-  const char *ptr;
-  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 grn_ts_text *ptr;
-  size_t size;
-} 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.
  */
 
@@ -355,6 +298,10 @@ 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_evaluate_to_buf() evaluates an expression. */
+grn_rc grn_ts_expr_evaluate_to_buf(grn_ctx *ctx, grn_ts_expr *expr,
+                                   const grn_ts_record *in, size_t n_in,
+                                   grn_ts_buf *out);
 
 /* grn_ts_expr_filter() filters records. */
 grn_rc grn_ts_expr_filter(grn_ctx *ctx, grn_ts_expr *expr,
@@ -365,30 +312,8 @@ grn_rc grn_ts_expr_filter(grn_ctx *ctx, grn_ts_expr *expr,
 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 and writes the values
- * of output columns (the evaluation results of output expressions) into the
- * output buffer (`ctx->impl->outbuf`).
- *
- * Note that the first `offset` records will be discarded and at most `limit`
- * records will be output.
- *
- * On success, grn_ts_select() returns GRN_SUCCESS.
- * On failure, grn_ts_select() returns an error code and set the details into
- * `ctx`.
- */
-grn_rc grn_ts_select(grn_ctx *ctx, grn_obj *table,
-                     const char *filter_ptr, size_t filter_size,
-                     const char *output_columns_ptr,
-                     size_t output_columns_size,
-                     size_t offset, size_t limit);
-
 #ifdef __cplusplus
 }
 #endif
 
-#endif /* GRN_TS_H */
+#endif /* GRN_TS_EXPR_H */




More information about the Groonga-commit mailing list
Back to archive index