[Groonga-commit] groonga/groonga at dfafbd5 [master] grn_ts: separate implementations of expression nodes

Back to archive index

susumu.yata null+****@clear*****
Wed Sep 9 07:27:21 JST 2015


susumu.yata	2015-09-09 07:27:21 +0900 (Wed, 09 Sep 2015)

  New Revision: dfafbd56a608213c421e6bcf6b7930413141a86a
  https://github.com/groonga/groonga/commit/dfafbd56a608213c421e6bcf6b7930413141a86a

  Message:
    grn_ts: separate implementations of expression nodes

  Modified files:
    lib/ts.c

  Modified: lib/ts.c (+784 -752)
===================================================================
--- lib/ts.c    2015-09-09 01:10:12 +0900 (d7506f1)
+++ lib/ts.c    2015-09-09 07:27:21 +0900 (25f64ca)
@@ -690,136 +690,13 @@ grn_ts_table_get_value(grn_ctx *ctx, grn_obj *table, grn_id id) {
 }
 
 /*-------------------------------------------------------------
- * grn_ts_expr_node.
+ * grn_ts_expr_id_node.
  */
 
 typedef struct {
   GRN_TS_EXPR_NODE_COMMON_MEMBERS
 } grn_ts_expr_id_node;
 
-typedef struct {
-  GRN_TS_EXPR_NODE_COMMON_MEMBERS
-} grn_ts_expr_score_node;
-
-typedef struct {
-  GRN_TS_EXPR_NODE_COMMON_MEMBERS
-  grn_obj *table;
-  grn_ts_buf buf;
-} grn_ts_expr_key_node;
-
-typedef struct {
-  GRN_TS_EXPR_NODE_COMMON_MEMBERS
-  grn_obj *table;
-} grn_ts_expr_value_node;
-
-typedef struct {
-  GRN_TS_EXPR_NODE_COMMON_MEMBERS
-  union {
-    grn_ts_bool bool_value;
-    grn_ts_int int_value;
-    grn_ts_float float_value;
-    grn_ts_time time_value;
-    grn_ts_text text_value;
-    grn_ts_geo_point geo_point_value;
-    grn_ts_bool_vector bool_vector_value;
-    grn_ts_int_vector int_vector_value;
-    grn_ts_float_vector float_vector_value;
-    grn_ts_time_vector time_vector_value;
-    grn_ts_text_vector text_vector_value;
-    grn_ts_geo_point_vector geo_point_vector_value;
-  } content;
-  char *text_buf;
-  void *vector_buf;
-} grn_ts_expr_const_node;
-
-typedef struct {
-  GRN_TS_EXPR_NODE_COMMON_MEMBERS
-  grn_obj *column;
-  grn_ts_buf buf;
-  grn_ts_buf body_buf;
-} grn_ts_expr_column_node;
-
-typedef struct {
-  GRN_TS_EXPR_NODE_COMMON_MEMBERS
-  grn_ts_op_type op_type;
-  grn_ts_expr_node **args;
-  size_t n_args;
-  void *buf;
-  size_t buf_size; /* Size in bytes. */
-  // TODO
-} grn_ts_expr_op_node;
-
-/* grn_ts_expr_node_fin() finalizes a node. */
-static grn_rc
-grn_ts_expr_node_fin(grn_ctx *ctx, grn_ts_expr_node *node) {
-  switch (node->type) {
-    case GRN_TS_EXPR_ID_NODE:
-    case GRN_TS_EXPR_SCORE_NODE: {
-      return GRN_SUCCESS;
-    }
-    case GRN_TS_EXPR_KEY_NODE: {
-      grn_ts_expr_key_node *key_node = (grn_ts_expr_key_node *)node;
-      grn_ts_buf_fin(ctx, &key_node->buf);
-      if (key_node->table) {
-        grn_obj_unlink(ctx, key_node->table);
-      }
-      return GRN_SUCCESS;
-    }
-    case GRN_TS_EXPR_VALUE_NODE: {
-      grn_ts_expr_value_node *value_node = (grn_ts_expr_value_node *)node;
-      if (value_node->table) {
-        grn_obj_unlink(ctx, value_node->table);
-      }
-      return GRN_SUCCESS;
-    }
-    case GRN_TS_EXPR_CONST_NODE: {
-      grn_ts_expr_const_node *const_node = (grn_ts_expr_const_node *)node;
-      if (const_node->vector_buf) {
-        GRN_FREE(const_node->vector_buf);
-      }
-      if (const_node->text_buf) {
-        GRN_FREE(const_node->text_buf);
-      }
-      return GRN_SUCCESS;
-    }
-    case GRN_TS_EXPR_COLUMN_NODE: {
-      grn_ts_expr_column_node *column_node = (grn_ts_expr_column_node *)node;
-      grn_ts_buf_fin(ctx, &column_node->body_buf);
-      grn_ts_buf_fin(ctx, &column_node->buf);
-      if (column_node->column) {
-        grn_obj_unlink(ctx, column_node->column);
-      }
-      return GRN_SUCCESS;
-    }
-    case GRN_TS_EXPR_OP_NODE: {
-      grn_ts_expr_op_node *op_node = (grn_ts_expr_op_node *)node;
-      // TODO: Free memory.
-      if (op_node->buf) {
-        GRN_FREE(op_node->buf);
-      }
-      if (op_node->args) {
-        GRN_FREE(op_node->args);
-      }
-      return GRN_SUCCESS;
-    }
-    default: {
-      return GRN_INVALID_ARGUMENT;
-    }
-  }
-}
-
-/* grn_ts_expr_node_close() destroys a node. */
-static grn_rc
-grn_ts_expr_node_close(grn_ctx *ctx, grn_ts_expr_node *node) {
-  grn_rc rc;
-  if (!node) {
-    return GRN_SUCCESS;
-  }
-  rc = grn_ts_expr_node_fin(ctx, node);
-  GRN_FREE(node);
-  return rc;
-}
-
 /* grn_ts_expr_id_node_open() creates a node associated with ID (_id). */
 static grn_rc
 grn_ts_expr_id_node_open(grn_ctx *ctx, grn_ts_expr_node **node) {
@@ -834,6 +711,27 @@ grn_ts_expr_id_node_open(grn_ctx *ctx, grn_ts_expr_node **node) {
   return GRN_SUCCESS;
 }
 
+/* grn_ts_expr_id_node_evaluate() outputs IDs. */
+static grn_rc
+grn_ts_expr_id_node_evaluate(grn_ctx *ctx, grn_ts_expr_id_node *node,
+                             const grn_ts_record *in, size_t n_in,
+                             void *out) {
+  size_t i;
+  grn_ts_int *out_ptr = (grn_ts_int *)out;
+  for (i = 0; i < n_in; i++) {
+    out_ptr[i] = (grn_ts_int)in[i].id;
+  }
+  return GRN_SUCCESS;
+}
+
+/*-------------------------------------------------------------
+ * grn_ts_expr_score_node.
+ */
+
+typedef struct {
+  GRN_TS_EXPR_NODE_COMMON_MEMBERS
+} grn_ts_expr_score_node;
+
 /*
  * grn_ts_expr_score_node_open() creates a node associated with score
  * (_score).
@@ -851,6 +749,37 @@ grn_ts_expr_score_node_open(grn_ctx *ctx, grn_ts_expr_node **node) {
   return GRN_SUCCESS;
 }
 
+/* grn_ts_expr_score_node_evaluate() outputs scores. */
+static grn_rc
+grn_ts_expr_score_node_evaluate(grn_ctx *ctx, grn_ts_expr_score_node *node,
+                                const grn_ts_record *in, size_t n_in,
+                                void *out) {
+  size_t i;
+  grn_ts_float *out_ptr = (grn_ts_float *)out;
+  for (i = 0; i < n_in; i++) {
+    out_ptr[i] = (grn_ts_float)in[i].score;
+  }
+  return GRN_SUCCESS;
+}
+
+/* grn_ts_expr_score_node_adjust() updates scores. */
+static grn_rc
+grn_ts_expr_score_node_adjust(grn_ctx *ctx, grn_ts_expr_score_node *node,
+                              grn_ts_record *io, size_t n_io) {
+  /* Nothing to do. */
+  return GRN_SUCCESS;
+}
+
+/*-------------------------------------------------------------
+ * grn_ts_expr_key_node.
+ */
+
+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_open() creates a node associated with key (_key). */
 static grn_rc
 grn_ts_expr_key_node_open(grn_ctx *ctx, grn_obj *table,
@@ -878,487 +807,468 @@ grn_ts_expr_key_node_open(grn_ctx *ctx, grn_obj *table,
   return GRN_SUCCESS;
 }
 
-/*
- * grn_ts_expr_value_node_open() creates a node associated with value
- * (_value).
- */
-static grn_rc
-grn_ts_expr_value_node_open(grn_ctx *ctx, grn_obj *table,
-                            grn_ts_expr_node **node) {
-  grn_rc rc;
-  grn_ts_expr_value_node *new_node;
-  if (!grn_ts_table_has_value(ctx, table)) {
-    return GRN_INVALID_ARGUMENT;
-  }
-  new_node = GRN_MALLOCN(grn_ts_expr_value_node, 1);
-  if (!new_node) {
-    return GRN_NO_MEMORY_AVAILABLE;
-  }
-  memset(new_node, 0, sizeof(*new_node));
-  rc = grn_ts_obj_increment_ref_count(ctx, table);
-  if (rc != GRN_SUCCESS) {
-    GRN_FREE(new_node);
-    return rc;
-  }
-  new_node->type = GRN_TS_EXPR_VALUE_NODE;
-  new_node->data_kind = grn_ts_data_type_to_kind(DB_OBJ(table)->range);
-  new_node->data_type = DB_OBJ(table)->range;
-  new_node->table = table;
-  *node = (grn_ts_expr_node *)new_node;
-  return GRN_SUCCESS;
-}
-
-#define GRN_TS_EXPR_CONST_NODE_OPEN_CASE_BLOCK(KIND, kind)\
+#define GRN_TS_EXPR_KEY_NODE_EVALUATE_CASE_BLOCK(KIND, kind)\
   case GRN_TS_ ## KIND: {\
-    node->content.kind ## _value = *(const grn_ts_ ## kind *)value;\
+    size_t i;\
+    grn_ts_ ## kind *out_ptr = (grn_ts_ ## kind *)out;\
+    for (i = 0; i < n_in; i++) {\
+      const grn_ts_ ## kind *key;\
+      size_t key_size;\
+      key = (const grn_ts_ ## kind *)grn_ts_table_get_key(ctx, node->table,\
+                                                          in[i].id,\
+                                                          &key_size);\
+      if (key && (key_size == sizeof(*key))) {\
+        out_ptr[i] = *key;\
+      } else {\
+        out_ptr[i] = grn_ts_ ## kind ## _zero();\
+      }\
+    }\
     return GRN_SUCCESS;\
   }
-/* grn_ts_expr_const_node_init_scalar() initializes a const scalar node. */
+#define GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE_BLOCK(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 type ## _t *key;\
+      size_t key_size;\
+      key = (const type ## _t *)grn_ts_table_get_key(ctx, node->table,\
+                                                     in[i].id, &key_size);\
+      if (key && (key_size == sizeof(*key))) {\
+        out_ptr[i] = (grn_ts_int)*key;\
+      } else {\
+        out_ptr[i] = grn_ts_int_zero();\
+      }\
+    }\
+    return GRN_SUCCESS;\
+  }
+/* grn_ts_expr_key_node_evaluate() outputs keys. */
 static grn_rc
-grn_ts_expr_const_node_init_scalar(grn_ctx *ctx, grn_ts_expr_const_node *node,
-                                   const void *value) {
+grn_ts_expr_key_node_evaluate(grn_ctx *ctx, grn_ts_expr_key_node *node,
+                              const grn_ts_record *in, size_t n_in,
+                              void *out) {
   switch (node->data_kind) {
-    GRN_TS_EXPR_CONST_NODE_OPEN_CASE_BLOCK(BOOL, bool)
-    GRN_TS_EXPR_CONST_NODE_OPEN_CASE_BLOCK(INT, int)
-    GRN_TS_EXPR_CONST_NODE_OPEN_CASE_BLOCK(FLOAT, float)
-    GRN_TS_EXPR_CONST_NODE_OPEN_CASE_BLOCK(TIME, time)
-    case GRN_TS_TEXT: {
-      grn_ts_text text_value;
-      char *text_buf;
-      text_value = *(const grn_ts_text *)value;
-      if (!text_value.size) {
-        node->content.text_value.ptr = NULL;
-        node->content.text_value.size = 0;
-        return GRN_SUCCESS;
-      }
-      text_buf = (char *)GRN_MALLOC(text_value.size);
-      if (!text_buf) {
-        return GRN_NO_MEMORY_AVAILABLE;
+    GRN_TS_EXPR_KEY_NODE_EVALUATE_CASE_BLOCK(BOOL, bool)
+    case GRN_TS_INT: {
+      switch (node->data_type) {
+        GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE_BLOCK(INT8, int8)
+        GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE_BLOCK(INT16, int16)
+        GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE_BLOCK(INT32, int32)
+        GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE_BLOCK(INT64, int64)
+        GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE_BLOCK(UINT8, uint8)
+        GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE_BLOCK(UINT16, uint16)
+        GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE_BLOCK(UINT32, uint32)
+        GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE_BLOCK(UINT64, uint64)
+        default: {
+          return GRN_OBJECT_CORRUPT;
+        }
       }
-      node->text_buf = text_buf;
-      grn_memcpy(text_buf, text_value.ptr, text_value.size);
-      node->content.text_value.ptr = text_buf;
-      node->content.text_value.size = text_value.size;
-      return GRN_SUCCESS;
     }
-    GRN_TS_EXPR_CONST_NODE_OPEN_CASE_BLOCK(GEO_POINT, geo_point)
-    default: {
-      return GRN_INVALID_ARGUMENT;
-    }
-  }
-}
-#undef GRN_TS_EXPR_CONST_NODE_OPEN_CASE_BLOCK
-
-#define GRN_TS_EXPR_CONST_NODE_OPEN_VECTOR_CASE_BLOCK(KIND, kind)\
-  case GRN_TS_ ## KIND ## _VECTOR: {\
-    grn_ts_ ## kind ## _vector vector;\
-    grn_ts_ ## kind *vector_buf;\
-    vector = *(const grn_ts_ ## kind ## _vector *)value;\
-    if (!vector.size) {\
-      node->content.kind ## _vector_value.ptr = NULL;\
-      node->content.kind ## _vector_value.size = 0;\
-      return GRN_SUCCESS;\
-    }\
-    vector_buf = GRN_MALLOCN(grn_ts_ ## kind, vector.size);\
-    if (!vector_buf) {\
-      return GRN_NO_MEMORY_AVAILABLE;\
-    }\
-    node->vector_buf = vector_buf;\
-    grn_memcpy(vector_buf, vector.ptr,\
-               sizeof(grn_ts_ ## kind) * vector.size);\
-    node->content.kind ## _vector_value.ptr = vector_buf;\
-    node->content.kind ## _vector_value.size = vector.size;\
-    return GRN_SUCCESS;\
-  }
-/* grn_ts_expr_const_node_init_vector() initializes a const vector node. */
-static grn_rc
-grn_ts_expr_const_node_init_vector(grn_ctx *ctx, grn_ts_expr_const_node *node,
-                                   const void *value) {
-  switch (node->data_kind) {
-    GRN_TS_EXPR_CONST_NODE_OPEN_VECTOR_CASE_BLOCK(BOOL, bool)
-    GRN_TS_EXPR_CONST_NODE_OPEN_VECTOR_CASE_BLOCK(INT, int)
-    GRN_TS_EXPR_CONST_NODE_OPEN_VECTOR_CASE_BLOCK(FLOAT, float)
-    GRN_TS_EXPR_CONST_NODE_OPEN_VECTOR_CASE_BLOCK(TIME, time)
-    case GRN_TS_TEXT_VECTOR: {
-      size_t i, offset = 0, total_size = 0;
-      grn_ts_text_vector vector;
-      grn_ts_text *vector_buf;
-      char *text_buf;
-      vector = *(const grn_ts_text_vector *)value;
-      if (!vector.size) {
-        node->content.text_vector_value.ptr = NULL;
-        node->content.text_vector_value.size = 0;
-        return GRN_SUCCESS;
-      }
-      vector_buf = GRN_MALLOCN(grn_ts_text, vector.size);
-      if (!vector_buf) {
-        return GRN_NO_MEMORY_AVAILABLE;
+    GRN_TS_EXPR_KEY_NODE_EVALUATE_CASE_BLOCK(FLOAT, float)
+    GRN_TS_EXPR_KEY_NODE_EVALUATE_CASE_BLOCK(TIME, time)
+    case GRN_TS_TEXT: {
+      size_t i;
+      char *buf_ptr;
+      grn_ts_text *out_ptr = (grn_ts_text *)out;
+      node->buf.pos = 0;
+      for (i = 0; i < n_in; i++) {
+        const char *key;
+        size_t key_size;
+        key = (const char *)grn_ts_table_get_key(ctx, node->table, in[i].id,
+                                                 &key_size);
+        if (key && key_size) {
+          grn_rc rc = grn_ts_buf_write(ctx, &node->buf, key, key_size);
+          if (rc == GRN_SUCCESS) {
+            out_ptr[i].size = key_size;
+          }
+        }
       }
-      node->vector_buf = vector_buf;
-      for (i = 0; i < vector.size; i++) {
-        total_size += vector.ptr[i].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;
       }
-      if (total_size) {
-        text_buf = (char *)GRN_MALLOC(total_size);
-        if (!text_buf) {
-          return GRN_NO_MEMORY_AVAILABLE;
+      return GRN_SUCCESS;
+    }
+    GRN_TS_EXPR_KEY_NODE_EVALUATE_CASE_BLOCK(GEO_POINT, geo_point)
+    case GRN_TS_REF: {
+      size_t i;
+      grn_ts_ref *out_ptr = (grn_ts_ref *)out;
+      for (i = 0; i < n_in; i++) {
+        const grn_ts_id *id;
+        size_t key_size;
+        id = (const grn_ts_id *)grn_ts_table_get_key(ctx, node->table,
+                                                     in[i].id, &key_size);
+        if (id && (key_size == sizeof(*id))) {
+          out_ptr[i].id = *id;
+          out_ptr[i].score = in[i].score;
+        } else {
+          out_ptr[i] = grn_ts_ref_zero();
         }
-        node->text_buf = text_buf;
       }
-      for (i = 0; i < vector.size; i++) {
-        grn_memcpy(text_buf + offset, vector.ptr[i].ptr, vector.ptr[i].size);
-        vector_buf[i].ptr = text_buf + offset;
-        vector_buf[i].size = vector.ptr[i].size;
-        offset += vector.ptr[i].size;
-      }
-      node->content.text_vector_value.ptr = vector_buf;
-      node->content.text_vector_value.size = vector.size;
       return GRN_SUCCESS;
     }
-    GRN_TS_EXPR_CONST_NODE_OPEN_VECTOR_CASE_BLOCK(GEO_POINT, geo_point)
     default: {
-      return GRN_UNKNOWN_ERROR;
+      return GRN_OBJECT_CORRUPT;
     }
   }
 }
-#undef GRN_TS_EXPR_CONST_NODE_OPEN_VECTOR_CASE_BLOCK
+#undef GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE_BLOCK
+#undef GRN_TS_EXPR_KEY_NODE_EVALUATE_CASE_BLOCK
 
-/* grn_ts_expr_const_node_open() creates a node associated with a const. */
+/* grn_ts_expr_key_node_filter() filters records. */
 static grn_rc
-grn_ts_expr_const_node_open(grn_ctx *ctx, grn_ts_data_kind kind,
-                            const void *value, grn_ts_expr_node **node) {
-  grn_rc rc = GRN_SUCCESS;
-  grn_ts_expr_const_node *new_node = GRN_MALLOCN(grn_ts_expr_const_node, 1);
-  if (!new_node) {
-    return GRN_NO_MEMORY_AVAILABLE;
-  }
-  new_node->type = GRN_TS_EXPR_CONST_NODE;
-  new_node->data_kind = kind;
-  new_node->data_type = grn_ts_data_kind_to_type(kind);
-  new_node->text_buf = NULL;
-  new_node->vector_buf = NULL;
-  if (kind & GRN_TS_VECTOR_FLAG) {
-    rc = grn_ts_expr_const_node_init_vector(ctx, new_node, value);
-  } else {
-    rc = grn_ts_expr_const_node_init_scalar(ctx, new_node, value);
-  }
-  if (rc != GRN_SUCCESS) {
-    grn_ts_expr_node_close(ctx, (grn_ts_expr_node *)new_node);
-    return rc;
+grn_ts_expr_key_node_filter(grn_ctx *ctx, grn_ts_expr_key_node *node,
+                            grn_ts_record *in, size_t n_in,
+                            grn_ts_record *out, size_t *n_out) {
+  size_t i, count = 0;
+  for (i = 0; i < n_in; i++) {
+    const grn_ts_bool *key;
+    size_t key_size;
+    key = (const grn_ts_bool *)grn_ts_table_get_key(ctx, node->table,
+                                                    in[i].id, &key_size);
+    if (key && (key_size == sizeof(*key)) && *key) {
+      out[count++] = in[i];
+    }
   }
-  *node = (grn_ts_expr_node *)new_node;
+  *n_out = count;
   return GRN_SUCCESS;
 }
 
-#define GRN_TS_EXPR_COLUMN_NODE_OPEN_CASE_BLOCK(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. */
+/* grn_ts_expr_key_node_adjust() updates scores. */
 static grn_rc
-grn_ts_expr_column_node_open(grn_ctx *ctx, grn_obj *column,
-                             grn_ts_expr_node **node) {
-  grn_rc rc;
-  grn_ts_expr_column_node *new_node = GRN_MALLOCN(grn_ts_expr_column_node, 1);
-  if (!new_node) {
-    return GRN_NO_MEMORY_AVAILABLE;
-  }
-  memset(new_node, 0, sizeof(*new_node));
-  rc = grn_ts_obj_increment_ref_count(ctx, column);
-  if (rc != GRN_SUCCESS) {
-    GRN_FREE(new_node);
-    return rc;
-  }
-  new_node->type = GRN_TS_EXPR_COLUMN_NODE;
-  new_node->data_kind = grn_ts_data_type_to_kind(DB_OBJ(column)->range);
-  if (column->header.type == GRN_COLUMN_VAR_SIZE) {
-    grn_obj_flags type = column->header.flags & GRN_OBJ_COLUMN_TYPE_MASK;
-    if (type == GRN_OBJ_COLUMN_VECTOR) {
-      new_node->data_kind |= GRN_TS_VECTOR_FLAG;
+grn_ts_expr_key_node_adjust(grn_ctx *ctx, grn_ts_expr_key_node *node,
+                            grn_ts_record *io, size_t n_io) {
+  size_t i;
+  for (i = 0; i < n_io; i++) {
+    const grn_ts_float *key;
+    size_t key_size;
+    key = (const grn_ts_float *)grn_ts_table_get_key(ctx, node->table,
+                                                     io[i].id, &key_size);
+    if (key && (key_size == sizeof(*key))) {
+      io[i].score = (grn_ts_score)*key;
     }
   }
-  new_node->data_type = DB_OBJ(column)->range;
-  new_node->column = column;
-  grn_ts_buf_init(ctx, &new_node->buf);
-  grn_ts_buf_init(ctx, &new_node->body_buf);
-  *node = (grn_ts_expr_node *)new_node;
   return GRN_SUCCESS;
 }
-#undef GRN_TS_EXPR_COLUMN_NODE_OPEN_CASE_BLOCK
 
-/* 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_ts_data_kind data_kind = GRN_TS_VOID;
-  grn_ts_data_type data_type = GRN_DB_VOID;
-  grn_ts_expr_node **args_clone = NULL;
-  grn_ts_expr_op_node *new_node;
+/*-------------------------------------------------------------
+ * grn_ts_expr_value_node.
+ */
 
-  /* Check arguments. */
-  switch (op_type) {
-    case GRN_TS_OP_LOGICAL_AND:
-    case GRN_TS_OP_LOGICAL_OR: {
-      if (args[1]->data_kind != GRN_TS_BOOL) {
-        return GRN_INVALID_ARGUMENT;
-      }
-      /* Fall through. */
-    }
-    case GRN_TS_OP_LOGICAL_NOT: {
-      if (args[0]->data_kind != GRN_TS_BOOL) {
-        return GRN_INVALID_ARGUMENT;
-      }
-      data_kind = GRN_TS_BOOL;
-      data_type = GRN_DB_BOOL;
-      break;
-    }
-    default: {
-      return GRN_INVALID_ARGUMENT;
-    }
-  }
-  if ((data_kind == GRN_TS_VOID) || (data_type == GRN_DB_VOID)) {
-    return GRN_UNKNOWN_ERROR;
-  }
+typedef struct {
+  GRN_TS_EXPR_NODE_COMMON_MEMBERS
+  grn_obj *table;
+} grn_ts_expr_value_node;
 
-  /* Create a copy of args. */
-  args_clone = GRN_MALLOCN(grn_ts_expr_node *, n_args);
-  if (!args_clone) {
-    return GRN_NO_MEMORY_AVAILABLE;
-  }
-  for (i = 0; i < n_args; i++) {
-    args_clone[i] = args[i];
+/*
+ * grn_ts_expr_value_node_open() creates a node associated with value
+ * (_value).
+ */
+static grn_rc
+grn_ts_expr_value_node_open(grn_ctx *ctx, grn_obj *table,
+                            grn_ts_expr_node **node) {
+  grn_rc rc;
+  grn_ts_expr_value_node *new_node;
+  if (!grn_ts_table_has_value(ctx, table)) {
+    return GRN_INVALID_ARGUMENT;
   }
-
-  /* Create an operator node. */
-  new_node = GRN_MALLOCN(grn_ts_expr_op_node, 1);
+  new_node = GRN_MALLOCN(grn_ts_expr_value_node, 1);
   if (!new_node) {
-    if (args_clone) {
-      GRN_FREE(args_clone);
-    }
     return GRN_NO_MEMORY_AVAILABLE;
   }
-  new_node->type = GRN_TS_EXPR_OP_NODE;
-  new_node->data_kind = data_kind;
-  new_node->data_type = data_type;
-  new_node->op_type = op_type;
-  new_node->args = args_clone;
-  new_node->n_args = n_args;
-  new_node->buf = NULL;
-  new_node->buf_size = 0;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_expr_id_node_evaluate() outputs IDs. */
-static grn_rc
-grn_ts_expr_id_node_evaluate(grn_ctx *ctx, grn_ts_expr_id_node *node,
-                             const grn_ts_record *in, size_t n_in,
-                             void *out) {
-  size_t i;
-  grn_ts_int *out_ptr = (grn_ts_int *)out;
-  for (i = 0; i < n_in; i++) {
-    out_ptr[i] = (grn_ts_int)in[i].id;
-  }
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_expr_score_node_evaluate() outputs scores. */
-static grn_rc
-grn_ts_expr_score_node_evaluate(grn_ctx *ctx, grn_ts_expr_score_node *node,
-                                const grn_ts_record *in, size_t n_in,
-                                void *out) {
-  size_t i;
-  grn_ts_float *out_ptr = (grn_ts_float *)out;
-  for (i = 0; i < n_in; i++) {
-    out_ptr[i] = (grn_ts_float)in[i].score;
+  memset(new_node, 0, sizeof(*new_node));
+  rc = grn_ts_obj_increment_ref_count(ctx, table);
+  if (rc != GRN_SUCCESS) {
+    GRN_FREE(new_node);
+    return rc;
   }
+  new_node->type = GRN_TS_EXPR_VALUE_NODE;
+  new_node->data_kind = grn_ts_data_type_to_kind(DB_OBJ(table)->range);
+  new_node->data_type = DB_OBJ(table)->range;
+  new_node->table = table;
+  *node = (grn_ts_expr_node *)new_node;
   return GRN_SUCCESS;
 }
 
-#define GRN_TS_EXPR_KEY_NODE_EVALUATE_CASE_BLOCK(KIND, kind)\
+#define GRN_TS_EXPR_VALUE_NODE_EVALUATE_CASE_BLOCK(KIND, kind)\
   case GRN_TS_ ## KIND: {\
     size_t i;\
     grn_ts_ ## kind *out_ptr = (grn_ts_ ## kind *)out;\
     for (i = 0; i < n_in; i++) {\
-      const grn_ts_ ## kind *key;\
-      size_t key_size;\
-      key = (const grn_ts_ ## kind *)grn_ts_table_get_key(ctx, node->table,\
-                                                          in[i].id,\
-                                                          &key_size);\
-      if (key && (key_size == sizeof(*key))) {\
-        out_ptr[i] = *key;\
-      } else {\
-        out_ptr[i] = grn_ts_ ## kind ## _zero();\
-      }\
+      const grn_ts_ ## kind *value;\
+      value = (const grn_ts_ ## kind *)grn_ts_table_get_value(ctx,\
+                                                              node->table,\
+                                                              in[i].id);\
+      out_ptr[i] = value ? *value : grn_ts_ ## kind ## _zero();\
     }\
     return GRN_SUCCESS;\
   }
-#define GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE_BLOCK(TYPE, type)\
+#define GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE_BLOCK(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 type ## _t *key;\
-      size_t key_size;\
-      key = (const type ## _t *)grn_ts_table_get_key(ctx, node->table,\
-                                                     in[i].id, &key_size);\
-      if (key && (key_size == sizeof(*key))) {\
-        out_ptr[i] = (grn_ts_int)*key;\
-      } else {\
-        out_ptr[i] = grn_ts_int_zero();\
-      }\
+      const type ## _t *value;\
+      value = (const type ## _t *)grn_ts_table_get_value(ctx, node->table,\
+                                                         in[i].id);\
+      out_ptr[i] = value ? (grn_ts_int)*value : grn_ts_int_zero();\
     }\
     return GRN_SUCCESS;\
   }
-/* grn_ts_expr_key_node_evaluate() outputs keys. */
+/* grn_ts_expr_value_node_evaluate() outputs values. */
 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) {
+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_KEY_NODE_EVALUATE_CASE_BLOCK(BOOL, bool)
+    GRN_TS_EXPR_VALUE_NODE_EVALUATE_CASE_BLOCK(BOOL, bool)
     case GRN_TS_INT: {
       switch (node->data_type) {
-        GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE_BLOCK(INT8, int8)
-        GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE_BLOCK(INT16, int16)
-        GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE_BLOCK(INT32, int32)
-        GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE_BLOCK(INT64, int64)
-        GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE_BLOCK(UINT8, uint8)
-        GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE_BLOCK(UINT16, uint16)
-        GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE_BLOCK(UINT32, uint32)
-        GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE_BLOCK(UINT64, uint64)
+        GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE_BLOCK(INT8, int8)
+        GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE_BLOCK(INT16, int16)
+        GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE_BLOCK(INT32, int32)
+        GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE_BLOCK(INT64, int64)
+        GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE_BLOCK(UINT8, uint8)
+        GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE_BLOCK(UINT16, uint16)
+        GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE_BLOCK(UINT32, uint32)
+        GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE_BLOCK(UINT64, uint64)
         default: {
           return GRN_OBJECT_CORRUPT;
         }
       }
     }
-    GRN_TS_EXPR_KEY_NODE_EVALUATE_CASE_BLOCK(FLOAT, float)
-    GRN_TS_EXPR_KEY_NODE_EVALUATE_CASE_BLOCK(TIME, time)
-    case GRN_TS_TEXT: {
+    GRN_TS_EXPR_VALUE_NODE_EVALUATE_CASE_BLOCK(FLOAT, float)
+    GRN_TS_EXPR_VALUE_NODE_EVALUATE_CASE_BLOCK(TIME, time)
+    GRN_TS_EXPR_VALUE_NODE_EVALUATE_CASE_BLOCK(GEO_POINT, geo_point)
+    case GRN_TS_REF: {
       size_t i;
-      char *buf_ptr;
-      grn_ts_text *out_ptr = (grn_ts_text *)out;
-      node->buf.pos = 0;
+      grn_ts_ref *out_ptr = (grn_ts_ref *)out;
       for (i = 0; i < n_in; i++) {
-        const char *key;
-        size_t key_size;
-        key = (const char *)grn_ts_table_get_key(ctx, node->table, in[i].id,
-                                                 &key_size);
-        if (key && key_size) {
-          grn_rc rc = grn_ts_buf_write(ctx, &node->buf, key, key_size);
-          if (rc == GRN_SUCCESS) {
-            out_ptr[i].size = key_size;
-          }
+        const grn_ts_id *value;
+        value = (const grn_ts_id *)grn_ts_table_get_value(ctx, node->table,
+                                                          in[i].id);
+        if (value) {
+          out_ptr[i].id = *value;
+          out_ptr[i].score = in[i].score;
+        } else {
+          out_ptr[i] = grn_ts_ref_zero();
         }
       }
-      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;
+    }
+    default: {
+      return GRN_OBJECT_CORRUPT;
+    }
+  }
+}
+#undef GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE_BLOCK
+#undef GRN_TS_EXPR_VALUE_NODE_EVALUATE_CASE_BLOCK
+
+/* 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 grn_ts_bool *value;
+    value = (const grn_ts_bool *)grn_ts_table_get_value(ctx, node->table,
+                                                        in[i].id);
+    if (value && *value) {
+      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 grn_ts_float *value;
+    value = (const grn_ts_float *)grn_ts_table_get_value(ctx, node->table,
+                                                         io[i].id);
+    if (value) {
+      io[i].score = (grn_ts_score)*value;
+    }
+  }
+  return GRN_SUCCESS;
+}
+
+/*-------------------------------------------------------------
+ * grn_ts_expr_const_node.
+ */
+
+typedef struct {
+  GRN_TS_EXPR_NODE_COMMON_MEMBERS
+  union {
+    grn_ts_bool bool_value;
+    grn_ts_int int_value;
+    grn_ts_float float_value;
+    grn_ts_time time_value;
+    grn_ts_text text_value;
+    grn_ts_geo_point geo_point_value;
+    grn_ts_bool_vector bool_vector_value;
+    grn_ts_int_vector int_vector_value;
+    grn_ts_float_vector float_vector_value;
+    grn_ts_time_vector time_vector_value;
+    grn_ts_text_vector text_vector_value;
+    grn_ts_geo_point_vector geo_point_vector_value;
+  } content;
+  char *text_buf;
+  void *vector_buf;
+} grn_ts_expr_const_node;
+
+#define GRN_TS_EXPR_CONST_NODE_OPEN_CASE_BLOCK(KIND, kind)\
+  case GRN_TS_ ## KIND: {\
+    node->content.kind ## _value = *(const grn_ts_ ## kind *)value;\
+    return GRN_SUCCESS;\
+  }
+/* grn_ts_expr_const_node_init_scalar() initializes a const scalar node. */
+static grn_rc
+grn_ts_expr_const_node_init_scalar(grn_ctx *ctx, grn_ts_expr_const_node *node,
+                                   const void *value) {
+  switch (node->data_kind) {
+    GRN_TS_EXPR_CONST_NODE_OPEN_CASE_BLOCK(BOOL, bool)
+    GRN_TS_EXPR_CONST_NODE_OPEN_CASE_BLOCK(INT, int)
+    GRN_TS_EXPR_CONST_NODE_OPEN_CASE_BLOCK(FLOAT, float)
+    GRN_TS_EXPR_CONST_NODE_OPEN_CASE_BLOCK(TIME, time)
+    case GRN_TS_TEXT: {
+      grn_ts_text text_value;
+      char *text_buf;
+      text_value = *(const grn_ts_text *)value;
+      if (!text_value.size) {
+        node->content.text_value.ptr = NULL;
+        node->content.text_value.size = 0;
+        return GRN_SUCCESS;
       }
-      return GRN_SUCCESS;
-    }
-    GRN_TS_EXPR_KEY_NODE_EVALUATE_CASE_BLOCK(GEO_POINT, geo_point)
-    case GRN_TS_REF: {
-      size_t i;
-      grn_ts_ref *out_ptr = (grn_ts_ref *)out;
-      for (i = 0; i < n_in; i++) {
-        const grn_ts_id *id;
-        size_t key_size;
-        id = (const grn_ts_id *)grn_ts_table_get_key(ctx, node->table,
-                                                     in[i].id, &key_size);
-        if (id && (key_size == sizeof(*id))) {
-          out_ptr[i].id = *id;
-          out_ptr[i].score = in[i].score;
-        } else {
-          out_ptr[i] = grn_ts_ref_zero();
-        }
+      text_buf = (char *)GRN_MALLOC(text_value.size);
+      if (!text_buf) {
+        return GRN_NO_MEMORY_AVAILABLE;
       }
+      node->text_buf = text_buf;
+      grn_memcpy(text_buf, text_value.ptr, text_value.size);
+      node->content.text_value.ptr = text_buf;
+      node->content.text_value.size = text_value.size;
       return GRN_SUCCESS;
     }
+    GRN_TS_EXPR_CONST_NODE_OPEN_CASE_BLOCK(GEO_POINT, geo_point)
     default: {
-      return GRN_OBJECT_CORRUPT;
+      return GRN_INVALID_ARGUMENT;
     }
   }
 }
-#undef GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE_BLOCK
-#undef GRN_TS_EXPR_KEY_NODE_EVALUATE_CASE_BLOCK
+#undef GRN_TS_EXPR_CONST_NODE_OPEN_CASE_BLOCK
 
-#define GRN_TS_EXPR_VALUE_NODE_EVALUATE_CASE_BLOCK(KIND, kind)\
-  case GRN_TS_ ## KIND: {\
-    size_t i;\
-    grn_ts_ ## kind *out_ptr = (grn_ts_ ## kind *)out;\
-    for (i = 0; i < n_in; i++) {\
-      const grn_ts_ ## kind *value;\
-      value = (const grn_ts_ ## kind *)grn_ts_table_get_value(ctx,\
-                                                              node->table,\
-                                                              in[i].id);\
-      out_ptr[i] = value ? *value : grn_ts_ ## kind ## _zero();\
+#define GRN_TS_EXPR_CONST_NODE_OPEN_VECTOR_CASE_BLOCK(KIND, kind)\
+  case GRN_TS_ ## KIND ## _VECTOR: {\
+    grn_ts_ ## kind ## _vector vector;\
+    grn_ts_ ## kind *vector_buf;\
+    vector = *(const grn_ts_ ## kind ## _vector *)value;\
+    if (!vector.size) {\
+      node->content.kind ## _vector_value.ptr = NULL;\
+      node->content.kind ## _vector_value.size = 0;\
+      return GRN_SUCCESS;\
     }\
-    return GRN_SUCCESS;\
-  }
-#define GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE_BLOCK(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 type ## _t *value;\
-      value = (const type ## _t *)grn_ts_table_get_value(ctx, node->table,\
-                                                         in[i].id);\
-      out_ptr[i] = value ? (grn_ts_int)*value : grn_ts_int_zero();\
+    vector_buf = GRN_MALLOCN(grn_ts_ ## kind, vector.size);\
+    if (!vector_buf) {\
+      return GRN_NO_MEMORY_AVAILABLE;\
     }\
+    node->vector_buf = vector_buf;\
+    grn_memcpy(vector_buf, vector.ptr,\
+               sizeof(grn_ts_ ## kind) * vector.size);\
+    node->content.kind ## _vector_value.ptr = vector_buf;\
+    node->content.kind ## _vector_value.size = vector.size;\
     return GRN_SUCCESS;\
   }
-/* grn_ts_expr_value_node_evaluate() outputs values. */
+/* grn_ts_expr_const_node_init_vector() initializes a const vector node. */
 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) {
+grn_ts_expr_const_node_init_vector(grn_ctx *ctx, grn_ts_expr_const_node *node,
+                                   const void *value) {
   switch (node->data_kind) {
-    GRN_TS_EXPR_VALUE_NODE_EVALUATE_CASE_BLOCK(BOOL, bool)
-    case GRN_TS_INT: {
-      switch (node->data_type) {
-        GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE_BLOCK(INT8, int8)
-        GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE_BLOCK(INT16, int16)
-        GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE_BLOCK(INT32, int32)
-        GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE_BLOCK(INT64, int64)
-        GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE_BLOCK(UINT8, uint8)
-        GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE_BLOCK(UINT16, uint16)
-        GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE_BLOCK(UINT32, uint32)
-        GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE_BLOCK(UINT64, uint64)
-        default: {
-          return GRN_OBJECT_CORRUPT;
-        }
+    GRN_TS_EXPR_CONST_NODE_OPEN_VECTOR_CASE_BLOCK(BOOL, bool)
+    GRN_TS_EXPR_CONST_NODE_OPEN_VECTOR_CASE_BLOCK(INT, int)
+    GRN_TS_EXPR_CONST_NODE_OPEN_VECTOR_CASE_BLOCK(FLOAT, float)
+    GRN_TS_EXPR_CONST_NODE_OPEN_VECTOR_CASE_BLOCK(TIME, time)
+    case GRN_TS_TEXT_VECTOR: {
+      size_t i, offset = 0, total_size = 0;
+      grn_ts_text_vector vector;
+      grn_ts_text *vector_buf;
+      char *text_buf;
+      vector = *(const grn_ts_text_vector *)value;
+      if (!vector.size) {
+        node->content.text_vector_value.ptr = NULL;
+        node->content.text_vector_value.size = 0;
+        return GRN_SUCCESS;
       }
-    }
-    GRN_TS_EXPR_VALUE_NODE_EVALUATE_CASE_BLOCK(FLOAT, float)
-    GRN_TS_EXPR_VALUE_NODE_EVALUATE_CASE_BLOCK(TIME, time)
-    GRN_TS_EXPR_VALUE_NODE_EVALUATE_CASE_BLOCK(GEO_POINT, geo_point)
-    case GRN_TS_REF: {
-      size_t i;
-      grn_ts_ref *out_ptr = (grn_ts_ref *)out;
-      for (i = 0; i < n_in; i++) {
-        const grn_ts_id *value;
-        value = (const grn_ts_id *)grn_ts_table_get_value(ctx, node->table,
-                                                          in[i].id);
-        if (value) {
-          out_ptr[i].id = *value;
-          out_ptr[i].score = in[i].score;
-        } else {
-          out_ptr[i] = grn_ts_ref_zero();
+      vector_buf = GRN_MALLOCN(grn_ts_text, vector.size);
+      if (!vector_buf) {
+        return GRN_NO_MEMORY_AVAILABLE;
+      }
+      node->vector_buf = vector_buf;
+      for (i = 0; i < vector.size; i++) {
+        total_size += vector.ptr[i].size;
+      }
+      if (total_size) {
+        text_buf = (char *)GRN_MALLOC(total_size);
+        if (!text_buf) {
+          return GRN_NO_MEMORY_AVAILABLE;
         }
+        node->text_buf = text_buf;
       }
+      for (i = 0; i < vector.size; i++) {
+        grn_memcpy(text_buf + offset, vector.ptr[i].ptr, vector.ptr[i].size);
+        vector_buf[i].ptr = text_buf + offset;
+        vector_buf[i].size = vector.ptr[i].size;
+        offset += vector.ptr[i].size;
+      }
+      node->content.text_vector_value.ptr = vector_buf;
+      node->content.text_vector_value.size = vector.size;
       return GRN_SUCCESS;
     }
+    GRN_TS_EXPR_CONST_NODE_OPEN_VECTOR_CASE_BLOCK(GEO_POINT, geo_point)
     default: {
-      return GRN_OBJECT_CORRUPT;
+      return GRN_UNKNOWN_ERROR;
     }
   }
 }
-#undef GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE_BLOCK
-#undef GRN_TS_EXPR_VALUE_NODE_EVALUATE_CASE_BLOCK
+#undef GRN_TS_EXPR_CONST_NODE_OPEN_VECTOR_CASE_BLOCK
+
+/* grn_ts_expr_const_node_open() creates a node associated with a const. */
+static grn_rc
+grn_ts_expr_const_node_open(grn_ctx *ctx, grn_ts_data_kind kind,
+                            const void *value, grn_ts_expr_node **node) {
+  grn_rc rc = GRN_SUCCESS;
+  grn_ts_expr_const_node *new_node = GRN_MALLOCN(grn_ts_expr_const_node, 1);
+  if (!new_node) {
+    return GRN_NO_MEMORY_AVAILABLE;
+  }
+  new_node->type = GRN_TS_EXPR_CONST_NODE;
+  new_node->data_kind = kind;
+  new_node->data_type = grn_ts_data_kind_to_type(kind);
+  new_node->text_buf = NULL;
+  new_node->vector_buf = NULL;
+  if (kind & GRN_TS_VECTOR_FLAG) {
+    rc = grn_ts_expr_const_node_init_vector(ctx, new_node, value);
+  } else {
+    rc = grn_ts_expr_const_node_init_scalar(ctx, new_node, value);
+  }
+  if (rc != GRN_SUCCESS) {
+    if (new_node->vector_buf) {
+      GRN_FREE(new_node->vector_buf);
+    }
+    if (new_node->text_buf) {
+      GRN_FREE(new_node->text_buf);
+    }
+    return rc;
+  }
+  *node = (grn_ts_expr_node *)new_node;
+  return GRN_SUCCESS;
+}
 
 #define GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE_BLOCK(KIND, kind)\
   case GRN_TS_ ## KIND: {\
@@ -1373,29 +1283,108 @@ grn_ts_expr_value_node_evaluate(grn_ctx *ctx, grn_ts_expr_value_node *node,
   GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE_BLOCK(KIND ## _VECTOR, kind ## _vector)
 /* grn_ts_expr_const_node_evaluate() outputs consts. */
 static grn_rc
-grn_ts_expr_const_node_evaluate(grn_ctx *ctx, grn_ts_expr_const_node *node,
-                                const grn_ts_record *in, size_t n_in,
-                                void *out) {
-  switch (node->data_kind) {
-    GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE_BLOCK(BOOL, bool)
-    GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE_BLOCK(INT, int)
-    GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE_BLOCK(FLOAT, float)
-    GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE_BLOCK(TIME, time)
-    GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE_BLOCK(TEXT, text)
-    GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE_BLOCK(GEO_POINT, geo_point)
-    GRN_TS_EXPR_CONST_NODE_EVALUATE_VECTOR_CASE_BLOCK(BOOL, bool)
-    GRN_TS_EXPR_CONST_NODE_EVALUATE_VECTOR_CASE_BLOCK(INT, int)
-    GRN_TS_EXPR_CONST_NODE_EVALUATE_VECTOR_CASE_BLOCK(FLOAT, float)
-    GRN_TS_EXPR_CONST_NODE_EVALUATE_VECTOR_CASE_BLOCK(TIME, time)
-    GRN_TS_EXPR_CONST_NODE_EVALUATE_VECTOR_CASE_BLOCK(TEXT, text)
-    GRN_TS_EXPR_CONST_NODE_EVALUATE_VECTOR_CASE_BLOCK(GEO_POINT, geo_point)
-    default: {
-      return GRN_INVALID_ARGUMENT;
+grn_ts_expr_const_node_evaluate(grn_ctx *ctx, grn_ts_expr_const_node *node,
+                                const grn_ts_record *in, size_t n_in,
+                                void *out) {
+  switch (node->data_kind) {
+    GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE_BLOCK(BOOL, bool)
+    GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE_BLOCK(INT, int)
+    GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE_BLOCK(FLOAT, float)
+    GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE_BLOCK(TIME, time)
+    GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE_BLOCK(TEXT, text)
+    GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE_BLOCK(GEO_POINT, geo_point)
+    GRN_TS_EXPR_CONST_NODE_EVALUATE_VECTOR_CASE_BLOCK(BOOL, bool)
+    GRN_TS_EXPR_CONST_NODE_EVALUATE_VECTOR_CASE_BLOCK(INT, int)
+    GRN_TS_EXPR_CONST_NODE_EVALUATE_VECTOR_CASE_BLOCK(FLOAT, float)
+    GRN_TS_EXPR_CONST_NODE_EVALUATE_VECTOR_CASE_BLOCK(TIME, time)
+    GRN_TS_EXPR_CONST_NODE_EVALUATE_VECTOR_CASE_BLOCK(TEXT, text)
+    GRN_TS_EXPR_CONST_NODE_EVALUATE_VECTOR_CASE_BLOCK(GEO_POINT, geo_point)
+    default: {
+      return GRN_INVALID_ARGUMENT;
+    }
+  }
+}
+#undef GRN_TS_EXPR_CONST_NODE_EVALUATE_VECTOR_CASE_BLOCK
+#undef GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE_BLOCK
+
+/* grn_ts_expr_const_node_filter() filters records. */
+static grn_rc
+grn_ts_expr_const_node_filter(grn_ctx *ctx, grn_ts_expr_const_node *node,
+                              grn_ts_record *in, size_t n_in,
+                              grn_ts_record *out, size_t *n_out) {
+  if (node->content.bool_value) {
+    if (in != out) {
+      size_t i;
+      for (i = 0; i < n_in; i++) {
+        out[i] = in[i];
+      }
+    }
+    *n_out = n_in;
+  } else {
+    *n_out = 0;
+  }
+  return GRN_SUCCESS;
+}
+
+/* grn_ts_expr_const_node_adjust() updates scores. */
+static grn_rc
+grn_ts_expr_const_node_adjust(grn_ctx *ctx, grn_ts_expr_const_node *node,
+                              grn_ts_record *io, size_t n_io) {
+  size_t i;
+  grn_ts_score score = (grn_ts_score)node->content.float_value;
+  for (i = 0; i < n_io; i++) {
+    io[i].score = score;
+  }
+  return GRN_SUCCESS;
+}
+
+/*-------------------------------------------------------------
+ * grn_ts_expr_column_node.
+ */
+
+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;
+
+#define GRN_TS_EXPR_COLUMN_NODE_OPEN_CASE_BLOCK(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) {
+    return GRN_NO_MEMORY_AVAILABLE;
+  }
+  memset(new_node, 0, sizeof(*new_node));
+  rc = grn_ts_obj_increment_ref_count(ctx, column);
+  if (rc != GRN_SUCCESS) {
+    GRN_FREE(new_node);
+    return rc;
+  }
+  new_node->type = GRN_TS_EXPR_COLUMN_NODE;
+  new_node->data_kind = grn_ts_data_type_to_kind(DB_OBJ(column)->range);
+  if (column->header.type == GRN_COLUMN_VAR_SIZE) {
+    grn_obj_flags type = column->header.flags & GRN_OBJ_COLUMN_TYPE_MASK;
+    if (type == GRN_OBJ_COLUMN_VECTOR) {
+      new_node->data_kind |= GRN_TS_VECTOR_FLAG;
     }
   }
+  new_node->data_type = DB_OBJ(column)->range;
+  new_node->column = column;
+  grn_ts_buf_init(ctx, &new_node->buf);
+  grn_ts_buf_init(ctx, &new_node->body_buf);
+  *node = (grn_ts_expr_node *)new_node;
+  return GRN_SUCCESS;
 }
-#undef GRN_TS_EXPR_CONST_NODE_EVALUATE_VECTOR_CASE_BLOCK
-#undef GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE_BLOCK
+#undef GRN_TS_EXPR_COLUMN_NODE_OPEN_CASE_BLOCK
 
 #define GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_CASE_BLOCK(KIND, kind)\
   case GRN_TS_ ## KIND: {\
@@ -1729,10 +1718,137 @@ grn_ts_expr_column_node_evaluate(grn_ctx *ctx, grn_ts_expr_column_node *node,
   }
 }
 
-/* Forward declaration for operator nodes. */
+/* grn_ts_expr_column_node_filter() filters records. */
 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);
+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.
+ */
+
+/* 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_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;
+  size_t n_args;
+  void *buf;
+  size_t buf_size; /* Size in bytes. */
+  // TODO
+} grn_ts_expr_op_node;
+
+/* 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_ts_data_kind data_kind = GRN_TS_VOID;
+  grn_ts_data_type data_type = GRN_DB_VOID;
+  grn_ts_expr_node **args_clone = NULL;
+  grn_ts_expr_op_node *new_node;
+
+  /* Check arguments. */
+  switch (op_type) {
+    case GRN_TS_OP_LOGICAL_AND:
+    case GRN_TS_OP_LOGICAL_OR: {
+      if (args[1]->data_kind != GRN_TS_BOOL) {
+        return GRN_INVALID_ARGUMENT;
+      }
+      /* Fall through. */
+    }
+    case GRN_TS_OP_LOGICAL_NOT: {
+      if (args[0]->data_kind != GRN_TS_BOOL) {
+        return GRN_INVALID_ARGUMENT;
+      }
+      data_kind = GRN_TS_BOOL;
+      data_type = GRN_DB_BOOL;
+      break;
+    }
+    default: {
+      return GRN_INVALID_ARGUMENT;
+    }
+  }
+  if ((data_kind == GRN_TS_VOID) || (data_type == GRN_DB_VOID)) {
+    return GRN_UNKNOWN_ERROR;
+  }
+
+  /* Create a copy of args. */
+  args_clone = GRN_MALLOCN(grn_ts_expr_node *, n_args);
+  if (!args_clone) {
+    return GRN_NO_MEMORY_AVAILABLE;
+  }
+  for (i = 0; i < n_args; i++) {
+    args_clone[i] = args[i];
+  }
+
+  /* Create an operator node. */
+  new_node = GRN_MALLOCN(grn_ts_expr_op_node, 1);
+  if (!new_node) {
+    if (args_clone) {
+      GRN_FREE(args_clone);
+    }
+    return GRN_NO_MEMORY_AVAILABLE;
+  }
+  new_node->type = GRN_TS_EXPR_OP_NODE;
+  new_node->data_kind = data_kind;
+  new_node->data_type = data_type;
+  new_node->op_type = op_type;
+  new_node->args = args_clone;
+  new_node->n_args = n_args;
+  new_node->buf = NULL;
+  new_node->buf_size = 0;
+  return GRN_SUCCESS;
+}
 
 /*
  * grn_ts_expr_op_node_reserve_buf() allocates memory to the 1st internal
@@ -1819,145 +1935,34 @@ grn_ts_op_logical_or_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
   if (rc != GRN_SUCCESS) {
     return rc;
   }
-  for (i = 0; i < n_in; i++) {
-    out_ptr[i] |= buf_ptr[i];
-  }
-  return GRN_SUCCESS;
-}
-
-/* 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_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);
-    }
-    // TODO
-    default: {
-      return GRN_OPERATION_NOT_SUPPORTED;
-    }
-  }
-}
-
-#define GRN_TS_EXPR_NODE_EVALUATE_CASE_BLOCK(TYPE, type)\
-  case GRN_TS_EXPR_ ## TYPE ## _NODE: {\
-    grn_ts_expr_ ## type ## _node *type ## _node;\
-    type ## _node = (grn_ts_expr_ ## type ## _node *)node;\
-    return grn_ts_expr_ ## type ## _node_evaluate(ctx, type ## _node,\
-                                                  in, n_in, out);\
-  }
-/* grn_ts_expr_node_evaluate() evaluates a subexpression. */
-static grn_rc
-grn_ts_expr_node_evaluate(grn_ctx *ctx, grn_ts_expr_node *node,
-                          const grn_ts_record *in, size_t n_in, void *out) {
-  switch (node->type) {
-    GRN_TS_EXPR_NODE_EVALUATE_CASE_BLOCK(ID, id)
-    GRN_TS_EXPR_NODE_EVALUATE_CASE_BLOCK(SCORE, score)
-    GRN_TS_EXPR_NODE_EVALUATE_CASE_BLOCK(KEY, key)
-    GRN_TS_EXPR_NODE_EVALUATE_CASE_BLOCK(VALUE, value)
-    GRN_TS_EXPR_NODE_EVALUATE_CASE_BLOCK(CONST, const)
-    GRN_TS_EXPR_NODE_EVALUATE_CASE_BLOCK(COLUMN, column)
-    GRN_TS_EXPR_NODE_EVALUATE_CASE_BLOCK(OP, op)
-    default: {
-      return GRN_INVALID_ARGUMENT;
-    }
-  }
-}
-#undef GRN_TS_EXPR_NODE_EVALUATE_CASE_BLOCK
-
-/* grn_ts_expr_key_node_filter() filters records. */
-static grn_rc
-grn_ts_expr_key_node_filter(grn_ctx *ctx, grn_ts_expr_key_node *node,
-                            grn_ts_record *in, size_t n_in,
-                            grn_ts_record *out, size_t *n_out) {
-  size_t i, count = 0;
-  for (i = 0; i < n_in; i++) {
-    const grn_ts_bool *key;
-    size_t key_size;
-    key = (const grn_ts_bool *)grn_ts_table_get_key(ctx, node->table,
-                                                    in[i].id, &key_size);
-    if (key && (key_size == sizeof(*key)) && *key) {
-      out[count++] = in[i];
-    }
-  }
-  *n_out = count;
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_expr_value_node_filter() filters records. */
-static grn_rc
-grn_ts_expr_value_node_filter(grn_ctx *ctx, grn_ts_expr_value_node *node,
-                              grn_ts_record *in, size_t n_in,
-                              grn_ts_record *out, size_t *n_out) {
-  size_t i, count = 0;
-  for (i = 0; i < n_in; i++) {
-    const grn_ts_bool *value;
-    value = (const grn_ts_bool *)grn_ts_table_get_value(ctx, node->table,
-                                                        in[i].id);
-    if (value && *value) {
-      out[count++] = in[i];
-    }
+  for (i = 0; i < n_in; i++) {
+    out_ptr[i] |= buf_ptr[i];
   }
-  *n_out = count;
   return GRN_SUCCESS;
 }
 
-/* grn_ts_expr_const_node_filter() filters records. */
+/* grn_ts_expr_op_node_evaluate() evaluates an operator. */
 static grn_rc
-grn_ts_expr_const_node_filter(grn_ctx *ctx, grn_ts_expr_const_node *node,
-                              grn_ts_record *in, size_t n_in,
-                              grn_ts_record *out, size_t *n_out) {
-  if (node->content.bool_value) {
-    if (in != out) {
-      size_t i;
-      for (i = 0; i < n_in; i++) {
-        out[i] = in[i];
-      }
+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);
     }
-    *n_out = n_in;
-  } else {
-    *n_out = 0;
-  }
-  return GRN_SUCCESS;
-}
-
-/* grn_ts_expr_column_node_filter() filters records. */
-static grn_rc
-grn_ts_expr_column_node_filter(grn_ctx *ctx, grn_ts_expr_column_node *node,
-                               grn_ts_record *in, size_t n_in,
-                               grn_ts_record *out, size_t *n_out) {
-  size_t i, count = 0;
-  grn_ra *ra = (grn_ra *)node->column;
-  grn_ra_cache cache;
-  GRN_RA_CACHE_INIT(ra, &cache);
-  for (i = 0; i < n_in; i++) {
-    grn_ts_bool *ptr = NULL;
-    if (in[i].id) {
-      ptr = grn_ra_ref_cache(ctx, ra, in[i].id, &cache);
+    case GRN_TS_OP_LOGICAL_AND: {
+      return grn_ts_op_logical_and_evaluate(ctx, node, in, n_in, out);
     }
-    if (ptr && *ptr) {
-      out[count++] = in[i];
+    case GRN_TS_OP_LOGICAL_OR: {
+      return grn_ts_op_logical_or_evaluate(ctx, node, in, n_in, out);
+    }
+    // TODO
+    default: {
+      return GRN_OPERATION_NOT_SUPPORTED;
     }
   }
-  GRN_RA_CACHE_FIN(ra, &cache);
-  *n_out = count;
-  return GRN_SUCCESS;
 }
 
-/* Forward declaration for operator nodes. */
-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);
-
 /* 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,
@@ -2028,119 +2033,146 @@ grn_ts_expr_op_node_filter(grn_ctx *ctx, grn_ts_expr_op_node *node,
   }
 }
 
-#define GRN_TS_EXPR_NODE_FILTER_CASE_BLOCK(TYPE, type)\
-  case GRN_TS_EXPR_ ## TYPE ## _NODE: {\
-    grn_ts_expr_ ## type ## _node *type ## _node;\
-    type ## _node = (grn_ts_expr_ ## type ## _node *)node;\
-    return grn_ts_expr_ ## type ## _node_filter(ctx, type ## _node,\
-                                                in, n_in, out, n_out);\
-  }
-/* grn_ts_expr_node_filter() filters records. */
+/* grn_ts_expr_op_node_adjust() updates scores. */
 static grn_rc
-grn_ts_expr_node_filter(grn_ctx *ctx, grn_ts_expr_node *node,
-                        grn_ts_record *in, size_t n_in,
-                        grn_ts_record *out, size_t *n_out) {
-  if (node->data_kind != GRN_TS_BOOL) {
-    return GRN_INVALID_ARGUMENT;
-  }
-  switch (node->type) {
-    GRN_TS_EXPR_NODE_FILTER_CASE_BLOCK(KEY, key)
-    GRN_TS_EXPR_NODE_FILTER_CASE_BLOCK(VALUE, value)
-    GRN_TS_EXPR_NODE_FILTER_CASE_BLOCK(CONST, const)
-    GRN_TS_EXPR_NODE_FILTER_CASE_BLOCK(COLUMN, column)
-    GRN_TS_EXPR_NODE_FILTER_CASE_BLOCK(OP, op)
+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) {
+    // TODO
     default: {
-      return GRN_INVALID_ARGUMENT;
+      return GRN_OPERATION_NOT_SUPPORTED;
     }
   }
 }
-#undef GRN_TS_EXPR_NODE_FILTER_CASE_BLOCK
 
-/* grn_ts_expr_score_node_adjust() updates scores. */
-static grn_rc
-grn_ts_expr_score_node_adjust(grn_ctx *ctx, grn_ts_expr_score_node *node,
-                              grn_ts_record *io, size_t n_io) {
-  /* Nothing to do. */
-  return GRN_SUCCESS;
-}
+/*-------------------------------------------------------------
+ * grn_ts_expr_node.
+ */
 
-/* grn_ts_expr_key_node_adjust() updates scores. */
+/* grn_ts_expr_node_fin() finalizes a node. */
 static grn_rc
-grn_ts_expr_key_node_adjust(grn_ctx *ctx, grn_ts_expr_key_node *node,
-                            grn_ts_record *io, size_t n_io) {
-  size_t i;
-  for (i = 0; i < n_io; i++) {
-    const grn_ts_float *key;
-    size_t key_size;
-    key = (const grn_ts_float *)grn_ts_table_get_key(ctx, node->table,
-                                                     io[i].id, &key_size);
-    if (key && (key_size == sizeof(*key))) {
-      io[i].score = (grn_ts_score)*key;
+grn_ts_expr_node_fin(grn_ctx *ctx, grn_ts_expr_node *node) {
+  switch (node->type) {
+    case GRN_TS_EXPR_ID_NODE:
+    case GRN_TS_EXPR_SCORE_NODE: {
+      return GRN_SUCCESS;
     }
-  }
-  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 grn_ts_float *value;
-    value = (const grn_ts_float *)grn_ts_table_get_value(ctx, node->table,
-                                                         io[i].id);
-    if (value) {
-      io[i].score = (grn_ts_score)*value;
+    case GRN_TS_EXPR_KEY_NODE: {
+      grn_ts_expr_key_node *key_node = (grn_ts_expr_key_node *)node;
+      grn_ts_buf_fin(ctx, &key_node->buf);
+      if (key_node->table) {
+        grn_obj_unlink(ctx, key_node->table);
+      }
+      return GRN_SUCCESS;
+    }
+    case GRN_TS_EXPR_VALUE_NODE: {
+      grn_ts_expr_value_node *value_node = (grn_ts_expr_value_node *)node;
+      if (value_node->table) {
+        grn_obj_unlink(ctx, value_node->table);
+      }
+      return GRN_SUCCESS;
+    }
+    case GRN_TS_EXPR_CONST_NODE: {
+      grn_ts_expr_const_node *const_node = (grn_ts_expr_const_node *)node;
+      if (const_node->vector_buf) {
+        GRN_FREE(const_node->vector_buf);
+      }
+      if (const_node->text_buf) {
+        GRN_FREE(const_node->text_buf);
+      }
+      return GRN_SUCCESS;
+    }
+    case GRN_TS_EXPR_COLUMN_NODE: {
+      grn_ts_expr_column_node *column_node = (grn_ts_expr_column_node *)node;
+      grn_ts_buf_fin(ctx, &column_node->body_buf);
+      grn_ts_buf_fin(ctx, &column_node->buf);
+      if (column_node->column) {
+        grn_obj_unlink(ctx, column_node->column);
+      }
+      return GRN_SUCCESS;
+    }
+    case GRN_TS_EXPR_OP_NODE: {
+      grn_ts_expr_op_node *op_node = (grn_ts_expr_op_node *)node;
+      // TODO: Free memory.
+      if (op_node->buf) {
+        GRN_FREE(op_node->buf);
+      }
+      if (op_node->args) {
+        GRN_FREE(op_node->args);
+      }
+      return GRN_SUCCESS;
+    }
+    default: {
+      return GRN_INVALID_ARGUMENT;
     }
   }
-  return GRN_SUCCESS;
 }
 
-/* grn_ts_expr_const_node_adjust() updates scores. */
+/* grn_ts_expr_node_close() destroys a node. */
 static grn_rc
-grn_ts_expr_const_node_adjust(grn_ctx *ctx, grn_ts_expr_const_node *node,
-                              grn_ts_record *io, size_t n_io) {
-  size_t i;
-  grn_ts_score score = (grn_ts_score)node->content.float_value;
-  for (i = 0; i < n_io; i++) {
-    io[i].score = score;
+grn_ts_expr_node_close(grn_ctx *ctx, grn_ts_expr_node *node) {
+  grn_rc rc;
+  if (!node) {
+    return GRN_SUCCESS;
   }
-  return GRN_SUCCESS;
+  rc = grn_ts_expr_node_fin(ctx, node);
+  GRN_FREE(node);
+  return rc;
 }
 
-/* grn_ts_expr_column_node_adjust() updates scores. */
+#define GRN_TS_EXPR_NODE_EVALUATE_CASE_BLOCK(TYPE, type)\
+  case GRN_TS_EXPR_ ## TYPE ## _NODE: {\
+    grn_ts_expr_ ## type ## _node *type ## _node;\
+    type ## _node = (grn_ts_expr_ ## type ## _node *)node;\
+    return grn_ts_expr_ ## type ## _node_evaluate(ctx, type ## _node,\
+                                                  in, n_in, out);\
+  }
+/* grn_ts_expr_node_evaluate() evaluates a subexpression. */
 static grn_rc
-grn_ts_expr_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_ts_expr_node_evaluate(grn_ctx *ctx, grn_ts_expr_node *node,
+                          const grn_ts_record *in, size_t n_in, void *out) {
+  switch (node->type) {
+    GRN_TS_EXPR_NODE_EVALUATE_CASE_BLOCK(ID, id)
+    GRN_TS_EXPR_NODE_EVALUATE_CASE_BLOCK(SCORE, score)
+    GRN_TS_EXPR_NODE_EVALUATE_CASE_BLOCK(KEY, key)
+    GRN_TS_EXPR_NODE_EVALUATE_CASE_BLOCK(VALUE, value)
+    GRN_TS_EXPR_NODE_EVALUATE_CASE_BLOCK(CONST, const)
+    GRN_TS_EXPR_NODE_EVALUATE_CASE_BLOCK(COLUMN, column)
+    GRN_TS_EXPR_NODE_EVALUATE_CASE_BLOCK(OP, op)
+    default: {
+      return GRN_INVALID_ARGUMENT;
     }
   }
-  GRN_RA_CACHE_FIN(ra, &cache);
-  return GRN_SUCCESS;
 }
+#undef GRN_TS_EXPR_NODE_EVALUATE_CASE_BLOCK
 
-/* grn_ts_expr_op_node_adjust() updates scores. */
+#define GRN_TS_EXPR_NODE_FILTER_CASE_BLOCK(TYPE, type)\
+  case GRN_TS_EXPR_ ## TYPE ## _NODE: {\
+    grn_ts_expr_ ## type ## _node *type ## _node;\
+    type ## _node = (grn_ts_expr_ ## type ## _node *)node;\
+    return grn_ts_expr_ ## type ## _node_filter(ctx, type ## _node,\
+                                                in, n_in, out, n_out);\
+  }
+/* grn_ts_expr_node_filter() filters records. */
 static grn_rc
-grn_ts_expr_op_node_adjust(grn_ctx *ctx, grn_ts_expr_op_node *node,
-                           grn_ts_record *io, size_t n_io) {
-  switch (node->op_type) {
-    // TODO
+grn_ts_expr_node_filter(grn_ctx *ctx, grn_ts_expr_node *node,
+                        grn_ts_record *in, size_t n_in,
+                        grn_ts_record *out, size_t *n_out) {
+  if (node->data_kind != GRN_TS_BOOL) {
+    return GRN_INVALID_ARGUMENT;
+  }
+  switch (node->type) {
+    GRN_TS_EXPR_NODE_FILTER_CASE_BLOCK(KEY, key)
+    GRN_TS_EXPR_NODE_FILTER_CASE_BLOCK(VALUE, value)
+    GRN_TS_EXPR_NODE_FILTER_CASE_BLOCK(CONST, const)
+    GRN_TS_EXPR_NODE_FILTER_CASE_BLOCK(COLUMN, column)
+    GRN_TS_EXPR_NODE_FILTER_CASE_BLOCK(OP, op)
     default: {
-      return GRN_OPERATION_NOT_SUPPORTED;
+      return GRN_INVALID_ARGUMENT;
     }
   }
 }
+#undef GRN_TS_EXPR_NODE_FILTER_CASE_BLOCK
 
 #define GRN_TS_EXPR_NODE_ADJUST_CASE_BLOCK(TYPE, type)\
   case GRN_TS_EXPR_ ## TYPE ## _NODE: {\
-------------- next part --------------
HTML����������������������������...
下载 



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