[Groonga-commit] groonga/groonga at 0fbf8b0 [master] egn: refactor the implementation for future enhancement

Back to archive index

susumu.yata null+****@clear*****
Wed Jul 15 12:12:30 JST 2015


susumu.yata	2015-07-15 12:12:30 +0900 (Wed, 15 Jul 2015)

  New Revision: 0fbf8b0bd7f5f6a9c80cf22802c7e6840dde5a19
  https://github.com/groonga/groonga/commit/0fbf8b0bd7f5f6a9c80cf22802c7e6840dde5a19

  Message:
    egn: refactor the implementation for future enhancement
    
    Operators are currently disabled.

  Modified files:
    lib/egn.cpp
    lib/grn_egn.h
    lib/grn_egn.hpp

  Modified: lib/egn.cpp (+2033 -2717)
===================================================================
--- lib/egn.cpp    2015-07-15 11:53:32 +0900 (257ecc1)
+++ lib/egn.cpp    2015-07-15 12:12:30 +0900 (9f0005b)
@@ -38,21 +38,46 @@
 
 namespace {
 
-enum { GRN_EGN_MAX_BATCH_SIZE = 1024 };
+enum {
+  GRN_EGN_MAX_BUILTIN_TYPE = GRN_DB_WGS84_GEO_POINT,
+  GRN_EGN_MAX_BATCH_SIZE = 1024
+};
 
-bool grn_egn_is_table_cursor(grn_obj *obj) {
-  if (!obj) {
-    return false;
-  }
-  switch (obj->header.type) {
-    case GRN_CURSOR_TABLE_PAT_KEY:
-    case GRN_CURSOR_TABLE_DAT_KEY:
-    case GRN_CURSOR_TABLE_HASH_KEY:
-    case GRN_CURSOR_TABLE_NO_KEY: {
-      return true;
+grn_egn_data_type grn_egn_simplify_builtin_type(grn_builtin_type builtin_type) {
+  switch (builtin_type) {
+    case GRN_DB_VOID: {
+      return GRN_EGN_VOID;
+    }
+    case GRN_DB_BOOL: {
+      return GRN_EGN_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_EGN_INT;
+    }
+    case GRN_DB_FLOAT: {
+      return GRN_EGN_FLOAT;
+    }
+    case GRN_DB_TIME: {
+      return GRN_EGN_TIME;
+    }
+    case GRN_DB_SHORT_TEXT:
+    case GRN_DB_TEXT:
+    case GRN_DB_LONG_TEXT: {
+      return GRN_EGN_TEXT;
+    }
+    case GRN_DB_TOKYO_GEO_POINT:
+    case GRN_DB_WGS84_GEO_POINT: {
+      return GRN_EGN_GEO_POINT;
     }
     default: {
-      return false;
+      return GRN_EGN_VOID;
     }
   }
 }
@@ -76,18 +101,7 @@ class TableCursor : public Cursor {
   }
 
   static grn_rc open(grn_ctx *ctx, grn_obj *cursor, Score default_score,
-                     Cursor **wrapper) {
-    if (!ctx || !grn_egn_is_table_cursor(cursor) || !wrapper) {
-      return GRN_INVALID_ARGUMENT;
-    }
-    TableCursor *new_wrapper =
-      new (std::nothrow) TableCursor(ctx, cursor, default_score);
-    if (!new_wrapper) {
-      return GRN_NO_MEMORY_AVAILABLE;
-    }
-    *wrapper = new_wrapper;
-    return GRN_SUCCESS;
-  }
+                     Cursor **wrapper);
 
   grn_rc read(Record *records, size_t size, size_t *count);
 
@@ -100,6 +114,31 @@ class TableCursor : public Cursor {
     : Cursor(), ctx_(ctx), cursor_(cursor), default_score_(default_score) {}
 };
 
+grn_rc TableCursor::open(grn_ctx *ctx, grn_obj *cursor, Score default_score,
+                         Cursor **wrapper) {
+  if (!ctx || !cursor || !wrapper) {
+    return GRN_INVALID_ARGUMENT;
+  }
+  switch (cursor->header.type) {
+    case GRN_CURSOR_TABLE_PAT_KEY:
+    case GRN_CURSOR_TABLE_DAT_KEY:
+    case GRN_CURSOR_TABLE_HASH_KEY:
+    case GRN_CURSOR_TABLE_NO_KEY: {
+      break;
+    }
+    default: {
+      return GRN_INVALID_ARGUMENT;
+    }
+  }
+  TableCursor *new_wrapper =
+    new (std::nothrow) TableCursor(ctx, cursor, default_score);
+  if (!new_wrapper) {
+    return GRN_NO_MEMORY_AVAILABLE;
+  }
+  *wrapper = new_wrapper;
+  return GRN_SUCCESS;
+}
+
 grn_rc TableCursor::read(Record *records, size_t size, size_t *count) {
   if ((!records && (size != 0)) || !count) {
     return GRN_INVALID_ARGUMENT;
@@ -201,8 +240,10 @@ class ExpressionNode {
   virtual ~ExpressionNode() {}
 
   virtual ExpressionNodeType type() const = 0;
-  virtual DataType data_type() const = 0;
   virtual grn_builtin_type builtin_type() const = 0;
+  virtual grn_obj *ref_table() const = 0;
+  virtual int dimension() const = 0;
+  virtual DataType data_type() const = 0;
 
   virtual grn_rc filter(Record *input, size_t input_size,
                         Record *output, size_t *output_size) {
@@ -211,118 +252,18 @@ class ExpressionNode {
   virtual grn_rc adjust(Record *records, size_t num_records) {
     return GRN_OPERATION_NOT_SUPPORTED;
   }
+  virtual grn_rc evaluate(const Record *records, size_t num_records,
+                          void *results) = 0;
 };
 
-// -- TypedNode<T> --
-
-template <typename T>
-class TypedNode : public ExpressionNode {
- public:
-  TypedNode() : ExpressionNode() {}
-  virtual ~TypedNode() {}
-
-  DataType data_type() const {
-    return T::data_type();
-  }
-  virtual grn_builtin_type builtin_type() const {
-    return T::default_builtin_type();
-  }
-
-  virtual grn_rc evaluate(
-    const Record *records, size_t num_records, T *results) = 0;
-};
-
-// -- TypedNode<Bool> --
-
-template <>
-class TypedNode<Bool> : public ExpressionNode {
- public:
-  TypedNode() : ExpressionNode(), values_for_filter_() {}
-  virtual ~TypedNode() {}
-
-  DataType data_type() const {
-    return Bool::data_type();
-  }
-  grn_builtin_type builtin_type() const {
-    return Bool::default_builtin_type();
-  }
-
-  virtual grn_rc filter(Record *input, size_t input_size,
-                        Record *output, size_t *output_size);
-
-  virtual grn_rc evaluate(
-    const Record *records, size_t num_records, Bool *results) = 0;
-
- private:
-  std::vector<Bool> values_for_filter_;
-};
-
-grn_rc TypedNode<Bool>::filter(Record *input, size_t input_size,
-                               Record *output, size_t *output_size) {
-  if (values_for_filter_.size() < input_size) {
-    values_for_filter_.resize(input_size);
-  }
-  grn_rc rc = evaluate(input, input_size, &*values_for_filter_.begin());
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  size_t count = 0;
-  for (size_t i = 0; i < input_size; ++i) {
-    if (values_for_filter_[i].raw) {
-      output[count] = input[i];
-      ++count;
-    }
-  }
-  *output_size = count;
-  return GRN_SUCCESS;
-}
-
-// -- TypedNode<Float> --
-
-template <>
-class TypedNode<Float> : public ExpressionNode {
- public:
-  TypedNode() : ExpressionNode(), values_for_adjust_() {}
-  virtual ~TypedNode() {}
-
-  DataType data_type() const {
-    return Float::data_type();
-  }
-  grn_builtin_type builtin_type() const {
-    return Float::default_builtin_type();
-  }
-
-  virtual grn_rc adjust(Record *records, size_t num_records);
-
-  virtual grn_rc evaluate(
-    const Record *records, size_t num_records, Float *results) = 0;
-
- private:
-  std::vector<Float> values_for_adjust_;
-};
-
-grn_rc TypedNode<Float>::adjust(Record *records, size_t num_records) {
-  if (values_for_adjust_.size() < num_records) {
-    values_for_adjust_.resize(num_records);
-  }
-  grn_rc rc = evaluate(records, num_records, &*values_for_adjust_.begin());
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  for (size_t i = 0; i < num_records; ++i) {
-    records[i].score = values_for_adjust_[i].raw;
-  }
-  return GRN_SUCCESS;
-}
-
 // -- IDNode --
 
-class IDNode : public TypedNode<Int> {
+class IDNode : public ExpressionNode {
  public:
   ~IDNode() {}
 
   static grn_rc open(ExpressionNode **node) {
-    ExpressionNode *new_node = new (std::nothrow) IDNode();
+    ExpressionNode *new_node = new (std::nothrow) IDNode;
     if (!new_node) {
       return GRN_NO_MEMORY_AVAILABLE;
     }
@@ -336,27 +277,35 @@ class IDNode : public TypedNode<Int> {
   grn_builtin_type builtin_type() const {
     return GRN_DB_UINT32;
   }
+  grn_obj *ref_table() const {
+    return NULL;
+  }
+  int dimension() const {
+    return 0;
+  }
+  DataType data_type() const {
+    return GRN_EGN_INT;
+  }
 
-  grn_rc evaluate(
-    const Record *records, size_t num_records, Int *results) {
+  grn_rc evaluate(const Record *records, size_t num_records, void *results) {
     for (size_t i = 0; i < num_records; ++i) {
-      results[i] = Int(records[i].id);
+      static_cast<grn_egn_int *>(results)[i] = records[i].id;
     }
     return GRN_SUCCESS;
   }
 
  private:
-  IDNode() : TypedNode<Int>() {}
+  IDNode() : ExpressionNode() {}
 };
 
 // -- ScoreNode --
 
-class ScoreNode : public TypedNode<Float> {
+class ScoreNode : public ExpressionNode {
  public:
   ~ScoreNode() {}
 
   static grn_rc open(ExpressionNode **node) {
-    ExpressionNode *new_node = new (std::nothrow) ScoreNode();
+    ExpressionNode *new_node = new (std::nothrow) ScoreNode;
     if (!new_node) {
       return GRN_NO_MEMORY_AVAILABLE;
     }
@@ -367,95 +316,134 @@ class ScoreNode : public TypedNode<Float> {
   ExpressionNodeType type() const {
     return GRN_EGN_SCORE_NODE;
   }
-
-  grn_rc evaluate(
-    const Record *records, size_t num_records, Float *results) {
-    for (size_t i = 0; i < num_records; ++i) {
-      results[i] = Float(records[i].score);
-    }
-    return GRN_SUCCESS;
+  grn_builtin_type builtin_type() const {
+    return GRN_DB_FLOAT;
   }
-
- private:
-  ScoreNode() : TypedNode<Float>() {}
-};
-
-// -- ConstantNode<T> --
-
-template <typename T>
-class ConstantNode : public TypedNode<T> {
- public:
-  ~ConstantNode() {}
-
-  static grn_rc open(const T &value, ExpressionNode **node) {
-    ConstantNode *new_node = new (std::nothrow) ConstantNode(value);
-    if (!new_node) {
-      return GRN_NO_MEMORY_AVAILABLE;
-    }
-    *node = new_node;
-    return GRN_SUCCESS;
+  grn_obj *ref_table() const {
+    return NULL;
   }
-
-  ExpressionNodeType type() const {
-    return GRN_EGN_CONSTANT_NODE;
+  int dimension() const {
+    return 0;
+  }
+  DataType data_type() const {
+    return GRN_EGN_FLOAT;
   }
 
+  grn_rc adjust(Record *records, size_t num_records) {
+    return GRN_SUCCESS;
+  }
   grn_rc evaluate(
-    const Record *records, size_t num_records, T *results) {
+    const Record *records, size_t num_records, void *results) {
     for (size_t i = 0; i < num_records; ++i) {
-      results[i] = value_;
+      static_cast<grn_egn_float *>(results)[i] = records[i].score;
     }
     return GRN_SUCCESS;
   }
 
  private:
-  T value_;
-
-  explicit ConstantNode(const T &value) : TypedNode<T>(), value_(value) {}
+  ScoreNode() : ExpressionNode() {}
 };
 
-// -- ConstantNode<Bool> --
+// -- ConstantNode --
 
-template <>
-class ConstantNode<Bool> : public TypedNode<Bool> {
+class ConstantNode : public ExpressionNode {
  public:
-  ~ConstantNode() {}
-
-  static grn_rc open(Bool value, ExpressionNode **node) {
-    ConstantNode *new_node = new (std::nothrow) ConstantNode(value);
-    if (!new_node) {
-      return GRN_NO_MEMORY_AVAILABLE;
+  ~ConstantNode() {
+    if (obj_) {
+      grn_obj_unlink(ctx_, obj_);
+    }
+    if (buf_) {
+      grn_obj_unlink(ctx_, buf_);
     }
-    *node = new_node;
-    return GRN_SUCCESS;
   }
 
+  static grn_rc open(grn_ctx *ctx, grn_obj *obj, ExpressionNode **node);
+
   ExpressionNodeType type() const {
     return GRN_EGN_CONSTANT_NODE;
   }
+  grn_builtin_type builtin_type() const {
+    return builtin_type_;
+  }
+  grn_obj *ref_table() const {
+    return NULL;
+  }
+  int dimension() const {
+    return dimension_;
+  }
+  DataType data_type() const {
+    return data_type_;
+  }
 
   grn_rc filter(Record *input, size_t input_size,
                 Record *output, size_t *output_size);
-
-  grn_rc evaluate(
-    const Record *records, size_t num_records, Bool *results) {
-    for (size_t i = 0; i < num_records; ++i) {
-      results[i] = value_;
-    }
-    return GRN_SUCCESS;
-  }
+  grn_rc adjust(Record *records, size_t num_records);
+  grn_rc evaluate(const Record *records, size_t num_records, void *results);
 
  private:
-  Bool value_;
-
-  explicit ConstantNode(Bool value) : TypedNode<Bool>(), value_(value) {}
+  grn_ctx *ctx_;
+  grn_obj *obj_;
+  grn_obj *buf_;
+  grn_builtin_type builtin_type_;
+  int dimension_;
+  DataType data_type_;
+
+  static grn_rc convert(grn_ctx *ctx, grn_obj *obj,
+                        grn_obj **new_obj, grn_obj **buf);
+  static grn_rc convert_bulk(grn_ctx *ctx, grn_obj *obj,
+                             grn_obj **new_obj, grn_obj **buf);
+  static grn_rc convert_uvector(grn_ctx *ctx, grn_obj *obj,
+                                grn_obj **new_obj, grn_obj **buf);
+  static grn_rc convert_vector(grn_ctx *ctx, grn_obj *obj,
+                               grn_obj **new_obj, grn_obj **buf);
+
+  ConstantNode(grn_ctx *ctx, grn_obj *obj, grn_obj *buf,
+               grn_builtin_type builtin_type, int dimension)
+    : ExpressionNode(),
+      ctx_(ctx),
+      obj_(obj),
+      buf_(buf),
+      builtin_type_(builtin_type),
+      dimension_(dimension),
+      data_type_(grn_egn_simplify_builtin_type(builtin_type)) {}
 };
 
-grn_rc ConstantNode<Bool>::filter(
-  Record *input, size_t input_size,
-  Record *output, size_t *output_size) {
-  if (value_.raw == GRN_TRUE) {
-    // The I/O areas are the same and there is no need to copy records.
+grn_rc ConstantNode::open(grn_ctx *ctx, grn_obj *obj, ExpressionNode **node) {
+  grn_obj *new_obj;
+  grn_obj *buf;
+  grn_rc rc = convert(ctx, obj, &new_obj, &buf);
+  if (rc != GRN_SUCCESS) {
+    return rc;
+  }
+  grn_builtin_type builtin_type =
+    static_cast<grn_builtin_type>(obj->header.domain);
+  int dimension = obj->header.type != GRN_BULK;
+  ConstantNode *new_node = new (std::nothrow) ConstantNode(
+    ctx, new_obj ? new_obj : obj, buf, builtin_type, dimension);
+  if (!new_node) {
+    if (new_obj) {
+      grn_obj_close(ctx, new_obj);
+    }
+    if (buf) {
+      grn_obj_close(ctx, buf);
+    }
+    return GRN_NO_MEMORY_AVAILABLE;
+  }
+  if (new_obj) {
+    grn_obj_unlink(ctx, obj);
+  }
+  *node = new_node;
+  return GRN_SUCCESS;
+}
+
+grn_rc ConstantNode::filter(Record *input, size_t input_size,
+                            Record *output, size_t *output_size) {
+  if ((dimension() != 0) || (data_type() != GRN_EGN_BOOL)) {
+    return GRN_OPERATION_NOT_PERMITTED;
+  }
+  grn_egn_bool value = GRN_BOOL_VALUE(obj_);
+  if (value) {
+    // If the I/O areas are the same, there is no need to copy records.
     if (input != output) {
       for (size_t i = 0; i < input_size; ++i) {
         output[i] = input[i];
@@ -468,255 +456,415 @@ grn_rc ConstantNode<Bool>::filter(
   return GRN_SUCCESS;
 }
 
-// -- ConstantNode<Int> --
-
-
-template <>
-class ConstantNode<Int> : public TypedNode<Int> {
- public:
-  ~ConstantNode() {}
-
-  static grn_rc open(grn_builtin_type builtin_type, Int value,
-                     ExpressionNode **node) {
-    ConstantNode *new_node =
-      new (std::nothrow) ConstantNode(builtin_type, value);
-    if (!new_node) {
-      return GRN_NO_MEMORY_AVAILABLE;
-    }
-    *node = new_node;
-    return GRN_SUCCESS;
-  }
-
-  ExpressionNodeType type() const {
-    return GRN_EGN_CONSTANT_NODE;
+grn_rc ConstantNode::adjust(Record *records, size_t num_records) {
+  if ((dimension() != 0) || (data_type() != GRN_EGN_FLOAT)) {
+    return GRN_OPERATION_NOT_PERMITTED;
   }
-  grn_builtin_type builtin_type() const {
-    return builtin_type_;
+  grn_egn_float value = GRN_FLOAT_VALUE(obj_);
+  for (size_t i = 0; i < num_records; ++i) {
+    records[i].score = value;
   }
+  return GRN_SUCCESS;
+}
 
-  grn_rc evaluate(const Record *records, size_t num_records, Int *results) {
-    for (size_t i = 0; i < num_records; ++i) {
-      results[i] = value_;
-    }
+grn_rc ConstantNode::evaluate(const Record *records, size_t num_records,
+                              void *results) {
+  if (num_records == 0) {
     return GRN_SUCCESS;
   }
-
- private:
-  grn_builtin_type builtin_type_;
-  Int value_;
-
-  explicit ConstantNode(grn_builtin_type builtin_type, Int value)
-    : TypedNode<Int>(), builtin_type_(builtin_type), value_(value) {}
-};
-
-// -- ConstantNode<Float> --
-
-template <>
-class ConstantNode<Float> : public TypedNode<Float> {
- public:
-  ~ConstantNode() {}
-
-  static grn_rc open(Float value, ExpressionNode **node) {
-    ConstantNode *new_node = new (std::nothrow) ConstantNode(value);
-    if (!new_node) {
-      return GRN_NO_MEMORY_AVAILABLE;
+  if (dimension() == 0) {
+    // Scalar types.
+    switch (data_type()) {
+      case GRN_EGN_BOOL: {
+        grn_egn_bool value = GRN_BOOL_VALUE(obj_);
+        for (size_t i = 0; i < num_records; ++i) {
+          static_cast<grn_egn_bool *>(results)[i] = value;
+        }
+        break;
+      }
+      case GRN_EGN_INT:
+      case GRN_EGN_FLOAT:
+      case GRN_EGN_TIME:
+      case GRN_EGN_GEO_POINT: {
+        const void *head = GRN_BULK_HEAD(obj_);
+        char *ptr = static_cast<char *>(results);
+        for (size_t i = 0; i < num_records; ++i) {
+          std::memcpy(ptr, head, 8);
+          ptr += 8;
+        }
+        break;
+      }
+      case GRN_EGN_TEXT: {
+        grn_egn_text value;
+        value.ptr = GRN_BULK_HEAD(obj_);
+        value.size = GRN_BULK_VSIZE(obj_);
+        for (size_t i = 0; i < num_records; ++i) {
+          static_cast<grn_egn_text *>(results)[i] = value;
+        }
+        break;
+      }
+      default: {
+        return GRN_UNKNOWN_ERROR;
+      }
     }
-    *node = new_node;
-    return GRN_SUCCESS;
-  }
-
-  ExpressionNodeType type() const {
-    return GRN_EGN_CONSTANT_NODE;
-  }
-
-  grn_rc adjust(Record *records, size_t num_records) {
-    for (size_t i = 0; i < num_records; ++i) {
-      records[i].score = value_.raw;
+  } else {
+    // Vector types.
+    switch (data_type()) {
+      case GRN_EGN_BOOL:
+      case GRN_EGN_INT:
+      case GRN_EGN_FLOAT:
+      case GRN_EGN_TIME:
+      case GRN_EGN_GEO_POINT: {
+        grn_egn_vector value;
+        value.ptr = GRN_BULK_HEAD(obj_);
+        value.size = grn_vector_size(ctx_, obj_);
+        for (size_t i = 0; i < num_records; ++i) {
+          static_cast<grn_egn_vector *>(results)[i] = value;
+        }
+        break;
+      }
+      case GRN_EGN_TEXT: {
+        grn_egn_vector value;
+        value.ptr = GRN_BULK_HEAD(obj_);
+        value.size = GRN_BULK_VSIZE(obj_) / sizeof(grn_egn_text);
+        for (size_t i = 0; i < num_records; ++i) {
+          static_cast<grn_egn_vector *>(results)[i] = value;
+        }
+        break;
+      }
+      default: {
+        return GRN_UNKNOWN_ERROR;
+      }
     }
-    return GRN_SUCCESS;
   }
+  return GRN_SUCCESS;
+}
 
-  grn_rc evaluate(
-    const Record *records, size_t num_records, Float *results) {
-    for (size_t i = 0; i < num_records; ++i) {
-      results[i] = value_;
-    }
-    return GRN_SUCCESS;
-  }
-
- private:
-  Float value_;
-
-  explicit ConstantNode(Float value) : TypedNode<Float>(), value_(value) {}
-};
-
-// -- ConstantNode<Text> --
-
-template <>
-class ConstantNode<Text> : public TypedNode<Text> {
- public:
-  ~ConstantNode() {}
-
-  static grn_rc open(grn_builtin_type builtin_type, const Text &value,
-                     ExpressionNode **node) {
-    ConstantNode *new_node = new (std::nothrow) ConstantNode(value);
-    if (!new_node) {
-      return GRN_NO_MEMORY_AVAILABLE;
+grn_rc ConstantNode::convert(grn_ctx *ctx, grn_obj *obj,
+                             grn_obj **new_obj, grn_obj **buf) {
+  *new_obj = NULL;
+  *buf = NULL;
+  switch (obj->header.type) {
+    case GRN_BULK: {
+      return convert_bulk(ctx, obj, new_obj, buf);
     }
-    try {
-      new_node->value_buf_.resize(value.raw.size);
-    } catch (const std::bad_alloc &) {
-      delete new_node;
-      return GRN_NO_MEMORY_AVAILABLE;
+    case GRN_UVECTOR: {
+      return convert_uvector(ctx, obj, new_obj, buf);
+    }
+    case GRN_VECTOR: {
+      return convert_vector(ctx, obj, new_obj, buf);
+    }
+    default: {
+      return GRN_INVALID_ARGUMENT;
     }
-    std::memcpy(&*new_node->value_buf_.begin(), value.raw.ptr, value.raw.size);
-    new_node->value_.raw.ptr = &*new_node->value_buf_.begin();
-    *node = new_node;
-    return GRN_SUCCESS;
   }
+}
 
-  ExpressionNodeType type() const {
-    return GRN_EGN_CONSTANT_NODE;
+#define GRN_EGN_CONVERT_BULK_INT_CASE_BLOCK(type)\
+  case GRN_DB_ ## type: {\
+    GRN_INT64_SET(ctx, *new_obj, GRN_ ## type ## _VALUE(obj));\
+    break;\
+  }
+grn_rc ConstantNode::convert_bulk(grn_ctx *ctx, grn_obj *obj,
+                                  grn_obj **new_obj, grn_obj **buf) {
+  switch (obj->header.domain) {
+    case GRN_DB_BOOL:
+    case GRN_DB_INT64:
+    case GRN_DB_FLOAT:
+    case GRN_DB_TIME:
+    case GRN_DB_SHORT_TEXT:
+    case GRN_DB_TEXT:
+    case GRN_DB_LONG_TEXT:
+    case GRN_DB_TOKYO_GEO_POINT:
+    case GRN_DB_WGS84_GEO_POINT: {
+      return GRN_SUCCESS;
+    }
+    case GRN_DB_INT8:
+    case GRN_DB_INT16:
+    case GRN_DB_INT32:
+    case GRN_DB_UINT8:
+    case GRN_DB_UINT16:
+    case GRN_DB_UINT32:
+    case GRN_DB_UINT64: {
+      *new_obj = grn_obj_open(ctx, GRN_BULK, 0, GRN_DB_INT64);
+      if (!*new_obj) {
+        return GRN_NO_MEMORY_AVAILABLE;
+      }
+      switch (obj->header.domain) {
+        GRN_EGN_CONVERT_BULK_INT_CASE_BLOCK(INT8)
+        GRN_EGN_CONVERT_BULK_INT_CASE_BLOCK(INT16)
+        GRN_EGN_CONVERT_BULK_INT_CASE_BLOCK(INT32)
+        GRN_EGN_CONVERT_BULK_INT_CASE_BLOCK(UINT8)
+        GRN_EGN_CONVERT_BULK_INT_CASE_BLOCK(UINT16)
+        GRN_EGN_CONVERT_BULK_INT_CASE_BLOCK(UINT32)
+        GRN_EGN_CONVERT_BULK_INT_CASE_BLOCK(UINT64)
+        default: {
+          return GRN_UNKNOWN_ERROR;
+        }
+      }
+      return GRN_SUCCESS;
+    }
+    default: {
+      return GRN_INVALID_ARGUMENT;
+    }
   }
-  grn_builtin_type builtin_type() const {
-    return builtin_type_;
+}
+#undef GRN_EGN_CONVERT_BULK_INT_CASE_BLOCK
+
+#define GRN_EGN_CONVERT_UVECTOR_INT_CASE_BLOCK(type)\
+  case GRN_DB_ ## type: {\
+    for (size_t i = 0; i < size; ++i) {\
+      GRN_INT64_SET_AT(ctx, *new_obj, i, GRN_ ## type ## _VALUE_AT(obj, i));\
+    }\
+    break;\
+  }
+grn_rc ConstantNode::convert_uvector(grn_ctx *ctx, grn_obj *obj,
+                                     grn_obj **new_obj, grn_obj **buf) {
+  switch (obj->header.domain) {
+    case GRN_DB_BOOL:
+    case GRN_DB_INT64:
+    case GRN_DB_FLOAT:
+    case GRN_DB_TIME:
+    case GRN_DB_TOKYO_GEO_POINT:
+    case GRN_DB_WGS84_GEO_POINT: {
+      return GRN_SUCCESS;
+    }
+    case GRN_DB_INT8:
+    case GRN_DB_INT16:
+    case GRN_DB_INT32:
+    case GRN_DB_UINT8:
+    case GRN_DB_UINT16:
+    case GRN_DB_UINT32:
+    case GRN_DB_UINT64: {
+      *new_obj = grn_obj_open(ctx, GRN_UVECTOR, 0, GRN_DB_INT64);
+      if (!new_obj) {
+        return GRN_NO_MEMORY_AVAILABLE;
+      }
+      size_t size = grn_vector_size(ctx, obj);
+      switch (obj->header.domain) {
+        GRN_EGN_CONVERT_UVECTOR_INT_CASE_BLOCK(INT8)
+        GRN_EGN_CONVERT_UVECTOR_INT_CASE_BLOCK(INT16)
+        GRN_EGN_CONVERT_UVECTOR_INT_CASE_BLOCK(INT32)
+        GRN_EGN_CONVERT_UVECTOR_INT_CASE_BLOCK(UINT8)
+        GRN_EGN_CONVERT_UVECTOR_INT_CASE_BLOCK(UINT16)
+        GRN_EGN_CONVERT_UVECTOR_INT_CASE_BLOCK(UINT32)
+        GRN_EGN_CONVERT_UVECTOR_INT_CASE_BLOCK(UINT64)
+        default: {
+          return GRN_UNKNOWN_ERROR;
+        }
+      }
+      return GRN_SUCCESS;
+    }
+    default: {
+      return GRN_INVALID_ARGUMENT;
+    }
   }
+}
+#undef GRN_EGN_CONVERT_UVECTOR_INT_CASE_BLOCK
 
-  grn_rc evaluate(
-    const Record *records, size_t num_records, Text *results) {
-    for (size_t i = 0; i < num_records; ++i) {
-      results[i] = value_;
+grn_rc ConstantNode::convert_vector(grn_ctx *ctx, grn_obj *obj,
+                                    grn_obj **new_obj, grn_obj **buf) {
+  switch (obj->header.domain) {
+    case GRN_DB_SHORT_TEXT:
+    case GRN_DB_TEXT:
+    case GRN_DB_LONG_TEXT: {
+      break;
+    }
+    default: {
+      return GRN_INVALID_ARGUMENT;
     }
-    return GRN_SUCCESS;
   }
-
- private:
-  grn_builtin_type builtin_type_;
-  Text value_;
-  std::vector<char> value_buf_;
-
-  explicit ConstantNode(const Text &value)
-    : TypedNode<Text>(), value_(value), value_buf_() {}
-};
-
-// -- ConstantNode<BoolVector> --
-
-template <>
-class ConstantNode<BoolVector> : public TypedNode<BoolVector> {
- public:
-  ~ConstantNode() {}
-
-  static grn_rc open(const BoolVector &value, ExpressionNode **node) {
-    ConstantNode *new_node = new (std::nothrow) ConstantNode(value);
-    if (!new_node) {
+  grn_rc rc = GRN_SUCCESS;
+  *new_obj = grn_obj_open(ctx, GRN_BULK, 0, GRN_DB_TEXT);
+  if (!*new_obj) {
+    return GRN_NO_MEMORY_AVAILABLE;
+  }
+  size_t size = grn_vector_size(ctx, obj);
+  rc = grn_bulk_resize(ctx, *new_obj, sizeof(grn_egn_text) * size);
+  if (rc == GRN_SUCCESS) {
+    *buf = grn_obj_open(ctx, GRN_BULK, 0, GRN_DB_TEXT);
+    if (!*buf) {
+      grn_obj_close(ctx, *new_obj);
       return GRN_NO_MEMORY_AVAILABLE;
     }
-    try {
-      new_node->value_buf_.resize(value.raw.size);
-    } catch (const std::bad_alloc &) {
-      delete new_node;
-      return GRN_NO_MEMORY_AVAILABLE;
+    grn_egn_text *values =
+      reinterpret_cast<grn_egn_text *>(GRN_BULK_HEAD(*new_obj));
+    for (size_t i = 0; i < size; ++i) {
+      const char *ptr;
+      values[i].size = grn_vector_get_element(ctx, obj, i, &ptr, NULL, NULL);
+      GRN_TEXT_PUT(ctx, *buf, ptr, values[i].size);
+      if (rc != GRN_SUCCESS) {
+        break;
+      }
+    }
+    if (rc == GRN_SUCCESS) {
+      const char *ptr = GRN_BULK_HEAD(*buf);
+      for (size_t i = 0; i < size; ++i) {
+        values[i].ptr = ptr;
+        ptr += values[i].size;
+      }
     }
-    std::memcpy(&*new_node->value_buf_.begin(), value.raw.ptr,
-                sizeof(grn_egn_bool) * value.raw.size);
-    new_node->value_.raw.ptr = &*new_node->value_buf_.begin();
-    *node = new_node;
-    return GRN_SUCCESS;
-  }
-
-  ExpressionNodeType type() const {
-    return GRN_EGN_CONSTANT_NODE;
   }
-
-  grn_rc evaluate(
-    const Record *records, size_t num_records, BoolVector *results) {
-    for (size_t i = 0; i < num_records; ++i) {
-      results[i] = value_;
+  if (rc != GRN_SUCCESS) {
+    if (*new_obj) {
+      grn_obj_close(ctx, *new_obj);
+    }
+    if (*buf) {
+      grn_obj_close(ctx, *buf);
     }
-    return GRN_SUCCESS;
   }
-
- private:
-  grn_builtin_type builtin_type_;
-  BoolVector value_;
-  std::vector<grn_egn_bool> value_buf_;
-
-  explicit ConstantNode(const BoolVector &value)
-    : TypedNode<BoolVector>(), value_(value), value_buf_() {}
-};
+  return GRN_SUCCESS;
+}
 
 // -- ColumnNode --
 
-template <typename T>
-class ColumnNode : public TypedNode<T> {
+class ColumnNode : public ExpressionNode {
  public:
-  ~ColumnNode() {}
-
-  static grn_rc open(grn_ctx *ctx, grn_obj *column, ExpressionNode **node) {
-    ColumnNode *new_node = new (std::nothrow) ColumnNode(ctx, column);
-    if (!new_node) {
-      return GRN_NO_MEMORY_AVAILABLE;
+  ~ColumnNode() {
+    if (column_) {
+      grn_obj_unlink(ctx_, column_);
+    }
+    if (ref_table_) {
+      grn_obj_unlink(ctx_, ref_table_);
+    }
+    if (buf_) {
+      grn_obj_close(ctx_, buf_);
+    }
+    if (deep_buf_) {
+      grn_obj_close(ctx_, deep_buf_);
     }
-    *node = new_node;
-    return GRN_SUCCESS;
   }
 
+  static grn_rc open(grn_ctx *ctx, grn_obj *column, ExpressionNode **node);
+
   ExpressionNodeType type() const {
     return GRN_EGN_COLUMN_NODE;
   }
-
-  grn_rc evaluate(
-    const Record *records, size_t num_records, T *results) {
-    // TODO
-    return GRN_OPERATION_NOT_SUPPORTED;
+  grn_builtin_type builtin_type() const {
+    return builtin_type_;
+  }
+  grn_obj *ref_table() const {
+    return NULL;
   }
+  int dimension() const {
+    return dimension_;
+  }
+  DataType data_type() const {
+    return data_type_;
+  }
+
+  grn_rc filter(Record *input, size_t input_size,
+                Record *output, size_t *output_size);
+  grn_rc adjust(Record *records, size_t num_records);
+  grn_rc evaluate(const Record *records, size_t num_records, void *results);
 
  private:
   grn_ctx *ctx_;
   grn_obj *column_;
-
-  ColumnNode(grn_ctx *ctx, grn_obj *column)
-    : TypedNode<T>(), ctx_(ctx), column_(column) {}
+  grn_obj *buf_;
+  grn_obj *deep_buf_;
+  grn_builtin_type builtin_type_;
+  grn_obj *ref_table_;
+  int dimension_;
+  DataType data_type_;
+
+  ColumnNode(grn_ctx *ctx, grn_obj *column, grn_builtin_type builtin_type,
+             grn_obj *ref_table, int dimension)
+    : ExpressionNode(),
+      ctx_(ctx),
+      column_(column),
+      buf_(NULL),
+      deep_buf_(NULL),
+      builtin_type_(builtin_type),
+      ref_table_(ref_table),
+      dimension_(dimension),
+      data_type_(grn_egn_simplify_builtin_type(builtin_type)) {}
+
+  grn_rc evaluate_scalar(const Record *records, size_t num_records,
+                         void *results);
+  grn_rc evaluate_scalar_text(const Record *records, size_t num_records,
+                              void *results);
+  grn_rc evaluate_vector(const Record *records, size_t num_records,
+                         void *results);
+  grn_rc evaluate_vector_int(const Record *records, size_t num_records,
+                             void *results);
+  grn_rc evaluate_vector_text(const Record *records, size_t num_records,
+                              void *results);
 };
 
-// -- ColumnNode<Bool> --
-
-template <>
-class ColumnNode<Bool> : public TypedNode<Bool> {
- public:
-  ~ColumnNode() {}
-
-  static grn_rc open(grn_ctx *ctx, grn_obj *column, ExpressionNode **node) {
-    ColumnNode *new_node = new (std::nothrow) ColumnNode(ctx, column);
-    if (!new_node) {
-      return GRN_NO_MEMORY_AVAILABLE;
+grn_rc ColumnNode::open(grn_ctx *ctx, grn_obj *column, ExpressionNode **node) {
+  grn_builtin_type builtin_type = GRN_DB_VOID;
+  grn_obj *ref_table = NULL;
+  int dimension = 0;
+  switch (column->header.type) {
+    case GRN_COLUMN_FIX_SIZE:
+    case GRN_COLUMN_VAR_SIZE: {
+      builtin_type = static_cast<grn_builtin_type>(DB_OBJ(column)->range);
+      if (column->header.type == GRN_COLUMN_VAR_SIZE) {
+        grn_obj_flags column_type =
+          column->header.flags & GRN_OBJ_COLUMN_TYPE_MASK;
+        if (column_type == GRN_OBJ_COLUMN_VECTOR) {
+          dimension = 1;
+        }
+      }
+      break;
+    }
+    case GRN_ACCESSOR: {
+      grn_accessor *accessor = (grn_accessor *)column;
+      switch (accessor->action) {
+        case GRN_ACCESSOR_GET_ID: {
+          return IDNode::open(node);
+        }
+        case GRN_ACCESSOR_GET_KEY: {
+          builtin_type = static_cast<grn_builtin_type>(
+            accessor->obj->header.domain);
+          break;
+        }
+        case GRN_ACCESSOR_GET_VALUE: {
+          builtin_type = static_cast<grn_builtin_type>(
+            DB_OBJ(accessor->obj)->range);
+          break;
+        }
+        case GRN_ACCESSOR_GET_SCORE: {
+          return IDNode::open(node);
+        }
+        default: {
+          return GRN_INVALID_ARGUMENT;
+        }
+      }
+      break;
+    }
+    default: {
+      return GRN_INVALID_ARGUMENT;
     }
-    *node = new_node;
-    return GRN_SUCCESS;
   }
-
-  ExpressionNodeType type() const {
-    return GRN_EGN_COLUMN_NODE;
+  if (static_cast<int>(builtin_type) > GRN_EGN_MAX_BUILTIN_TYPE) {
+    builtin_type = GRN_DB_UINT32;
+    ref_table = grn_ctx_at(ctx, column->header.domain);
+    if (!ref_table) {
+      if (ctx->rc != GRN_SUCCESS) {
+        return ctx->rc;
+      }
+      return GRN_UNKNOWN_ERROR;
+    } else if (!grn_obj_is_table(ctx, ref_table)) {
+      grn_obj_unlink(ctx, ref_table);
+      return GRN_UNKNOWN_ERROR;
+    }
   }
+  ColumnNode *new_node = new (std::nothrow) ColumnNode(
+    ctx, column, builtin_type, ref_table, dimension);
+  if (!new_node) {
+    return GRN_NO_MEMORY_AVAILABLE;
+  }
+  *node = new_node;
+  return GRN_SUCCESS;
+}
 
-  grn_rc filter(
-    Record *input, size_t input_size,
-    Record *output, size_t *output_size);
-
-  grn_rc evaluate(
-    const Record *records, size_t num_records, Bool *results);
-
- private:
-  grn_ctx *ctx_;
-  grn_obj *column_;
-
-  ColumnNode(grn_ctx *ctx, grn_obj *column)
-    : TypedNode<Bool>(), ctx_(ctx), column_(column) {}
-};
-
-grn_rc ColumnNode<Bool>::filter(
-  Record *input, size_t input_size,
-  Record *output, size_t *output_size) {
+grn_rc ColumnNode::filter(Record *input, size_t input_size,
+                          Record *output, size_t *output_size) {
+  if ((dimension() != 0) || (data_type() != GRN_EGN_BOOL)) {
+    return GRN_OPERATION_NOT_PERMITTED;
+  }
   grn_obj value;
   GRN_BOOL_INIT(&value, 0);
   size_t count = 0;
@@ -726,7 +874,7 @@ grn_rc ColumnNode<Bool>::filter(
     if (ctx_->rc != GRN_SUCCESS) {
       return ctx_->rc;
     }
-    if (GRN_BOOL_VALUE(&value) == GRN_TRUE) {
+    if (GRN_BOOL_VALUE(&value)) {
       output[count] = input[i];
       ++count;
     }
@@ -736,1474 +884,930 @@ grn_rc ColumnNode<Bool>::filter(
   return GRN_SUCCESS;
 }
 
-grn_rc ColumnNode<Bool>::evaluate(
-  const Record *records, size_t num_records, Bool *results) {
+grn_rc ColumnNode::adjust(Record *records, size_t num_records) {
+  if ((dimension() != 0) || (data_type() != GRN_EGN_FLOAT)) {
+    return GRN_OPERATION_NOT_PERMITTED;
+  }
   grn_obj value;
-  GRN_BOOL_INIT(&value, 0);
-  for (size_t i = 0; i < num_records; i++) {
+  GRN_FLOAT_INIT(&value, 0);
+  for (size_t i = 0; i < num_records; ++i) {
     GRN_BULK_REWIND(&value);
     grn_obj_get_value(ctx_, column_, records[i].id, &value);
-    if (ctx_->rc != GRN_SUCCESS) {
-      return ctx_->rc;
-    }
-    results[i] = Bool(GRN_BOOL_VALUE(&value) == GRN_TRUE);
+    records[i].score = GRN_FLOAT_VALUE(&value);
   }
   GRN_OBJ_FIN(ctx_, &value);
   return GRN_SUCCESS;
 }
 
-// -- ColumnNode<Int> --
-
-template <>
-class ColumnNode<Int> : public TypedNode<Int> {
- public:
-  ~ColumnNode() {}
-
-  static grn_rc open(grn_ctx *ctx, grn_obj *column, ExpressionNode **node) {
-    ColumnNode *new_node = new (std::nothrow) ColumnNode(ctx, column);
-    if (!new_node) {
-      return GRN_NO_MEMORY_AVAILABLE;
-    }
-    *node = new_node;
+grn_rc ColumnNode::evaluate(const Record *records, size_t num_records,
+                            void *results) {
+  if (num_records == 0) {
     return GRN_SUCCESS;
   }
-
-  ExpressionNodeType type() const {
-    return GRN_EGN_COLUMN_NODE;
-  }
-  grn_builtin_type builtin_type() const {
-    return static_cast<grn_builtin_type>(grn_obj_get_range(ctx_, column_));
+  if (dimension() == 0) {
+    return evaluate_scalar(records, num_records, results);
+  } else {
+    return evaluate_vector(records, num_records, results);
   }
+}
 
-  grn_rc evaluate(
-    const Record *records, size_t num_records, Int *results);
-
- private:
-  grn_ctx *ctx_;
-  grn_obj *column_;
-
-  ColumnNode(grn_ctx *ctx, grn_obj *column)
-    : TypedNode<Int>(), ctx_(ctx), column_(column) {}
-};
-
-grn_rc ColumnNode<Int>::evaluate(
-  const Record *records, size_t num_records, Int *results) {
-  grn_id range = grn_obj_get_range(ctx_, column_);
+#define GRN_EGN_EVALUATE_SCALAR_CASE_BLOCK(type, egn_type)\
+  case GRN_DB_ ## type: {\
+    GRN_ ## type ## _INIT(&value, 0);\
+    for (size_t i = 0; i < num_records; ++i) {\
+      GRN_BULK_REWIND(&value);\
+      grn_obj_get_value(ctx_, column_, records[i].id, &value);\
+      if (ctx_->rc != GRN_SUCCESS) {\
+        break;\
+      }\
+      static_cast<grn_egn_ ## egn_type *>(results)[i] =\
+        GRN_ ## type ## _VALUE(&value);\
+    }\
+    break;\
+  }
+grn_rc ColumnNode::evaluate_scalar(const Record *records, size_t num_records,
+                                   void *results) {
   grn_obj value;
-  switch (range) {
-    case GRN_DB_INT8: {
-      GRN_INT8_INIT(&value, 0);
-      for (size_t i = 0; i < num_records; i++) {
-        GRN_BULK_REWIND(&value);
-        grn_obj_get_value(ctx_, column_, records[i].id, &value);
-        results[i] = Int(GRN_INT8_VALUE(&value));
-      }
-      break;
-    }
-    case GRN_DB_INT16: {
-      GRN_INT16_INIT(&value, 0);
-      for (size_t i = 0; i < num_records; i++) {
-        GRN_BULK_REWIND(&value);
-        grn_obj_get_value(ctx_, column_, records[i].id, &value);
-        results[i] = Int(GRN_INT16_VALUE(&value));
-      }
-      break;
+  switch (builtin_type()) {
+    GRN_EGN_EVALUATE_SCALAR_CASE_BLOCK(BOOL, bool)
+    GRN_EGN_EVALUATE_SCALAR_CASE_BLOCK(INT8, int)
+    GRN_EGN_EVALUATE_SCALAR_CASE_BLOCK(INT16, int)
+    GRN_EGN_EVALUATE_SCALAR_CASE_BLOCK(INT32, int)
+    GRN_EGN_EVALUATE_SCALAR_CASE_BLOCK(INT64, int)
+    GRN_EGN_EVALUATE_SCALAR_CASE_BLOCK(UINT8, int)
+    GRN_EGN_EVALUATE_SCALAR_CASE_BLOCK(UINT16, int)
+    GRN_EGN_EVALUATE_SCALAR_CASE_BLOCK(UINT32, int)
+    GRN_EGN_EVALUATE_SCALAR_CASE_BLOCK(UINT64, int)
+    GRN_EGN_EVALUATE_SCALAR_CASE_BLOCK(FLOAT, float)
+    GRN_EGN_EVALUATE_SCALAR_CASE_BLOCK(TIME, time)
+    case GRN_DB_SHORT_TEXT:
+    case GRN_DB_TEXT:
+    case GRN_DB_LONG_TEXT: {
+      return evaluate_scalar_text(records, num_records, results);
     }
-    case GRN_DB_INT32: {
-      GRN_INT32_INIT(&value, 0);
-      for (size_t i = 0; i < num_records; i++) {
-        GRN_BULK_REWIND(&value);
-        grn_obj_get_value(ctx_, column_, records[i].id, &value);
-        results[i] = Int(GRN_INT32_VALUE(&value));
+    case GRN_DB_TOKYO_GEO_POINT:
+    case GRN_DB_WGS84_GEO_POINT: {
+      if (builtin_type() == GRN_DB_TOKYO_GEO_POINT) {
+        GRN_TOKYO_GEO_POINT_INIT(&value, 0);
+      } else {
+        GRN_WGS84_GEO_POINT_INIT(&value, 0);
       }
-      break;
-    }
-    case GRN_DB_INT64: {
-      GRN_INT64_INIT(&value, 0);
-      for (size_t i = 0; i < num_records; i++) {
+      for (size_t i = 0; i < num_records; ++i) {
         GRN_BULK_REWIND(&value);
         grn_obj_get_value(ctx_, column_, records[i].id, &value);
-        results[i] = Int(GRN_INT64_VALUE(&value));
+        if (ctx_->rc != GRN_SUCCESS) {
+          break;
+        }
+        grn_egn_geo_point *ptr = &static_cast<grn_egn_geo_point *>(results)[i];
+        GRN_GEO_POINT_VALUE(&value, ptr->latitude, ptr->longitude);
       }
       break;
     }
-    case GRN_DB_UINT8: {
-      GRN_UINT8_INIT(&value, 0);
-      for (size_t i = 0; i < num_records; i++) {
-        GRN_BULK_REWIND(&value);
-        grn_obj_get_value(ctx_, column_, records[i].id, &value);
-        results[i] = Int(GRN_UINT8_VALUE(&value));
-      }
-      break;
-    }
-    case GRN_DB_UINT16: {
-      GRN_UINT16_INIT(&value, 0);
-      for (size_t i = 0; i < num_records; i++) {
-        GRN_BULK_REWIND(&value);
-        grn_obj_get_value(ctx_, column_, records[i].id, &value);
-        results[i] = Int(GRN_UINT16_VALUE(&value));
-      }
-      break;
-    }
-    case GRN_DB_UINT32: {
-      GRN_UINT32_INIT(&value, 0);
-      for (size_t i = 0; i < num_records; i++) {
-        GRN_BULK_REWIND(&value);
-        grn_obj_get_value(ctx_, column_, records[i].id, &value);
-        results[i] = Int(GRN_UINT32_VALUE(&value));
-      }
-      break;
-    }
-    case GRN_DB_UINT64: {
-      GRN_UINT64_INIT(&value, 0);
-      for (size_t i = 0; i < num_records; i++) {
-        GRN_BULK_REWIND(&value);
-        grn_obj_get_value(ctx_, column_, records[i].id, &value);
-        // FIXME: Type conversion from UInt64 to Int may lose the content.
-        results[i] = Int(GRN_UINT64_VALUE(&value));
-      }
-      break;
-    }
-  }
-  GRN_OBJ_FIN(ctx_, &value);
-  return GRN_SUCCESS;
-}
-
-// -- ColumnNode<Float> --
-
-template <>
-class ColumnNode<Float> : public TypedNode<Float> {
- public:
-  ~ColumnNode() {}
-
-  static grn_rc open(grn_ctx *ctx, grn_obj *column, ExpressionNode **node) {
-    ColumnNode *new_node = new (std::nothrow) ColumnNode(ctx, column);
-    if (!new_node) {
-      return GRN_NO_MEMORY_AVAILABLE;
-    }
-    *node = new_node;
-    return GRN_SUCCESS;
-  }
-
-  ExpressionNodeType type() const {
-    return GRN_EGN_COLUMN_NODE;
-  }
-
-  grn_rc adjust(Record *records, size_t num_records);
-
-  grn_rc evaluate(
-    const Record *records, size_t num_records, Float *results);
-
- private:
-  grn_ctx *ctx_;
-  grn_obj *column_;
-
-  ColumnNode(grn_ctx *ctx, grn_obj *column)
-    : TypedNode<Float>(), ctx_(ctx), column_(column) {}
-};
-
-grn_rc ColumnNode<Float>::adjust(Record *records, size_t num_records) {
-  grn_obj value;
-  GRN_FLOAT_INIT(&value, 0);
-  for (size_t i = 0; i < num_records; ++i) {
-    GRN_BULK_REWIND(&value);
-    grn_obj_get_value(ctx_, column_, records[i].id, &value);
-    records[i].score = GRN_FLOAT_VALUE(&value);
-  }
-  GRN_OBJ_FIN(ctx_, &value);
-  return GRN_SUCCESS;
-}
-
-grn_rc ColumnNode<Float>::evaluate(
-  const Record *records, size_t num_records, Float *results) {
-  grn_obj value;
-  GRN_FLOAT_INIT(&value, 0);
-  for (size_t i = 0; i < num_records; i++) {
-    GRN_BULK_REWIND(&value);
-    grn_obj_get_value(ctx_, column_, records[i].id, &value);
-    results[i] = Float(GRN_FLOAT_VALUE(&value));
-  }
-  GRN_OBJ_FIN(ctx_, &value);
-  return GRN_SUCCESS;
-}
-
-// -- ColumnNode<Time> --
-
-template <>
-class ColumnNode<Time> : public TypedNode<Time> {
- public:
-  ~ColumnNode() {}
-
-  static grn_rc open(grn_ctx *ctx, grn_obj *column, ExpressionNode **node) {
-    ColumnNode *new_node = new (std::nothrow) ColumnNode(ctx, column);
-    if (!new_node) {
-      return GRN_NO_MEMORY_AVAILABLE;
-    }
-    *node = new_node;
-    return GRN_SUCCESS;
-  }
-
-  ExpressionNodeType type() const {
-    return GRN_EGN_COLUMN_NODE;
-  }
-
-  grn_rc evaluate(
-    const Record *records, size_t num_records, Time *results);
-
- private:
-  grn_ctx *ctx_;
-  grn_obj *column_;
-
-  ColumnNode(grn_ctx *ctx, grn_obj *column)
-    : TypedNode<Time>(), ctx_(ctx), column_(column) {}
-};
-
-grn_rc ColumnNode<Time>::evaluate(
-  const Record *records, size_t num_records, Time *results) {
-  grn_obj value;
-  GRN_TIME_INIT(&value, 0);
-  for (size_t i = 0; i < num_records; i++) {
-    GRN_BULK_REWIND(&value);
-    grn_obj_get_value(ctx_, column_, records[i].id, &value);
-    results[i] = Time(GRN_TIME_VALUE(&value));
-  }
-  GRN_OBJ_FIN(ctx_, &value);
-  return GRN_SUCCESS;
-}
-
-// -- ColumnNode<Text> --
-
-template <>
-class ColumnNode<Text> : public TypedNode<Text> {
- public:
-  ~ColumnNode() {
-    GRN_OBJ_FIN(ctx_, &buf_);
-  }
-
-  static grn_rc open(grn_ctx *ctx, grn_obj *column, ExpressionNode **node) {
-    ColumnNode *new_node = new (std::nothrow) ColumnNode(ctx, column);
-    if (!new_node) {
-      return GRN_NO_MEMORY_AVAILABLE;
-    }
-    *node = new_node;
-    return GRN_SUCCESS;
-  }
-
-  ExpressionNodeType type() const {
-    return GRN_EGN_COLUMN_NODE;
-  }
-  grn_builtin_type builtin_type() const {
-    return static_cast<grn_builtin_type>(grn_obj_get_range(ctx_, column_));
-  }
-
-  grn_rc evaluate(
-    const Record *records, size_t num_records, Text *results);
-
- private:
-  grn_ctx *ctx_;
-  grn_obj *column_;
-  grn_obj buf_;
-
-  ColumnNode(grn_ctx *ctx, grn_obj *column)
-    : TypedNode<Text>(), ctx_(ctx), column_(column), buf_() {
-    GRN_TEXT_INIT(&buf_, 0);
-  }
-};
-
-grn_rc ColumnNode<Text>::evaluate(
-  const Record *records, size_t num_records, Text *results) {
-  GRN_BULK_REWIND(&buf_);
-  size_t offset = 0;
-  for (size_t i = 0; i < num_records; i++) {
-    grn_obj_get_value(ctx_, column_, records[i].id, &buf_);
-    if (ctx_->rc != GRN_SUCCESS) {
-      return ctx_->rc;
-    }
-    size_t next_offset = GRN_TEXT_LEN(&buf_);
-    results[i].raw.size = next_offset - offset;
-    offset = next_offset;
-  }
-  char *ptr = GRN_TEXT_VALUE(&buf_);
-  for (size_t i = 0; i < num_records; i++) {
-    results[i].raw.ptr = ptr;
-    ptr += results[i].raw.size;
-  }
-  return GRN_SUCCESS;
-}
-
-// -- ColumnNode<GeoPoint> --
-
-template <>
-class ColumnNode<GeoPoint> : public TypedNode<GeoPoint> {
- public:
-  ~ColumnNode() {}
-
-  static grn_rc open(grn_ctx *ctx, grn_obj *column, ExpressionNode **node) {
-    ColumnNode *new_node = new (std::nothrow) ColumnNode(ctx, column);
-    if (!new_node) {
-      return GRN_NO_MEMORY_AVAILABLE;
-    }
-    *node = new_node;
-    return GRN_SUCCESS;
-  }
-
-  ExpressionNodeType type() const {
-    return GRN_EGN_COLUMN_NODE;
-  }
-  grn_builtin_type builtin_type() const {
-    return static_cast<grn_builtin_type>(grn_obj_get_range(ctx_, column_));
-  }
-
-  grn_rc evaluate(
-    const Record *records, size_t num_records, GeoPoint *results);
-
- private:
-  grn_ctx *ctx_;
-  grn_obj *column_;
-
-  ColumnNode(grn_ctx *ctx, grn_obj *column)
-    : TypedNode<GeoPoint>(), ctx_(ctx), column_(column) {}
-};
-
-grn_rc ColumnNode<GeoPoint>::evaluate(
-  const Record *records, size_t num_records, GeoPoint *results) {
-  grn_obj value;
-  GRN_WGS84_GEO_POINT_INIT(&value, 0);
-  for (size_t i = 0; i < num_records; i++) {
-    GRN_BULK_REWIND(&value);
-    grn_obj_get_value(ctx_, column_, records[i].id, &value);
-    GRN_GEO_POINT_VALUE(
-      &value, results[i].raw.latitude, results[i].raw.longitude);
-  }
-  GRN_OBJ_FIN(ctx_, &value);
-  return GRN_SUCCESS;
-}
-
-// -- ColumnNode<BoolVector> --
-
-template <>
-class ColumnNode<BoolVector> : public TypedNode<BoolVector> {
- public:
-  ~ColumnNode() {
-    GRN_OBJ_FIN(ctx_, &buf_);
-  }
-
-  static grn_rc open(grn_ctx *ctx, grn_obj *column, ExpressionNode **node) {
-    ColumnNode *new_node = new (std::nothrow) ColumnNode(ctx, column);
-    if (!new_node) {
-      return GRN_NO_MEMORY_AVAILABLE;
-    }
-    *node = new_node;
-    return GRN_SUCCESS;
-  }
-
-  ExpressionNodeType type() const {
-    return GRN_EGN_COLUMN_NODE;
-  }
-  grn_builtin_type builtin_type() const {
-    return static_cast<grn_builtin_type>(grn_obj_get_range(ctx_, column_));
-  }
-
-  grn_rc evaluate(
-    const Record *records, size_t num_records, BoolVector *results);
-
- private:
-  grn_ctx *ctx_;
-  grn_obj *column_;
-  grn_obj buf_;
-
-  ColumnNode(grn_ctx *ctx, grn_obj *column)
-    : TypedNode<BoolVector>(), ctx_(ctx), column_(column), buf_() {
-    GRN_BOOL_INIT(&buf_, GRN_OBJ_VECTOR);
-  }
-};
-
-grn_rc ColumnNode<BoolVector>::evaluate(
-  const Record *records, size_t num_records, BoolVector *results) {
-  GRN_BULK_REWIND(&buf_);
-  size_t offset = 0;
-  for (size_t i = 0; i < num_records; i++) {
-    grn_obj_get_value(ctx_, column_, records[i].id, &buf_);
-    if (ctx_->rc != GRN_SUCCESS) {
-      return ctx_->rc;
-    }
-    size_t next_size = GRN_BULK_VSIZE(&buf_);
-    size_t next_offset = next_size / sizeof(grn_egn_bool);
-    results[i].raw.size = next_offset - offset;
-    offset = next_offset;
-  }
-  grn_egn_bool *ptr = reinterpret_cast<grn_egn_bool *>(GRN_BULK_HEAD(&buf_));
-  for (size_t i = 0; i < num_records; i++) {
-    results[i].raw.ptr = ptr;
-    ptr += results[i].raw.size;
-  }
-  return GRN_SUCCESS;
-}
-
-// -- ColumnNode<IntVector> --
-
-template <>
-class ColumnNode<IntVector> : public TypedNode<IntVector> {
- public:
-  ~ColumnNode() {
-    GRN_OBJ_FIN(ctx_, &buf_);
-    std::free(int_buf_);
-  }
-
-  static grn_rc open(grn_ctx *ctx, grn_obj *column, ExpressionNode **node) {
-    ColumnNode *new_node = new (std::nothrow) ColumnNode(ctx, column);
-    if (!new_node) {
-      return GRN_NO_MEMORY_AVAILABLE;
-    }
-    *node = new_node;
-    return GRN_SUCCESS;
-  }
-
-  ExpressionNodeType type() const {
-    return GRN_EGN_COLUMN_NODE;
-  }
-  grn_builtin_type builtin_type() const {
-    return static_cast<grn_builtin_type>(grn_obj_get_range(ctx_, column_));
-  }
-
-  grn_rc evaluate(
-    const Record *records, size_t num_records, IntVector *results);
-
- private:
-  grn_ctx *ctx_;
-  grn_obj *column_;
-  grn_obj buf_;
-  grn_egn_int *int_buf_;
-
-  ColumnNode(grn_ctx *ctx, grn_obj *column)
-    : TypedNode<IntVector>(), ctx_(ctx), column_(column), buf_(),
-      int_buf_(NULL) {
-    switch (grn_obj_get_range(ctx_, column_)) {
-      case GRN_DB_INT8: {
-        GRN_INT8_INIT(&buf_, GRN_OBJ_VECTOR);
-        break;
-      }
-      case GRN_DB_INT16: {
-        GRN_INT16_INIT(&buf_, GRN_OBJ_VECTOR);
-        break;
-      }
-      case GRN_DB_INT32: {
-        GRN_INT32_INIT(&buf_, GRN_OBJ_VECTOR);
-        break;
-      }
-      case GRN_DB_INT64: {
-        GRN_INT64_INIT(&buf_, GRN_OBJ_VECTOR);
-        break;
-      }
-      case GRN_DB_UINT8: {
-        GRN_UINT8_INIT(&buf_, GRN_OBJ_VECTOR);
-        break;
-      }
-      case GRN_DB_UINT16: {
-        GRN_UINT16_INIT(&buf_, GRN_OBJ_VECTOR);
-        break;
-      }
-      case GRN_DB_UINT32: {
-        GRN_UINT32_INIT(&buf_, GRN_OBJ_VECTOR);
-        break;
-      }
-      case GRN_DB_UINT64: {
-        GRN_UINT64_INIT(&buf_, GRN_OBJ_VECTOR);
-        break;
-      }
-    }
-  }
-};
-
-grn_rc ColumnNode<IntVector>::evaluate(
-  const Record *records, size_t num_records, IntVector *results) {
-  GRN_BULK_REWIND(&buf_);
-  size_t offset = 0;
-  for (size_t i = 0; i < num_records; i++) {
-    grn_obj_get_value(ctx_, column_, records[i].id, &buf_);
-    if (ctx_->rc != GRN_SUCCESS) {
-      return ctx_->rc;
-    }
-    size_t next_size = GRN_BULK_VSIZE(&buf_);
-    size_t next_offset;
-    switch (builtin_type()) {
-      case GRN_DB_INT8: {
-        next_offset = next_size / sizeof(int8_t);
-        break;
-      }
-      case GRN_DB_INT16: {
-        next_offset = next_size / sizeof(int16_t);
-        break;
-      }
-      case GRN_DB_INT32: {
-        next_offset = next_size / sizeof(int32_t);
-        break;
-      }
-      case GRN_DB_INT64: {
-        next_offset = next_size / sizeof(int64_t);
-        break;
-      }
-      case GRN_DB_UINT8: {
-        next_offset = next_size / sizeof(uint8_t);
-        break;
-      }
-      case GRN_DB_UINT16: {
-        next_offset = next_size / sizeof(uint16_t);
-        break;
-      }
-      case GRN_DB_UINT32: {
-        next_offset = next_size / sizeof(uint32_t);
-        break;
-      }
-      case GRN_DB_UINT64: {
-        next_offset = next_size / sizeof(uint64_t);
-        break;
-      }
-      default: {
-        return GRN_UNKNOWN_ERROR;
-      }
-    }
-    results[i].raw.size = next_offset - offset;
-    offset = next_offset;
-  }
-  grn_egn_int *new_buf = static_cast<grn_egn_int *>(
-    std::realloc(int_buf_, sizeof(grn_egn_int) * offset));
-  if (!new_buf) {
-    return GRN_NO_MEMORY_AVAILABLE;
-  }
-  int_buf_ = new_buf;
-  switch (builtin_type()) {
-    case GRN_DB_INT8: {
-      int8_t *ptr = reinterpret_cast<int8_t *>(GRN_BULK_HEAD(&buf_));
-      for (size_t i = 0; i < offset; ++i) {
-        int_buf_[i] = ptr[i];
-      }
-      break;
-    }
-    case GRN_DB_INT16: {
-      int16_t *ptr = reinterpret_cast<int16_t *>(GRN_BULK_HEAD(&buf_));
-      for (size_t i = 0; i < offset; ++i) {
-        int_buf_[i] = ptr[i];
-      }
-      break;
-    }
-    case GRN_DB_INT32: {
-      int32_t *ptr = reinterpret_cast<int32_t *>(GRN_BULK_HEAD(&buf_));
-      for (size_t i = 0; i < offset; ++i) {
-        int_buf_[i] = ptr[i];
-      }
-      break;
-    }
-    case GRN_DB_INT64: {
-      int64_t *ptr = reinterpret_cast<int64_t *>(GRN_BULK_HEAD(&buf_));
-      for (size_t i = 0; i < offset; ++i) {
-        int_buf_[i] = ptr[i];
-      }
-      break;
-    }
-    case GRN_DB_UINT8: {
-      uint8_t *ptr = reinterpret_cast<uint8_t *>(GRN_BULK_HEAD(&buf_));
-      for (size_t i = 0; i < offset; ++i) {
-        int_buf_[i] = ptr[i];
-      }
-      break;
-    }
-    case GRN_DB_UINT16: {
-      uint16_t *ptr = reinterpret_cast<uint16_t *>(GRN_BULK_HEAD(&buf_));
-      for (size_t i = 0; i < offset; ++i) {
-        int_buf_[i] = ptr[i];
-      }
-      break;
-    }
-    case GRN_DB_UINT32: {
-      uint32_t *ptr = reinterpret_cast<uint32_t *>(GRN_BULK_HEAD(&buf_));
-      for (size_t i = 0; i < offset; ++i) {
-        int_buf_[i] = ptr[i];
-      }
-      break;
-    }
-    case GRN_DB_UINT64: {
-      uint64_t *ptr = reinterpret_cast<uint64_t *>(GRN_BULK_HEAD(&buf_));
-      for (size_t i = 0; i < offset; ++i) {
-        int_buf_[i] = ptr[i];
-      }
-      break;
-    }
-    default: {
-      return GRN_UNKNOWN_ERROR;
-    }
-  }
-  grn_egn_int *ptr = int_buf_;
-  for (size_t i = 0; i < num_records; i++) {
-    results[i].raw.ptr = ptr;
-    ptr += results[i].raw.size;
-  }
-  return GRN_SUCCESS;
-}
-
-// -- ColumnNode<FloatVector> --
-
-template <>
-class ColumnNode<FloatVector> : public TypedNode<FloatVector> {
- public:
-  ~ColumnNode() {
-    GRN_OBJ_FIN(ctx_, &buf_);
-  }
-
-  static grn_rc open(grn_ctx *ctx, grn_obj *column, ExpressionNode **node) {
-    ColumnNode *new_node = new (std::nothrow) ColumnNode(ctx, column);
-    if (!new_node) {
-      return GRN_NO_MEMORY_AVAILABLE;
-    }
-    *node = new_node;
-    return GRN_SUCCESS;
-  }
-
-  ExpressionNodeType type() const {
-    return GRN_EGN_COLUMN_NODE;
-  }
-  grn_builtin_type builtin_type() const {
-    return static_cast<grn_builtin_type>(grn_obj_get_range(ctx_, column_));
-  }
-
-  grn_rc evaluate(
-    const Record *records, size_t num_records, FloatVector *results);
-
- private:
-  grn_ctx *ctx_;
-  grn_obj *column_;
-  grn_obj buf_;
-
-  ColumnNode(grn_ctx *ctx, grn_obj *column)
-    : TypedNode<FloatVector>(), ctx_(ctx), column_(column), buf_() {
-    GRN_FLOAT_INIT(&buf_, GRN_OBJ_VECTOR);
-  }
-};
-
-grn_rc ColumnNode<FloatVector>::evaluate(
-  const Record *records, size_t num_records, FloatVector *results) {
-  GRN_BULK_REWIND(&buf_);
-  size_t offset = 0;
-  for (size_t i = 0; i < num_records; i++) {
-    grn_obj_get_value(ctx_, column_, records[i].id, &buf_);
-    if (ctx_->rc != GRN_SUCCESS) {
-      return ctx_->rc;
-    }
-    size_t next_size = GRN_BULK_VSIZE(&buf_);
-    size_t next_offset = next_size / sizeof(grn_egn_float);
-    results[i].raw.size = next_offset - offset;
-    offset = next_offset;
-  }
-  grn_egn_float *ptr = reinterpret_cast<grn_egn_float *>(GRN_BULK_HEAD(&buf_));
-  for (size_t i = 0; i < num_records; i++) {
-    results[i].raw.ptr = ptr;
-    ptr += results[i].raw.size;
-  }
-  return GRN_SUCCESS;
-}
-
-// -- ColumnNode<TimeVector> --
-
-template <>
-class ColumnNode<TimeVector> : public TypedNode<TimeVector> {
- public:
-  ~ColumnNode() {
-    GRN_OBJ_FIN(ctx_, &buf_);
-  }
-
-  static grn_rc open(grn_ctx *ctx, grn_obj *column, ExpressionNode **node) {
-    ColumnNode *new_node = new (std::nothrow) ColumnNode(ctx, column);
-    if (!new_node) {
-      return GRN_NO_MEMORY_AVAILABLE;
-    }
-    *node = new_node;
-    return GRN_SUCCESS;
-  }
-
-  ExpressionNodeType type() const {
-    return GRN_EGN_COLUMN_NODE;
-  }
-  grn_builtin_type builtin_type() const {
-    return static_cast<grn_builtin_type>(grn_obj_get_range(ctx_, column_));
-  }
-
-  grn_rc evaluate(
-    const Record *records, size_t num_records, TimeVector *results);
-
- private:
-  grn_ctx *ctx_;
-  grn_obj *column_;
-  grn_obj buf_;
-
-  ColumnNode(grn_ctx *ctx, grn_obj *column)
-    : TypedNode<TimeVector>(), ctx_(ctx), column_(column), buf_() {
-    GRN_TIME_INIT(&buf_, GRN_OBJ_VECTOR);
-  }
-};
-
-grn_rc ColumnNode<TimeVector>::evaluate(
-  const Record *records, size_t num_records, TimeVector *results) {
-  GRN_BULK_REWIND(&buf_);
-  size_t offset = 0;
-  for (size_t i = 0; i < num_records; i++) {
-    grn_obj_get_value(ctx_, column_, records[i].id, &buf_);
-    if (ctx_->rc != GRN_SUCCESS) {
-      return ctx_->rc;
-    }
-    size_t next_size = GRN_BULK_VSIZE(&buf_);
-    size_t next_offset = next_size / sizeof(grn_egn_time);
-    results[i].raw.size = next_offset - offset;
-    offset = next_offset;
-  }
-  grn_egn_time *ptr = reinterpret_cast<grn_egn_time *>(GRN_BULK_HEAD(&buf_));
-  for (size_t i = 0; i < num_records; i++) {
-    results[i].raw.ptr = ptr;
-    ptr += results[i].raw.size;
-  }
-  return GRN_SUCCESS;
-}
-
-// -- ColumnNode<TextVector> --
-
-template <>
-class ColumnNode<TextVector> : public TypedNode<TextVector> {
- public:
-  ~ColumnNode() {
-    GRN_OBJ_FIN(ctx_, &buf_);
-  }
-
-  static grn_rc open(grn_ctx *ctx, grn_obj *column, ExpressionNode **node) {
-    ColumnNode *new_node = new (std::nothrow) ColumnNode(ctx, column);
-    if (!new_node) {
-      return GRN_NO_MEMORY_AVAILABLE;
-    }
-    *node = new_node;
-    return GRN_SUCCESS;
-  }
-
-  ExpressionNodeType type() const {
-    return GRN_EGN_COLUMN_NODE;
-  }
-  grn_builtin_type builtin_type() const {
-    return static_cast<grn_builtin_type>(grn_obj_get_range(ctx_, column_));
-  }
-
-  grn_rc evaluate(
-    const Record *records, size_t num_records, TextVector *results);
-
- private:
-  grn_ctx *ctx_;
-  grn_obj *column_;
-  grn_obj buf_;
-  std::vector<grn_egn_text> refs_;
-
-  ColumnNode(grn_ctx *ctx, grn_obj *column)
-    : TypedNode<TextVector>(), ctx_(ctx), column_(column), buf_(), refs_() {
-    GRN_TEXT_INIT(&buf_, GRN_OBJ_VECTOR);
-  }
-};
-
-grn_rc ColumnNode<TextVector>::evaluate(
-  const Record *records, size_t num_records, TextVector *results) {
-  GRN_BULK_REWIND(&buf_);
-  size_t offset = 0;
-  for (size_t i = 0; i < num_records; i++) {
-    grn_obj_get_value(ctx_, column_, records[i].id, &buf_);
-    if (ctx_->rc != GRN_SUCCESS) {
-      return ctx_->rc;
-    }
-    size_t next_offset = grn_vector_size(ctx_, &buf_);
-    results[i].raw.size = next_offset - offset;
-    offset = next_offset;
-  }
-  try {
-    refs_.resize(offset);
-  } catch (const std::bad_alloc &) {
-    return GRN_NO_MEMORY_AVAILABLE;
-  }
-  offset = 0;
-  size_t total = 0;
-  for (size_t i = 0; i < num_records; i++) {
-    size_t partial_total = 0;
-    for (size_t j = 0; j < results[i].raw.size; ++j) {
-      refs_[offset + j].size = grn_vector_get_element(
-        ctx_, &buf_, offset + j, &refs_[offset + j].ptr, NULL, NULL);
-      partial_total += refs_[offset + j].size;
-    }
-    total += partial_total;
-    results[i].raw.ptr = &*refs_.begin() + offset;
-    offset += results[i].raw.size;
-  }
-  return GRN_SUCCESS;
-}
-
-// -- ColumnNode<GeoPointVector> --
-
-template <>
-class ColumnNode<GeoPointVector> : public TypedNode<GeoPointVector> {
- public:
-  ~ColumnNode() {
-    GRN_OBJ_FIN(ctx_, &buf_);
-  }
-
-  static grn_rc open(grn_ctx *ctx, grn_obj *column, ExpressionNode **node) {
-    ColumnNode *new_node = new (std::nothrow) ColumnNode(ctx, column);
-    if (!new_node) {
-      return GRN_NO_MEMORY_AVAILABLE;
-    }
-    *node = new_node;
-    return GRN_SUCCESS;
-  }
-
-  ExpressionNodeType type() const {
-    return GRN_EGN_COLUMN_NODE;
-  }
-  grn_builtin_type builtin_type() const {
-    return static_cast<grn_builtin_type>(grn_obj_get_range(ctx_, column_));
-  }
-
-  grn_rc evaluate(
-    const Record *records, size_t num_records, GeoPointVector *results);
-
- private:
-  grn_ctx *ctx_;
-  grn_obj *column_;
-  grn_obj buf_;
-
-  ColumnNode(grn_ctx *ctx, grn_obj *column)
-    : TypedNode<GeoPointVector>(), ctx_(ctx), column_(column), buf_() {
-    if (grn_obj_get_range(ctx_, column_) == GRN_DB_TOKYO_GEO_POINT) {
-      GRN_TOKYO_GEO_POINT_INIT(&buf_, GRN_OBJ_VECTOR);
-    } else {
-      GRN_WGS84_GEO_POINT_INIT(&buf_, GRN_OBJ_VECTOR);
-    }
-  }
-};
-
-grn_rc ColumnNode<GeoPointVector>::evaluate(
-  const Record *records, size_t num_records, GeoPointVector *results) {
-  GRN_BULK_REWIND(&buf_);
-  size_t offset = 0;
-  for (size_t i = 0; i < num_records; i++) {
-    grn_obj_get_value(ctx_, column_, records[i].id, &buf_);
-    if (ctx_->rc != GRN_SUCCESS) {
-      return ctx_->rc;
-    }
-    size_t next_size = GRN_BULK_VSIZE(&buf_);
-    size_t next_offset = next_size / sizeof(grn_egn_geo_point);
-    results[i].raw.size = next_offset - offset;
-    offset = next_offset;
-  }
-  grn_egn_geo_point *ptr =
-    reinterpret_cast<grn_egn_geo_point *>(GRN_BULK_HEAD(&buf_));
-  for (size_t i = 0; i < num_records; i++) {
-    results[i].raw.ptr = ptr;
-    ptr += results[i].raw.size;
-  }
-  return GRN_SUCCESS;
-}
-
-// -- OperatorNode --
-
-template <typename T>
-class OperatorNode : public TypedNode<T> {
- public:
-  OperatorNode() : TypedNode<T>() {}
-  virtual ~OperatorNode() {}
-
-  ExpressionNodeType type() const {
-    return GRN_EGN_OPERATOR_NODE;
-  }
-};
-
-template <typename T>
-grn_rc operator_node_fill_arg_values(
-  const Record *records, size_t num_records,
-  TypedNode<T> *arg, std::vector<T> *arg_values) {
-  size_t old_size = arg_values->size();
-  if (old_size < num_records) try {
-    arg_values->resize(num_records);
-  } catch (const std::bad_alloc &) {
-    return GRN_NO_MEMORY_AVAILABLE;
-  }
-  switch (arg->type()) {
-    case GRN_EGN_CONSTANT_NODE: {
-      if (old_size < num_records) {
-        return arg->evaluate(records + old_size, num_records - old_size,
-          &*arg_values->begin() + old_size);
-      }
-      return GRN_SUCCESS;
-    }
     default: {
-      return arg->evaluate(records, num_records, &*arg_values->begin());
-    }
-  }
-}
-
-// --- UnaryNode ---
-
-template <typename T, typename U>
-class UnaryNode : public OperatorNode<T> {
- public:
-  explicit UnaryNode(ExpressionNode *arg)
-    : OperatorNode<T>(), arg_(static_cast<TypedNode<U> *>(arg)),
-      arg_values_() {}
-  virtual ~UnaryNode() {
-    delete arg_;
-  }
-
- protected:
-  TypedNode<U> *arg_;
-  std::vector<U> arg_values_;
-
-  grn_rc fill_arg_values(const Record *records, size_t num_records) {
-    return operator_node_fill_arg_values(
-      records, num_records, arg_, &arg_values_);
-  }
-};
-
-// ---- LogicalNotNode ----
-
-class LogicalNotNode : public UnaryNode<Bool, Bool> {
- public:
-  ~LogicalNotNode() {}
-
-  static grn_rc open(ExpressionNode *arg, ExpressionNode **node) {
-    LogicalNotNode *new_node = new (std::nothrow) LogicalNotNode(arg);
-    if (!new_node) {
-      return GRN_NO_MEMORY_AVAILABLE;
-    }
-    *node = new_node;
-    return GRN_SUCCESS;
-  }
-
-  grn_rc filter(
-    Record *input, size_t input_size,
-    Record *output, size_t *output_size);
-
-  grn_rc evaluate(
-    const Record *records, size_t num_records, Bool *results);
-
- private:
-  std::vector<Record> temp_records_;
-
-  explicit LogicalNotNode(ExpressionNode *arg)
-    : UnaryNode<Bool, Bool>(arg), temp_records_() {}
-};
-
-grn_rc LogicalNotNode::filter(
-  Record *input, size_t input_size,
-  Record *output, size_t *output_size) {
-  if (temp_records_.size() <= input_size) {
-    try {
-      temp_records_.resize(input_size + 1);
-      temp_records_[input_size].id = GRN_ID_NIL;
-    } catch (const std::bad_alloc &) {
-      return GRN_NO_MEMORY_AVAILABLE;
-    }
-  }
-  size_t temp_size;
-  grn_rc rc =
-    arg_->filter(input, input_size, &*temp_records_.begin(), &temp_size);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  if (temp_size == 0) {
-    *output_size = 0;
-    return GRN_SUCCESS;
-  }
-
-  size_t count = 0;
-  for (size_t i = 0; i < input_size; ++i) {
-    if (input[i].id != temp_records_[i - count].id) {
-      output[count] = input[i];
-      ++count;
-    }
-  }
-  *output_size = count;
-  return GRN_SUCCESS;
-}
-
-grn_rc LogicalNotNode::evaluate(
-  const Record *records, size_t num_records, Bool *results) {
-  grn_rc rc = arg_->evaluate(records, num_records, results);
-  if (rc == GRN_SUCCESS) {
-    for (size_t i = 0; i < num_records; ++i) {
-      results[i] = Bool(results[i].raw != GRN_TRUE);
-    }
-  }
-  return rc;
-}
-
-// --- BinaryNode ---
-
-template <typename T, typename U, typename V>
-class BinaryNode : public OperatorNode<T> {
- public:
-  BinaryNode(ExpressionNode *arg1, ExpressionNode *arg2)
-    : OperatorNode<T>(),
-      arg1_(static_cast<TypedNode<U> *>(arg1)),
-      arg2_(static_cast<TypedNode<V> *>(arg2)),
-      arg1_values_(), arg2_values_() {}
-  virtual ~BinaryNode() {
-    delete arg1_;
-    delete arg2_;
-  }
-
- protected:
-  TypedNode<U> *arg1_;
-  TypedNode<V> *arg2_;
-  std::vector<U> arg1_values_;
-  std::vector<V> arg2_values_;
-
-  grn_rc fill_arg1_values(const Record *records, size_t num_records) {
-    return operator_node_fill_arg_values(
-      records, num_records, arg1_, &arg1_values_);
-  }
-  grn_rc fill_arg2_values(const Record *records, size_t num_records) {
-    return operator_node_fill_arg_values(
-      records, num_records, arg2_, &arg2_values_);
-  }
-};
-
-// ---- LogicalAndNode ----
-
-class LogicalAndNode : public BinaryNode<Bool, Bool, Bool> {
- public:
-  ~LogicalAndNode() {}
-
-  static grn_rc open(
-    ExpressionNode *arg1, ExpressionNode *arg2, ExpressionNode **node) {
-    LogicalAndNode *new_node = new (std::nothrow) LogicalAndNode(arg1, arg2);
-    if (!new_node) {
-      return GRN_NO_MEMORY_AVAILABLE;
-    }
-    *node = new_node;
-    return GRN_SUCCESS;
-  }
-
-  grn_rc filter(
-    Record *input, size_t input_size,
-    Record *output, size_t *output_size) {
-    grn_rc rc = arg1_->filter(input, input_size, output, output_size);
-    if (rc == GRN_SUCCESS) {
-      rc = arg2_->filter(output, *output_size, output, output_size);
-    }
-    return rc;
-  }
-
-  grn_rc evaluate(
-    const Record *records, size_t num_records, Bool *results);
-
- private:
-  std::vector<Record> temp_records_;
-
-  LogicalAndNode(ExpressionNode *arg1, ExpressionNode *arg2)
-    : BinaryNode<Bool, Bool, Bool>(arg1, arg2), temp_records_() {}
-};
-
-grn_rc LogicalAndNode::evaluate(
-  const Record *records, size_t num_records, Bool *results) {
-  // Evaluate "arg1" for all the records.
-  // Then, evaluate "arg2" for non-false records.
-  grn_rc rc = arg1_->evaluate(records, num_records, results);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  if (temp_records_.size() < num_records) try {
-    temp_records_.resize(num_records);
-  } catch (const std::bad_alloc &) {
-    return GRN_NO_MEMORY_AVAILABLE;
-  }
-  size_t count = 0;
-  for (size_t i = 0; i < num_records; ++i) {
-    if (results[i].raw == GRN_TRUE) {
-      temp_records_[count] = records[i];
-      ++count;
-    }
-  }
-  if (count == 0) {
-    // Nothing to do.
-    return GRN_SUCCESS;
-  }
-  rc = fill_arg2_values(&*temp_records_.begin(), count);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-
-  // Merge the evaluation results.
-  count = 0;
-  for (size_t i = 0; i < num_records; ++i) {
-    if (results[i].raw == GRN_TRUE) {
-      results[i] = arg2_values_[count];
-      ++count;
-    }
-  }
-  return GRN_SUCCESS;
-}
-
-// ---- LogicalOrNode ----
-
-class LogicalOrNode : public BinaryNode<Bool, Bool, Bool> {
- public:
-  ~LogicalOrNode() {}
-
-  static grn_rc open(
-    ExpressionNode *arg1, ExpressionNode *arg2, ExpressionNode **node) {
-    LogicalOrNode *new_node = new (std::nothrow) LogicalOrNode(arg1, arg2);
-    if (!new_node) {
-      return GRN_NO_MEMORY_AVAILABLE;
-    }
-    *node = new_node;
-    return GRN_SUCCESS;
-  }
-
-  grn_rc filter(
-    Record *input, size_t input_size,
-    Record *output, size_t *output_size);
-
-  grn_rc evaluate(
-    const Record *records, size_t num_records, Bool *results);
-
- private:
-  std::vector<Record> temp_records_;
-
-  LogicalOrNode(ExpressionNode *arg1, ExpressionNode *arg2)
-    : BinaryNode<Bool, Bool, Bool>(arg1, arg2), temp_records_() {}
-};
-
-grn_rc LogicalOrNode::filter(
-  Record *input, size_t input_size,
-  Record *output, size_t *output_size) {
-  // Evaluate "arg1" for all the records.
-  // Then, evaluate "arg2" for non-true records.
-  grn_rc rc = fill_arg1_values(input, input_size);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  if (temp_records_.size() < input_size) try {
-    temp_records_.resize(input_size);
-  } catch (const std::bad_alloc &) {
-    return GRN_NO_MEMORY_AVAILABLE;
-  }
-  size_t count = 0;
-  for (size_t i = 0; i < input_size; ++i) {
-    if (arg1_values_[i].raw == GRN_FALSE) {
-      temp_records_[count] = input[i];
-      ++count;
-    }
-  }
-  if (count == 0) {
-    if (input != output) {
-      for (size_t i = 0; i < input_size; ++i) {
-        output[i] = input[i];
-      }
-    }
-    *output_size = input_size;
-    return GRN_SUCCESS;
-  }
-  rc = fill_arg2_values(&*temp_records_.begin(), count);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-
-  // Merge the evaluation results.
-  count = 0;
-  size_t output_count = 0;
-  for (size_t i = 0; i < input_size; ++i) {
-    if (arg1_values_[i].raw == GRN_TRUE) {
-      output[output_count] = input[i];
-      ++output_count;
-    } else {
-      if (arg2_values_[count].raw == GRN_TRUE) {
-        output[output_count] = input[i];
-        ++output_count;
-      }
-      ++count;
-    }
-  }
-  *output_size = output_count;
-  return GRN_SUCCESS;
-}
-
-grn_rc LogicalOrNode::evaluate(
-  const Record *records, size_t num_records, Bool *results) {
-  // Evaluate "arg1" for all the records.
-  // Then, evaluate "arg2" for non-true records.
-  grn_rc rc = arg1_->evaluate(records, num_records, results);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  if (temp_records_.size() < num_records) try {
-    temp_records_.resize(num_records);
-  } catch (const std::bad_alloc &) {
-    return GRN_NO_MEMORY_AVAILABLE;
-  }
-  size_t count = 0;
-  for (size_t i = 0; i < num_records; ++i) {
-    if (results[i].raw == GRN_FALSE) {
-      temp_records_[count] = records[i];
-      ++count;
-    }
-  }
-  if (count == 0) {
-    // Nothing to do.
-    return GRN_SUCCESS;
-  }
-  rc = fill_arg2_values(&*temp_records_.begin(), count);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-
-  // Merge the evaluation results.
-  count = 0;
-  for (size_t i = 0; i < num_records; ++i) {
-    if (results[i].raw == GRN_FALSE) {
-      results[i] = arg2_values_[count];
-      ++count;
-    }
-  }
-  return GRN_SUCCESS;
-}
-
-// -- GenericBinaryNode --
-
-template <typename T,
-          typename U = typename T::Value,
-          typename V = typename T::Arg1,
-          typename W = typename T::Arg2>
-class GenericBinaryNode : public BinaryNode<U, V, W> {
- public:
-  GenericBinaryNode(ExpressionNode *arg1, ExpressionNode *arg2)
-    : BinaryNode<U, V, W>(arg1, arg2), operator_() {}
-  ~GenericBinaryNode() {}
-
-  grn_rc evaluate(
-    const Record *records, size_t num_records, Bool *results);
-
- private:
-  T operator_;
-};
-
-template <typename T, typename U, typename V, typename W>
-grn_rc GenericBinaryNode<T, U, V, W>::evaluate(
-    const Record *records, size_t num_records, Bool *results) {
-  grn_rc rc = this->fill_arg1_values(records, num_records);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  rc = this->fill_arg2_values(records, num_records);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  for (size_t i = 0; i < num_records; ++i) {
-    results[i] = operator_(this->arg1_values_[i], this->arg2_values_[i]);
-  }
-  return GRN_SUCCESS;
-}
-
-template <typename T, typename V, typename W>
-class GenericBinaryNode<T, Bool, V, W> : public BinaryNode<Bool, V, W> {
- public:
-  GenericBinaryNode(ExpressionNode *arg1, ExpressionNode *arg2)
-    : BinaryNode<Bool, V, W>(arg1, arg2), operator_() {}
-  ~GenericBinaryNode() {}
-
-  grn_rc filter(
-    Record *input, size_t input_size,
-    Record *output, size_t *output_size);
-
-  grn_rc evaluate(
-    const Record *records, size_t num_records, Bool *results);
-
- private:
-  T operator_;
-};
-
-template <typename T, typename V, typename W>
-grn_rc GenericBinaryNode<T, Bool, V, W>::filter(
-    Record *input, size_t input_size,
-    Record *output, size_t *output_size) {
-  grn_rc rc = this->fill_arg1_values(input, input_size);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  rc = this->fill_arg2_values(input, input_size);
-  if (rc != GRN_SUCCESS) {
-    return rc;
-  }
-  size_t count = 0;
-  for (size_t i = 0; i < input_size; ++i) {
-    if (operator_(this->arg1_values_[i], this->arg2_values_[i]).raw ==
-      GRN_TRUE) {
-      output[count] = input[i];
-      ++count;
+      return GRN_UNKNOWN_ERROR;
     }
   }
-  *output_size = count;
+  GRN_OBJ_FIN(ctx_, &value);
+  if (ctx_->rc != GRN_SUCCESS) {
+    return ctx_->rc;
+  }
   return GRN_SUCCESS;
 }
+#undef GRN_EGN_EVALUATE_CASE_BLOCK
 
-template <typename T, typename V, typename W>
-grn_rc GenericBinaryNode<T, Bool, V, W>::evaluate(
-  const Record *records, size_t num_records, Bool *results) {
-  grn_rc rc = this->fill_arg1_values(records, num_records);
-  if (rc != GRN_SUCCESS) {
-    return rc;
+grn_rc ColumnNode::evaluate_scalar_text(const Record *records,
+                                        size_t num_records, void *results) {
+  if (!buf_) {
+    buf_ = grn_obj_open(ctx_, GRN_BULK, 0, GRN_DB_TEXT);
+    if (!buf_) {
+      if (ctx_->rc != GRN_SUCCESS) {
+        return ctx_->rc;
+      }
+      return GRN_UNKNOWN_ERROR;
+    }
   }
-  rc = this->fill_arg2_values(records, num_records);
-  if (rc != GRN_SUCCESS) {
-    return rc;
+  GRN_BULK_REWIND(buf_);
+  grn_egn_text *values = static_cast<grn_egn_text *>(results);
+  size_t offset = 0;
+  for (size_t i = 0; i < num_records; ++i) {
+    grn_obj_get_value(ctx_, column_, records[i].id, buf_);
+    if (ctx_->rc != GRN_SUCCESS) {
+      return ctx_->rc;
+    }
+    size_t size = GRN_TEXT_LEN(buf_);
+    values[i].size = size - offset;
+    offset = size;
   }
+  const char *ptr = GRN_TEXT_VALUE(buf_);
   for (size_t i = 0; i < num_records; ++i) {
-    results[i] = operator_(this->arg1_values_[i], this->arg2_values_[i]);
+    values[i].ptr = ptr;
+    ptr += values[i].size;
   }
   return GRN_SUCCESS;
 }
 
-// ----- EqualNode -----
-
-template <typename T>
-struct EqualOperator {
-  typedef Bool Value;
-  typedef T Arg1;
-  typedef T Arg2;
-  Value operator()(const Arg1 &arg1, const Arg2 &arg2) const {
-    return Bool(arg1 == arg2);
-  }
-};
-
-template <typename T>
-grn_rc equal_node_open(EqualOperator<T> op,
-  ExpressionNode *arg1, ExpressionNode *arg2, ExpressionNode **node) {
-  GenericBinaryNode<EqualOperator<T> > *new_node =
-    new (std::nothrow) GenericBinaryNode<EqualOperator<T> >(arg1, arg2);
-  if (!new_node) {
-    return GRN_NO_MEMORY_AVAILABLE;
+#define GRN_EGN_EVALUATE_VECTOR_CASE_BLOCK(type, egn_type)\
+  case GRN_DB_ ## type: {\
+    if (!buf_) {\
+      buf_ = grn_obj_open(ctx_, GRN_UVECTOR, 0, GRN_DB_ ## type);\
+      if (!buf_) {\
+        if (ctx_->rc != GRN_SUCCESS) {\
+          return ctx_->rc;\
+        }\
+        return GRN_UNKNOWN_ERROR;\
+      }\
+    }\
+    GRN_BULK_REWIND(buf_);\
+    grn_egn_vector *vectors = static_cast<grn_egn_vector *>(results);\
+    size_t offset = 0;\
+    for (size_t i = 0; i < num_records; i++) {\
+      grn_obj_get_value(ctx_, column_, records[i].id, buf_);\
+      if (ctx_->rc != GRN_SUCCESS) {\
+        return ctx_->rc;\
+      }\
+      size_t size = grn_vector_size(ctx_, buf_);\
+      vectors[i].size = size - offset;\
+      offset = size;\
+    }\
+    grn_egn_ ## egn_type *ptr =\
+      reinterpret_cast<grn_egn_ ## egn_type *>(GRN_BULK_HEAD(buf_));\
+    for (size_t i = 0; i < num_records; i++) {\
+      vectors[i].ptr = ptr;\
+      ptr += vectors[i].size;\
+    }\
+    return GRN_SUCCESS;\
+  }
+grn_rc ColumnNode::evaluate_vector(const Record *records, size_t num_records,
+                                   void *results) {
+  switch (builtin_type()) {
+    case GRN_DB_INT8:
+    case GRN_DB_INT16:
+    case GRN_DB_INT32:
+    case GRN_DB_UINT8:
+    case GRN_DB_UINT16:
+    case GRN_DB_UINT32: {
+      return evaluate_vector_int(records, num_records, results);
+    }
+    GRN_EGN_EVALUATE_VECTOR_CASE_BLOCK(BOOL, bool)
+    GRN_EGN_EVALUATE_VECTOR_CASE_BLOCK(INT64, int)
+    GRN_EGN_EVALUATE_VECTOR_CASE_BLOCK(UINT64, int)
+    GRN_EGN_EVALUATE_VECTOR_CASE_BLOCK(FLOAT, float)
+    GRN_EGN_EVALUATE_VECTOR_CASE_BLOCK(TIME, float)
+    case GRN_DB_SHORT_TEXT:
+    case GRN_DB_TEXT:
+    case GRN_DB_LONG_TEXT: {
+      return evaluate_vector_text(records, num_records, results);
+    }
+    case GRN_DB_TOKYO_GEO_POINT:
+    case GRN_DB_WGS84_GEO_POINT: {
+      if (!buf_) {
+        buf_ = grn_obj_open(ctx_, GRN_UVECTOR, 0, builtin_type());
+        if (!buf_) {
+          if (ctx_->rc != GRN_SUCCESS) {
+            return ctx_->rc;
+          }
+          return GRN_UNKNOWN_ERROR;
+        }
+      }
+      GRN_BULK_REWIND(buf_);
+      grn_egn_vector *vectors = static_cast<grn_egn_vector *>(results);
+      size_t offset = 0;
+      for (size_t i = 0; i < num_records; i++) {
+        grn_obj_get_value(ctx_, column_, records[i].id, buf_);
+        if (ctx_->rc != GRN_SUCCESS) {
+          return ctx_->rc;
+        }
+        size_t size = grn_vector_size(ctx_, buf_);
+        vectors[i].size = size - offset;
+        offset = size;
+      }
+      grn_egn_geo_point *ptr =
+        reinterpret_cast<grn_egn_geo_point *>(GRN_BULK_HEAD(buf_));
+      for (size_t i = 0; i < num_records; i++) {
+        vectors[i].ptr = ptr;
+        ptr += vectors[i].size;
+      }
+      return GRN_SUCCESS;
+    }
+    default: {
+      return GRN_UNKNOWN_ERROR;
+    }
   }
-  *node = new_node;
-  return GRN_SUCCESS;
 }
 
-// ----- NotEqualNode -----
-
-template <typename T>
-struct NotEqualOperator {
-  typedef Bool Value;
-  typedef T Arg1;
-  typedef T Arg2;
-  Value operator()(const Arg1 &arg1, const Arg2 &arg2) const {
-    return Bool(arg1 != arg2);
+#define GRN_EGN_EVALUATE_VECTOR_INT_CASE_BLOCK(type)\
+  case GRN_DB_ ## type: {\
+    if (!deep_buf_) {\
+      deep_buf_ = grn_obj_open(ctx_, GRN_UVECTOR, 0, GRN_DB_ ## type);\
+      if (!deep_buf_) {\
+        if (ctx_->rc != GRN_SUCCESS) {\
+          return ctx_->rc;\
+        }\
+        return GRN_UNKNOWN_ERROR;\
+      }\
+    }\
+    GRN_BULK_REWIND(deep_buf_);\
+    grn_egn_vector *vectors = static_cast<grn_egn_vector *>(results);\
+    size_t offset = 0;\
+    for (size_t i = 0; i < num_records; i++) {\
+      grn_obj_get_value(ctx_, column_, records[i].id, deep_buf_);\
+      if (ctx_->rc != GRN_SUCCESS) {\
+        return ctx_->rc;\
+      }\
+      size_t size = grn_vector_size(ctx_, deep_buf_);\
+      vectors[i].size = size - offset;\
+      offset = size;\
+    }\
+    grn_rc rc = grn_bulk_resize(ctx_, buf_, sizeof(grn_egn_int) * offset);\
+    if (rc != GRN_SUCCESS) {\
+      return rc;\
+    }\
+    grn_egn_int *ptr = reinterpret_cast<grn_egn_int *>(GRN_BULK_HEAD(buf_));\
+    for (size_t i = 0; i < offset; ++i) {\
+      ptr[i] = GRN_ ## type ## _VALUE_AT(deep_buf_, i);\
+    }\
+    for (size_t i = 0; i < num_records; i++) {\
+      vectors[i].ptr = ptr;\
+      ptr += vectors[i].size;\
+    }\
+    return GRN_SUCCESS;\
+  }
+grn_rc ColumnNode::evaluate_vector_int(const Record *records,
+                                       size_t num_records, void *results) {
+  if (!buf_) {
+    buf_ = grn_obj_open(ctx_, GRN_UVECTOR, 0, GRN_DB_INT64);
+    if (!buf_) {
+      if (ctx_->rc != GRN_SUCCESS) {
+        return ctx_->rc;
+      }
+      return GRN_UNKNOWN_ERROR;
+    }
   }
-};
-
-template <typename T>
-grn_rc not_equal_node_open(NotEqualOperator<T> op,
-  ExpressionNode *arg1, ExpressionNode *arg2, ExpressionNode **node) {
-  GenericBinaryNode<NotEqualOperator<T> > *new_node =
-    new (std::nothrow) GenericBinaryNode<NotEqualOperator<T> >(arg1, arg2);
-  if (!new_node) {
-    return GRN_NO_MEMORY_AVAILABLE;
+  GRN_BULK_REWIND(buf_);
+  switch (builtin_type()) {
+    GRN_EGN_EVALUATE_VECTOR_INT_CASE_BLOCK(INT8)
+    GRN_EGN_EVALUATE_VECTOR_INT_CASE_BLOCK(INT16)
+    GRN_EGN_EVALUATE_VECTOR_INT_CASE_BLOCK(INT32)
+    GRN_EGN_EVALUATE_VECTOR_INT_CASE_BLOCK(UINT8)
+    GRN_EGN_EVALUATE_VECTOR_INT_CASE_BLOCK(UINT16)
+    GRN_EGN_EVALUATE_VECTOR_INT_CASE_BLOCK(UINT32)
+    default: {
+      return GRN_UNKNOWN_ERROR;
+    }
   }
-  *node = new_node;
-  return GRN_SUCCESS;
 }
+#undef GRN_EGN_EVALUATE_VECTOR_INT_CASE_BLOCK
 
-// ----- LessNode -----
-
-template <typename T>
-struct LessOperator {
-  typedef Bool Value;
-  typedef T Arg1;
-  typedef T Arg2;
-  Value operator()(const Arg1 &arg1, const Arg2 &arg2) const {
-    return Bool(arg1 < arg2);
-  }
-};
-
-template <typename T>
-grn_rc less_node_open(LessOperator<T> op,
-  ExpressionNode *arg1, ExpressionNode *arg2, ExpressionNode **node) {
-  GenericBinaryNode<LessOperator<T> > *new_node =
-    new (std::nothrow) GenericBinaryNode<LessOperator<T> >(arg1, arg2);
-  if (!new_node) {
-    return GRN_NO_MEMORY_AVAILABLE;
+grn_rc ColumnNode::evaluate_vector_text(const Record *records,
+                                        size_t num_records, void *results) {
+  if (!deep_buf_) {
+    deep_buf_ = grn_obj_open(ctx_, GRN_VECTOR, 0, GRN_DB_TEXT);
+    if (!deep_buf_) {
+      if (ctx_->rc != GRN_SUCCESS) {
+        return ctx_->rc;
+      }
+      return GRN_UNKNOWN_ERROR;
+    }
   }
-  *node = new_node;
-  return GRN_SUCCESS;
-}
-
-// ----- LessEqualNode -----
-
-template <typename T>
-struct LessEqualOperator {
-  typedef Bool Value;
-  typedef T Arg1;
-  typedef T Arg2;
-  Value operator()(const Arg1 &arg1, const Arg2 &arg2) const {
-    return Bool(arg1 < arg2);
+  GRN_BULK_REWIND(deep_buf_);
+  grn_egn_vector *vectors = static_cast<grn_egn_vector *>(results);
+  size_t offset = 0;
+  for (size_t i = 0; i < num_records; ++i) {
+    grn_obj_get_value(ctx_, column_, records[i].id, deep_buf_);
+    if (ctx_->rc != GRN_SUCCESS) {
+      return ctx_->rc;
+    }
+    size_t size = grn_vector_size(ctx_, deep_buf_);
+    vectors[i].size = size - offset;
+    offset = size;
   }
-};
-
-template <typename T>
-grn_rc less_equal_node_open(LessEqualOperator<T> op,
-  ExpressionNode *arg1, ExpressionNode *arg2, ExpressionNode **node) {
-  GenericBinaryNode<LessEqualOperator<T> > *new_node =
-    new (std::nothrow) GenericBinaryNode<LessEqualOperator<T> >(arg1, arg2);
-  if (!new_node) {
-    return GRN_NO_MEMORY_AVAILABLE;
+  if (!buf_) {
+    buf_ = grn_obj_open(ctx_, GRN_BULK, 0, GRN_DB_TEXT);
+    if (!buf_) {
+      if (ctx_->rc != GRN_SUCCESS) {
+        return ctx_->rc;
+      }
+      return GRN_UNKNOWN_ERROR;
+    }
   }
-  *node = new_node;
-  return GRN_SUCCESS;
-}
-
-// ----- GreaterNode -----
-
-template <typename T>
-struct GreaterOperator {
-  typedef Bool Value;
-  typedef T Arg1;
-  typedef T Arg2;
-  Value operator()(const Arg1 &arg1, const Arg2 &arg2) const {
-    return Bool(arg1 < arg2);
+  grn_rc rc = grn_bulk_resize(ctx_, buf_, sizeof(grn_egn_text) * offset);
+  if (rc != GRN_SUCCESS) {
+    return rc;
   }
-};
-
-template <typename T>
-grn_rc greater_node_open(GreaterOperator<T> op,
-  ExpressionNode *arg1, ExpressionNode *arg2, ExpressionNode **node) {
-  GenericBinaryNode<GreaterOperator<T> > *new_node =
-    new (std::nothrow) GenericBinaryNode<GreaterOperator<T> >(arg1, arg2);
-  if (!new_node) {
-    return GRN_NO_MEMORY_AVAILABLE;
+  grn_egn_text *texts = reinterpret_cast<grn_egn_text *>(GRN_BULK_HEAD(buf_));
+  offset = 0;
+  for (size_t i = 0; i < num_records; ++i) {
+    for (size_t j = 0; j < vectors[i].size; ++j) {
+      texts[offset + j].size = grn_vector_get_element(
+        ctx_, deep_buf_, offset + j, &texts[offset + j].ptr, NULL, NULL);
+    }
+    vectors[i].ptr = &texts[offset];
+    offset += vectors[i].size;
   }
-  *node = new_node;
   return GRN_SUCCESS;
 }
 
-// ----- GreaterEqualNode -----
+//// -- OperatorNode --
+
+//template <typename T>
+//class OperatorNode : public TypedNode<T> {
+// public:
+//  OperatorNode() : TypedNode<T>() {}
+//  virtual ~OperatorNode() {}
+
+//  ExpressionNodeType type() const {
+//    return GRN_EGN_OPERATOR_NODE;
+//  }
+//};
+
+//template <typename T>
+//grn_rc operator_node_fill_arg_values(
+//  const Record *records, size_t num_records,
+//  TypedNode<T> *arg, std::vector<T> *arg_values) {
+//  size_t old_size = arg_values->size();
+//  if (old_size < num_records) try {
+//    arg_values->resize(num_records);
+//  } catch (const std::bad_alloc &) {
+//    return GRN_NO_MEMORY_AVAILABLE;
+//  }
+//  switch (arg->type()) {
+//    case GRN_EGN_CONSTANT_NODE: {
+//      if (old_size < num_records) {
+//        return arg->evaluate(records + old_size, num_records - old_size,
+//          &*arg_values->begin() + old_size);
+//      }
+//      return GRN_SUCCESS;
+//    }
+//    default: {
+//      return arg->evaluate(records, num_records, &*arg_values->begin());
+//    }
+//  }
+//}
+
+//// --- UnaryNode ---
+
+//template <typename T, typename U>
+//class UnaryNode : public OperatorNode<T> {
+// public:
+//  explicit UnaryNode(ExpressionNode *arg)
+//    : OperatorNode<T>(), arg_(static_cast<TypedNode<U> *>(arg)),
+//      arg_values_() {}
+//  virtual ~UnaryNode() {
+//    delete arg_;
+//  }
+
+// protected:
+//  TypedNode<U> *arg_;
+//  std::vector<U> arg_values_;
+
+//  grn_rc fill_arg_values(const Record *records, size_t num_records) {
+//    return operator_node_fill_arg_values(
+//      records, num_records, arg_, &arg_values_);
+//  }
+//};
+
+//// ---- LogicalNotNode ----
+
+//class LogicalNotNode : public UnaryNode<Bool, Bool> {
+// public:
+//  ~LogicalNotNode() {}
+
+//  static grn_rc open(ExpressionNode *arg, ExpressionNode **node) {
+//    LogicalNotNode *new_node = new (std::nothrow) LogicalNotNode(arg);
+//    if (!new_node) {
+//      return GRN_NO_MEMORY_AVAILABLE;
+//    }
+//    *node = new_node;
+//    return GRN_SUCCESS;
+//  }
+
+//  grn_rc filter(
+//    Record *input, size_t input_size,
+//    Record *output, size_t *output_size);
+
+//  grn_rc evaluate(
+//    const Record *records, size_t num_records, Bool *results);
+
+// private:
+//  std::vector<Record> temp_records_;
+
+//  explicit LogicalNotNode(ExpressionNode *arg)
+//    : UnaryNode<Bool, Bool>(arg), temp_records_() {}
+//};
+
+//grn_rc LogicalNotNode::filter(
+//  Record *input, size_t input_size,
+//  Record *output, size_t *output_size) {
+//  if (temp_records_.size() <= input_size) {
+//    try {
+//      temp_records_.resize(input_size + 1);
+//      temp_records_[input_size].id = GRN_ID_NIL;
+//    } catch (const std::bad_alloc &) {
+//      return GRN_NO_MEMORY_AVAILABLE;
+//    }
+//  }
+//  size_t temp_size;
+//  grn_rc rc =
+//    arg_->filter(input, input_size, &*temp_records_.begin(), &temp_size);
+//  if (rc != GRN_SUCCESS) {
+//    return rc;
+//  }
+//  if (temp_size == 0) {
+//    *output_size = 0;
+//    return GRN_SUCCESS;
+//  }
+
+//  size_t count = 0;
+//  for (size_t i = 0; i < input_size; ++i) {
+//    if (input[i].id != temp_records_[i - count].id) {
+//      output[count] = input[i];
+//      ++count;
+//    }
+//  }
+//  *output_size = count;
+//  return GRN_SUCCESS;
+//}
+
+//grn_rc LogicalNotNode::evaluate(
+//  const Record *records, size_t num_records, Bool *results) {
+//  grn_rc rc = arg_->evaluate(records, num_records, results);
+//  if (rc == GRN_SUCCESS) {
+//    for (size_t i = 0; i < num_records; ++i) {
+//      results[i] = Bool(results[i].raw != GRN_TRUE);
+//    }
+//  }
+//  return rc;
+//}
+
+//// --- BinaryNode ---
+
+//template <typename T, typename U, typename V>
+//class BinaryNode : public OperatorNode<T> {
+// public:
+//  BinaryNode(ExpressionNode *arg1, ExpressionNode *arg2)
+//    : OperatorNode<T>(),
+//      arg1_(static_cast<TypedNode<U> *>(arg1)),
+//      arg2_(static_cast<TypedNode<V> *>(arg2)),
+//      arg1_values_(), arg2_values_() {}
+//  virtual ~BinaryNode() {
+//    delete arg1_;
+//    delete arg2_;
+//  }
+
+// protected:
+//  TypedNode<U> *arg1_;
+//  TypedNode<V> *arg2_;
+//  std::vector<U> arg1_values_;
+//  std::vector<V> arg2_values_;
+
+//  grn_rc fill_arg1_values(const Record *records, size_t num_records) {
+//    return operator_node_fill_arg_values(
+//      records, num_records, arg1_, &arg1_values_);
+//  }
+//  grn_rc fill_arg2_values(const Record *records, size_t num_records) {
+//    return operator_node_fill_arg_values(
+//      records, num_records, arg2_, &arg2_values_);
+//  }
+//};
+
+//// ---- LogicalAndNode ----
+
+//class LogicalAndNode : public BinaryNode<Bool, Bool, Bool> {
+// public:
+//  ~LogicalAndNode() {}
+
+//  static grn_rc open(
+//    ExpressionNode *arg1, ExpressionNode *arg2, ExpressionNode **node) {
+//    LogicalAndNode *new_node = new (std::nothrow) LogicalAndNode(arg1, arg2);
+//    if (!new_node) {
+//      return GRN_NO_MEMORY_AVAILABLE;
+//    }
+//    *node = new_node;
+//    return GRN_SUCCESS;
+//  }
+
+//  grn_rc filter(
+//    Record *input, size_t input_size,
+//    Record *output, size_t *output_size) {
+//    grn_rc rc = arg1_->filter(input, input_size, output, output_size);
+//    if (rc == GRN_SUCCESS) {
+//      rc = arg2_->filter(output, *output_size, output, output_size);
+//    }
+//    return rc;
+//  }
+
+//  grn_rc evaluate(
+//    const Record *records, size_t num_records, Bool *results);
+
+// private:
+//  std::vector<Record> temp_records_;
+
+//  LogicalAndNode(ExpressionNode *arg1, ExpressionNode *arg2)
+//    : BinaryNode<Bool, Bool, Bool>(arg1, arg2), temp_records_() {}
+//};
+
+//grn_rc LogicalAndNode::evaluate(
+//  const Record *records, size_t num_records, Bool *results) {
+//  // Evaluate "arg1" for all the records.
+//  // Then, evaluate "arg2" for non-false records.
+//  grn_rc rc = arg1_->evaluate(records, num_records, results);
+//  if (rc != GRN_SUCCESS) {
+//    return rc;
+//  }
+//  if (temp_records_.size() < num_records) try {
+//    temp_records_.resize(num_records);
+//  } catch (const std::bad_alloc &) {
+//    return GRN_NO_MEMORY_AVAILABLE;
+//  }
+//  size_t count = 0;
+//  for (size_t i = 0; i < num_records; ++i) {
+//    if (results[i].raw == GRN_TRUE) {
+//      temp_records_[count] = records[i];
+//      ++count;
+//    }
+//  }
+//  if (count == 0) {
+//    // Nothing to do.
+//    return GRN_SUCCESS;
+//  }
+//  rc = fill_arg2_values(&*temp_records_.begin(), count);
+//  if (rc != GRN_SUCCESS) {
+//    return rc;
+//  }
+
+//  // Merge the evaluation results.
+//  count = 0;
+//  for (size_t i = 0; i < num_records; ++i) {
+//    if (results[i].raw == GRN_TRUE) {
+//      results[i] = arg2_values_[count];
+//      ++count;
+//    }
+//  }
+//  return GRN_SUCCESS;
+//}
+
+//// ---- LogicalOrNode ----
 
-template <typename T>
-struct GreaterEqualOperator {
-  typedef Bool Value;
-  typedef T Arg1;
-  typedef T Arg2;
-  Value operator()(const Arg1 &arg1, const Arg2 &arg2) const {
-    return Bool(arg1 < arg2);
-  }
-};
+//class LogicalOrNode : public BinaryNode<Bool, Bool, Bool> {
+// public:
+//  ~LogicalOrNode() {}
 
-template <typename T>
-grn_rc greater_equal_node_open(GreaterEqualOperator<T> op,
-  ExpressionNode *arg1, ExpressionNode *arg2, ExpressionNode **node) {
-  GenericBinaryNode<GreaterEqualOperator<T> > *new_node =
-    new (std::nothrow) GenericBinaryNode<GreaterEqualOperator<T> >(arg1, arg2);
-  if (!new_node) {
-    return GRN_NO_MEMORY_AVAILABLE;
-  }
-  *node = new_node;
-  return GRN_SUCCESS;
-}
+//  static grn_rc open(
+//    ExpressionNode *arg1, ExpressionNode *arg2, ExpressionNode **node) {
+//    LogicalOrNode *new_node = new (std::nothrow) LogicalOrNode(arg1, arg2);
+//    if (!new_node) {
+//      return GRN_NO_MEMORY_AVAILABLE;
+//    }
+//    *node = new_node;
+//    return GRN_SUCCESS;
+//  }
+
+//  grn_rc filter(
+//    Record *input, size_t input_size,
+//    Record *output, size_t *output_size);
+
+//  grn_rc evaluate(
+//    const Record *records, size_t num_records, Bool *results);
+
+// private:
+//  std::vector<Record> temp_records_;
+
+//  LogicalOrNode(ExpressionNode *arg1, ExpressionNode *arg2)
+//    : BinaryNode<Bool, Bool, Bool>(arg1, arg2), temp_records_() {}
+//};
+
+//grn_rc LogicalOrNode::filter(
+//  Record *input, size_t input_size,
+//  Record *output, size_t *output_size) {
+//  // Evaluate "arg1" for all the records.
+//  // Then, evaluate "arg2" for non-true records.
+//  grn_rc rc = fill_arg1_values(input, input_size);
+//  if (rc != GRN_SUCCESS) {
+//    return rc;
+//  }
+//  if (temp_records_.size() < input_size) try {
+//    temp_records_.resize(input_size);
+//  } catch (const std::bad_alloc &) {
+//    return GRN_NO_MEMORY_AVAILABLE;
+//  }
+//  size_t count = 0;
+//  for (size_t i = 0; i < input_size; ++i) {
+//    if (arg1_values_[i].raw == GRN_FALSE) {
+//      temp_records_[count] = input[i];
+//      ++count;
+//    }
+//  }
+//  if (count == 0) {
+//    if (input != output) {
+//      for (size_t i = 0; i < input_size; ++i) {
+//        output[i] = input[i];
+//      }
+//    }
+//    *output_size = input_size;
+//    return GRN_SUCCESS;
+//  }
+//  rc = fill_arg2_values(&*temp_records_.begin(), count);
+//  if (rc != GRN_SUCCESS) {
+//    return rc;
+//  }
+
+//  // Merge the evaluation results.
+//  count = 0;
+//  size_t output_count = 0;
+//  for (size_t i = 0; i < input_size; ++i) {
+//    if (arg1_values_[i].raw == GRN_TRUE) {
+//      output[output_count] = input[i];
+//      ++output_count;
+//    } else {
+//      if (arg2_values_[count].raw == GRN_TRUE) {
+//        output[output_count] = input[i];
+//        ++output_count;
+//      }
+//      ++count;
+//    }
+//  }
+//  *output_size = output_count;
+//  return GRN_SUCCESS;
+//}
+
+//grn_rc LogicalOrNode::evaluate(
+//  const Record *records, size_t num_records, Bool *results) {
+//  // Evaluate "arg1" for all the records.
+//  // Then, evaluate "arg2" for non-true records.
+//  grn_rc rc = arg1_->evaluate(records, num_records, results);
+//  if (rc != GRN_SUCCESS) {
+//    return rc;
+//  }
+//  if (temp_records_.size() < num_records) try {
+//    temp_records_.resize(num_records);
+//  } catch (const std::bad_alloc &) {
+//    return GRN_NO_MEMORY_AVAILABLE;
+//  }
+//  size_t count = 0;
+//  for (size_t i = 0; i < num_records; ++i) {
+//    if (results[i].raw == GRN_FALSE) {
+//      temp_records_[count] = records[i];
+//      ++count;
+//    }
+//  }
+//  if (count == 0) {
+//    // Nothing to do.
+//    return GRN_SUCCESS;
+//  }
+//  rc = fill_arg2_values(&*temp_records_.begin(), count);
+//  if (rc != GRN_SUCCESS) {
+//    return rc;
+//  }
+
+//  // Merge the evaluation results.
+//  count = 0;
+//  for (size_t i = 0; i < num_records; ++i) {
+//    if (results[i].raw == GRN_FALSE) {
+//      results[i] = arg2_values_[count];
+//      ++count;
+//    }
+//  }
+//  return GRN_SUCCESS;
+//}
+
+//// -- GenericBinaryNode --
+
+//template <typename T,
+//          typename U = typename T::Value,
+//          typename V = typename T::Arg1,
+//          typename W = typename T::Arg2>
+//class GenericBinaryNode : public BinaryNode<U, V, W> {
+// public:
+//  GenericBinaryNode(ExpressionNode *arg1, ExpressionNode *arg2)
+//    : BinaryNode<U, V, W>(arg1, arg2), operator_() {}
+//  ~GenericBinaryNode() {}
+
+//  grn_rc evaluate(
+//    const Record *records, size_t num_records, Bool *results);
+
+// private:
+//  T operator_;
+//};
+
+//template <typename T, typename U, typename V, typename W>
+//grn_rc GenericBinaryNode<T, U, V, W>::evaluate(
+//    const Record *records, size_t num_records, Bool *results) {
+//  grn_rc rc = this->fill_arg1_values(records, num_records);
+//  if (rc != GRN_SUCCESS) {
+//    return rc;
+//  }
+//  rc = this->fill_arg2_values(records, num_records);
+//  if (rc != GRN_SUCCESS) {
+//    return rc;
+//  }
+//  for (size_t i = 0; i < num_records; ++i) {
+//    results[i] = operator_(this->arg1_values_[i], this->arg2_values_[i]);
+//  }
+//  return GRN_SUCCESS;
+//}
+
+//template <typename T, typename V, typename W>
+//class GenericBinaryNode<T, Bool, V, W> : public BinaryNode<Bool, V, W> {
+// public:
+//  GenericBinaryNode(ExpressionNode *arg1, ExpressionNode *arg2)
+//    : BinaryNode<Bool, V, W>(arg1, arg2), operator_() {}
+//  ~GenericBinaryNode() {}
+
+//  grn_rc filter(
+//    Record *input, size_t input_size,
+//    Record *output, size_t *output_size);
+
+//  grn_rc evaluate(
+//    const Record *records, size_t num_records, Bool *results);
+
+// private:
+//  T operator_;
+//};
+
+//template <typename T, typename V, typename W>
+//grn_rc GenericBinaryNode<T, Bool, V, W>::filter(
+//    Record *input, size_t input_size,
+//    Record *output, size_t *output_size) {
+//  grn_rc rc = this->fill_arg1_values(input, input_size);
+//  if (rc != GRN_SUCCESS) {
+//    return rc;
+//  }
+//  rc = this->fill_arg2_values(input, input_size);
+//  if (rc != GRN_SUCCESS) {
+//    return rc;
+//  }
+//  size_t count = 0;
+//  for (size_t i = 0; i < input_size; ++i) {
+//    if (operator_(this->arg1_values_[i], this->arg2_values_[i]).raw ==
+//      GRN_TRUE) {
+//      output[count] = input[i];
+//      ++count;
+//    }
+//  }
+//  *output_size = count;
+//  return GRN_SUCCESS;
+//}
+
+//template <typename T, typename V, typename W>
+//grn_rc GenericBinaryNode<T, Bool, V, W>::evaluate(
+//  const Record *records, size_t num_records, Bool *results) {
+//  grn_rc rc = this->fill_arg1_values(records, num_records);
+//  if (rc != GRN_SUCCESS) {
+//    return rc;
+//  }
+//  rc = this->fill_arg2_values(records, num_records);
+//  if (rc != GRN_SUCCESS) {
+//    return rc;
+//  }
+//  for (size_t i = 0; i < num_records; ++i) {
+//    results[i] = operator_(this->arg1_values_[i], this->arg2_values_[i]);
+//  }
+//  return GRN_SUCCESS;
+//}
+
+//// ----- EqualNode -----
+
+//template <typename T>
+//struct EqualOperator {
+//  typedef Bool Value;
+//  typedef T Arg1;
+//  typedef T Arg2;
+//  Value operator()(const Arg1 &arg1, const Arg2 &arg2) const {
+//    return Bool(arg1 == arg2);
+//  }
+//};
+
+//template <typename T>
+//grn_rc equal_node_open(EqualOperator<T> op,
+//  ExpressionNode *arg1, ExpressionNode *arg2, ExpressionNode **node) {
+//  GenericBinaryNode<EqualOperator<T> > *new_node =
+//    new (std::nothrow) GenericBinaryNode<EqualOperator<T> >(arg1, arg2);
+//  if (!new_node) {
+//    return GRN_NO_MEMORY_AVAILABLE;
+//  }
+//  *node = new_node;
+//  return GRN_SUCCESS;
+//}
+
+//// ----- NotEqualNode -----
+
+//template <typename T>
+//struct NotEqualOperator {
+//  typedef Bool Value;
+//  typedef T Arg1;
+//  typedef T Arg2;
+//  Value operator()(const Arg1 &arg1, const Arg2 &arg2) const {
+//    return Bool(arg1 != arg2);
+//  }
+//};
+
+//template <typename T>
+//grn_rc not_equal_node_open(NotEqualOperator<T> op,
+//  ExpressionNode *arg1, ExpressionNode *arg2, ExpressionNode **node) {
+//  GenericBinaryNode<NotEqualOperator<T> > *new_node =
+//    new (std::nothrow) GenericBinaryNode<NotEqualOperator<T> >(arg1, arg2);
+//  if (!new_node) {
+//    return GRN_NO_MEMORY_AVAILABLE;
+//  }
+//  *node = new_node;
+//  return GRN_SUCCESS;
+//}
+
+//// ----- LessNode -----
+
+//template <typename T>
+//struct LessOperator {
+//  typedef Bool Value;
+//  typedef T Arg1;
+//  typedef T Arg2;
+//  Value operator()(const Arg1 &arg1, const Arg2 &arg2) const {
+//    return Bool(arg1 < arg2);
+//  }
+//};
+
+//template <typename T>
+//grn_rc less_node_open(LessOperator<T> op,
+//  ExpressionNode *arg1, ExpressionNode *arg2, ExpressionNode **node) {
+//  GenericBinaryNode<LessOperator<T> > *new_node =
+//    new (std::nothrow) GenericBinaryNode<LessOperator<T> >(arg1, arg2);
+//  if (!new_node) {
+//    return GRN_NO_MEMORY_AVAILABLE;
+//  }
+//  *node = new_node;
+//  return GRN_SUCCESS;
+//}
+
+//// ----- LessEqualNode -----
+
+//template <typename T>
+//struct LessEqualOperator {
+//  typedef Bool Value;
+//  typedef T Arg1;
+//  typedef T Arg2;
+//  Value operator()(const Arg1 &arg1, const Arg2 &arg2) const {
+//    return Bool(arg1 < arg2);
+//  }
+//};
+
+//template <typename T>
+//grn_rc less_equal_node_open(LessEqualOperator<T> op,
+//  ExpressionNode *arg1, ExpressionNode *arg2, ExpressionNode **node) {
+//  GenericBinaryNode<LessEqualOperator<T> > *new_node =
+//    new (std::nothrow) GenericBinaryNode<LessEqualOperator<T> >(arg1, arg2);
+//  if (!new_node) {
+//    return GRN_NO_MEMORY_AVAILABLE;
+//  }
+//  *node = new_node;
+//  return GRN_SUCCESS;
+//}
+
+//// ----- GreaterNode -----
+
+//template <typename T>
+//struct GreaterOperator {
+//  typedef Bool Value;
+//  typedef T Arg1;
+//  typedef T Arg2;
+//  Value operator()(const Arg1 &arg1, const Arg2 &arg2) const {
+//    return Bool(arg1 < arg2);
+//  }
+//};
+
+//template <typename T>
+//grn_rc greater_node_open(GreaterOperator<T> op,
+//  ExpressionNode *arg1, ExpressionNode *arg2, ExpressionNode **node) {
+//  GenericBinaryNode<GreaterOperator<T> > *new_node =
+//    new (std::nothrow) GenericBinaryNode<GreaterOperator<T> >(arg1, arg2);
+//  if (!new_node) {
+//    return GRN_NO_MEMORY_AVAILABLE;
+//  }
+//  *node = new_node;
+//  return GRN_SUCCESS;
+//}
+
+//// ----- GreaterEqualNode -----
+
+//template <typename T>
+//struct GreaterEqualOperator {
+//  typedef Bool Value;
+//  typedef T Arg1;
+//  typedef T Arg2;
+//  Value operator()(const Arg1 &arg1, const Arg2 &arg2) const {
+//    return Bool(arg1 < arg2);
+//  }
+//};
+
+//template <typename T>
+//grn_rc greater_equal_node_open(GreaterEqualOperator<T> op,
+//  ExpressionNode *arg1, ExpressionNode *arg2, ExpressionNode **node) {
+//  GenericBinaryNode<GreaterEqualOperator<T> > *new_node =
+//    new (std::nothrow) GenericBinaryNode<GreaterEqualOperator<T> >(arg1, arg2);
+//  if (!new_node) {
+//    return GRN_NO_MEMORY_AVAILABLE;
+//  }
+//  *node = new_node;
+//  return GRN_SUCCESS;
+//}
 
 // -- ExpressionToken --
 
@@ -2410,83 +2014,83 @@ grn_rc ExpressionParser::tokenize(const char *query, size_t query_size) {
     rest += pos;
     rest_size -= pos;
     switch (rest[0]) {
-      case '!': {
-        if ((rest_size >= 2) && (rest[1] == '=')) {
-          tokens_.push_back(ExpressionToken("!=", GRN_EGN_NOT_EQUAL));
-          rest += 2;
-          rest_size -= 2;
-        } else {
-          tokens_.push_back(ExpressionToken("!", GRN_EGN_LOGICAL_NOT));
-          ++rest;
-          --rest_size;
-        }
-        break;
-      }
-//      case '~': {
-//        tokens_.push_back(ExpressionToken("~", GRN_OP_BITWISE_NOT));
-//        rest = rest.substring(1);
+//      case '!': {
+//        if ((rest_size >= 2) && (rest[1] == '=')) {
+//          tokens_.push_back(ExpressionToken("!=", GRN_EGN_NOT_EQUAL));
+//          rest += 2;
+//          rest_size -= 2;
+//        } else {
+//          tokens_.push_back(ExpressionToken("!", GRN_EGN_LOGICAL_NOT));
+//          ++rest;
+//          --rest_size;
+//        }
 //        break;
 //      }
-      case '=': {
-        if ((rest_size >= 2) && (rest[1] == '=')) {
-          tokens_.push_back(ExpressionToken("==", GRN_EGN_EQUAL));
-          rest += 2;
-          rest_size -= 2;
-        } else {
-          return GRN_INVALID_ARGUMENT;
-        }
-        break;
-      }
-      case '<': {
-        if ((rest_size >= 2) && (rest[1] == '=')) {
-          tokens_.push_back(ExpressionToken("<=", GRN_EGN_LESS_EQUAL));
-          rest += 2;
-          rest_size -= 2;
-        } else {
-          tokens_.push_back(ExpressionToken("<", GRN_EGN_LESS));
-          ++rest;
-          --rest_size;
-        }
-        break;
-      }
-      case '>': {
-        if ((rest_size >= 2) && (rest[1] == '=')) {
-          tokens_.push_back(ExpressionToken(">=", GRN_EGN_GREATER_EQUAL));
-          rest += 2;
-          rest_size -= 2;
-        } else {
-          tokens_.push_back(ExpressionToken(">", GRN_EGN_GREATER));
-          ++rest;
-          --rest_size;
-        }
-        break;
-      }
-      case '&': {
-        if ((rest_size >= 2) && (rest[1] == '&')) {
-          tokens_.push_back(ExpressionToken("&&", GRN_EGN_LOGICAL_AND));
-          rest += 2;
-          rest_size -= 2;
-        } else {
-//          tokens_.push_back(ExpressionToken("&", GRN_OP_BITWISE_AND));
+////      case '~': {
+////        tokens_.push_back(ExpressionToken("~", GRN_OP_BITWISE_NOT));
+////        rest = rest.substring(1);
+////        break;
+////      }
+//      case '=': {
+//        if ((rest_size >= 2) && (rest[1] == '=')) {
+//          tokens_.push_back(ExpressionToken("==", GRN_EGN_EQUAL));
+//          rest += 2;
+//          rest_size -= 2;
+//        } else {
+//          return GRN_INVALID_ARGUMENT;
+//        }
+//        break;
+//      }
+//      case '<': {
+//        if ((rest_size >= 2) && (rest[1] == '=')) {
+//          tokens_.push_back(ExpressionToken("<=", GRN_EGN_LESS_EQUAL));
+//          rest += 2;
+//          rest_size -= 2;
+//        } else {
+//          tokens_.push_back(ExpressionToken("<", GRN_EGN_LESS));
 //          ++rest;
 //          --rest_size;
-          return GRN_INVALID_ARGUMENT;
-        }
-        break;
-      }
-      case '|': {
-        if ((rest_size >= 2) && (rest[1] == '|')) {
-          tokens_.push_back(ExpressionToken("||", GRN_EGN_LOGICAL_OR));
-          rest += 2;
-          rest_size -= 2;
-        } else {
-//          tokens_.push_back(ExpressionToken("|", GRN_OP_BITWISE_OR));
+//        }
+//        break;
+//      }
+//      case '>': {
+//        if ((rest_size >= 2) && (rest[1] == '=')) {
+//          tokens_.push_back(ExpressionToken(">=", GRN_EGN_GREATER_EQUAL));
+//          rest += 2;
+//          rest_size -= 2;
+//        } else {
+//          tokens_.push_back(ExpressionToken(">", GRN_EGN_GREATER));
 //          ++rest;
 //          --rest_size;
-          return GRN_INVALID_ARGUMENT;
-        }
-        break;
-      }
+//        }
+//        break;
+//      }
+//      case '&': {
+//        if ((rest_size >= 2) && (rest[1] == '&')) {
+//          tokens_.push_back(ExpressionToken("&&", GRN_EGN_LOGICAL_AND));
+//          rest += 2;
+//          rest_size -= 2;
+//        } else {
+////          tokens_.push_back(ExpressionToken("&", GRN_OP_BITWISE_AND));
+////          ++rest;
+////          --rest_size;
+//          return GRN_INVALID_ARGUMENT;
+//        }
+//        break;
+//      }
+//      case '|': {
+//        if ((rest_size >= 2) && (rest[1] == '|')) {
+//          tokens_.push_back(ExpressionToken("||", GRN_EGN_LOGICAL_OR));
+//          rest += 2;
+//          rest_size -= 2;
+//        } else {
+////          tokens_.push_back(ExpressionToken("|", GRN_OP_BITWISE_OR));
+////          ++rest;
+////          --rest_size;
+//          return GRN_INVALID_ARGUMENT;
+//        }
+//        break;
+//      }
 //      case '^': {
 //        tokens_.push_back(ExpressionToken("^", GRN_OP_BITWISE_XOR));
 //        rest = rest.substring(1);
@@ -2648,31 +2252,49 @@ grn_rc ExpressionParser::push_token(const ExpressionToken &token) {
       break;
     }
     case CONSTANT_TOKEN: {
-      grn_obj obj;
+      grn_obj *obj;
       const std::string string = token.string();
       if (std::isdigit(static_cast<uint8_t>(string[0]))) {
         if (string.find_first_of('.') == string.npos) {
-          GRN_INT64_INIT(&obj, 0);
-          GRN_INT64_SET(ctx_, &obj, strtoll(string.c_str(), NULL, 10));
+          obj = grn_obj_open(ctx_, GRN_BULK, 0, GRN_DB_INT64);
+          if (obj) {
+            GRN_INT64_SET(ctx_, obj, strtoll(string.c_str(), NULL, 10));
+          }
         } else {
-          GRN_FLOAT_INIT(&obj, 0);
-          GRN_FLOAT_SET(ctx_, &obj, strtod(string.c_str(), NULL));
+          obj = grn_obj_open(ctx_, GRN_BULK, 0, GRN_DB_FLOAT);
+          if (obj) {
+            GRN_FLOAT_SET(ctx_, obj, strtod(string.c_str(), NULL));
+          }
         }
       } else if (string == "true") {
-        GRN_BOOL_INIT(&obj, 0);
-        GRN_BOOL_SET(ctx_, &obj, GRN_TRUE);
+        obj = grn_obj_open(ctx_, GRN_BULK, 0, GRN_DB_BOOL);
+        if (obj) {
+          GRN_BOOL_SET(ctx_, obj, GRN_TRUE);
+        }
       } else if (string == "false") {
-        GRN_BOOL_INIT(&obj, 0);
-        GRN_BOOL_SET(ctx_, &obj, GRN_FALSE);
+        obj = grn_obj_open(ctx_, GRN_BULK, 0, GRN_DB_BOOL);
+        if (obj) {
+          GRN_BOOL_SET(ctx_, obj, GRN_FALSE);
+        }
       } else {
-        GRN_TEXT_INIT(&obj, 0);
-        GRN_TEXT_SET(ctx_, &obj, string.data(), string.size());
+        obj = grn_obj_open(ctx_, GRN_BULK, 0, GRN_DB_TEXT);
+        if (obj) {
+          GRN_TEXT_SET(ctx_, obj, string.data(), string.size());
+        }
+      }
+      if (!obj) {
+        if (ctx_->rc != GRN_SUCCESS) {
+          return ctx_->rc;
+        }
+        return GRN_UNKNOWN_ERROR;
       }
       rc = push_token(ExpressionToken(string, DUMMY_TOKEN));
       if (rc == GRN_SUCCESS) {
-        rc = expression_->push_object(&obj);
+        rc = expression_->push_object(obj);
+      }
+      if (rc != GRN_SUCCESS) {
+        grn_obj_close(ctx_, obj);
       }
-      GRN_OBJ_FIN(ctx_, &obj);
       break;
     }
     case NAME_TOKEN: {
@@ -2849,8 +2471,7 @@ grn_rc ExpressionParser::push_token(const ExpressionToken &token) {
 // -- Expression --
 
 Expression::Expression(grn_ctx *ctx, grn_obj *table)
-  : ctx_(ctx), table_(table), type_(GRN_EGN_INCOMPLETE),
-    data_type_(GRN_EGN_VOID), builtin_type_(GRN_DB_VOID), stack_() {}
+  : ctx_(ctx), table_(table), type_(GRN_EGN_INCOMPLETE), stack_() {}
 
 Expression::~Expression() {
   for (size_t i = 0; i < stack_.size(); ++i) {
@@ -2874,110 +2495,44 @@ grn_rc Expression::open(
 grn_rc Expression::parse(grn_ctx *ctx, grn_obj *table,
   const char *query, size_t query_size, Expression **expression) {
   if (!ctx || !grn_obj_is_table(ctx, table) ||
-      !query || (query_size == 0) || !expression) {
-    return GRN_INVALID_ARGUMENT;
-  }
-  return ExpressionParser::parse(ctx, table, query, query_size, expression);
-}
-
-grn_rc Expression::push_object(grn_obj *obj) {
-  if (!obj) {
-    return GRN_INVALID_ARGUMENT;
-  }
-  grn_rc rc = GRN_UNKNOWN_ERROR;
-  switch (obj->header.type) {
-    case GRN_BULK: {
-      rc = push_bulk_object(obj);
-      break;
-    }
-    case GRN_UVECTOR: {
-      // FIXME: To be supported.
-      return GRN_INVALID_ARGUMENT;
-    }
-    case GRN_VECTOR: {
-      rc = push_vector_object(obj);
-      return GRN_INVALID_ARGUMENT;
-    }
-    case GRN_ACCESSOR: {
-      grn_accessor *accessor = (grn_accessor *)obj;
-      switch (accessor->action) {
-        case GRN_ACCESSOR_GET_ID: {
-          ExpressionNode *node;
-          rc = IDNode::open(&node);
-          if (rc == GRN_SUCCESS) try {
-            stack_.push_back(node);
-          } catch (const std::bad_alloc &) {
-            delete node;
-            return GRN_NO_MEMORY_AVAILABLE;
-          }
-          break;
-        }
-        case GRN_ACCESSOR_GET_KEY: {
-          // TODO: KeyNode should be provided for performance.
-          ExpressionNode *node;
-          grn_id range = grn_obj_get_range(ctx_, obj);
-          switch (range) {
-            case GRN_DB_BOOL: {
-              rc = ColumnNode<Bool>::open(ctx_, obj, &node);
-              break;
-            }
-            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: {
-              rc = ColumnNode<Int>::open(ctx_, obj, &node);
-              break;
-            }
-            case GRN_DB_FLOAT: {
-              rc = ColumnNode<Float>::open(ctx_, obj, &node);
-              break;
-            }
-            case GRN_DB_TIME: {
-              rc = ColumnNode<Time>::open(ctx_, obj, &node);
-              break;
-            }
-            case GRN_DB_TOKYO_GEO_POINT:
-            case GRN_DB_WGS84_GEO_POINT: {
-              rc = ColumnNode<GeoPoint>::open(ctx_, obj, &node);
-              break;
-            }
-            default: {
-              return GRN_INVALID_ARGUMENT;
-            }
-          }
-          if (rc == GRN_SUCCESS) try {
-            stack_.push_back(node);
-          } catch (const std::bad_alloc &) {
-            delete node;
-            return GRN_NO_MEMORY_AVAILABLE;
-          }
-          break;
-        }
-        case GRN_ACCESSOR_GET_VALUE: {
-          // TODO
-          return GRN_INVALID_ARGUMENT;
-        }
-        case GRN_ACCESSOR_GET_SCORE: {
-          ExpressionNode *node;
-          rc = ScoreNode::open(&node);
-          if (rc == GRN_SUCCESS) try {
-            stack_.push_back(node);
-          } catch (const std::bad_alloc &) {
-            delete node;
-            return GRN_NO_MEMORY_AVAILABLE;
-          }
-          break;
-        }
-        default: {
-          return GRN_INVALID_ARGUMENT;
-        }
-      }
+      !query || (query_size == 0) || !expression) {
+    return GRN_INVALID_ARGUMENT;
+  }
+  return ExpressionParser::parse(ctx, table, query, query_size, expression);
+}
+
+DataType Expression::data_type() const {
+  ExpressionNode *root = this->root();
+  return root ? root->data_type() : GRN_EGN_VOID;
+}
+grn_builtin_type Expression::builtin_type() const {
+  ExpressionNode *root = this->root();
+  return root ? root->builtin_type() : GRN_DB_VOID;
+}
+
+grn_obj *Expression::ref_table() const {
+  ExpressionNode *root = this->root();
+  return root ? root->ref_table() : NULL;
+}
+
+int Expression::dimension() const {
+  ExpressionNode *root = this->root();
+  return root ? root->dimension() : 0;
+}
+
+grn_rc Expression::push_object(grn_obj *obj) {
+  if (!obj) {
+    return GRN_INVALID_ARGUMENT;
+  }
+  grn_rc rc = GRN_UNKNOWN_ERROR;
+  switch (obj->header.type) {
+    case GRN_BULK:
+    case GRN_UVECTOR:
+    case GRN_VECTOR: {
+      rc = push_constant_object(obj);
       break;
     }
+    case GRN_ACCESSOR:
     case GRN_COLUMN_FIX_SIZE:
     case GRN_COLUMN_VAR_SIZE: {
       rc = push_column_object(obj);
@@ -2988,7 +2543,7 @@ grn_rc Expression::push_object(grn_obj *obj) {
     }
   }
   if (rc == GRN_SUCCESS) {
-    update_types();
+    update_type();
   }
   return rc;
 }
@@ -3033,7 +2588,7 @@ grn_rc Expression::push_operator(OperatorType operator_type) {
   }
   if (rc == GRN_SUCCESS) {
     stack_.push_back(node);
-    update_types();
+    update_type();
   }
   return rc;
 }
@@ -3096,11 +2651,9 @@ grn_rc Expression::adjust(Record *records, size_t num_records) {
   return GRN_SUCCESS;
 }
 
-template <typename T>
-grn_rc Expression::evaluate(
-  const Record *records, size_t num_records, T *results) {
-  if (((!records || !results) && (num_records != 0)) ||
-      (T::data_type() != data_type())) {
+grn_rc Expression::evaluate(const Record *records, size_t num_records,
+                            void *results) {
+  if ((!records || !results) && (num_records != 0)) {
     return GRN_INVALID_ARGUMENT;
   }
   ExpressionNode *root = this->root();
@@ -3109,23 +2662,9 @@ grn_rc Expression::evaluate(
   }
   // FIXME: Records should be processed per block.
   //        However, the contents of old blocks will be lost.
-  return static_cast<TypedNode<T> *>(root)->evaluate(
-    records, num_records, results);
+  return root->evaluate(records, num_records, results);
 }
 
-template grn_rc Expression::evaluate(
-  const Record *records, size_t num_records, Bool *results);
-template grn_rc Expression::evaluate(
-  const Record *records, size_t num_records, Int *results);
-template grn_rc Expression::evaluate(
-  const Record *records, size_t num_records, Float *results);
-template grn_rc Expression::evaluate(
-  const Record *records, size_t num_records, Time *results);
-template grn_rc Expression::evaluate(
-  const Record *records, size_t num_records, Text *results);
-template grn_rc Expression::evaluate(
-  const Record *records, size_t num_records, GeoPoint *results);
-
 ExpressionNode *Expression::root() const {
   if (stack_.size() != 1) {
     return NULL;
@@ -3133,12 +2672,10 @@ ExpressionNode *Expression::root() const {
   return stack_.front();
 }
 
-void Expression::update_types() {
+void Expression::update_type() {
   ExpressionNode *root = this->root();
   if (!root) {
     type_ = GRN_EGN_INCOMPLETE;
-    data_type_ = GRN_EGN_VOID;
-    builtin_type_ = GRN_DB_VOID;
   } else {
     switch (root->type()) {
       case GRN_EGN_ID_NODE: {
@@ -3163,441 +2700,233 @@ void Expression::update_types() {
         break;
       }
     }
-    data_type_ = root->data_type();
-    builtin_type_ = root->builtin_type();
-  }
-}
-
-grn_rc Expression::push_bulk_object(grn_obj *obj) {
-  grn_rc rc;
-  ExpressionNode *node;
-  grn_builtin_type builtin_type =
-    static_cast<grn_builtin_type>(obj->header.domain);
-  switch (builtin_type) {
-    case GRN_DB_BOOL: {
-      rc = ConstantNode<Bool>::open(Bool(GRN_BOOL_VALUE(obj)), &node);
-      break;
-    }
-    case GRN_DB_INT8: {
-      rc = ConstantNode<Int>::open(
-        builtin_type, Int(GRN_INT8_VALUE(obj)), &node);
-      break;
-    }
-    case GRN_DB_INT16: {
-      rc = ConstantNode<Int>::open(
-        builtin_type, Int(GRN_INT16_VALUE(obj)), &node);
-      break;
-    }
-    case GRN_DB_INT32: {
-      rc = ConstantNode<Int>::open(
-        builtin_type, Int(GRN_INT32_VALUE(obj)), &node);
-      break;
-    }
-    case GRN_DB_INT64: {
-      rc = ConstantNode<Int>::open(
-        builtin_type, Int(GRN_INT64_VALUE(obj)), &node);
-      break;
-    }
-    case GRN_DB_UINT8: {
-      rc = ConstantNode<Int>::open(
-        builtin_type, Int(GRN_UINT8_VALUE(obj)), &node);
-      break;
-    }
-    case GRN_DB_UINT16: {
-      rc = ConstantNode<Int>::open(
-        builtin_type, Int(GRN_UINT16_VALUE(obj)), &node);
-      break;
-    }
-    case GRN_DB_UINT32: {
-      rc = ConstantNode<Int>::open(
-        builtin_type, Int(GRN_UINT32_VALUE(obj)), &node);
-      break;
-    }
-    case GRN_DB_UINT64: {
-      // FIXME: Type conversion from UInt64 to Int may lose the content.
-      rc = ConstantNode<Int>::open(
-        builtin_type, Int(GRN_UINT64_VALUE(obj)), &node);
-      break;
-    }
-    case GRN_DB_FLOAT: {
-      rc = ConstantNode<Float>::open(Float(GRN_FLOAT_VALUE(obj)), &node);
-      break;
-    }
-    case GRN_DB_TIME: {
-      rc = ConstantNode<Time>::open(Time(GRN_TIME_VALUE(obj)), &node);
-      break;
-    }
-    case GRN_DB_SHORT_TEXT:
-    case GRN_DB_TEXT:
-    case GRN_DB_LONG_TEXT: {
-      Text value(GRN_TEXT_VALUE(obj), GRN_TEXT_LEN(obj));
-      rc = ConstantNode<Text>::open(builtin_type, value, &node);
-      break;
-    }
-    // TODO: TokyoGeoPoint and Wgs84GeoPoint should be provided?
-    case GRN_DB_TOKYO_GEO_POINT:
-    case GRN_DB_WGS84_GEO_POINT: {
-      GeoPoint value;
-      GRN_GEO_POINT_VALUE(obj, value.raw.latitude, value.raw.longitude);
-      rc = ConstantNode<GeoPoint>::open(value, &node);
-      break;
-    }
-    default: {
-      return GRN_INVALID_ARGUMENT;
-    }
-  }
-  if (rc == GRN_SUCCESS) try {
-    stack_.push_back(node);
-  } catch (const std::bad_alloc &) {
-    delete node;
-    return GRN_NO_MEMORY_AVAILABLE;
-  }
-  return rc;
-}
-
-grn_rc Expression::push_vector_object(grn_obj *obj) {
-  grn_rc rc;
-  ExpressionNode *node;
-  grn_builtin_type builtin_type =
-    static_cast<grn_builtin_type>(obj->header.domain);
-  switch (builtin_type) {
-    case GRN_DB_BOOL: {
-      BoolVector value;
-      value.raw.ptr = reinterpret_cast<grn_egn_bool *>(GRN_BULK_HEAD(obj));
-      value.raw.size = GRN_BULK_VSIZE(obj) / sizeof(grn_egn_bool);
-      rc = ConstantNode<BoolVector>::open(value, &node);
-      break;
-    }
-    default: {
-      return GRN_INVALID_ARGUMENT;
-    }
-  }
-  if (rc == GRN_SUCCESS) try {
-    stack_.push_back(node);
-  } catch (const std::bad_alloc &) {
-    delete node;
-    return GRN_NO_MEMORY_AVAILABLE;
   }
-  return rc;
 }
 
-grn_rc Expression::push_column_object(grn_obj *obj) {
-  grn_obj *owner_table = grn_column_table(ctx_, obj);
-  if (owner_table != table_) {
-    return GRN_INVALID_ARGUMENT;
-  }
-  grn_id range = grn_obj_get_range(ctx_, obj);
-  grn_rc rc;
+grn_rc Expression::push_constant_object(grn_obj *obj) {
   ExpressionNode *node;
-  switch (obj->header.type) {
-    case GRN_COLUMN_FIX_SIZE: {
-      switch (range) {
-        case GRN_DB_BOOL: {
-          rc = ColumnNode<Bool>::open(ctx_, obj, &node);
-          break;
-        }
-        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: {
-          rc = ColumnNode<Int>::open(ctx_, obj, &node);
-          break;
-        }
-        case GRN_DB_FLOAT: {
-          rc = ColumnNode<Float>::open(ctx_, obj, &node);
-          break;
-        }
-        case GRN_DB_TIME: {
-          rc = ColumnNode<Time>::open(ctx_, obj, &node);
-          break;
-        }
-        case GRN_DB_TOKYO_GEO_POINT:
-        case GRN_DB_WGS84_GEO_POINT: {
-          rc = ColumnNode<GeoPoint>::open(ctx_, obj, &node);
-          break;
-        }
-        default: {
-          return GRN_INVALID_ARGUMENT;
-        }
-      }
-      break;
-    }
-    case GRN_COLUMN_VAR_SIZE: {
-      grn_obj_flags column_type = obj->header.flags & GRN_OBJ_COLUMN_TYPE_MASK;
-      switch (column_type) {
-        case GRN_OBJ_COLUMN_SCALAR: {
-          switch (range) {
-            case GRN_DB_SHORT_TEXT:
-            case GRN_DB_TEXT:
-            case GRN_DB_LONG_TEXT: {
-              rc = ColumnNode<Text>::open(ctx_, obj, &node);
-              break;
-            }
-            default: {
-              return GRN_INVALID_ARGUMENT;
-            }
-            break;
-          }
-          break;
-        }
-        case GRN_OBJ_COLUMN_VECTOR: {
-          switch (range) {
-            case GRN_DB_BOOL: {
-              rc = ColumnNode<BoolVector>::open(ctx_, obj, &node);
-              break;
-            }
-            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: {
-              rc = ColumnNode<IntVector>::open(ctx_, obj, &node);
-              break;
-            }
-            case GRN_DB_FLOAT: {
-              rc = ColumnNode<FloatVector>::open(ctx_, obj, &node);
-              break;
-            }
-            case GRN_DB_TIME: {
-              rc = ColumnNode<TimeVector>::open(ctx_, obj, &node);
-              break;
-            }
-            case GRN_DB_SHORT_TEXT:
-            case GRN_DB_TEXT:
-            case GRN_DB_LONG_TEXT: {
-              rc = ColumnNode<TextVector>::open(ctx_, obj, &node);
-              break;
-            }
-            case GRN_DB_TOKYO_GEO_POINT:
-            case GRN_DB_WGS84_GEO_POINT: {
-              rc = ColumnNode<GeoPointVector>::open(ctx_, obj, &node);
-              break;
-            }
-            default: {
-              return GRN_INVALID_ARGUMENT;
-            }
-          }
-          break;
-        }
-        default: {
-          return GRN_INVALID_ARGUMENT;
-        }
-      }
-      break;
-    }
-    default: {
-      return GRN_INVALID_ARGUMENT;
-    }
-  }
+  grn_rc rc = ConstantNode::open(ctx_, obj, &node);
   if (rc == GRN_SUCCESS) try {
     stack_.push_back(node);
   } catch (const std::bad_alloc &) {
     delete node;
     return GRN_NO_MEMORY_AVAILABLE;
-  }
-  return rc;
-}
-
-grn_rc Expression::create_unary_node(OperatorType operator_type,
-  ExpressionNode *arg, ExpressionNode **node) {
-  grn_rc rc = GRN_SUCCESS;
-  switch (operator_type) {
-    case GRN_EGN_LOGICAL_NOT: {
-      if (arg->data_type() != GRN_EGN_BOOL) {
-        return GRN_UNKNOWN_ERROR;
-      }
-      rc = LogicalNotNode::open(arg, node);
-      break;
-    }
-    default: {
-      return GRN_INVALID_ARGUMENT;
-    }
-  }
-  return rc;
-}
-
-grn_rc Expression::create_binary_node(OperatorType operator_type,
-  ExpressionNode *arg1, ExpressionNode *arg2, ExpressionNode **node) {
-  switch (operator_type) {
-    case GRN_EGN_LOGICAL_AND: {
-      if ((arg1->data_type() != GRN_EGN_BOOL) ||
-          (arg1->data_type() != GRN_EGN_BOOL)) {
-        return GRN_INVALID_FORMAT;
-      }
-      return LogicalAndNode::open(arg1, arg2, node);
-    }
-    case GRN_EGN_LOGICAL_OR: {
-      if ((arg1->data_type() != GRN_EGN_BOOL) ||
-          (arg1->data_type() != GRN_EGN_BOOL)) {
-        return GRN_INVALID_FORMAT;
-      }
-      return LogicalOrNode::open(arg1, arg2, node);
-    }
-    case GRN_EGN_EQUAL: {
-      if (arg1->data_type() != arg2->data_type()) {
-        return GRN_INVALID_FORMAT;
-      }
-      switch (arg1->data_type()) {
-        case GRN_EGN_BOOL: {
-          return equal_node_open(EqualOperator<Bool>(), arg1, arg2, node);
-        }
-        case GRN_EGN_INT: {
-          return equal_node_open(EqualOperator<Int>(), arg1, arg2, node);
-        }
-        case GRN_EGN_FLOAT: {
-          return equal_node_open(EqualOperator<Float>(), arg1, arg2, node);
-        }
-        case GRN_EGN_TIME: {
-          return equal_node_open(EqualOperator<Time>(), arg1, arg2, node);
-        }
-        case GRN_EGN_TEXT: {
-          return equal_node_open(EqualOperator<Text>(), arg1, arg2, node);
-        }
-        case GRN_EGN_GEO_POINT: {
-          return equal_node_open(EqualOperator<GeoPoint>(), arg1, arg2, node);
-        }
-        default: {
-          return GRN_UNKNOWN_ERROR;
-        }
-      }
-    }
-    case GRN_EGN_NOT_EQUAL: {
-      if (arg1->data_type() != arg2->data_type()) {
-        return GRN_INVALID_FORMAT;
-      }
-      switch (arg1->data_type()) {
-        case GRN_EGN_BOOL: {
-          return not_equal_node_open(
-            NotEqualOperator<Bool>(), arg1, arg2, node);
-        }
-        case GRN_EGN_INT: {
-          return not_equal_node_open(
-            NotEqualOperator<Int>(), arg1, arg2, node);
-        }
-        case GRN_EGN_FLOAT: {
-          return not_equal_node_open(
-            NotEqualOperator<Float>(), arg1, arg2, node);
-        }
-        case GRN_EGN_TIME: {
-          return not_equal_node_open(
-            NotEqualOperator<Time>(), arg1, arg2, node);
-        }
-        case GRN_EGN_TEXT: {
-          return not_equal_node_open(
-            NotEqualOperator<Text>(), arg1, arg2, node);
-        }
-        case GRN_EGN_GEO_POINT: {
-          return not_equal_node_open(
-            NotEqualOperator<GeoPoint>(), arg1, arg2, node);
-        }
-        default: {
-          return GRN_UNKNOWN_ERROR;
-        }
-      }
-    }
-    case GRN_EGN_LESS: {
-      if (arg1->data_type() != arg2->data_type()) {
-        return GRN_INVALID_FORMAT;
-      }
-      switch (arg1->data_type()) {
-        case GRN_EGN_INT: {
-          return less_node_open(LessOperator<Int>(), arg1, arg2, node);
-        }
-        case GRN_EGN_FLOAT: {
-          return less_node_open(LessOperator<Float>(), arg1, arg2, node);
-        }
-        case GRN_EGN_TIME: {
-          return less_node_open(LessOperator<Time>(), arg1, arg2, node);
-        }
-        case GRN_EGN_TEXT: {
-          return less_node_open(LessOperator<Text>(), arg1, arg2, node);
-        }
-        default: {
-          return GRN_UNKNOWN_ERROR;
-        }
-      }
-    }
-    case GRN_EGN_LESS_EQUAL: {
-      if (arg1->data_type() != arg2->data_type()) {
-        return GRN_INVALID_FORMAT;
-      }
-      switch (arg1->data_type()) {
-        case GRN_EGN_INT: {
-          return less_equal_node_open(
-            LessEqualOperator<Int>(), arg1, arg2, node);
-        }
-        case GRN_EGN_FLOAT: {
-          return less_equal_node_open(
-            LessEqualOperator<Float>(), arg1, arg2, node);
-        }
-        case GRN_EGN_TIME: {
-          return less_equal_node_open(
-            LessEqualOperator<Time>(), arg1, arg2, node);
-        }
-        case GRN_EGN_TEXT: {
-          return less_equal_node_open(
-            LessEqualOperator<Text>(), arg1, arg2, node);
-        }
-        default: {
-          return GRN_UNKNOWN_ERROR;
-        }
-      }
-    }
-    case GRN_EGN_GREATER: {
-      if (arg1->data_type() != arg2->data_type()) {
-        return GRN_INVALID_FORMAT;
-      }
-      switch (arg1->data_type()) {
-        case GRN_EGN_INT: {
-          return greater_node_open(GreaterOperator<Int>(), arg1, arg2, node);
-        }
-        case GRN_EGN_FLOAT: {
-          return greater_node_open(GreaterOperator<Float>(), arg1, arg2, node);
-        }
-        case GRN_EGN_TIME: {
-          return greater_node_open(GreaterOperator<Time>(), arg1, arg2, node);
-        }
-        case GRN_EGN_TEXT: {
-          return greater_node_open(GreaterOperator<Text>(), arg1, arg2, node);
-        }
-        default: {
-          return GRN_UNKNOWN_ERROR;
-        }
-      }
-    }
-    case GRN_EGN_GREATER_EQUAL: {
-      if (arg1->data_type() != arg2->data_type()) {
-        return GRN_INVALID_FORMAT;
-      }
-      switch (arg1->data_type()) {
-        case GRN_EGN_INT: {
-          return greater_equal_node_open(
-            GreaterEqualOperator<Int>(), arg1, arg2, node);
-        }
-        case GRN_EGN_FLOAT: {
-          return greater_equal_node_open(
-            GreaterEqualOperator<Float>(), arg1, arg2, node);
-        }
-        case GRN_EGN_TIME: {
-          return greater_equal_node_open(
-            GreaterEqualOperator<Time>(), arg1, arg2, node);
-        }
-        case GRN_EGN_TEXT: {
-          return greater_equal_node_open(
-            GreaterEqualOperator<Text>(), arg1, arg2, node);
-        }
-        default: {
-          return GRN_UNKNOWN_ERROR;
-        }
-      }
+  }
+  return rc;
+}
+
+grn_rc Expression::push_column_object(grn_obj *obj) {
+  if ((obj->header.type == GRN_COLUMN_FIX_SIZE) ||
+      (obj->header.type == GRN_COLUMN_VAR_SIZE)) {
+    grn_obj *owner_table = grn_column_table(ctx_, obj);
+    if (owner_table != table_) {
+      return GRN_INVALID_ARGUMENT;
+    }
+  }
+  ExpressionNode *node;
+  grn_rc rc = ColumnNode::open(ctx_, obj, &node);
+  if (rc == GRN_SUCCESS) try {
+    stack_.push_back(node);
+  } catch (const std::bad_alloc &) {
+    delete node;
+    return GRN_NO_MEMORY_AVAILABLE;
+  }
+  return rc;
+}
+
+grn_rc Expression::create_unary_node(OperatorType operator_type,
+  ExpressionNode *arg, ExpressionNode **node) {
+  grn_rc rc = GRN_SUCCESS;
+  switch (operator_type) {
+//    case GRN_EGN_LOGICAL_NOT: {
+//      if (arg->data_type() != GRN_EGN_BOOL) {
+//        return GRN_UNKNOWN_ERROR;
+//      }
+//      rc = LogicalNotNode::open(arg, node);
+//      break;
+//    }
+    default: {
+      return GRN_INVALID_ARGUMENT;
     }
+  }
+  return rc;
+}
+
+grn_rc Expression::create_binary_node(OperatorType operator_type,
+  ExpressionNode *arg1, ExpressionNode *arg2, ExpressionNode **node) {
+  switch (operator_type) {
+//    case GRN_EGN_LOGICAL_AND: {
+//      if ((arg1->data_type() != GRN_EGN_BOOL) ||
+//          (arg1->data_type() != GRN_EGN_BOOL)) {
+//        return GRN_INVALID_FORMAT;
+//      }
+//      return LogicalAndNode::open(arg1, arg2, node);
+//    }
+//    case GRN_EGN_LOGICAL_OR: {
+//      if ((arg1->data_type() != GRN_EGN_BOOL) ||
+//          (arg1->data_type() != GRN_EGN_BOOL)) {
+//        return GRN_INVALID_FORMAT;
+//      }
+//      return LogicalOrNode::open(arg1, arg2, node);
+//    }
+//    case GRN_EGN_EQUAL: {
+//      if (arg1->data_type() != arg2->data_type()) {
+//        return GRN_INVALID_FORMAT;
+//      }
+//      switch (arg1->data_type()) {
+//        case GRN_EGN_BOOL: {
+//          return equal_node_open(EqualOperator<Bool>(), arg1, arg2, node);
+//        }
+//        case GRN_EGN_INT: {
+//          return equal_node_open(EqualOperator<Int>(), arg1, arg2, node);
+//        }
+//        case GRN_EGN_FLOAT: {
+//          return equal_node_open(EqualOperator<Float>(), arg1, arg2, node);
+//        }
+//        case GRN_EGN_TIME: {
+//          return equal_node_open(EqualOperator<Time>(), arg1, arg2, node);
+//        }
+//        case GRN_EGN_TEXT: {
+//          return equal_node_open(EqualOperator<Text>(), arg1, arg2, node);
+//        }
+//        case GRN_EGN_GEO_POINT: {
+//          return equal_node_open(EqualOperator<GeoPoint>(), arg1, arg2, node);
+//        }
+//        default: {
+//          return GRN_UNKNOWN_ERROR;
+//        }
+//      }
+//    }
+//    case GRN_EGN_NOT_EQUAL: {
+//      if (arg1->data_type() != arg2->data_type()) {
+//        return GRN_INVALID_FORMAT;
+//      }
+//      switch (arg1->data_type()) {
+//        case GRN_EGN_BOOL: {
+//          return not_equal_node_open(
+//            NotEqualOperator<Bool>(), arg1, arg2, node);
+//        }
+//        case GRN_EGN_INT: {
+//          return not_equal_node_open(
+//            NotEqualOperator<Int>(), arg1, arg2, node);
+//        }
+//        case GRN_EGN_FLOAT: {
+//          return not_equal_node_open(
+//            NotEqualOperator<Float>(), arg1, arg2, node);
+//        }
+//        case GRN_EGN_TIME: {
+//          return not_equal_node_open(
+//            NotEqualOperator<Time>(), arg1, arg2, node);
+//        }
+//        case GRN_EGN_TEXT: {
+//          return not_equal_node_open(
+//            NotEqualOperator<Text>(), arg1, arg2, node);
+//        }
+//        case GRN_EGN_GEO_POINT: {
+//          return not_equal_node_open(
+//            NotEqualOperator<GeoPoint>(), arg1, arg2, node);
+//        }
+//        default: {
+//          return GRN_UNKNOWN_ERROR;
+//        }
+//      }
+//    }
+//    case GRN_EGN_LESS: {
+//      if (arg1->data_type() != arg2->data_type()) {
+//        return GRN_INVALID_FORMAT;
+//      }
+//      switch (arg1->data_type()) {
+//        case GRN_EGN_INT: {
+//          return less_node_open(LessOperator<Int>(), arg1, arg2, node);
+//        }
+//        case GRN_EGN_FLOAT: {
+//          return less_node_open(LessOperator<Float>(), arg1, arg2, node);
+//        }
+//        case GRN_EGN_TIME: {
+//          return less_node_open(LessOperator<Time>(), arg1, arg2, node);
+//        }
+//        case GRN_EGN_TEXT: {
+//          return less_node_open(LessOperator<Text>(), arg1, arg2, node);
+//        }
+//        default: {
+//          return GRN_UNKNOWN_ERROR;
+//        }
+//      }
+//    }
+//    case GRN_EGN_LESS_EQUAL: {
+//      if (arg1->data_type() != arg2->data_type()) {
+//        return GRN_INVALID_FORMAT;
+//      }
+//      switch (arg1->data_type()) {
+//        case GRN_EGN_INT: {
+//          return less_equal_node_open(
+//            LessEqualOperator<Int>(), arg1, arg2, node);
+//        }
+//        case GRN_EGN_FLOAT: {
+//          return less_equal_node_open(
+//            LessEqualOperator<Float>(), arg1, arg2, node);
+//        }
+//        case GRN_EGN_TIME: {
+//          return less_equal_node_open(
+//            LessEqualOperator<Time>(), arg1, arg2, node);
+//        }
+//        case GRN_EGN_TEXT: {
+//          return less_equal_node_open(
+//            LessEqualOperator<Text>(), arg1, arg2, node);
+//        }
+//        default: {
+//          return GRN_UNKNOWN_ERROR;
+//        }
+//      }
+//    }
+//    case GRN_EGN_GREATER: {
+//      if (arg1->data_type() != arg2->data_type()) {
+//        return GRN_INVALID_FORMAT;
+//      }
+//      switch (arg1->data_type()) {
+//        case GRN_EGN_INT: {
+//          return greater_node_open(GreaterOperator<Int>(), arg1, arg2, node);
+//        }
+//        case GRN_EGN_FLOAT: {
+//          return greater_node_open(GreaterOperator<Float>(), arg1, arg2, node);
+//        }
+//        case GRN_EGN_TIME: {
+//          return greater_node_open(GreaterOperator<Time>(), arg1, arg2, node);
+//        }
+//        case GRN_EGN_TEXT: {
+//          return greater_node_open(GreaterOperator<Text>(), arg1, arg2, node);
+//        }
+//        default: {
+//          return GRN_UNKNOWN_ERROR;
+//        }
+//      }
+//    }
+//    case GRN_EGN_GREATER_EQUAL: {
+//      if (arg1->data_type() != arg2->data_type()) {
+//        return GRN_INVALID_FORMAT;
+//      }
+//      switch (arg1->data_type()) {
+//        case GRN_EGN_INT: {
+//          return greater_equal_node_open(
+//            GreaterEqualOperator<Int>(), arg1, arg2, node);
+//        }
+//        case GRN_EGN_FLOAT: {
+//          return greater_equal_node_open(
+//            GreaterEqualOperator<Float>(), arg1, arg2, node);
+//        }
+//        case GRN_EGN_TIME: {
+//          return greater_equal_node_open(
+//            GreaterEqualOperator<Time>(), arg1, arg2, node);
+//        }
+//        case GRN_EGN_TEXT: {
+//          return greater_equal_node_open(
+//            GreaterEqualOperator<Text>(), arg1, arg2, node);
+//        }
+//        default: {
+//          return GRN_UNKNOWN_ERROR;
+//        }
+//      }
+//    }
     default: {
       return GRN_INVALID_ARGUMENT;
     }
@@ -3767,102 +3096,72 @@ grn_egn_select_output(grn_ctx *ctx, grn_obj *table,
     GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, '"');
     GRN_TEXT_PUT(ctx, ctx->impl->outbuf, names[i].data(), names[i].size());
     GRN_TEXT_PUT(ctx, ctx->impl->outbuf, "\",\"", 3);
-    switch (expressions[i]->data_type()) {
-      case GRN_EGN_BOOL:
-      case GRN_EGN_BOOL_VECTOR: {
+    switch (expressions[i]->builtin_type()) {
+      case GRN_DB_BOOL: {
         GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "Bool");
         break;
       }
-      case GRN_EGN_INT:
-      case GRN_EGN_INT_VECTOR: {
-        switch (expressions[i]->builtin_type()) {
-          case GRN_DB_INT8: {
-            GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "Int8");
-            break;
-          }
-          case GRN_DB_INT16: {
-            GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "Int16");
-            break;
-          }
-          case GRN_DB_INT32: {
-            GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "Int32");
-            break;
-          }
-          case GRN_DB_INT64: {
-            GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "Int64");
-            break;
-          }
-          case GRN_DB_UINT8: {
-            GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "UInt8");
-            break;
-          }
-          case GRN_DB_UINT16: {
-            GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "UInt16");
-            break;
-          }
-          case GRN_DB_UINT32: {
-            GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "UInt32");
-            break;
-          }
-          case GRN_DB_UINT64: {
-            GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "UInt64");
-            break;
-          }
-          default: {
-            GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "Int");
-            break;
-          }
-        }
+      case GRN_DB_INT8: {
+        GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "Int8");
         break;
       }
-      case GRN_EGN_FLOAT:
-      case GRN_EGN_FLOAT_VECTOR: {
+      case GRN_DB_INT16: {
+        GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "Int16");
+        break;
+      }
+      case GRN_DB_INT32: {
+        GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "Int32");
+        break;
+      }
+      case GRN_DB_INT64: {
+        GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "Int64");
+        break;
+      }
+      case GRN_DB_UINT8: {
+        GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "UInt8");
+        break;
+      }
+      case GRN_DB_UINT16: {
+        GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "UInt16");
+        break;
+      }
+      case GRN_DB_UINT32: {
+        // TODO
+//        if (expressions[i]->ref_table()) {
+//        }
+        GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "UInt32");
+        break;
+      }
+      case GRN_DB_UINT64: {
+        GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "UInt64");
+        break;
+      }
+      case GRN_DB_FLOAT: {
         GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "Float");
         break;
       }
-      case GRN_EGN_TIME:
-      case GRN_EGN_TIME_VECTOR: {
+      case GRN_DB_TIME: {
         GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "Time");
         break;
       }
-      case GRN_EGN_TEXT:
-      case GRN_EGN_TEXT_VECTOR: {
-        switch (expressions[i]->builtin_type()) {
-          case GRN_DB_SHORT_TEXT: {
-            GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "ShortText");
-            break;
-          }
-          case GRN_DB_TEXT: {
-            GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "Text");
-            break;
-          }
-          case GRN_DB_LONG_TEXT: {
-            GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "LongText");
-            break;
-          }
-          default: {
-            GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "Text");
-            break;
-          }
-        }
+      case GRN_DB_SHORT_TEXT: {
+        GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "ShortText");
         break;
       }
-      case GRN_EGN_GEO_POINT:
-      case GRN_EGN_GEO_POINT_VECTOR: {
-        switch (expressions[i]->builtin_type()) {
-          case GRN_DB_TOKYO_GEO_POINT: {
-            GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "TokyoGeoPoint");
-            break;
-          }
-          case GRN_DB_WGS84_GEO_POINT: {
-            GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "WGS84GeoPoint");
-            break;
-          }
-          default: {
-            GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "GeoPoint");
-            break;
-          }
-        }
+      case GRN_DB_TEXT: {
+        GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "Text");
+        break;
+      }
+      case GRN_DB_LONG_TEXT: {
+        GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "LongText");
+        break;
+      }
+      case GRN_DB_TOKYO_GEO_POINT: {
+        GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "TokyoGeoPoint");
+        break;
+      }
+      case GRN_DB_WGS84_GEO_POINT: {
+        GRN_TEXT_PUTS(ctx, ctx->impl->outbuf, "WGS84GeoPoint");
         break;
       }
       default: {
@@ -3883,218 +3182,235 @@ grn_egn_select_output(grn_ctx *ctx, grn_obj *table,
         batch_size = num_records - count;
       }
       for (size_t i = 0; i < expressions.size(); ++i) {
-        switch (expressions[i]->data_type()) {
-          case GRN_EGN_BOOL: {
-            bufs[i].resize(sizeof(grn_egn_bool) * batch_size);
-            expressions[i]->evaluate(records + count, batch_size,
-                                     (grn::egn::Bool *)&bufs[i][0]);
-            break;
-          }
-          case GRN_EGN_INT: {
-            bufs[i].resize(sizeof(grn_egn_int) * batch_size);
-            expressions[i]->evaluate(records + count, batch_size,
-                                     (grn::egn::Int *)&bufs[i][0]);
-            break;
-          }
-          case GRN_EGN_FLOAT: {
-            bufs[i].resize(sizeof(grn_egn_float) * batch_size);
-            expressions[i]->evaluate(records + count, batch_size,
-                                     (grn::egn::Float *)&bufs[i][0]);
-            break;
-          }
-          case GRN_EGN_TIME: {
-            bufs[i].resize(sizeof(grn_egn_time) * batch_size);
-            expressions[i]->evaluate(records + count, batch_size,
-                                     (grn::egn::Time *)&bufs[i][0]);
-            break;
-          }
-          case GRN_EGN_TEXT: {
-            bufs[i].resize(sizeof(grn_egn_text) * batch_size);
-            expressions[i]->evaluate(records + count, batch_size,
-                                     (grn::egn::Text *)&bufs[i][0]);
-            break;
-          }
-          case GRN_EGN_GEO_POINT: {
-            bufs[i].resize(sizeof(grn_egn_geo_point) * batch_size);
-            expressions[i]->evaluate(records + count, batch_size,
-                                     (grn::egn::GeoPoint *)&bufs[i][0]);
-            break;
-          }
-          case GRN_EGN_BOOL_VECTOR: {
-            bufs[i].resize(sizeof(grn_egn_bool_vector) * batch_size);
-            expressions[i]->evaluate(records + count, batch_size,
-                                     (grn::egn::BoolVector *)&bufs[i][0]);
-            break;
-          }
-          case GRN_EGN_INT_VECTOR: {
-            bufs[i].resize(sizeof(grn_egn_int_vector) * batch_size);
-            expressions[i]->evaluate(records + count, batch_size,
-                                     (grn::egn::IntVector *)&bufs[i][0]);
-            break;
-          }
-          case GRN_EGN_FLOAT_VECTOR: {
-            bufs[i].resize(sizeof(grn_egn_float_vector) * batch_size);
-            expressions[i]->evaluate(records + count, batch_size,
-                                     (grn::egn::FloatVector *)&bufs[i][0]);
-            break;
-          }
-          case GRN_EGN_TIME_VECTOR: {
-            bufs[i].resize(sizeof(grn_egn_time_vector) * batch_size);
-            expressions[i]->evaluate(records + count, batch_size,
-                                     (grn::egn::TimeVector *)&bufs[i][0]);
-            break;
-          }
-          case GRN_EGN_TEXT_VECTOR: {
-            bufs[i].resize(sizeof(grn_egn_text_vector) * batch_size);
-            expressions[i]->evaluate(records + count, batch_size,
-                                     (grn::egn::TextVector *)&bufs[i][0]);
-            break;
-          }
-          case GRN_EGN_GEO_POINT_VECTOR: {
-            bufs[i].resize(sizeof(grn_egn_geo_point_vector) * batch_size);
-            expressions[i]->evaluate(records + count, batch_size,
-                                     (grn::egn::GeoPointVector *)&bufs[i][0]);
-            break;
-          }
-          default: {
-            break;
-          }
-        }
-      }
-      for (size_t i = 0; i < batch_size; ++i) {
-        GRN_OUTPUT_ARRAY_OPEN("HIT", expressions.size());
-        for (size_t j = 0; j < expressions.size(); ++j) {
-          if (j != 0) {
-            GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ',');
+        if (expressions[i]->dimension() == 0) {
+          switch (expressions[i]->data_type()) {
+            case GRN_EGN_BOOL: {
+              bufs[i].resize(sizeof(grn_egn_bool) * batch_size);
+              expressions[i]->evaluate(records + count, batch_size,
+                                       (grn::egn::Bool *)&bufs[i][0]);
+              break;
+            }
+            case GRN_EGN_INT: {
+              bufs[i].resize(sizeof(grn_egn_int) * batch_size);
+              expressions[i]->evaluate(records + count, batch_size,
+                                       (grn::egn::Int *)&bufs[i][0]);
+              break;
+            }
+            case GRN_EGN_FLOAT: {
+              bufs[i].resize(sizeof(grn_egn_float) * batch_size);
+              expressions[i]->evaluate(records + count, batch_size,
+                                       (grn::egn::Float *)&bufs[i][0]);
+              break;
+            }
+            case GRN_EGN_TIME: {
+              bufs[i].resize(sizeof(grn_egn_time) * batch_size);
+              expressions[i]->evaluate(records + count, batch_size,
+                                       (grn::egn::Time *)&bufs[i][0]);
+              break;
+            }
+            case GRN_EGN_TEXT: {
+              bufs[i].resize(sizeof(grn_egn_text) * batch_size);
+              expressions[i]->evaluate(records + count, batch_size,
+                                       (grn::egn::Text *)&bufs[i][0]);
+              break;
+            }
+            case GRN_EGN_GEO_POINT: {
+              bufs[i].resize(sizeof(grn_egn_geo_point) * batch_size);
+              expressions[i]->evaluate(records + count, batch_size,
+                                       (grn::egn::GeoPoint *)&bufs[i][0]);
+              break;
+            }
+            default: {
+              break;
+            }
           }
-          switch (expressions[j]->data_type()) {
+        } else {
+          switch (expressions[i]->data_type()) {
             case GRN_EGN_BOOL: {
-              if (((grn_egn_bool *)&bufs[j][0])[i]) {
-                GRN_TEXT_PUT(ctx, ctx->impl->outbuf, "true", 4);
-              } else {
-                GRN_TEXT_PUT(ctx, ctx->impl->outbuf, "false", 5);
-              }
+              bufs[i].resize(sizeof(grn_egn_vector) * batch_size);
+              expressions[i]->evaluate(records + count, batch_size,
+                                       (grn_egn_vector *)&bufs[i][0]);
               break;
             }
             case GRN_EGN_INT: {
-              grn_text_lltoa(ctx, ctx->impl->outbuf,
-                             ((grn_egn_int *)&bufs[j][0])[i]);
+              bufs[i].resize(sizeof(grn_egn_vector) * batch_size);
+              expressions[i]->evaluate(records + count, batch_size,
+                                       (grn_egn_vector *)&bufs[i][0]);
               break;
             }
             case GRN_EGN_FLOAT: {
-              grn_text_ftoa(ctx, ctx->impl->outbuf,
-                            ((grn_egn_float *)&bufs[j][0])[i]);
+              bufs[i].resize(sizeof(grn_egn_vector) * batch_size);
+              expressions[i]->evaluate(records + count, batch_size,
+                                       (grn_egn_vector *)&bufs[i][0]);
               break;
             }
             case GRN_EGN_TIME: {
-              grn_text_ftoa(ctx, ctx->impl->outbuf,
-                            ((grn_egn_time *)&bufs[j][0])[i] * 0.000001);
+              bufs[i].resize(sizeof(grn_egn_vector) * batch_size);
+              expressions[i]->evaluate(records + count, batch_size,
+                                       (grn_egn_vector *)&bufs[i][0]);
               break;
             }
             case GRN_EGN_TEXT: {
-              grn_egn_text text = ((grn_egn_text *)&bufs[j][0])[i];
-              grn_text_esc(ctx, ctx->impl->outbuf, text.ptr, text.size);
+              bufs[i].resize(sizeof(grn_egn_vector) * batch_size);
+              expressions[i]->evaluate(records + count, batch_size,
+                                       (grn_egn_vector *)&bufs[i][0]);
               break;
             }
             case GRN_EGN_GEO_POINT: {
-              grn_egn_geo_point geo_point =
-                ((grn_egn_geo_point *)&bufs[j][0])[i];
-              GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, '"');
-              grn_text_itoa(ctx, ctx->impl->outbuf, geo_point.latitude);
-              GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, 'x');
-              grn_text_itoa(ctx, ctx->impl->outbuf, geo_point.longitude);
-              GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, '"');
+              bufs[i].resize(sizeof(grn_egn_vector) * batch_size);
+              expressions[i]->evaluate(records + count, batch_size,
+                                       (grn_egn_vector *)&bufs[i][0]);
               break;
             }
-            case GRN_EGN_BOOL_VECTOR: {
-              GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, '[');
-              grn_egn_bool_vector value =
-                ((grn_egn_bool_vector *)&bufs[j][0])[i];
-              for (size_t k = 0; k < value.size; ++k) {
-                if (k != 0) {
-                  GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ',');
-                }
-                if (value.ptr[k]) {
+            default: {
+              break;
+            }
+          }
+        }
+      }
+      for (size_t i = 0; i < batch_size; ++i) {
+        GRN_OUTPUT_ARRAY_OPEN("HIT", expressions.size());
+        for (size_t j = 0; j < expressions.size(); ++j) {
+          if (j != 0) {
+            GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ',');
+          }
+          if (expressions[j]->dimension() == 0) {
+            switch (expressions[j]->data_type()) {
+              case GRN_EGN_BOOL: {
+                if (((grn_egn_bool *)&bufs[j][0])[i]) {
                   GRN_TEXT_PUT(ctx, ctx->impl->outbuf, "true", 4);
                 } else {
                   GRN_TEXT_PUT(ctx, ctx->impl->outbuf, "false", 5);
                 }
+                break;
+              }
+              case GRN_EGN_INT: {
+                grn_text_lltoa(ctx, ctx->impl->outbuf,
+                               ((grn_egn_int *)&bufs[j][0])[i]);
+                break;
+              }
+              case GRN_EGN_FLOAT: {
+                grn_text_ftoa(ctx, ctx->impl->outbuf,
+                              ((grn_egn_float *)&bufs[j][0])[i]);
+                break;
+              }
+              case GRN_EGN_TIME: {
+                grn_text_ftoa(ctx, ctx->impl->outbuf,
+                              ((grn_egn_time *)&bufs[j][0])[i] * 0.000001);
+                break;
+              }
+              case GRN_EGN_TEXT: {
+                grn_egn_text text = ((grn_egn_text *)&bufs[j][0])[i];
+                grn_text_esc(ctx, ctx->impl->outbuf, text.ptr, text.size);
+                break;
+              }
+              case GRN_EGN_GEO_POINT: {
+                grn_egn_geo_point geo_point =
+                  ((grn_egn_geo_point *)&bufs[j][0])[i];
+                GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, '"');
+                grn_text_itoa(ctx, ctx->impl->outbuf, geo_point.latitude);
+                GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, 'x');
+                grn_text_itoa(ctx, ctx->impl->outbuf, geo_point.longitude);
+                GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, '"');
+                break;
+              }
+              default: {
+                break;
               }
-              GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ']');
-              break;
             }
-            case GRN_EGN_INT_VECTOR: {
-              GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, '[');
-              grn_egn_int_vector value =
-                ((grn_egn_int_vector *)&bufs[j][0])[i];
-              for (size_t k = 0; k < value.size; ++k) {
-                if (k != 0) {
-                  GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ',');
+          } else {
+            grn_egn_vector vector =
+              reinterpret_cast<grn_egn_vector *>(&bufs[j][0])[i];
+            switch (expressions[j]->data_type()) {
+              case GRN_EGN_BOOL: {
+                const grn_egn_bool *ptr =
+                  static_cast<const grn_egn_bool *>(vector.ptr);
+                GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, '[');
+                for (size_t k = 0; k < vector.size; ++k) {
+                  if (k != 0) {
+                    GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ',');
+                  }
+                  if (ptr[k]) {
+                    GRN_TEXT_PUT(ctx, ctx->impl->outbuf, "true", 4);
+                  } else {
+                    GRN_TEXT_PUT(ctx, ctx->impl->outbuf, "false", 5);
+                  }
                 }
-                grn_text_lltoa(ctx, ctx->impl->outbuf, value.ptr[k]);
+                GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ']');
+                break;
               }
-              GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ']');
-              break;
-            }
-            case GRN_EGN_FLOAT_VECTOR: {
-              GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, '[');
-              grn_egn_float_vector value =
-                ((grn_egn_float_vector *)&bufs[j][0])[i];
-              for (size_t k = 0; k < value.size; ++k) {
-                if (k != 0) {
-                  GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ',');
+              case GRN_EGN_INT: {
+                const grn_egn_int *ptr =
+                  static_cast<const grn_egn_int *>(vector.ptr);
+                GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, '[');
+                for (size_t k = 0; k < vector.size; ++k) {
+                  if (k != 0) {
+                    GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ',');
+                  }
+                  grn_text_lltoa(ctx, ctx->impl->outbuf, ptr[k]);
                 }
-                grn_text_ftoa(ctx, ctx->impl->outbuf, value.ptr[k]);
+                GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ']');
+                break;
               }
-              GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ']');
-              break;
-            }
-            case GRN_EGN_TIME_VECTOR: {
-              GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, '[');
-              grn_egn_time_vector value =
-                ((grn_egn_time_vector *)&bufs[j][0])[i];
-              for (size_t k = 0; k < value.size; ++k) {
-                if (k != 0) {
-                  GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ',');
+              case GRN_EGN_FLOAT: {
+                const grn_egn_float *ptr =
+                  static_cast<const grn_egn_float *>(vector.ptr);
+                GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, '[');
+                for (size_t k = 0; k < vector.size; ++k) {
+                  if (k != 0) {
+                    GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ',');
+                  }
+                  grn_text_ftoa(ctx, ctx->impl->outbuf, ptr[k]);
                 }
-                grn_text_ftoa(ctx, ctx->impl->outbuf, value.ptr[k] * 0.000001);
+                GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ']');
+                break;
               }
-              GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ']');
-              break;
-            }
-            case GRN_EGN_TEXT_VECTOR: {
-              GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, '[');
-              grn_egn_text_vector value =
-                ((grn_egn_text_vector *)&bufs[j][0])[i];
-              for (size_t k = 0; k < value.size; ++k) {
-                if (k != 0) {
-                  GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ',');
+              case GRN_EGN_TIME: {
+                const grn_egn_time *ptr =
+                  static_cast<const grn_egn_time *>(vector.ptr);
+                GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, '[');
+                for (size_t k = 0; k < vector.size; ++k) {
+                  if (k != 0) {
+                    GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ',');
+                  }
+                  grn_text_ftoa(ctx, ctx->impl->outbuf, ptr[k] * 0.000001);
                 }
-                grn_text_esc(ctx, ctx->impl->outbuf, value.ptr[k].ptr,
-                             value.ptr[k].size);
+                GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ']');
+                break;
               }
-              GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ']');
-              break;
-            }
-            case GRN_EGN_GEO_POINT_VECTOR: {
-              GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, '[');
-              grn_egn_geo_point_vector value =
-                ((grn_egn_geo_point_vector *)&bufs[j][0])[i];
-              for (size_t k = 0; k < value.size; ++k) {
-                if (k != 0) {
-                  GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ',');
+              case GRN_EGN_TEXT: {
+                const grn_egn_text *ptr =
+                  static_cast<const grn_egn_text *>(vector.ptr);
+                GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, '[');
+                for (size_t k = 0; k < vector.size; ++k) {
+                  if (k != 0) {
+                    GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ',');
+                  }
+                  grn_text_esc(ctx, ctx->impl->outbuf, ptr[k].ptr, ptr[k].size);
                 }
-                GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, '"');
-                grn_text_itoa(ctx, ctx->impl->outbuf, value.ptr[k].latitude);
-                GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, 'x');
-                grn_text_itoa(ctx, ctx->impl->outbuf, value.ptr[k].longitude);
-                GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, '"');
+                GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ']');
+                break;
+              }
+              case GRN_EGN_GEO_POINT: {
+                const grn_egn_geo_point *ptr =
+                  static_cast<const grn_egn_geo_point *>(vector.ptr);
+                GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, '[');
+                for (size_t k = 0; k < vector.size; ++k) {
+                  if (k != 0) {
+                    GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ',');
+                  }
+                  GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, '"');
+                  grn_text_itoa(ctx, ctx->impl->outbuf, ptr[k].latitude);
+                  GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, 'x');
+                  grn_text_itoa(ctx, ctx->impl->outbuf, ptr[k].longitude);
+                  GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, '"');
+                }
+                GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ']');
+                break;
+              }
+              default: {
+                break;
               }
-              GRN_TEXT_PUTC(ctx, ctx->impl->outbuf, ']');
-              break;
-            }
-            default: {
-              break;
             }
           }
         }

  Modified: lib/grn_egn.h (+26 -36)
===================================================================
--- lib/grn_egn.h    2015-07-15 11:53:32 +0900 (b41205c)
+++ lib/grn_egn.h    2015-07-15 12:12:30 +0900 (68d571e)
@@ -28,22 +28,32 @@ extern "C" {
 // Constant values.
 
 typedef enum {
-  GRN_EGN_VOID,
-  GRN_EGN_BOOL,
-  GRN_EGN_INT,
-  GRN_EGN_FLOAT,
-  GRN_EGN_TIME,
-  GRN_EGN_TEXT,
-  GRN_EGN_GEO_POINT,
-  GRN_EGN_BOOL_VECTOR,
-  GRN_EGN_INT_VECTOR,
-  GRN_EGN_FLOAT_VECTOR,
-  GRN_EGN_TIME_VECTOR,
-  GRN_EGN_TEXT_VECTOR,
-  GRN_EGN_GEO_POINT_VECTOR,
-  GRN_EGN_DEEP_VECTOR
+  GRN_EGN_VOID,     // GRN_DB_VOID.
+  GRN_EGN_BOOL,     // GRN_DB_BOOL.
+  GRN_EGN_INT,      // GRN_DB_(U)INT8/16/32/64.
+  GRN_EGN_FLOAT,    // GRN_DB_FLOAT.
+  GRN_EGN_TIME,     // GRN_DB_TIME.
+  GRN_EGN_TEXT,     // GRN_DB_(SHORT_/LONG_)TEST
+  GRN_EGN_GEO_POINT // GRN_DB_TOKYO/WGS84_GEO_POINT.
 } grn_egn_data_type;
 
+//typedef enum {
+//  GRN_EGN_VOID,
+//  GRN_EGN_BOOL,
+//  GRN_EGN_INT,
+//  GRN_EGN_FLOAT,
+//  GRN_EGN_TIME,
+//  GRN_EGN_TEXT,
+//  GRN_EGN_GEO_POINT,
+//  GRN_EGN_BOOL_VECTOR,
+//  GRN_EGN_INT_VECTOR,
+//  GRN_EGN_FLOAT_VECTOR,
+//  GRN_EGN_TIME_VECTOR,
+//  GRN_EGN_TEXT_VECTOR,
+//  GRN_EGN_GEO_POINT_VECTOR,
+//  GRN_EGN_DEEP_VECTOR
+//} grn_egn_data_type;
+
 typedef enum {
   GRN_EGN_NOP,
   GRN_EGN_LOGICAL_NOT,
@@ -92,29 +102,9 @@ typedef struct {
 } grn_egn_text;
 typedef grn_geo_point grn_egn_geo_point;
 typedef struct {
-  const grn_egn_bool *ptr;
-  size_t size;
-} grn_egn_bool_vector;
-typedef struct {
-  const grn_egn_int *ptr;
-  size_t size;
-} grn_egn_int_vector;
-typedef struct {
-  const grn_egn_float *ptr;
-  size_t size;
-} grn_egn_float_vector;
-typedef struct {
-  const grn_egn_time *ptr;
-  size_t size;
-} grn_egn_time_vector;
-typedef struct {
-  const grn_egn_text *ptr;
-  size_t size;
-} grn_egn_text_vector;
-typedef struct {
-  const grn_egn_geo_point *ptr;
+  const void *ptr;
   size_t size;
-} grn_egn_geo_point_vector;
+} grn_egn_vector;
 
 /*
  * grn_egn_select() finds records passing through a filter (specified by

  Modified: lib/grn_egn.hpp (+7 -122)
===================================================================
--- lib/grn_egn.hpp    2015-07-15 11:53:32 +0900 (f91c00a)
+++ lib/grn_egn.hpp    2015-07-15 12:12:30 +0900 (a3d6266)
@@ -212,115 +212,6 @@ inline bool operator!=(GeoPoint lhs, GeoPoint rhs) {
          (lhs.raw.longitude != rhs.raw.longitude);
 }
 
-struct BoolVector {
-  typedef grn_egn_bool_vector Raw;
-  Raw raw;
-
-  static DataType data_type() {
-    return GRN_EGN_BOOL_VECTOR;
-  }
-  static grn_builtin_type default_builtin_type() {
-    return GRN_DB_BOOL;
-  }
-
-  BoolVector() : raw() {}
-  BoolVector(const BoolVector &value) : raw(value.raw) {}
-  explicit BoolVector(const Raw &value) : raw(value) {}
-  BoolVector(const grn_egn_bool *ptr, size_t size) : raw((Raw){ptr, size}) {}
-  ~BoolVector() {}
-};
-
-struct IntVector {
-  typedef grn_egn_int_vector Raw;
-  Raw raw;
-
-  static DataType data_type() {
-    return GRN_EGN_INT_VECTOR;
-  }
-  static grn_builtin_type default_builtin_type() {
-    return GRN_DB_INT64;
-  }
-
-  IntVector() : raw() {}
-  IntVector(const IntVector &value) : raw(value.raw) {}
-  explicit IntVector(const Raw &value) : raw(value) {}
-  IntVector(const grn_egn_int *ptr, size_t size) : raw((Raw){ptr, size}) {}
-  ~IntVector() {}
-};
-
-struct FloatVector {
-  typedef grn_egn_float_vector Raw;
-  Raw raw;
-
-  static DataType data_type() {
-    return GRN_EGN_FLOAT_VECTOR;
-  }
-  static grn_builtin_type default_builtin_type() {
-    return GRN_DB_FLOAT;
-  }
-
-  FloatVector() : raw() {}
-  FloatVector(const FloatVector &value) : raw(value.raw) {}
-  explicit FloatVector(const Raw &value) : raw(value) {}
-  FloatVector(const grn_egn_float *ptr, size_t size) : raw((Raw){ptr, size}) {}
-  ~FloatVector() {}
-};
-
-struct TimeVector {
-  typedef grn_egn_time_vector Raw;
-  Raw raw;
-
-  static DataType data_type() {
-    return GRN_EGN_INT_VECTOR;
-  }
-  static grn_builtin_type default_builtin_type() {
-    return GRN_DB_INT64;
-  }
-
-  TimeVector() : raw() {}
-  TimeVector(const TimeVector &value) : raw(value.raw) {}
-  explicit TimeVector(const Raw &value) : raw(value) {}
-  TimeVector(const grn_egn_time *ptr, size_t size) : raw((Raw){ptr, size}) {}
-  ~TimeVector() {}
-};
-
-struct TextVector {
-  typedef grn_egn_text_vector Raw;
-  Raw raw;
-
-  static DataType data_type() {
-    return GRN_EGN_TEXT_VECTOR;
-  }
-  static grn_builtin_type default_builtin_type() {
-    return GRN_DB_TEXT;
-  }
-
-  TextVector() : raw() {}
-  TextVector(const TextVector &value) : raw(value.raw) {}
-  explicit TextVector(const Raw &value) : raw(value) {}
-  TextVector(const grn_egn_text *ptr, size_t size) : raw((Raw){ptr, size}) {}
-  ~TextVector() {}
-};
-
-struct GeoPointVector {
-  typedef grn_egn_geo_point_vector Raw;
-  Raw raw;
-
-  static DataType data_type() {
-    return GRN_EGN_GEO_POINT_VECTOR;
-  }
-  static grn_builtin_type default_builtin_type() {
-    return GRN_DB_VOID;
-  }
-
-  GeoPointVector() : raw() {}
-  GeoPointVector(const GeoPointVector &value) : raw(value.raw) {}
-  explicit GeoPointVector(const Raw &value) : raw(value) {}
-  GeoPointVector(const grn_egn_geo_point *ptr, size_t size)
-    : raw((Raw){ptr, size}) {}
-  ~GeoPointVector() {}
-};
-
 // Cursor is a base class which provides an interface for sequential access to
 // records.
 class Cursor {
@@ -352,12 +243,10 @@ class Expression {
   ExpressionType type() const {
     return type_;
   }
-  DataType data_type() const {
-    return data_type_;
-  }
-  grn_builtin_type builtin_type() const {
-    return builtin_type_;
-  }
+  DataType data_type() const;
+  grn_builtin_type builtin_type() const;
+  grn_obj *ref_table() const;
+  int dimension() const;
 
   grn_rc push_object(grn_obj *obj);
   grn_rc push_operator(OperatorType operator_type);
@@ -366,15 +255,12 @@ class Expression {
                 Record *output, size_t *output_size);
   grn_rc adjust(Record *records, size_t num_records);
 
-  template <typename T>
-  grn_rc evaluate(const Record *records, size_t num_records, T *results);
+  grn_rc evaluate(const Record *records, size_t num_records, void *results);
 
  private:
   grn_ctx *ctx_;
   grn_obj *table_;
   ExpressionType type_;
-  DataType data_type_;
-  grn_builtin_type builtin_type_;
   std::vector<ExpressionNode *> stack_;
 
   // Disable copy and assignment.
@@ -383,10 +269,9 @@ class Expression {
 
   ExpressionNode *root() const;
 
-  void update_types();
+  void update_type();
 
-  grn_rc push_bulk_object(grn_obj *obj);
-  grn_rc push_vector_object(grn_obj *obj);
+  grn_rc push_constant_object(grn_obj *obj);
   grn_rc push_column_object(grn_obj *obj);
 
   grn_rc create_unary_node(OperatorType operator_type,




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