[Groonga-commit] groonga/grnxx at 86e5523 [master] Update the implementation of Expression.

Back to archive index

susumu.yata null+****@clear*****
Tue Aug 12 19:05:59 JST 2014


susumu.yata	2014-08-12 19:05:59 +0900 (Tue, 12 Aug 2014)

  New Revision: 86e55238771033fd7764372a6acbf7699afd6ce3
  https://github.com/groonga/grnxx/commit/86e55238771033fd7764372a6acbf7699afd6ce3

  Message:
    Update the implementation of Expression.

  Removed files:
    lib/grnxx/expression2.cpp
  Modified files:
    include/grnxx/expression.hpp
    include/grnxx/types.hpp
    lib/grnxx/Makefile.am
    lib/grnxx/expression.cpp
    lib/grnxx/types.cpp

  Modified: include/grnxx/expression.hpp (+118 -60)
===================================================================
--- include/grnxx/expression.hpp    2014-08-12 16:14:13 +0900 (9e6f17d)
+++ include/grnxx/expression.hpp    2014-08-12 19:05:59 +0900 (fa7bac3)
@@ -5,13 +5,20 @@
 #include "grnxx/types.hpp"
 
 namespace grnxx {
+namespace expression {
+
+class Node;
+
+}  // namespace expression
+
+using ExpressionNode = expression::Node;
 
 enum OperatorType {
   // -- Unary operators --
 
-//  LOGICAL_NOT_OPERATOR,  // For Bool.
+  LOGICAL_NOT_OPERATOR,  // For Bool.
 
-//  BITWISE_NOT_OPERATOR,  // For Int.
+  BITWISE_NOT_OPERATOR,  // For Int.
 
   POSITIVE_OPERATOR,  // For Int, Float.
   NEGATIVE_OPERATOR,  // For Int, Float.
@@ -35,10 +42,10 @@ enum OperatorType {
   NOT_EQUAL_OPERATOR,  // For any types.
 
   // Comparison operators.
-  LESS_OPERATOR,           // Int, Float, Time.
-  LESS_EQUAL_OPERATOR,     // Int, Float, Time.
-  GREATER_OPERATOR,        // Int, Float, Time.
-  GREATER_EQUAL_OPERATOR,  // Int, Float, Time.
+  LESS_OPERATOR,           // Int, Float, Time, Text.
+  LESS_EQUAL_OPERATOR,     // Int, Float, Time, Text.
+  GREATER_OPERATOR,        // Int, Float, Time, Text.
+  GREATER_EQUAL_OPERATOR,  // Int, Float, Time, Text.
 
   // Bitwise operators.
   BITWISE_AND_OPERATOR,  // For Bool, Int.
@@ -49,11 +56,13 @@ enum OperatorType {
   PLUS_OPERATOR,            // For Int, Float.
   MINUS_OPERATOR,           // For Int, Float.
   MULTIPLICATION_OPERATOR,  // For Int, Float.
-//  DIVISION_OPERATOR,        // For Int, Float.
-//  MODULUS_OPERATOR,         // For Int.
+  DIVISION_OPERATOR,        // For Int, Float.
+  MODULUS_OPERATOR,         // For Int.
 
   // Array operators.
 //  SUBSCRIPT_OPERATOR,
+
+  // -- Ternary operators --
 };
 
 class Expression {
@@ -68,34 +77,60 @@ class Expression {
   DataType data_type() const;
   // Return the evaluation block size.
   Int block_size() const {
-    // TODO: This value should be optimized.
-    return 1024;
+    return block_size_;
   }
 
   // Filter out false records.
   //
-  // Evaluates the expression for the given record set and removes records
-  // whose evaluation results are false.
+  // Evaluates the expression for "*records" and removes records whose
+  // evaluation results are false.
+  // Note that the first "offset" records are left without evaluation.
   //
-  // Returns true on success.
+  // On success, returns true.
   // On failure, returns false and stores error information into "*error" if
   // "error" != nullptr.
   bool filter(Error *error, Array<Record> *records, Int offset = 0);
 
+  // Extract true records.
+  //
+  // Evaluates the expression for "input_records" and copies records whose
+  // evaluation results are true into "*output_records".
+  // "*output_records" is truncated to fit the number of extracted records.
+  //
+  // Fails if "output_records->size()" is less than "input_records.size()".
+  //
+  // On success, returns true.
+  // On failure, returns false and stores error information into "*error" if
+  // "error" != nullptr.
+  bool filter(Error *error,
+              ArrayCRef<Record> input_records,
+              ArrayRef<Record> *output_records);
+
   // Adjust scores of records.
   //
-  // Evaluates the expression for the given record set and replaces their
-  // scores with the evaluation results.
-  // The first "offset" records are not modified.
+  // Evaluates the expression for "*records" and replaces the scores with
+  // the evaluation results.
+  // Note that the first "offset" records are not modified.
   //
-  // Returns true on success.
+  // On success, returns true.
   // On failure, returns false and stores error information into "*error" if
   // "error" != nullptr.
   bool adjust(Error *error, Array<Record> *records, Int offset = 0);
 
+  // Adjust scores of records.
+  //
+  // Evaluates the expression for "records" and replaces the scores with
+  // the evaluation results.
+  //
+  // On success, returns true.
+  // On failure, returns false and stores error information into "*error" if
+  // "error" != nullptr.
+  bool adjust(Error *error, ArrayRef<Record> records);
+
   // Evaluate the expression.
   //
-  // The result is stored into "*results".
+  // Evaluates the expression for "records" and stores the results into
+  // "*results".
   //
   // Fails if "T" is different from the result data type.
   //
@@ -104,27 +139,29 @@ class Expression {
   // "error" != nullptr.
   template <typename T>
   bool evaluate(Error *error,
-                const ArrayRef<Record> &records,
+                ArrayCRef<Record> records,
                 Array<T> *results);
 
   // Evaluate the expression.
   //
-  // The result is stored into "*results".
+  // Evaluates the expression for "records" and stores the results into
+  // "*results".
   //
-  // Fails if the number of records is different from the size of "*results".
   // Fails if "T" is different from the result data type.
+  // Fails if "results.size()" != "records.size()".
   //
   // On success, returns true.
   // On failure, returns false and stores error information into "*error" if
   // "error" != nullptr.
   template <typename T>
   bool evaluate(Error *error,
-                const ArrayRef<Record> &records,
-                ArrayRef<T> *results);
+                ArrayCRef<Record> records,
+                ArrayRef<T> results);
 
  private:
   const Table *table_;
   unique_ptr<ExpressionNode> root_;
+  Int block_size_;
 
   // Create an expression.
   //
@@ -133,14 +170,12 @@ class Expression {
   // "error" != nullptr.
   static unique_ptr<Expression> create(Error *error,
                                        const Table *table,
-                                       unique_ptr<ExpressionNode> &&root);
-
-  Expression(const Table *table, unique_ptr<ExpressionNode> &&root);
+                                       unique_ptr<ExpressionNode> &&root,
+                                       const ExpressionOptions &options);
 
-  template <typename T>
-  bool evaluate_block(Error *error,
-                      const ArrayRef<Record> &records,
-                      ArrayRef<T> *results);
+  Expression(const Table *table,
+             unique_ptr<ExpressionNode> &&root,
+             Int block_size);
 
   friend ExpressionBuilder;
 };
@@ -149,7 +184,7 @@ class ExpressionBuilder {
  public:
   // Create an object for building expressons.
   //
-  // Returns a poitner to the builder on success.
+  // On success, returns a poitner to the builder.
   // On failure, returns nullptr and stores error information into "*error" if
   // "error" != nullptr.
   static unique_ptr<ExpressionBuilder> create(Error *error,
@@ -157,13 +192,14 @@ class ExpressionBuilder {
 
   ~ExpressionBuilder();
 
+  // Return the target table.
   const Table *table() const {
     return table_;
   }
 
   // Push a datum.
   //
-  // Returns true on success.
+  // On success, returns true.
   // On failure, returns false and stores error information into "*error" if
   // "error" != nullptr.
   bool push_datum(Error *error, const Datum &datum);
@@ -173,7 +209,7 @@ class ExpressionBuilder {
   // If "name" == "_id", pushes a pseudo column associated with row IDs.
   // If "name" == "_score", pushes a pseudo column associated with scores.
   //
-  // Returns true on success.
+  // On success, returns true.
   // On failure, returns false and stores error information into "*error" if
   // "error" != nullptr.
   bool push_column(Error *error, String name);
@@ -182,24 +218,26 @@ class ExpressionBuilder {
   //
   // Pops operands and pushes an operator.
   // Fails if there are not enough operands.
-  // Fails if the combination of operands are invalid.
+  // Fails if the combination of operands is invalid.
   //
-  // Returns true on success.
+  // On success, returns true.
   // On failure, returns false and stores error information into "*error" if
   // "error" != nullptr.
   bool push_operator(Error *error, OperatorType operator_type);
 
-  // Clear the stack.
+  // Clear the internal stack.
   void clear();
 
-  // Complete building an expression and clear the builder.
+  // Complete building an expression and clear the internal stack.
   //
   // Fails if the stack is empty or contains more than one nodes.
   //
-  // Returns a poitner to the expression on success.
+  // On success, returns a pointer to the expression.
   // On failure, returns nullptr and stores error information into "*error" if
   // "error" != nullptr.
-  unique_ptr<Expression> release(Error *error);
+  unique_ptr<Expression> release(
+      Error *error,
+      const ExpressionOptions &options = ExpressionOptions());
 
  private:
   const Table *table_;
@@ -207,35 +245,55 @@ class ExpressionBuilder {
 
   explicit ExpressionBuilder(const Table *table);
 
+  // Create a node associated with a constant.
+  unique_ptr<ExpressionNode> create_datum_node(Error *error,
+                                               const Datum &datum);
+  // Create a node associated with a column.
+  unique_ptr<ExpressionNode> create_column_node(Error *error, String name);
+
   // Push a unary operator.
   bool push_unary_operator(Error *error, OperatorType operator_type);
-  // Push a positive operator.
-  bool push_positive_operator(Error *error);
-  // Push a negative operator.
-  bool push_negative_operator(Error *error);
-  // Push a typecast operator to Int.
-  bool push_to_int_operator(Error *error);
-  // Push a typecast operator to Float.
-  bool push_to_float_operator(Error *error);
-
   // Push a binary operator.
   bool push_binary_operator(Error *error, OperatorType operator_type);
-  // Push an operator &&.
-  bool push_logical_and_operator(Error *error);
-  // Push an operator ||.
-  bool push_logical_or_operator(Error *error);
-  // Push an operator == or !=.
+
+  // Create a node associated with a unary operator.
+  unique_ptr<ExpressionNode> create_unary_node(
+      Error *error,
+      OperatorType operator_type,
+      unique_ptr<ExpressionNode> &&arg);
+  // Create a node associated with a binary operator.
+  unique_ptr<ExpressionNode> create_binary_node(
+      Error *error,
+      OperatorType operator_type,
+      unique_ptr<ExpressionNode> &&arg1,
+      unique_ptr<ExpressionNode> &&arg2);
+
+  // Create a equality test node.
   template <typename T>
-  bool push_equality_operator(Error *error);
-  // Push an operator <, <=, >, or >=.
+  unique_ptr<ExpressionNode> create_equality_test_node(
+      Error *error,
+      unique_ptr<ExpressionNode> &&arg1,
+      unique_ptr<ExpressionNode> &&arg2);
+  // Create a comparison node.
   template <typename T>
-  bool push_comparison_operator(Error *error);
-  // Push an operator &, |, or ^.
+  unique_ptr<ExpressionNode> create_comparison_node(
+      Error *error,
+      unique_ptr<ExpressionNode> &&arg1,
+      unique_ptr<ExpressionNode> &&arg2);
+  // Create a bitwise node.
   template <typename T>
-  bool push_bitwise_operator(Error *error);
-  // Push an operator +, -, or *.
+  unique_ptr<ExpressionNode> create_bitwise_node(
+      Error *error,
+      OperatorType operator_type,
+      unique_ptr<ExpressionNode> &&arg1,
+      unique_ptr<ExpressionNode> &&arg2);
+  // Create an arithmetic node.
   template <typename T>
-  bool push_arithmetic_operator(Error *error);
+  unique_ptr<ExpressionNode> create_arithmetic_node(
+      Error *error,
+      OperatorType operator_type,
+      unique_ptr<ExpressionNode> &&arg1,
+      unique_ptr<ExpressionNode> &&arg2);
 };
 
 }  // namespace grnxx

  Modified: include/grnxx/types.hpp (+7 -1)
===================================================================
--- include/grnxx/types.hpp    2014-08-12 16:14:13 +0900 (adff2b1)
+++ include/grnxx/types.hpp    2014-08-12 19:05:59 +0900 (80fe110)
@@ -397,6 +397,13 @@ struct CursorOptions {
   CursorOptions();
 };
 
+struct ExpressionOptions {
+  // Records are evaluated per block.
+  Int block_size;
+
+  ExpressionOptions();
+};
+
 struct SorterOptions {
   // The first "offset" records are skipped (default: 0).
   Int offset;
@@ -411,7 +418,6 @@ struct SorterOptions {
 class Datum;
 class Cursor;
 class Expression;
-class ExpressionNode;
 class ExpressionBuilder;
 class OrderSet;
 class OrderSetBuilder;

  Modified: lib/grnxx/Makefile.am (+0 -1)
===================================================================
--- lib/grnxx/Makefile.am    2014-08-12 16:14:13 +0900 (285c21d)
+++ lib/grnxx/Makefile.am    2014-08-12 19:05:59 +0900 (a9e9b12)
@@ -14,7 +14,6 @@ libgrnxx_la_SOURCES =			\
 	db.cpp				\
 	error.cpp			\
 	expression.cpp			\
-	expression2.cpp			\
 	index.cpp			\
 	library.cpp			\
 	name.cpp			\

  Modified: lib/grnxx/expression.cpp (+2333 -927)
===================================================================
--- lib/grnxx/expression.cpp    2014-08-12 16:14:13 +0900 (281e606)
+++ lib/grnxx/expression.cpp    2014-08-12 19:05:59 +0900 (81f8fba)
@@ -8,8 +8,9 @@
 #include <iostream>  // For debugging.
 
 namespace grnxx {
-namespace {
+namespace expression {
 
+// TODO: Only CONSTANT_NODE and VARIABLE_NODE are required?
 enum NodeType {
   DATUM_NODE,
   ROW_ID_NODE,
@@ -18,12 +19,12 @@ enum NodeType {
   OPERATOR_NODE
 };
 
-}  // namespace
+// -- Node --
 
-class ExpressionNode {
+class Node {
  public:
-  ExpressionNode() {}
-  virtual ~ExpressionNode() {}
+  Node() {}
+  virtual ~Node() {}
 
   // Return the node type.
   virtual NodeType node_type() const = 0;
@@ -36,11 +37,11 @@ class ExpressionNode {
   // whose evaluation results are true into "*output_records".
   // "*output_records" is truncated to the number of true records.
   //
-  // Returns true on success.
+  // On success, returns true.
   // On failure, returns false and stores error information into "*error" if
   // "error" != nullptr.
   virtual bool filter(Error *error,
-                      const ArrayRef<Record> &input_records,
+                      ArrayCRef<Record> input_records,
                       ArrayRef<Record> *output_records) = 0;
 
   // Adjust scores of records.
@@ -51,161 +52,336 @@ class ExpressionNode {
   // Returns true on success.
   // On failure, returns false and stores error information into "*error" if
   // "error" != nullptr.
-  virtual bool adjust(Error *error, ArrayRef<Record> *records) = 0;
+  virtual bool adjust(Error *error, ArrayRef<Record> records) = 0;
+};
+
+// -- TypedNode --
+
+template <typename T>
+class TypedNode : public Node {
+ public:
+  using Value = T;
+
+  TypedNode() : Node() {}
+  virtual ~TypedNode() {}
+
+  DataType data_type() const {
+    return TypeTraits<Value>::data_type();
+  }
+
+  bool filter(Error *error,
+              ArrayCRef<Record> input_records,
+              ArrayRef<Record> *output_records) {
+    // Other than TypedNode<Bool> don't support filter().
+    GRNXX_ERROR_SET(error, INVALID_OPERATION, "Invalid operation");
+    return false;
+  }
+
+  bool adjust(Error *error, ArrayRef<Record> records) {
+    // Other than TypedNode<Float> don't support adjust().
+    GRNXX_ERROR_SET(error, INVALID_OPERATION, "Invalid operation");
+    return false;
+  }
 
   // Evaluate the expression subtree.
   //
-  // The evaluation results are stored into each expression node.
+  // The evaluation results are stored into "*results".
   //
-  // Returns true on success.
+  // On success, returns true.
   // On failure, returns false and stores error information into "*error" if
   // "error" != nullptr.
-  virtual bool evaluate(Error *error, const ArrayRef<Record> &records) = 0;
+  virtual bool evaluate(Error *error,
+                        ArrayCRef<Record> records,
+                        ArrayRef<Value> results) = 0;
 };
 
-namespace {
-
-template <typename T>
-class Node : public ExpressionNode {
+template <>
+class TypedNode<Bool> : public Node {
  public:
-  Node() : ExpressionNode(), values_() {}
-  virtual ~Node() {}
+  using Value = Bool;
+
+  TypedNode() : Node() {}
+  virtual ~TypedNode() {}
 
   DataType data_type() const {
-    return TypeTraits<T>::data_type();
+    return TypeTraits<Value>::data_type();
   }
 
+  // Derived classes must override this member function.
   virtual bool filter(Error *error,
-                      const ArrayRef<Record> &input_records,
-                      ArrayRef<Record> *output_records);
-  virtual bool adjust(Error *error, ArrayRef<Record> *records);
-
-  virtual bool evaluate(Error *error, const ArrayRef<Record> &records) = 0;
+                      ArrayCRef<Record> input_records,
+                      ArrayRef<Record> *output_records) = 0;
 
-  T get(Int i) const {
-    return values_[i];
+  bool adjust(Error *error, ArrayRef<Record> records) {
+    // Other than TypedNode<Float> don't support adjust().
+    GRNXX_ERROR_SET(error, INVALID_OPERATION, "Invalid operation");
+    return false;
   }
 
- protected:
-  Array<T> values_;
+  virtual bool evaluate(Error *error,
+                        ArrayCRef<Record> records,
+                        ArrayRef<Value> results) = 0;
 };
 
-template <typename T>
-bool Node<T>::filter(Error *error,
-                     const ArrayRef<Record> &input_records,
-                     ArrayRef<Record> *output_records) {
-  // Only Node<Bool> supports filter().
-  GRNXX_ERROR_SET(error, INVALID_OPERATION, "Invalid operation");
-  return false;
-}
+//template <>
+//bool TypedNode<Bool>::filter(Error *error,
+//                             ArrayCRef<Record> input_records,
+//                             ArrayRef<Record> *output_records) {
+//  // TODO: This implementation should be overridden by derived classes.
+//  Array<Bool> results;
+//  if (!results.resize(error, input_records.size())) {
+//    return false;
+//  }
+//  if (!evaluate(error, input_records, results)) {
+//    return false;
+//  }
+//  Int count = 0;
+//  for (Int i = 0; i < input_records.size(); ++i) {
+//    if (results[i]) {
+//      output_records->set(count, input_records.get(i));
+//      ++count;
+//    }
+//  }
+//  *output_records = output_records->ref(0, count);
+//  return true;
+//}
 
 template <>
-bool Node<Bool>::filter(Error *error,
-                        const ArrayRef<Record> &input_records,
-                        ArrayRef<Record> *output_records) {
-  if (!evaluate(error, input_records)) {
+class TypedNode<Float> : public Node {
+ public:
+  using Value = Float;
+
+  TypedNode() : Node() {}
+  virtual ~TypedNode() {}
+
+  DataType data_type() const {
+    return TypeTraits<Value>::data_type();
+  }
+
+  bool filter(Error *error,
+              ArrayCRef<Record> input_records,
+              ArrayRef<Record> *output_records) {
+    // Other than TypedNode<Bool> don't support filter().
+    GRNXX_ERROR_SET(error, INVALID_OPERATION, "Invalid operation");
     return false;
   }
-  Int dest = 0;
-  for (Int i = 0; i < input_records.size(); ++i) {
-    if (values_[i]) {
-      output_records->set(dest, input_records.get(i));
-      ++dest;
+
+  // Derived classes must override this member function.
+  virtual bool adjust(Error *error, ArrayRef<Record> records) = 0;
+
+  virtual bool evaluate(Error *error,
+                        ArrayCRef<Record> records,
+                        ArrayRef<Value> results) = 0;
+};
+
+//template <>
+//bool TypedNode<Float>::adjust(Error *error, ArrayRef<Record> records) {
+//  // TODO: This implementation should be overridden by derived classes.
+//  Array<Float> scores;
+//  if (!scores.resize(error, records.size())) {
+//    return false;
+//  }
+//  if (!evaluate(error, records, scores)) {
+//    return false;
+//  }
+//  for (Int i = 0; i < records.size(); ++i) {
+//    records.set_score(i, scores[i]);
+//  }
+//  return true;
+//}
+
+// -- DatumNode --
+
+template <typename T>
+class DatumNode : public TypedNode<T> {
+ public:
+  using Value = T;
+
+  static unique_ptr<Node> create(Error *error, Value datum) {
+    unique_ptr<Node> node(new (nothrow) DatumNode(datum));
+    if (!node) {
+      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
     }
+    return node;
   }
-  *output_records = output_records->ref(0, dest);
-  return true;
-}
 
-template <typename T>
-bool Node<T>::adjust(Error *error, ArrayRef<Record> *records) {
-  // Only Node<Float> supports adjust().
-  GRNXX_ERROR_SET(error, INVALID_OPERATION, "Invalid operation");
-  return false;
-}
+  explicit DatumNode(Value datum)
+      : TypedNode<Value>(),
+        datum_(datum) {}
 
-template <>
-bool Node<Float>::adjust(Error *error, ArrayRef<Record> *records) {
-  if (!evaluate(error, *records)) {
-    return false;
+  NodeType node_type() const {
+    return DATUM_NODE;
   }
-  for (Int i = 0; i < records->size(); ++i) {
-    records->set_score(i, values_[i]);
+
+  bool evaluate(Error *error,
+                ArrayCRef<Record> records,
+                ArrayRef<Value> results) {
+    for (Int i = 0; i < records.size(); ++i) {
+      results[i] = datum_;
+    }
+    return true;
   }
-  return true;
-}
 
-// -- DatumNode --
+ private:
+  T datum_;
+};
 
-template <typename T>
-class DatumNode : public Node<T> {
+template <>
+class DatumNode<Bool> : public TypedNode<Bool> {
  public:
-  explicit DatumNode(T datum) : Node<T>(), datum_(datum) {}
-  virtual ~DatumNode() {}
+  using Value = Bool;
+
+  static unique_ptr<Node> create(Error *error, Value datum) {
+    unique_ptr<Node> node(new (nothrow) DatumNode(datum));
+    if (!node) {
+      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
+    }
+    return node;
+  }
+
+  explicit DatumNode(Value datum)
+      : TypedNode<Value>(),
+        datum_(datum) {}
 
   NodeType node_type() const {
     return DATUM_NODE;
   }
 
-  bool evaluate(Error *error, const ArrayRef<Record> &records);
+  bool filter(Error *error,
+              ArrayCRef<Record> input_records,
+              ArrayRef<Record> *output_records);
+  bool evaluate(Error *error,
+                ArrayCRef<Record> records,
+                ArrayRef<Value> results);
 
  private:
-  T datum_;
+  Value datum_;
 };
 
-template <typename T>
-bool DatumNode<T>::evaluate(Error *error, const ArrayRef<Record> &records) {
-  if (static_cast<size_t>(records.size()) <= this->values_.size()) {
-    // The buffer is already filled and there is nothing to do.
-    return true;
+bool DatumNode<Bool>::filter(Error *error,
+                             ArrayCRef<Record> input_records,
+                             ArrayRef<Record> *output_records) {
+  if (datum_) {
+    if (input_records != *output_records) {
+      for (Int i = 0; i < input_records.size(); ++i) {
+        output_records->set(i, input_records.get(i));
+      }
+    }
+  } else {
+    *output_records = output_records->ref(0, 0);
+  }
+  return true;
+}
+
+bool DatumNode<Bool>::evaluate(Error *error,
+                               ArrayCRef<Record> records,
+                               ArrayRef<Value> results) {
+  // TODO: Fill results per 64 bits.
+  for (Int i = 0; i < records.size(); ++i) {
+    results.set(i, datum_);
   }
-  return this->values_.resize(error, records.size(), datum_);
+  return true;
 }
 
 template <>
-class DatumNode<Text> : public Node<Text> {
+class DatumNode<Float> : public TypedNode<Float> {
  public:
-  explicit DatumNode(Text datum)
-      : Node<Text>(),
-        datum_(datum.data(), datum.size()) {}
-  virtual ~DatumNode() {}
+  using Value = Float;
+
+  static unique_ptr<Node> create(Error *error, Value datum) {
+    unique_ptr<Node> node(new (nothrow) DatumNode(datum));
+    if (!node) {
+      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
+    }
+    return node;
+  }
+
+  explicit DatumNode(Value datum)
+      : TypedNode<Float>(),
+        datum_(datum) {}
 
   NodeType node_type() const {
     return DATUM_NODE;
   }
 
-  bool evaluate(Error *error, const ArrayRef<Record> &records);
+  bool adjust(Error *error, ArrayRef<Record> records) {
+    for (Int i = 0; i < records.size(); ++i) {
+      records.set_score(i, datum_);
+    }
+    return true;
+  }
+  bool evaluate(Error *error,
+                ArrayCRef<Record> records,
+                ArrayRef<Value> results) {
+    for (Int i = 0; i < records.size(); ++i) {
+      results[i] = datum_;
+    }
+    return true;
+  }
 
  private:
-  std::string datum_;
+  Float datum_;
 };
 
-bool DatumNode<Text>::evaluate(Error *error, const ArrayRef<Record> &records) {
-  if (static_cast<size_t>(records.size()) <= this->values_.size()) {
-    // The buffer is already filled and there is nothing to do.
+template <>
+class DatumNode<Text> : public TypedNode<Text> {
+ public:
+  using Value = Text;
+
+  static unique_ptr<Node> create(Error *error, Value datum) try {
+    return unique_ptr<Node>(new DatumNode(datum));
+  } catch (...) {
+    GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
+    return nullptr;
+  }
+
+  explicit DatumNode(Value datum)
+      : TypedNode<Value>(),
+        datum_(datum.data(), datum.size()) {}
+
+  NodeType node_type() const {
+    return DATUM_NODE;
+  }
+
+  bool evaluate(Error *error,
+                ArrayCRef<Record> records,
+                ArrayRef<Value> results) {
+    Text datum(datum_.data(), datum_.size());
+    for (Int i = 0; i < records.size(); ++i) {
+      results[i] = datum;
+    }
     return true;
   }
-  return this->values_.resize(error, records.size(),
-                              Text(datum_.data(), datum_.size()));
-}
+
+ private:
+  std::string datum_;
+};
 
 // -- RowIDNode --
 
-class RowIDNode : public Node<Int> {
+class RowIDNode : public TypedNode<Int> {
  public:
-  RowIDNode() : Node<Int>() {}
-  ~RowIDNode() {}
+  using Value = Int;
+
+  static unique_ptr<Node> create(Error *error, Value datum) {
+    unique_ptr<Node> node(new (nothrow) RowIDNode);
+    if (!node) {
+      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
+    }
+    return node;
+  }
+
+  RowIDNode() : TypedNode<Value>() {}
 
   NodeType node_type() const {
     return ROW_ID_NODE;
   }
 
-  bool evaluate(Error *error, const ArrayRef<Record> &records) {
-    if (!this->values_.resize(error, records.size())) {
-      return false;
-    }
+  bool evaluate(Error *error,
+                ArrayCRef<Record> records,
+                ArrayRef<Value> results) {
     for (Int i = 0; i < records.size(); ++i) {
-      this->values_[i] = records.get_row_id(i);
+      results[i] = records.get_row_id(i);
     }
     return true;
   }
@@ -213,21 +389,33 @@ class RowIDNode : public Node<Int> {
 
 // -- ScoreNode --
 
-class ScoreNode : public Node<Float> {
+class ScoreNode : public TypedNode<Float> {
  public:
-  ScoreNode() : Node<Float>() {}
-  ~ScoreNode() {}
+  using Value = Float;
+
+  static unique_ptr<Node> create(Error *error, Value datum) {
+    unique_ptr<Node> node(new (nothrow) ScoreNode);
+    if (!node) {
+      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
+    }
+    return node;
+  }
+
+  ScoreNode() : TypedNode<Value>() {}
 
   NodeType node_type() const {
     return SCORE_NODE;
   }
 
-  bool evaluate(Error *error, const ArrayRef<Record> &records) {
-    if (!this->values_.resize(error, records.size())) {
-      return false;
-    }
+  bool adjust(Error *error, ArrayRef<Record> records) {
+    // Nothing to do.
+    return true;
+  }
+  bool evaluate(Error *error,
+                ArrayCRef<Record> records,
+                ArrayRef<Value> results) {
     for (Int i = 0; i < records.size(); ++i) {
-      this->values_[i] = records.get_score(i);
+      results[i] = records.get_score(i);
     }
     return true;
   }
@@ -236,23 +424,31 @@ class ScoreNode : public Node<Float> {
 // -- ColumnNode --
 
 template <typename T>
-class ColumnNode : public Node<T> {
+class ColumnNode : public TypedNode<T> {
  public:
+  using Value = T;
+
+  static unique_ptr<Node> create(Error *error, const Column *column) {
+    unique_ptr<Node> node(new (nothrow) ColumnNode(column));
+    if (!node) {
+      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
+    }
+    return node;
+  }
+
   explicit ColumnNode(const Column *column)
-      : Node<T>(),
-        column_(static_cast<const ColumnImpl<T> *>(column)) {}
-  virtual ~ColumnNode() {}
+      : TypedNode<Value>(),
+        column_(static_cast<const ColumnImpl<Value> *>(column)) {}
 
   NodeType node_type() const {
     return COLUMN_NODE;
   }
 
-  bool evaluate(Error *error, const ArrayRef<Record> &records) {
-    if (!this->values_.resize(error, records.size())) {
-      return false;
-    }
+  bool evaluate(Error *error,
+                ArrayCRef<Record> records,
+                ArrayRef<Value> results) {
     for (Int i = 0; i < records.size(); ++i) {
-      this->values_.set(i, column_->get(records.get_row_id(i)));
+      results[i] = column_->get(records.get_row_id(i));
     }
     return true;
   }
@@ -261,474 +457,1734 @@ class ColumnNode : public Node<T> {
   const ColumnImpl<T> *column_;
 };
 
-// -- OperatorNode --
+template <>
+class ColumnNode<Bool> : public TypedNode<Bool> {
+ public:
+  using Value = Bool;
 
-// ---- UnaryNode ----
+  static unique_ptr<Node> create(Error *error, const Column *column) {
+    unique_ptr<Node> node(new (nothrow) ColumnNode(column));
+    if (!node) {
+      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
+    }
+    return node;
+  }
 
-struct Negative {
-  template <typename T>
-  struct Functor {
-    using Arg = T;
-    using Result = T;
-    Result operator()(Arg arg) const {
-      return -arg;
-    };
-  };
-};
+  explicit ColumnNode(const Column *column)
+      : TypedNode<Value>(),
+        column_(static_cast<const ColumnImpl<Value> *>(column)) {}
 
-template <typename T>
-struct Typecast {
-  template <typename U>
-  struct Functor {
-    using Arg = U;
-    using Result = T;
-    Result operator()(Arg arg) const {
-      return static_cast<Result>(arg);
-    };
-  };
+  NodeType node_type() const {
+    return COLUMN_NODE;
+  }
+
+  bool filter(Error *error,
+              ArrayCRef<Record> input_records,
+              ArrayRef<Record> *output_records);
+  bool evaluate(Error *error,
+                ArrayCRef<Record> records,
+                ArrayRef<Value> results) {
+    for (Int i = 0; i < records.size(); ++i) {
+      results.set(i, column_->get(records.get_row_id(i)));
+    }
+    return true;
+  }
+
+ private:
+  const ColumnImpl<Value> *column_;
 };
 
-template <typename T>
-class UnaryNode : public Node<typename T::Result> {
+bool ColumnNode<Bool>::filter(Error *error,
+                              ArrayCRef<Record> input_records,
+                              ArrayRef<Record> *output_records) {
+  Int dest = 0;
+  for (Int i = 0; i < input_records.size(); ++i) {
+    if (column_->get(input_records.get_row_id(i))) {
+      output_records->set(dest, input_records.get(i));
+      ++dest;
+    }
+  }
+  *output_records = output_records->ref(0, dest);
+  return true;
+}
+
+template <>
+class ColumnNode<Float> : public TypedNode<Float> {
  public:
-  using Operator = T;
-  using Arg = typename Operator::Arg;
-
-  UnaryNode(Operator op,
-            unique_ptr<ExpressionNode> &&arg)
-      : Node<typename Operator::Result>(),
-        operator_(op),
-        arg_(static_cast<Node<Arg> *>(arg.release())) {}
-  virtual ~UnaryNode() {}
+  using Value = Float;
+
+  static unique_ptr<Node> create(Error *error, const Column *column) {
+    unique_ptr<Node> node(new (nothrow) ColumnNode(column));
+    if (!node) {
+      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
+    }
+    return node;
+  }
+
+  explicit ColumnNode(const Column *column)
+      : TypedNode<Value>(),
+        column_(static_cast<const ColumnImpl<Value> *>(column)) {}
 
   NodeType node_type() const {
-    return OPERATOR_NODE;
+    return COLUMN_NODE;
   }
 
-  bool evaluate(Error *error, const ArrayRef<Record> &records);
+  bool adjust(Error *error, ArrayRef<Record> records) {
+    for (Int i = 0; i < records.size(); ++i) {
+      records.set_score(i, column_->get(records.get_row_id(i)));
+    }
+    return true;
+  }
+  bool evaluate(Error *error,
+                ArrayCRef<Record> records,
+                ArrayRef<Value> results) {
+    for (Int i = 0; i < records.size(); ++i) {
+      results[i] = column_->get(records.get_row_id(i));
+    }
+    return true;
+  }
 
  private:
-  Operator operator_;
-  unique_ptr<Node<Arg>> arg_;
+  const ColumnImpl<Value> *column_;
 };
 
+// -- OperatorNode --
+
 template <typename T>
-bool UnaryNode<T>::evaluate(Error *error, const ArrayRef<Record> &records) {
-  if (!this->values_.resize(error, records.size())) {
-    GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    return false;
+class OperatorNode : public TypedNode<T> {
+ public:
+  using Value = T;
+
+  OperatorNode() : TypedNode<Value>() {}
+  virtual ~OperatorNode() {}
+
+  NodeType node_type() const {
+    return OPERATOR_NODE;
   }
-  if (!arg_->evaluate(error, records)) {
-    return false;
+};
+
+// Evaluate "*arg" for "records".
+//
+// The evaluation results are stored into "*arg_values".
+//
+// On success, returns true.
+// On failure, returns false and stores error information into "*error" if
+// "error" != nullptr.
+template <typename T>
+bool fill_node_arg_values(Error *error, ArrayCRef<Record> records,
+                          TypedNode<T> *arg, Array<T> *arg_values) {
+  Int old_size = arg_values->size();
+  if (old_size < records.size()) {
+    if (!arg_values->resize(error, records.size())) {
+      return false;
+    }
   }
-  for (Int i = 0; i < records.size(); ++i) {
-    this->values_[i] = operator_(arg_->get(i));
+  switch (arg->node_type()) {
+    case DATUM_NODE: {
+      if (old_size < records.size()) {
+        if (!arg->evaluate(error, records.ref(old_size),
+                           arg_values->ref(old_size))) {
+          return false;
+        }
+      }
+      break;
+    }
+    default: {
+      if (!arg->evaluate(error, records, arg_values->ref(0, records.size()))) {
+        return false;
+      }
+    }
   }
   return true;
 }
 
-// ---- BinaryNode ----
+// --- UnaryNode ---
 
-struct Equal {
-  template <typename T>
-  struct Functor {
-    using Arg1 = T;
-    using Arg2 = T;
-    using Result = Bool;
-    Bool operator()(Arg1 lhs, Arg2 rhs) const {
-      return lhs == rhs;
-    };
-  };
-};
+template <typename T, typename U>
+class UnaryNode : public OperatorNode<T> {
+ public:
+  using Value = T;
+  using Arg = U;
 
-struct NotEqual {
-  template <typename T>
-  struct Functor {
-    using Arg1 = T;
-    using Arg2 = T;
-    using Result = Bool;
-    Bool operator()(Arg1 lhs, Arg2 rhs) const {
-      return lhs != rhs;
-    };
-  };
-};
+  explicit UnaryNode(unique_ptr<Node> &&arg)
+      : OperatorNode<Value>(),
+        arg_(static_cast<TypedNode<Arg> *>(arg.release())),
+        arg_values_() {}
+  virtual ~UnaryNode() {}
 
-struct Less {
-  template <typename T>
-  struct Functor {
-    using Arg1 = T;
-    using Arg2 = T;
-    using Result = Bool;
-    Bool operator()(Arg1 lhs, Arg2 rhs) const {
-      return lhs < rhs;
-    };
-  };
-};
+ protected:
+  unique_ptr<TypedNode<Arg>> arg_;
+  Array<Arg> arg_values_;
 
-struct LessEqual {
-  template <typename T>
-  struct Functor {
-    using Arg1 = T;
-    using Arg2 = T;
-    using Result = Bool;
-    Bool operator()(Arg1 lhs, Arg2 rhs) const {
-      return lhs <= rhs;
-    };
-  };
+  bool fill_arg_values(Error *error, ArrayCRef<Record> records) {
+    return fill_node_arg_values(error, records, arg_.get(), &arg_values_);
+  }
 };
 
-struct Greater {
-  template <typename T>
-  struct Functor {
-    using Arg1 = T;
-    using Arg2 = T;
-    using Result = Bool;
-    Bool operator()(Arg1 lhs, Arg2 rhs) const {
-      return lhs > rhs;
-    };
-  };
-};
+// ---- LogicalNotNode ----
 
-struct GreaterEqual {
-  template <typename T>
-  struct Functor {
-    using Arg1 = T;
-    using Arg2 = T;
-    using Result = Bool;
-    Bool operator()(Arg1 lhs, Arg2 rhs) const {
-      return lhs >= rhs;
-    };
-  };
-};
+class LogicalNotNode : public UnaryNode<Bool, Bool> {
+ public:
+  using Value = Bool;
+  using Arg = Bool;
 
-struct BitwiseAnd {
-  template <typename T>
-  struct Functor {
-    using Arg1 = T;
-    using Arg2 = T;
-    using Result = T;
-    T operator()(Arg1 lhs, Arg2 rhs) const {
-      return lhs & rhs;
-    };
-  };
-};
+  static unique_ptr<Node> create(Error *error, unique_ptr<Node> &&arg) {
+    unique_ptr<Node> node(new (nothrow) LogicalNotNode(std::move(arg)));
+    if (!node) {
+      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
+    }
+    return node;
+  }
 
-struct BitwiseOr {
-  template <typename T>
-  struct Functor {
-    using Arg1 = T;
-    using Arg2 = T;
-    using Result = T;
-    T operator()(Arg1 lhs, Arg2 rhs) const {
-      return lhs | rhs;
-    };
+  explicit LogicalNotNode(unique_ptr<Node> &&arg)
+      : UnaryNode<Value, Arg>(std::move(arg)),
+        temp_records_() {}
+
+  bool filter(Error *error,
+              ArrayCRef<Record> input_records,
+              ArrayRef<Record> *output_records);
+  bool evaluate(Error *error,
+                ArrayCRef<Record> records,
+                ArrayRef<Value> results);
+
+ private:
+  Array<Record> temp_records_;
+};
+
+bool LogicalNotNode::filter(Error *error,
+                            ArrayCRef<Record> input_records,
+                            ArrayRef<Record> *output_records) {
+  // Apply an argument filter to "input_records" and store the result to
+  // "temp_records_". Then, appends a sentinel to the end.
+  if (!temp_records_.resize(error, input_records.size() + 1)) {
+    return false;
+  }
+  ArrayRef<Record> ref = temp_records_;
+  if (!arg_->filter(error, input_records, &ref)) {
+    return false;
+  }
+  temp_records_.set_row_id(ref.size(), NULL_ROW_ID);
+
+  // Extract records which appear in "input_records" and don't appear in "ref".
+  Int count = 0;
+  for (Int i = 0, j = 0; i < input_records.size(); ++i) {
+    if (input_records.get_row_id(i) == ref.get_row_id(j)) {
+      ++j;
+      continue;
+    }
+    output_records->set(count, input_records.get(i));
+    ++count;
+  }
+  *output_records = output_records->ref(0, count);
+  return true;
+}
+
+bool LogicalNotNode::evaluate(Error *error,
+                              ArrayCRef<Record> records,
+                              ArrayRef<Value> results) {
+  // Apply an argument filter to "records" and store the result to
+  // "temp_records_". Then, appends a sentinel to the end.
+  if (!temp_records_.resize(error, records.size() + 1)) {
+    return false;
+  }
+  ArrayRef<Record> ref = temp_records_;
+  if (!arg_->filter(error, records, &ref)) {
+    return false;
+  }
+  temp_records_.set_row_id(ref.size(), NULL_ROW_ID);
+
+  // Compare records in "records" and "ref".
+  Int count = 0;
+  for (Int i = 0; i < records.size(); ++i) {
+    if (records.get_row_id(i) == ref.get_row_id(count)) {
+      results.set(i, false);
+      ++count;
+    } else {
+      results.set(i, true);
+    }
+  }
+  return true;
+}
+
+// ---- BitwiseNotNode ----
+
+template <typename T> class BitwiseNotNode;
+
+template <>
+class BitwiseNotNode<Bool> : public UnaryNode<Bool, Bool> {
+ public:
+  using Value = Bool;
+  using Arg = Bool;
+
+  static unique_ptr<Node> create(Error *error, unique_ptr<Node> &&arg) {
+    unique_ptr<Node> node(new (nothrow) BitwiseNotNode(std::move(arg)));
+    if (!node) {
+      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
+    }
+    return node;
+  }
+
+  explicit BitwiseNotNode(unique_ptr<Node> &&arg)
+      : UnaryNode<Value, Arg>(std::move(arg)) {}
+
+  bool filter(Error *error,
+              ArrayCRef<Record> input_records,
+              ArrayRef<Record> *output_records);
+  bool evaluate(Error *error,
+                ArrayCRef<Record> records,
+                ArrayRef<Value> results);
+};
+
+bool BitwiseNotNode<Bool>::filter(Error *error,
+                                  ArrayCRef<Record> input_records,
+                                  ArrayRef<Record> *output_records) {
+  if (!fill_arg_values(error, input_records)) {
+    return false;
+  }
+  Int count = 0;
+  for (Int i = 0; i < input_records.size(); ++i) {
+    if (arg_values_[i]) {
+      output_records->set(count, input_records.get(i));
+      ++count;
+    }
+  }
+  *output_records = output_records->ref(0, count);
+  return true;
+}
+
+bool BitwiseNotNode<Bool>::evaluate(Error *error,
+                                    ArrayCRef<Record> records,
+                                    ArrayRef<Value> results) {
+  if (!arg_->evaluate(error, records, results)) {
+    return false;
+  }
+  // TODO: Should be processed per 64 bits.
+  //       Check the 64-bit boundary and do it!
+  for (Int i = 0; i < records.size(); ++i) {
+    results.set(i, !results.get(i));
+  }
+  return true;
+}
+
+template <>
+class BitwiseNotNode<Int> : public UnaryNode<Int, Int> {
+ public:
+  using Value = Int;
+  using Arg = Int;
+
+  static unique_ptr<Node> create(Error *error, unique_ptr<Node> &&arg) {
+    unique_ptr<Node> node(
+        new (nothrow) BitwiseNotNode(std::move(arg)));
+    if (!node) {
+      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
+    }
+    return node;
+  }
+
+  explicit BitwiseNotNode(unique_ptr<Node> &&arg)
+      : UnaryNode<Value, Arg>(std::move(arg)) {}
+
+  bool evaluate(Error *error,
+                ArrayCRef<Record> records,
+                ArrayRef<Value> results);
+};
+
+bool BitwiseNotNode<Int>::evaluate(Error *error,
+                                   ArrayCRef<Record> records,
+                                   ArrayRef<Value> results) {
+  if (!arg_->evaluate(error, records, results)) {
+    return false;
+  }
+  for (Int i = 0; i < records.size(); ++i) {
+    results.set(i, ~results.get(i));
+  }
+  return true;
+}
+
+// ---- PositiveNode ----
+
+// Nothing to do.
+
+// ---- NegativeNode ----
+
+template <typename T> class NegativeNode;
+
+template <>
+class NegativeNode<Int> : public UnaryNode<Int, Int> {
+ public:
+  using Value = Int;
+  using Arg = Int;
+
+  static unique_ptr<Node> create(Error *error, unique_ptr<Node> &&arg) {
+    unique_ptr<Node> node(new (nothrow) NegativeNode(std::move(arg)));
+    if (!node) {
+      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
+    }
+    return node;
+  }
+
+  explicit NegativeNode(unique_ptr<Node> &&arg)
+      : UnaryNode<Value, Arg>(std::move(arg)) {}
+
+  bool evaluate(Error *error,
+                ArrayCRef<Record> records,
+                ArrayRef<Value> results);
+};
+
+bool NegativeNode<Int>::evaluate(Error *error,
+                                 ArrayCRef<Record> records,
+                                 ArrayRef<Value> results) {
+  if (!arg_->evaluate(error, records, results)) {
+    return false;
+  }
+  for (Int i = 0; i < records.size(); ++i) {
+    results.set(i, -results.get(i));
+  }
+  return true;
+}
+
+template <>
+class NegativeNode<Float> : public UnaryNode<Float, Float> {
+ public:
+  using Value = Float;
+  using Arg = Float;
+
+  static unique_ptr<Node> create(Error *error, unique_ptr<Node> &&arg) {
+    unique_ptr<Node> node(new (nothrow) NegativeNode(std::move(arg)));
+    if (!node) {
+      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
+    }
+    return node;
+  }
+
+  explicit NegativeNode(unique_ptr<Node> &&arg)
+      : UnaryNode<Value, Arg>(std::move(arg)) {}
+
+  bool adjust(Error *error, ArrayRef<Record> records);
+  bool evaluate(Error *error,
+                ArrayCRef<Record> records,
+                ArrayRef<Value> results);
+};
+
+bool NegativeNode<Float>::adjust(Error *error, ArrayRef<Record> records) {
+  if (!fill_arg_values(error, records)) {
+    return false;
+  }
+  for (Int i = 0; i < records.size(); ++i) {
+    records.set_score(i, arg_values_[i]);
+  }
+  return true;
+}
+
+bool NegativeNode<Float>::evaluate(Error *error,
+                                   ArrayCRef<Record> records,
+                                   ArrayRef<Value> results) {
+  if (!arg_->evaluate(error, records, results)) {
+    return false;
+  }
+  for (Int i = 0; i < records.size(); ++i) {
+    results.set(i, -results.get(i));
+  }
+  return true;
+}
+
+// ---- ToIntNode ----
+
+class ToIntNode : public UnaryNode<Int, Float> {
+ public:
+  using Value = Int;
+  using Arg = Float;
+
+  static unique_ptr<Node> create(Error *error, unique_ptr<Node> &&arg) {
+    unique_ptr<Node> node(new (nothrow) ToIntNode(std::move(arg)));
+    if (!node) {
+      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
+    }
+    return node;
+  }
+
+  explicit ToIntNode(unique_ptr<Node> &&arg)
+      : UnaryNode<Value, Arg>(std::move(arg)) {}
+
+  bool evaluate(Error *error,
+                ArrayCRef<Record> records,
+                ArrayRef<Value> results);
+};
+
+bool ToIntNode::evaluate(Error *error,
+                         ArrayCRef<Record> records,
+                         ArrayRef<Value> results) {
+  if (!fill_arg_values(error, records)) {
+    return false;
+  }
+  for (Int i = 0; i < records.size(); ++i) {
+    results.set(i, static_cast<Value>(arg_values_[i]));
+  }
+  return true;
+}
+
+// ---- ToFloatNode ----
+
+class ToFloatNode : public UnaryNode<Float, Int> {
+ public:
+  using Value = Float;
+  using Arg = Int;
+
+  static unique_ptr<Node> create(Error *error, unique_ptr<Node> &&arg) {
+    unique_ptr<Node> node(new (nothrow) ToFloatNode(std::move(arg)));
+    if (!node) {
+      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
+    }
+    return node;
+  }
+
+  explicit ToFloatNode(unique_ptr<Node> &&arg)
+      : UnaryNode<Value, Arg>(std::move(arg)) {}
+
+  bool adjust(Error *error, ArrayRef<Record> records);
+  bool evaluate(Error *error,
+                ArrayCRef<Record> records,
+                ArrayRef<Value> results);
+};
+
+bool ToFloatNode::adjust(Error *error, ArrayRef<Record> records) {
+  if (!fill_arg_values(error, records)) {
+    return false;
+  }
+  for (Int i = 0; i < records.size(); ++i) {
+    records.set_score(i, static_cast<Value>(arg_values_[i]));
+  }
+  return true;
+}
+
+bool ToFloatNode::evaluate(Error *error,
+                           ArrayCRef<Record> records,
+                           ArrayRef<Value> results) {
+  if (!fill_arg_values(error, records)) {
+    return false;
+  }
+  for (Int i = 0; i < records.size(); ++i) {
+    results.set(i, static_cast<Value>(arg_values_[i]));
+  }
+  return true;
+}
+
+// --- BinaryNode ---
+
+template <typename T, typename U, typename V>
+class BinaryNode : public OperatorNode<T> {
+ public:
+  using Value = T;
+  using Arg1 = U;
+  using Arg2 = V;
+
+  BinaryNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
+      : OperatorNode<Value>(),
+        arg1_(static_cast<TypedNode<Arg1> *>(arg1.release())),
+        arg2_(static_cast<TypedNode<Arg2> *>(arg2.release())),
+        arg1_values_(),
+        arg2_values_() {}
+  virtual ~BinaryNode() {}
+
+ protected:
+  unique_ptr<TypedNode<Arg1>> arg1_;
+  unique_ptr<TypedNode<Arg2>> arg2_;
+  Array<Arg1> arg1_values_;
+  Array<Arg2> arg2_values_;
+
+  bool fill_arg1_values(Error *error, ArrayCRef<Record> records) {
+    return fill_node_arg_values(error, records, arg1_.get(), &arg1_values_);
+  }
+  bool fill_arg2_values(Error *error, ArrayCRef<Record> records) {
+    return fill_node_arg_values(error, records, arg2_.get(), &arg2_values_);
+  }
+};
+
+// ---- LogicalAndNode ----
+
+class LogicalAndNode : public BinaryNode<Bool, Bool, Bool> {
+ public:
+  using Value = Bool;
+  using Arg1 = Bool;
+  using Arg2 = Bool;
+
+  static unique_ptr<Node> create(Error *error,
+                                 unique_ptr<Node> &&arg1,
+                                 unique_ptr<Node> &&arg2) {
+    unique_ptr<Node> node(
+        new (nothrow) LogicalAndNode(std::move(arg1), std::move(arg2)));
+    if (!node) {
+      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
+    }
+    return node;
+  }
+
+  LogicalAndNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
+      : BinaryNode<Value, Arg1, Arg2>(std::move(arg1), std::move(arg2)),
+        temp_records_() {}
+
+  bool filter(Error *error,
+              ArrayCRef<Record> input_records,
+              ArrayRef<Record> *output_records) {
+    return arg1_->filter(error, input_records, output_records) &&
+           arg2_->filter(error, *output_records, output_records);
+  }
+  bool evaluate(Error *error,
+                ArrayCRef<Record> records,
+                ArrayRef<Value> results);
+
+ private:
+  Array<Record> temp_records_;
+};
+
+bool LogicalAndNode::evaluate(Error *error,
+                              ArrayCRef<Record> records,
+                              ArrayRef<Value> results) {
+  // Apply argument filters to "records" and store the result to
+  // "temp_records_". Then, appends a sentinel to the end.
+  if (!temp_records_.resize(error, records.size() + 1)) {
+    return false;
+  }
+  ArrayRef<Record> ref = temp_records_;
+  if (!arg1_->filter(error, records, &ref) ||
+      !arg2_->filter(error, ref, &ref)) {
+    return false;
+  }
+  temp_records_.set_row_id(ref.size(), NULL_ROW_ID);
+
+  // Compare records in "records" and "ref".
+  Int count = 0;
+  for (Int i = 0; i < records.size(); ++i) {
+    if (records.get_row_id(i) == ref.get_row_id(count)) {
+      results.set(i, true);
+      ++count;
+    } else {
+      results.set(i, false);
+    }
+  }
+  return true;
+}
+
+// ---- LogicalOrNode ----
+
+class LogicalOrNode : public BinaryNode<Bool, Bool, Bool> {
+ public:
+  using Value = Bool;
+  using Arg1 = Bool;
+  using Arg2 = Bool;
+
+  static unique_ptr<Node> create(Error *error,
+                                 unique_ptr<Node> &&arg1,
+                                 unique_ptr<Node> &&arg2) {
+    unique_ptr<Node> node(
+        new (nothrow) LogicalOrNode(std::move(arg1), std::move(arg2)));
+    if (!node) {
+      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
+    }
+    return node;
+  }
+
+  LogicalOrNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
+      : BinaryNode<Value, Arg1, Arg2>(std::move(arg1), std::move(arg2)),
+        temp_records_() {}
+
+  bool filter(Error *error,
+              ArrayCRef<Record> input_records,
+              ArrayRef<Record> *output_records);
+  bool evaluate(Error *error,
+                ArrayCRef<Record> records,
+                ArrayRef<Value> results);
+
+ private:
+  Array<Record> temp_records_;
+};
+
+bool LogicalOrNode::filter(Error *error,
+                            ArrayCRef<Record> input_records,
+                            ArrayRef<Record> *output_records) {
+  // Apply the 1st argument filter to "input_records" and store the result into
+  // "temp_records_", Then, appends a sentinel to the end.
+  if (!temp_records_.resize(error, input_records.size() + 2)) {
+    return false;
+  }
+  ArrayRef<Record> ref1 = temp_records_;
+  if (!arg1_->filter(error, input_records, &ref1)) {
+    return false;
+  }
+  if (ref1.size() == 0) {
+    // There are no arg1-true records.
+    return arg2_->filter(error, input_records, output_records);
+  } else if (ref1.size() == temp_records_.size()) {
+    // There are no arg1-false records.
+    if (input_records != *output_records) {
+      for (Int i = 0; i < input_records.size(); ++i) {
+        output_records->set(i, input_records.get(i));
+      }
+    }
+    return true;
+  }
+  temp_records_.set_row_id(ref1.size(), NULL_ROW_ID);
+
+  // Append arg1-false records to the end of "temp_records_".
+  // Then, applies the 2nd argument filter to it and appends a sentinel.
+  ArrayRef<Record> ref2 =
+      temp_records_.ref(ref1.size() + 1, input_records.size() - ref1.size());
+  Int arg1_count = 0;
+  Int arg2_count = 0;
+  for (Int i = 0; i < input_records.size(); ++i) {
+    if (input_records.get_row_id(i) == ref1.get_row_id(arg1_count)) {
+      ++arg1_count;
+    } else {
+      ref2.set(arg2_count, input_records.get(i));
+      ++arg2_count;
+    }
+  }
+  if (!arg2_->filter(error, ref2, &ref2)) {
+    return false;
+  }
+  if (ref2.size() == 0) {
+    // There are no arg2-true records.
+    for (Int i = 0; i < ref1.size(); ++i) {
+      output_records->set(i, ref1.get(i));
+    }
+    *output_records = output_records->ref(0, ref1.size());
+    return true;
+  } else if (ref2.size() == arg2_count) {
+    // There are no arg2-false records.
+    if (input_records != *output_records) {
+      for (Int i = 0; i < input_records.size(); ++i) {
+        output_records->set(i, input_records.get(i));
+      }
+      *output_records = output_records->ref(0, input_records.size());
+    }
+    return true;
+  }
+  temp_records_.set_row_id(ref1.size() + 1 + ref2.size(), NULL_ROW_ID);
+
+  // Merge the arg1-true records and the arg2-true records.
+  arg1_count = 0;
+  arg2_count = 0;
+  for (Int i = 0; i < input_records.size(); ++i) {
+    if (input_records.get_row_id(i) == ref1.get_row_id(arg1_count)) {
+      output_records->set(arg1_count + arg2_count, input_records.get(i));
+      ++arg1_count;
+    } else if (input_records.get_row_id(i) == ref2.get_row_id(arg2_count)) {
+      output_records->set(arg1_count + arg2_count, input_records.get(i));
+      ++arg2_count;
+    }
+  }
+  *output_records = output_records->ref(0, arg1_count + arg2_count);
+  return true;
+}
+
+bool LogicalOrNode::evaluate(Error *error,
+                              ArrayCRef<Record> records,
+                              ArrayRef<Value> results) {
+  // Apply the 1st argument filter to "records" and store the result into
+  // "temp_records_", Then, appends a sentinel to the end.
+  if (!temp_records_.resize(error, records.size() + 2)) {
+    return false;
+  }
+  ArrayRef<Record> ref1 = temp_records_;
+  if (!arg1_->filter(error, records, &ref1)) {
+    return false;
+  }
+  if (ref1.size() == 0) {
+    // There are no arg1-true records.
+    return arg2_->evaluate(error, records, results);
+  } else if (ref1.size() == temp_records_.size()) {
+    // There are no arg1-false records.
+    // TODO: Fill the array per 64 bits.
+    for (Int i = 0; i < records.size(); ++i) {
+      results.set(i, true);
+    }
+    return true;
+  }
+  temp_records_.set_row_id(ref1.size(), NULL_ROW_ID);
+
+  // Append arg1-false records to the end of "temp_records_".
+  // Then, applies the 2nd argument filter to it and appends a sentinel.
+  ArrayRef<Record> ref2 =
+      temp_records_.ref(ref1.size() + 1, records.size() - ref1.size());
+  Int arg1_count = 0;
+  Int arg2_count = 0;
+  for (Int i = 0; i < records.size(); ++i) {
+    if (records.get_row_id(i) == ref1.get_row_id(arg1_count)) {
+      ++arg1_count;
+    } else {
+      ref2.set(arg2_count, records.get(i));
+      ++arg2_count;
+    }
+  }
+  if (!arg2_->filter(error, ref2, &ref2)) {
+    return false;
+  }
+  if (ref2.size() == 0) {
+    // There are no arg2-true records.
+    arg1_count = 0;
+    for (Int i = 0; i < records.size(); ++i) {
+      if (records.get_row_id(i) == ref1.get_row_id(arg1_count)) {
+        results.set(i, true);
+        ++arg1_count;
+      } else {
+        results.set(i, false);
+      }
+    }
+    return true;
+  } else if (ref2.size() == arg2_count) {
+    // There are no arg2-false records.
+    // TODO: Fill the array per 64 bits.
+    for (Int i = 0; i < records.size(); ++i) {
+      results.set(i, true);
+    }
+    return true;
+  }
+  temp_records_.set_row_id(ref1.size() + 1 + ref2.size(), NULL_ROW_ID);
+
+  // Merge the arg1-true records and the arg2-true records.
+  arg1_count = 0;
+  arg2_count = 0;
+  for (Int i = 0; i < records.size(); ++i) {
+    if (records.get_row_id(i) == ref1.get_row_id(arg1_count)) {
+      results.set(i, true);
+      ++arg1_count;
+    } else if (records.get_row_id(i) == ref2.get_row_id(arg2_count)) {
+      results.set(i, true);
+      ++arg2_count;
+    } else {
+      results.set(i, false);
+    }
+  }
+  return true;
+}
+
+// ---- ComparisonNode ----
+
+template <typename T>
+class ComparisonNode
+    : public BinaryNode<Bool, typename T::Arg, typename T::Arg> {
+ public:
+  using Comparer = T;
+  using Value = Bool;
+  using Arg1 = typename T::Arg;
+  using Arg2 = typename T::Arg;
+
+  static unique_ptr<Node> create(Error *error,
+                                 unique_ptr<Node> &&arg1,
+                                 unique_ptr<Node> &&arg2) {
+    unique_ptr<Node> node(
+        new (nothrow) ComparisonNode(std::move(arg1), std::move(arg2)));
+    if (!node) {
+      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
+    }
+    return node;
+  }
+
+  ComparisonNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
+      : BinaryNode<Value, Arg1, Arg2>(std::move(arg1), std::move(arg2)),
+        comparer_() {}
+
+  bool filter(Error *error,
+              ArrayCRef<Record> input_records,
+              ArrayRef<Record> *output_records);
+  bool evaluate(Error *error,
+                ArrayCRef<Record> records,
+                ArrayRef<Value> results);
+
+ protected:
+  Comparer comparer_;
+};
+
+template <typename T>
+bool ComparisonNode<T>::filter(Error *error,
+                               ArrayCRef<Record> input_records,
+                               ArrayRef<Record> *output_records) {
+  if (!this->fill_arg1_values(error, input_records) ||
+      !this->fill_arg2_values(error, input_records)) {
+    return false;
+  }
+  Int count = 0;
+  for (Int i = 0; i < input_records.size(); ++i) {
+    if (comparer_(this->arg1_values_[i], this->arg2_values_[i])) {
+      output_records->set(count, input_records.get(i));
+      ++count;
+    }
+  }
+  *output_records = output_records->ref(0, count);
+  return true;
+}
+
+template <typename T>
+bool ComparisonNode<T>::evaluate(Error *error,
+                                 ArrayCRef<Record> records,
+                                 ArrayRef<Value> results) {
+  if (!this->fill_arg1_values(error, records) ||
+      !this->fill_arg2_values(error, records)) {
+    return false;
+  }
+  for (Int i = 0; i < records.size(); ++i) {
+    results.set(i, comparer_(this->arg1_values_[i], this->arg2_values_[i]));
+  }
+  return true;
+}
+
+// ----- EqualNode -----
+
+// TODO: EqualNode for Bool should be specialized.
+
+struct Equal {
+  template <typename T>
+  struct Comparer {
+    using Arg = T;
+    Bool operator()(Arg arg1, Arg arg2) const {
+      return arg1 == arg2;
+    }
+  };
+};
+
+template <typename T>
+using EqualNode = ComparisonNode<Equal::Comparer<T>>;
+
+// ----- NotEqualNode -----
+
+// TODO: NotEqualNode for Bool should be specialized.
+
+struct NotEqual {
+  template <typename T>
+  struct Comparer {
+    using Arg = T;
+    Bool operator()(Arg arg1, Arg arg2) const {
+      return arg1 != arg2;
+    }
+  };
+};
+
+template <typename T>
+using NotEqualNode = ComparisonNode<NotEqual::Comparer<T>>;
+
+// ----- LessNode -----
+
+struct Less {
+  template <typename T>
+  struct Comparer {
+    using Arg = T;
+    Bool operator()(Arg arg1, Arg arg2) const {
+      return arg1 < arg2;
+    }
+  };
+};
+
+template <typename T>
+using LessNode = ComparisonNode<Less::Comparer<T>>;
+
+// ----- LessEqualNode -----
+
+struct LessEqual {
+  template <typename T>
+  struct Comparer {
+    using Arg = T;
+    Bool operator()(Arg arg1, Arg arg2) const {
+      return arg1 <= arg2;
+    }
+  };
+};
+
+template <typename T>
+using LessEqualNode = ComparisonNode<LessEqual::Comparer<T>>;
+
+// ----- GreaterNode -----
+
+struct Greater {
+  template <typename T>
+  struct Comparer {
+    using Arg = T;
+    Bool operator()(Arg arg1, Arg arg2) const {
+      return arg1 > arg2;
+    }
+  };
+};
+
+template <typename T>
+using GreaterNode = ComparisonNode<Greater::Comparer<T>>;
+
+// ----- GreaterEqualNode -----
+
+struct GreaterEqual {
+  template <typename T>
+  struct Comparer {
+    using Arg = T;
+    Bool operator()(Arg arg1, Arg arg2) const {
+      return arg1 >= arg2;
+    }
   };
 };
 
-struct BitwiseXor {
-  template <typename T>
-  struct Functor {
-    using Arg1 = T;
-    using Arg2 = T;
-    using Result = T;
-    T operator()(Arg1 lhs, Arg2 rhs) const {
-      return lhs ^ rhs;
-    };
-  };
-};
+template <typename T>
+using GreaterEqualNode = ComparisonNode<GreaterEqual::Comparer<T>>;
+
+// ---- BitwiseAndNode ----
+
+// TODO: BitwiseAnd/Or/XorNode should be implemented on the same base class?
+
+template <typename T> class BitwiseAndNode;
+
+template <>
+class BitwiseAndNode<Bool> : public BinaryNode<Bool, Bool, Bool> {
+ public:
+  using Value = Bool;
+  using Arg1 = Bool;
+  using Arg2 = Bool;
+
+  static unique_ptr<Node> create(Error *error,
+                                 unique_ptr<Node> &&arg1,
+                                 unique_ptr<Node> &&arg2) {
+    unique_ptr<Node> node(
+        new (nothrow) BitwiseAndNode(std::move(arg1), std::move(arg2)));
+    if (!node) {
+      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
+    }
+    return node;
+  }
+
+  BitwiseAndNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
+      : BinaryNode<Value, Arg1, Arg2>(std::move(arg1), std::move(arg2)) {}
+
+  bool filter(Error *error,
+              ArrayCRef<Record> input_records,
+              ArrayRef<Record> *output_records);
+  bool evaluate(Error *error,
+                ArrayCRef<Record> records,
+                ArrayRef<Value> results);
+};
+
+bool BitwiseAndNode<Bool>::filter(Error *error,
+                                  ArrayCRef<Record> input_records,
+                                  ArrayRef<Record> *output_records) {
+  if (!fill_arg1_values(error, input_records) ||
+      !fill_arg2_values(error, input_records)) {
+    return false;
+  }
+  Int count = 0;
+  for (Int i = 0; i < input_records.size(); ++i) {
+    if (this->arg1_values_[i] & this->arg2_values_[i]) {
+      output_records->set(count, input_records.get(i));
+      ++count;
+    }
+  }
+  *output_records = output_records->ref(0, count);
+  return true;
+}
+
+bool BitwiseAndNode<Bool>::evaluate(Error *error,
+                                    ArrayCRef<Record> records,
+                                    ArrayRef<Value> results) {
+  if (!fill_arg1_values(error, records) ||
+      !fill_arg2_values(error, records)) {
+    return false;
+  }
+  // TODO: Should be processed per 64 bits.
+  //       Check the 64-bit boundary and do it!
+  for (Int i = 0; i < records.size(); ++i) {
+    results.set(i, this->arg1_values_[i] & this->arg2_values_[i]);
+  }
+  return true;
+}
+
+template <>
+class BitwiseAndNode<Int> : public BinaryNode<Int, Int, Int> {
+ public:
+  using Value = Int;
+  using Arg1 = Int;
+  using Arg2 = Int;
+
+  static unique_ptr<Node> create(Error *error,
+                                 unique_ptr<Node> &&arg1,
+                                 unique_ptr<Node> &&arg2) {
+    unique_ptr<Node> node(
+        new (nothrow) BitwiseAndNode(std::move(arg1), std::move(arg2)));
+    if (!node) {
+      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
+    }
+    return node;
+  }
+
+  BitwiseAndNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
+      : BinaryNode<Value, Arg1, Arg2>(std::move(arg1), std::move(arg2)) {}
+
+  bool evaluate(Error *error,
+                ArrayCRef<Record> records,
+                ArrayRef<Value> results);
+};
+
+bool BitwiseAndNode<Int>::evaluate(Error *error,
+                                   ArrayCRef<Record> records,
+                                   ArrayRef<Value> results) {
+  if (!fill_arg1_values(error, records) ||
+      !fill_arg2_values(error, records)) {
+    return false;
+  }
+  // TODO: Should be processed per 64 bits.
+  //       Check the 64-bit boundary and do it!
+  for (Int i = 0; i < records.size(); ++i) {
+    results.set(i, this->arg1_values_[i] & this->arg2_values_[i]);
+  }
+  return true;
+}
+
+// ---- BitwiseOrNode ----
+
+template <typename T> class BitwiseOrNode;
+
+template <>
+class BitwiseOrNode<Bool> : public BinaryNode<Bool, Bool, Bool> {
+ public:
+  using Value = Bool;
+  using Arg1 = Bool;
+  using Arg2 = Bool;
+
+  static unique_ptr<Node> create(Error *error,
+                                 unique_ptr<Node> &&arg1,
+                                 unique_ptr<Node> &&arg2) {
+    unique_ptr<Node> node(
+        new (nothrow) BitwiseOrNode(std::move(arg1), std::move(arg2)));
+    if (!node) {
+      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
+    }
+    return node;
+  }
+
+  BitwiseOrNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
+      : BinaryNode<Value, Arg1, Arg2>(std::move(arg1), std::move(arg2)) {}
+
+  bool filter(Error *error,
+              ArrayCRef<Record> input_records,
+              ArrayRef<Record> *output_records);
+  bool evaluate(Error *error,
+                ArrayCRef<Record> records,
+                ArrayRef<Value> results);
+};
+
+bool BitwiseOrNode<Bool>::filter(Error *error,
+                                 ArrayCRef<Record> input_records,
+                                 ArrayRef<Record> *output_records) {
+  if (!fill_arg1_values(error, input_records) ||
+      !fill_arg2_values(error, input_records)) {
+    return false;
+  }
+  Int count = 0;
+  for (Int i = 0; i < input_records.size(); ++i) {
+    if (this->arg1_values_[i] | this->arg2_values_[i]) {
+      output_records->set(count, input_records.get(i));
+      ++count;
+    }
+  }
+  *output_records = output_records->ref(0, count);
+  return true;
+}
+
+bool BitwiseOrNode<Bool>::evaluate(Error *error,
+                                   ArrayCRef<Record> records,
+                                   ArrayRef<Value> results) {
+  if (!fill_arg1_values(error, records) ||
+      !fill_arg2_values(error, records)) {
+    return false;
+  }
+  // TODO: Should be processed per 64 bits.
+  //       Check the 64-bit boundary and do it!
+  for (Int i = 0; i < records.size(); ++i) {
+    results.set(i, this->arg1_values_[i] | this->arg2_values_[i]);
+  }
+  return true;
+}
+
+template <>
+class BitwiseOrNode<Int> : public BinaryNode<Int, Int, Int> {
+ public:
+  using Value = Int;
+  using Arg1 = Int;
+  using Arg2 = Int;
+
+  static unique_ptr<Node> create(Error *error,
+                                 unique_ptr<Node> &&arg1,
+                                 unique_ptr<Node> &&arg2) {
+    unique_ptr<Node> node(
+        new (nothrow) BitwiseOrNode(std::move(arg1), std::move(arg2)));
+    if (!node) {
+      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
+    }
+    return node;
+  }
+
+  BitwiseOrNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
+      : BinaryNode<Value, Arg1, Arg2>(std::move(arg1), std::move(arg2)) {}
+
+  bool evaluate(Error *error,
+                ArrayCRef<Record> records,
+                ArrayRef<Value> results);
+};
+
+bool BitwiseOrNode<Int>::evaluate(Error *error,
+                                  ArrayCRef<Record> records,
+                                  ArrayRef<Value> results) {
+  if (!fill_arg1_values(error, records) ||
+      !fill_arg2_values(error, records)) {
+    return false;
+  }
+  // TODO: Should be processed per 64 bits.
+  //       Check the 64-bit boundary and do it!
+  for (Int i = 0; i < records.size(); ++i) {
+    results.set(i, this->arg1_values_[i] | this->arg2_values_[i]);
+  }
+  return true;
+}
+
+// ---- BitwiseXorNode ----
+
+template <typename T> class BitwiseXorNode;
+
+template <>
+class BitwiseXorNode<Bool> : public BinaryNode<Bool, Bool, Bool> {
+ public:
+  using Value = Bool;
+  using Arg1 = Bool;
+  using Arg2 = Bool;
+
+  static unique_ptr<Node> create(Error *error,
+                                 unique_ptr<Node> &&arg1,
+                                 unique_ptr<Node> &&arg2) {
+    unique_ptr<Node> node(
+        new (nothrow) BitwiseXorNode(std::move(arg1), std::move(arg2)));
+    if (!node) {
+      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
+    }
+    return node;
+  }
+
+  BitwiseXorNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
+      : BinaryNode<Value, Arg1, Arg2>(std::move(arg1), std::move(arg2)) {}
+
+  bool filter(Error *error,
+              ArrayCRef<Record> input_records,
+              ArrayRef<Record> *output_records);
+  bool evaluate(Error *error,
+                ArrayCRef<Record> records,
+                ArrayRef<Value> results);
+};
+
+bool BitwiseXorNode<Bool>::filter(Error *error,
+                                  ArrayCRef<Record> input_records,
+                                  ArrayRef<Record> *output_records) {
+  if (!fill_arg1_values(error, input_records) ||
+      !fill_arg2_values(error, input_records)) {
+    return false;
+  }
+  Int count = 0;
+  for (Int i = 0; i < input_records.size(); ++i) {
+    if (this->arg1_values_[i] ^ this->arg2_values_[i]) {
+      output_records->set(count, input_records.get(i));
+      ++count;
+    }
+  }
+  *output_records = output_records->ref(0, count);
+  return true;
+}
+
+bool BitwiseXorNode<Bool>::evaluate(Error *error,
+                                    ArrayCRef<Record> records,
+                                    ArrayRef<Value> results) {
+  if (!fill_arg1_values(error, records) ||
+      !fill_arg2_values(error, records)) {
+    return false;
+  }
+  // TODO: Should be processed per 64 bits.
+  //       Check the 64-bit boundary and do it!
+  for (Int i = 0; i < records.size(); ++i) {
+    results.set(i, this->arg1_values_[i] ^ this->arg2_values_[i]);
+  }
+  return true;
+}
+
+template <>
+class BitwiseXorNode<Int> : public BinaryNode<Int, Int, Int> {
+ public:
+  using Value = Int;
+  using Arg1 = Int;
+  using Arg2 = Int;
 
-struct Plus {
-  template <typename T>
-  struct Functor {
-    using Arg1 = T;
-    using Arg2 = T;
-    using Result = T;
-    T operator()(Arg1 lhs, Arg2 rhs) const {
-      return lhs + rhs;
-    };
-  };
-};
+  static unique_ptr<Node> create(Error *error,
+                                 unique_ptr<Node> &&arg1,
+                                 unique_ptr<Node> &&arg2) {
+    unique_ptr<Node> node(
+        new (nothrow) BitwiseXorNode(std::move(arg1), std::move(arg2)));
+    if (!node) {
+      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
+    }
+    return node;
+  }
 
-struct Minus {
-  template <typename T>
-  struct Functor {
-    using Arg1 = T;
-    using Arg2 = T;
-    using Result = T;
-    T operator()(Arg1 lhs, Arg2 rhs) const {
-      return lhs - rhs;
-    };
-  };
-};
+  BitwiseXorNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
+      : BinaryNode<Value, Arg1, Arg2>(std::move(arg1), std::move(arg2)) {}
 
-struct Multiplication {
-  template <typename T>
-  struct Functor {
-    using Arg1 = T;
-    using Arg2 = T;
-    using Result = T;
-    T operator()(Arg1 lhs, Arg2 rhs) const {
-      return lhs * rhs;
-    };
-  };
+  bool evaluate(Error *error,
+                ArrayCRef<Record> records,
+                ArrayRef<Value> results);
 };
 
-template <typename Op>
-class BinaryNode : public Node<typename Op::Result> {
+bool BitwiseXorNode<Int>::evaluate(Error *error,
+                                   ArrayCRef<Record> records,
+                                   ArrayRef<Value> results) {
+  if (!fill_arg1_values(error, records) ||
+      !fill_arg2_values(error, records)) {
+    return false;
+  }
+  // TODO: Should be processed per 64 bits.
+  //       Check the 64-bit boundary and do it!
+  for (Int i = 0; i < records.size(); ++i) {
+    results.set(i, this->arg1_values_[i] ^ this->arg2_values_[i]);
+  }
+  return true;
+}
+
+// ---- PlusOperator ----
+
+template <typename T> class PlusNode;
+
+template <>
+class PlusNode<Int> : public BinaryNode<Int, Int, Int> {
  public:
-  using Arg1 = typename Op::Arg1;
-  using Arg2 = typename Op::Arg2;
-
-  BinaryNode(Op op,
-             unique_ptr<ExpressionNode> &&lhs,
-             unique_ptr<ExpressionNode> &&rhs)
-      : Node<typename Op::Result>(),
-        operator_(op),
-        lhs_(static_cast<Node<Arg1> *>(lhs.release())),
-        rhs_(static_cast<Node<Arg2> *>(rhs.release())) {}
-  virtual ~BinaryNode() {}
+  using Value = Int;
+  using Arg1 = Int;
+  using Arg2 = Int;
 
-  NodeType node_type() const {
-    return OPERATOR_NODE;
+  static unique_ptr<Node> create(Error *error,
+                                 unique_ptr<Node> &&arg1,
+                                 unique_ptr<Node> &&arg2) {
+    unique_ptr<Node> node(
+        new (nothrow) PlusNode(std::move(arg1), std::move(arg2)));
+    if (!node) {
+      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
+    }
+    return node;
   }
 
-  bool evaluate(Error *error, const ArrayRef<Record> &records);
+  PlusNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
+      : BinaryNode<Value, Arg1, Arg2>(std::move(arg1), std::move(arg2)) {}
 
- private:
-  Op operator_;
-  unique_ptr<Node<Arg1>> lhs_;
-  unique_ptr<Node<Arg2>> rhs_;
+  bool evaluate(Error *error,
+                ArrayCRef<Record> records,
+                ArrayRef<Value> results);
 };
 
-template <typename Op>
-bool BinaryNode<Op>::evaluate(Error *error, const ArrayRef<Record> &records) {
-  if (!this->values_.resize(error, records.size())) {
-    GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    return false;
-  }
-  if (!lhs_->evaluate(error, records) ||
-      !rhs_->evaluate(error, records)) {
+bool PlusNode<Int>::evaluate(Error *error,
+                             ArrayCRef<Record> records,
+                             ArrayRef<Value> results) {
+  if (!fill_arg1_values(error, records) ||
+      !fill_arg2_values(error, records)) {
     return false;
   }
   for (Int i = 0; i < records.size(); ++i) {
-    this->values_.set(i, operator_(lhs_->get(i), rhs_->get(i)));
+    results.set(i, this->arg1_values_[i] + this->arg2_values_[i]);
   }
   return true;
 }
 
-class LogicalAndNode : public Node<Bool> {
+template <>
+class PlusNode<Float> : public BinaryNode<Float, Float, Float> {
  public:
-  LogicalAndNode(unique_ptr<ExpressionNode> &&lhs,
-                 unique_ptr<ExpressionNode> &&rhs)
-      : Node<Bool>(),
-        lhs_(static_cast<Node<Bool> *>(lhs.release())),
-        rhs_(static_cast<Node<Bool> *>(rhs.release())),
-        temp_records_() {}
-  virtual ~LogicalAndNode() {}
+  using Value = Float;
+  using Arg1 = Float;
+  using Arg2 = Float;
 
-  NodeType node_type() const {
-    return OPERATOR_NODE;
+  static unique_ptr<Node> create(Error *error,
+                                 unique_ptr<Node> &&arg1,
+                                 unique_ptr<Node> &&arg2) {
+    unique_ptr<Node> node(
+        new (nothrow) PlusNode(std::move(arg1), std::move(arg2)));
+    if (!node) {
+      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
+    }
+    return node;
   }
 
-  bool filter(Error *error,
-              const ArrayRef<Record> &input_records,
-              ArrayRef<Record> *output_records);
-
-  bool evaluate(Error *error, const ArrayRef<Record> &records);
+  PlusNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
+      : BinaryNode<Value, Arg1, Arg2>(std::move(arg1), std::move(arg2)) {}
 
- private:
-  unique_ptr<Node<Bool>> lhs_;
-  unique_ptr<Node<Bool>> rhs_;
-  Array<Record> temp_records_;
+  bool adjust(Error *error, ArrayRef<Record> records);
+  bool evaluate(Error *error,
+                ArrayCRef<Record> records,
+                ArrayRef<Value> results);
 };
 
-bool LogicalAndNode::filter(Error *error,
-                            const ArrayRef<Record> &input_records,
-                            ArrayRef<Record> *output_records) {
-  return lhs_->filter(error, input_records, output_records) &&
-         rhs_->filter(error, *output_records, output_records);
-}
-
-bool LogicalAndNode::evaluate(Error *error, const ArrayRef<Record> &records) {
-  if (!this->values_.resize(error, records.size())) {
+bool PlusNode<Float>::adjust(Error *error, ArrayRef<Record> records) {
+  if (!fill_arg1_values(error, records) ||
+      !fill_arg2_values(error, records)) {
     return false;
   }
-  if (!lhs_->evaluate(error, records)) {
+  for (Int i = 0; i < records.size(); ++i) {
+    records.set_score(i, this->arg1_values_[i] + this->arg2_values_[i]);
+  }
+  return true;
+}
+
+bool PlusNode<Float>::evaluate(Error *error,
+                               ArrayCRef<Record> records,
+                               ArrayRef<Value> results) {
+  if (!fill_arg1_values(error, records) ||
+      !fill_arg2_values(error, records)) {
     return false;
   }
-  // False records must not be evaluated for the 2nd argument.
-  temp_records_.clear();
   for (Int i = 0; i < records.size(); ++i) {
-    if (lhs_->get(i)) {
-      if (!temp_records_.push_back(error, records.get(i))) {
-        return false;
-      }
+    results.set(i, this->arg1_values_[i] + this->arg2_values_[i]);
+  }
+  return true;
+}
+
+// ---- MinusOperator ----
+
+template <typename T> class MinusNode;
+
+template <>
+class MinusNode<Int> : public BinaryNode<Int, Int, Int> {
+ public:
+  using Value = Int;
+  using Arg1 = Int;
+  using Arg2 = Int;
+
+  static unique_ptr<Node> create(Error *error,
+                                 unique_ptr<Node> &&arg1,
+                                 unique_ptr<Node> &&arg2) {
+    unique_ptr<Node> node(
+        new (nothrow) MinusNode(std::move(arg1), std::move(arg2)));
+    if (!node) {
+      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
     }
+    return node;
   }
-  if (!rhs_->evaluate(error, temp_records_)) {
+
+  MinusNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
+      : BinaryNode<Value, Arg1, Arg2>(std::move(arg1), std::move(arg2)) {}
+
+  bool evaluate(Error *error,
+                ArrayCRef<Record> records,
+                ArrayRef<Value> results);
+};
+
+bool MinusNode<Int>::evaluate(Error *error,
+                              ArrayCRef<Record> records,
+                              ArrayRef<Value> results) {
+  if (!fill_arg1_values(error, records) ||
+      !fill_arg2_values(error, records)) {
     return false;
   }
-  Int j = 0;
   for (Int i = 0; i < records.size(); ++i) {
-    this->values_.set(i, lhs_->get(i) ? rhs_->get(j++) : false);
+    results.set(i, this->arg1_values_[i] - this->arg2_values_[i]);
   }
   return true;
 }
 
-class LogicalOrNode : public Node<Bool> {
+template <>
+class MinusNode<Float> : public BinaryNode<Float, Float, Float> {
  public:
-  LogicalOrNode(unique_ptr<ExpressionNode> &&lhs,
-                 unique_ptr<ExpressionNode> &&rhs)
-      : Node<Bool>(),
-        lhs_(static_cast<Node<Bool> *>(lhs.release())),
-        rhs_(static_cast<Node<Bool> *>(rhs.release())),
-        left_records_(),
-        right_records_() {}
-  virtual ~LogicalOrNode() {}
+  using Value = Float;
+  using Arg1 = Float;
+  using Arg2 = Float;
 
-  NodeType node_type() const {
-    return OPERATOR_NODE;
+  static unique_ptr<Node> create(Error *error,
+                                 unique_ptr<Node> &&arg1,
+                                 unique_ptr<Node> &&arg2) {
+    unique_ptr<Node> node(
+        new (nothrow) MinusNode(std::move(arg1), std::move(arg2)));
+    if (!node) {
+      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
+    }
+    return node;
   }
 
-  bool filter(Error *error,
-              const ArrayRef<Record> &input_records,
-              ArrayRef<Record> *output_records);
-
-  bool evaluate(Error *error, const ArrayRef<Record> &records);
+  MinusNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
+      : BinaryNode<Value, Arg1, Arg2>(std::move(arg1), std::move(arg2)) {}
 
- private:
-  unique_ptr<Node<Bool>> lhs_;
-  unique_ptr<Node<Bool>> rhs_;
-  Array<Record> left_records_;
-  Array<Record> right_records_;
+  bool adjust(Error *error, ArrayRef<Record> records);
+  bool evaluate(Error *error,
+                ArrayCRef<Record> records,
+                ArrayRef<Value> results);
 };
 
-bool LogicalOrNode::filter(Error *error,
-                           const ArrayRef<Record> &input_records,
-                           ArrayRef<Record> *output_records) {
-  // Make a copy of the given record set and apply the left-filter to it.
-  if (!left_records_.resize(error, input_records.size())) {
+bool MinusNode<Float>::adjust(Error *error, ArrayRef<Record> records) {
+  if (!fill_arg1_values(error, records) ||
+      !fill_arg2_values(error, records)) {
     return false;
   }
-  for (Int i = 0; i < input_records.size(); ++i) {
-    left_records_.set(i, input_records.get(i));
+  for (Int i = 0; i < records.size(); ++i) {
+    records.set_score(i, this->arg1_values_[i] - this->arg2_values_[i]);
   }
-  ArrayRef<Record> left_record_ref = left_records_;
-  if (!lhs_->filter(error, left_record_ref, &left_record_ref)) {
+  return true;
+}
+
+bool MinusNode<Float>::evaluate(Error *error,
+                                ArrayCRef<Record> records,
+                                ArrayRef<Value> results) {
+  if (!fill_arg1_values(error, records) ||
+      !fill_arg2_values(error, records)) {
     return false;
   }
-  if (!left_records_.resize(error, left_record_ref.size())) {
-    return false;
+  for (Int i = 0; i < records.size(); ++i) {
+    results.set(i, this->arg1_values_[i] - this->arg2_values_[i]);
   }
-  if (left_records_.size() == 0) {
-    // There are no left-true records.
-    return rhs_->filter(error, input_records, output_records);
-  } else if (left_records_.size() == input_records.size()) {
-    // There are no left-false records.
-    // This means that all the records pass through the filter.
-    if (&input_records != output_records) {
-      *output_records = output_records->ref(0, input_records.size());
-      for (Int i = 0; i < input_records.size(); ++i) {
-        output_records->set(i, input_records.get(i));
-      }
+  return true;
+}
+
+// ---- MultiplicationOperator ----
+
+template <typename T> class MultiplicationNode;
+
+template <>
+class MultiplicationNode<Int> : public BinaryNode<Int, Int, Int> {
+ public:
+  using Value = Int;
+  using Arg1 = Int;
+  using Arg2 = Int;
+
+  static unique_ptr<Node> create(Error *error,
+                                 unique_ptr<Node> &&arg1,
+                                 unique_ptr<Node> &&arg2) {
+    unique_ptr<Node> node(
+        new (nothrow) MultiplicationNode(std::move(arg1), std::move(arg2)));
+    if (!node) {
+      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
     }
-    return true;
+    return node;
   }
 
-  // Enumerate left-false records and apply the right-filter to it.
-  if (!right_records_.resize(error,
-                             input_records.size() - left_records_.size())) {
+  MultiplicationNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
+      : BinaryNode<Value, Arg1, Arg2>(std::move(arg1), std::move(arg2)) {}
+
+  bool evaluate(Error *error,
+                ArrayCRef<Record> records,
+                ArrayRef<Value> results);
+};
+
+bool MultiplicationNode<Int>::evaluate(Error *error,
+                                       ArrayCRef<Record> records,
+                                       ArrayRef<Value> results) {
+  if (!fill_arg1_values(error, records) ||
+      !fill_arg2_values(error, records)) {
     return false;
   }
-  Int left_count = 0;
-  Int right_count = 0;
-  for (Int i = 0; i < input_records.size(); ++i) {
-    if (input_records.get_row_id(i) ==
-        left_records_.get_row_id((left_count))) {
-      ++left_count;
-    } else {
-      right_records_.set(right_count, input_records.get(i));
-      ++right_count;
+  for (Int i = 0; i < records.size(); ++i) {
+    results.set(i, this->arg1_values_[i] * this->arg2_values_[i]);
+  }
+  return true;
+}
+
+template <>
+class MultiplicationNode<Float> : public BinaryNode<Float, Float, Float> {
+ public:
+  using Value = Float;
+  using Arg1 = Float;
+  using Arg2 = Float;
+
+  static unique_ptr<Node> create(Error *error,
+                                 unique_ptr<Node> &&arg1,
+                                 unique_ptr<Node> &&arg2) {
+    unique_ptr<Node> node(
+        new (nothrow) MultiplicationNode(std::move(arg1), std::move(arg2)));
+    if (!node) {
+      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
     }
+    return node;
   }
-  ArrayRef<Record> right_record_ref = right_records_;
-  if (!rhs_->filter(error, right_record_ref, &right_record_ref)) {
+
+  MultiplicationNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
+      : BinaryNode<Value, Arg1, Arg2>(std::move(arg1), std::move(arg2)) {}
+
+  bool adjust(Error *error, ArrayRef<Record> records);
+  bool evaluate(Error *error,
+                ArrayCRef<Record> records,
+                ArrayRef<Value> results);
+};
+
+bool MultiplicationNode<Float>::adjust(Error *error,
+                                       ArrayRef<Record> records) {
+  if (!fill_arg1_values(error, records) ||
+      !fill_arg2_values(error, records)) {
     return false;
   }
-  if (!right_records_.resize(error, right_record_ref.size())) {
+  for (Int i = 0; i < records.size(); ++i) {
+    records.set_score(i, this->arg1_values_[i] * this->arg2_values_[i]);
+  }
+  return true;
+}
+
+bool MultiplicationNode<Float>::evaluate(Error *error,
+                                         ArrayCRef<Record> records,
+                                         ArrayRef<Value> results) {
+  if (!fill_arg1_values(error, records) ||
+      !fill_arg2_values(error, records)) {
     return false;
   }
-  if (right_records_.size() == 0) {
-    // There are no right-true records.
-    *output_records = output_records->ref(0, left_records_.size());
-    for (Int i = 0; i < output_records->size(); ++i) {
-      output_records->set(i, left_records_.get(i));
-    }
-    return true;
-  } else if (right_records_.size() == right_count) {
-    // There are no right-false records.
-    // This means that all the records pass through the filter.
-    if (&input_records != output_records) {
-      *output_records = output_records->ref(0, input_records.size());
-      for (Int i = 0; i < input_records.size(); ++i) {
-        output_records->set(i, input_records.get(i));
-      }
+  for (Int i = 0; i < records.size(); ++i) {
+    results.set(i, this->arg1_values_[i] * this->arg2_values_[i]);
+  }
+  return true;
+}
+
+// ---- DivisionOperator ----
+
+template <typename T> class DivisionNode;
+
+template <>
+class DivisionNode<Int> : public BinaryNode<Int, Int, Int> {
+ public:
+  using Value = Int;
+  using Arg1 = Int;
+  using Arg2 = Int;
+
+  static unique_ptr<Node> create(Error *error,
+                                 unique_ptr<Node> &&arg1,
+                                 unique_ptr<Node> &&arg2) {
+    unique_ptr<Node> node(
+        new (nothrow) DivisionNode(std::move(arg1), std::move(arg2)));
+    if (!node) {
+      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
     }
-    return true;
+    return node;
   }
 
-  // Append sentinels.
-  if (!left_records_.push_back(error, Record(NULL_ROW_ID, 0.0)) ||
-      !right_records_.push_back(error, Record(NULL_ROW_ID, 0.0))) {
+  DivisionNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
+      : BinaryNode<Value, Arg1, Arg2>(std::move(arg1), std::move(arg2)) {}
+
+  bool evaluate(Error *error,
+                ArrayCRef<Record> records,
+                ArrayRef<Value> results);
+};
+
+bool DivisionNode<Int>::evaluate(Error *error,
+                                 ArrayCRef<Record> records,
+                                 ArrayRef<Value> results) {
+  if (!fill_arg1_values(error, records) ||
+      !fill_arg2_values(error, records)) {
     return false;
   }
-
-  // Merge the left-true records and the right-true records.
-  left_count = 0;
-  right_count = 0;
-  for (Int i = 0; i < input_records.size(); ++i) {
-    if (input_records.get_row_id(i) ==
-        left_records_.get_row_id(left_count)) {
-      output_records->set(left_count + right_count, input_records.get(i));
-      ++left_count;
-    } else if (input_records.get_row_id(i) ==
-               right_records_.get_row_id(right_count)) {
-      output_records->set(left_count + right_count, input_records.get(i));
-      ++right_count;
+  for (Int i = 0; i < records.size(); ++i) {
+    if (this->arg2_values_[i] == 0) {
+      GRNXX_ERROR_SET(error, DIVISION_BY_ZERO, "Division by zero");
+      return false;
+    } else if ((this->arg2_values_[i] == -1) &&
+               (this->arg1_values_[i] == numeric_limits<Int>::min())) {
+      GRNXX_ERROR_SET(error, DIVISION_OVERFLOW, "Division overflow");
+      return false;
     }
+    results.set(i, this->arg1_values_[i] / this->arg2_values_[i]);
   }
-  *output_records = output_records->ref(0, left_count + right_count);
   return true;
 }
 
-bool LogicalOrNode::evaluate(Error *error, const ArrayRef<Record> &records) {
-  // TODO: This logic should be tested.
-  if (!this->values_.resize(error, records.size())) {
+template <>
+class DivisionNode<Float> : public BinaryNode<Float, Float, Float> {
+ public:
+  using Value = Float;
+  using Arg1 = Float;
+  using Arg2 = Float;
+
+  static unique_ptr<Node> create(Error *error,
+                                 unique_ptr<Node> &&arg1,
+                                 unique_ptr<Node> &&arg2) {
+    unique_ptr<Node> node(
+        new (nothrow) DivisionNode(std::move(arg1), std::move(arg2)));
+    if (!node) {
+      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
+    }
+    return node;
+  }
+
+  DivisionNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
+      : BinaryNode<Value, Arg1, Arg2>(std::move(arg1), std::move(arg2)) {}
+
+  bool adjust(Error *error, ArrayRef<Record> records);
+  bool evaluate(Error *error,
+                ArrayCRef<Record> records,
+                ArrayRef<Value> results);
+};
+
+bool DivisionNode<Float>::adjust(Error *error,
+                                 ArrayRef<Record> records) {
+  if (!fill_arg1_values(error, records) ||
+      !fill_arg2_values(error, records)) {
     return false;
   }
-  if (!lhs_->evaluate(error, records)) {
+  for (Int i = 0; i < records.size(); ++i) {
+    records.set_score(i, this->arg1_values_[i] / this->arg2_values_[i]);
+  }
+  return true;
+}
+
+bool DivisionNode<Float>::evaluate(Error *error,
+                                   ArrayCRef<Record> records,
+                                   ArrayRef<Value> results) {
+  if (!fill_arg1_values(error, records) ||
+      !fill_arg2_values(error, records)) {
     return false;
   }
-  // True records must not be evaluated for the 2nd argument.
-  left_records_.clear();
   for (Int i = 0; i < records.size(); ++i) {
-    if (!lhs_->get(i)) {
-      if (!left_records_.push_back(error, records.get(i))) {
-        return false;
-      }
+    results.set(i, this->arg1_values_[i] / this->arg2_values_[i]);
+  }
+  return true;
+}
+
+// ---- ModulusOperator ----
+
+template <typename T> class ModulusNode;
+
+template <>
+class ModulusNode<Int> : public BinaryNode<Int, Int, Int> {
+ public:
+  using Value = Int;
+  using Arg1 = Int;
+  using Arg2 = Int;
+
+  static unique_ptr<Node> create(Error *error,
+                                 unique_ptr<Node> &&arg1,
+                                 unique_ptr<Node> &&arg2) {
+    unique_ptr<Node> node(
+        new (nothrow) ModulusNode(std::move(arg1), std::move(arg2)));
+    if (!node) {
+      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
     }
+    return node;
   }
-  if (!rhs_->evaluate(error, left_records_)) {
+
+  ModulusNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
+      : BinaryNode<Value, Arg1, Arg2>(std::move(arg1), std::move(arg2)) {}
+
+  bool evaluate(Error *error,
+                ArrayCRef<Record> records,
+                ArrayRef<Value> results);
+};
+
+bool ModulusNode<Int>::evaluate(Error *error,
+                                ArrayCRef<Record> records,
+                                ArrayRef<Value> results) {
+  if (!fill_arg1_values(error, records) ||
+      !fill_arg2_values(error, records)) {
     return false;
   }
-  Int j = 0;
   for (Int i = 0; i < records.size(); ++i) {
-    this->values_.set(i, lhs_->get(i) ? true : rhs_->get(j++));
+    if (this->arg2_values_[i] == 0) {
+      GRNXX_ERROR_SET(error, DIVISION_BY_ZERO, "Division by zero");
+      return false;
+    } else if ((this->arg2_values_[i] == -1) &&
+               (this->arg1_values_[i] == numeric_limits<Int>::min())) {
+      GRNXX_ERROR_SET(error, DIVISION_OVERFLOW, "Division overflow");
+      return false;
+    }
+    results.set(i, this->arg1_values_[i] % this->arg2_values_[i]);
   }
   return true;
 }
 
-}  // namespace
+}  // namespace expression
+
+using namespace expression;
 
 // -- Expression --
 
@@ -739,111 +2195,112 @@ DataType Expression::data_type() const {
 }
 
 bool Expression::filter(Error *error, Array<Record> *records, Int offset) {
-  ArrayRef<Record> input_ref = records->ref(offset);
-  ArrayRef<Record> output_ref = records->ref(offset);
-  while (input_ref.size() > block_size()) {
-    ArrayRef<Record> input_block = input_ref.ref(0, block_size());
-    if (input_ref.size() == output_ref.size()) {
-      if (!root_->filter(error, input_block, &input_block)) {
-        return false;
-      }
-      input_ref = input_ref.ref(block_size());
-      output_ref = output_ref.ref(input_block.size());
-    } else {
-      ArrayRef<Record> output_block = output_ref;
-      if (!root_->filter(error, input_block, &output_block)) {
-        return false;
-      }
-      input_ref = input_ref.ref(block_size());
-      output_ref = output_ref.ref(output_block.size());
+  ArrayRef<Record> output_records = records->ref();
+  if (!filter(error, *records, &output_records)) {
+    return false;
+  }
+  return records->resize(error, output_records.size());
+}
+
+bool Expression::filter(Error *error,
+                        ArrayCRef<Record> input_records,
+                        ArrayRef<Record> *output_records) {
+  ArrayCRef<Record> input = input_records;
+  ArrayRef<Record> output = *output_records;
+  Int count = 0;
+  while (input.size() > block_size_) {
+    ArrayCRef<Record> input_block = input.ref(0, block_size_);
+    ArrayRef<Record> output_block = output.ref(0, block_size_);
+    if (!root_->filter(error, input_block, &output_block)) {
+      return false;
     }
+    input = input.ref(block_size_);
+    output = output.ref(output_block.size());
+    count += output_block.size();
   }
-  ArrayRef<Record> output_block = output_ref;
-  if (!root_->filter(error, input_ref, &output_block)) {
+  if (!root_->filter(error, input, &output)) {
     return false;
   }
-  output_ref = output_ref.ref(output_block.size());
-  return records->resize(error, records->size() - output_ref.size());
+  count += output.size();
+  *output_records = output_records->ref(0, count);
+  return true;
 }
 
 bool Expression::adjust(Error *error, Array<Record> *records, Int offset) {
-  ArrayRef<Record> ref = records->ref(offset);
-  while (ref.size() > block_size()) {
-    ArrayRef<Record> block = ref.ref(0, block_size());
-    if (!root_->adjust(error, &block)) {
+  return adjust(error, records->ref(offset));
+}
+
+bool Expression::adjust(Error *error, ArrayRef<Record> records) {
+  while (records.size() > block_size_) {
+    if (!root_->adjust(error, records.ref(0, block_size_))) {
       return false;
     }
-    ref = ref.ref(block_size());
+    records = records.ref(block_size_);
   }
-  return root_->adjust(error, &ref);
+  return root_->adjust(error, records);
 }
 
 template <typename T>
 bool Expression::evaluate(Error *error,
-                          const ArrayRef<Record> &records,
+                          ArrayCRef<Record> records,
                           Array<T> *results) {
-  if (TypeTraits<T>::data_type() != data_type()) {
-    GRNXX_ERROR_SET(error, INVALID_ARGUMENT, "Invalid data type");
-    return false;
-  }
   if (!results->resize(error, records.size())) {
     return false;
   }
-  ArrayRef<T> ref = *results;
-  return evaluate(error, records, &ref);
-}
-
-template bool Expression::evaluate(Error *error,
-                                   const ArrayRef<Record> &records,
-                                   Array<Bool> *results);
-template bool Expression::evaluate(Error *error,
-                                   const ArrayRef<Record> &records,
-                                   Array<Int> *results);
-template bool Expression::evaluate(Error *error,
-                                   const ArrayRef<Record> &records,
-                                   Array<Float> *results);
-template bool Expression::evaluate(Error *error,
-                                   const ArrayRef<Record> &records,
-                                   Array<Time> *results);
-template bool Expression::evaluate(Error *error,
-                                   const ArrayRef<Record> &records,
-                                   Array<GeoPoint> *results);
-template bool Expression::evaluate(Error *error,
-                                   const ArrayRef<Record> &records,
-                                   Array<Text> *results);
+  return evaluate(error, records, results->ref());
+}
+
+#define GRNXX_INSTANTIATE_EXPRESSION_EVALUATE(type) \
+  template bool Expression::evaluate(Error *error, \
+                                     ArrayCRef<Record> records, \
+                                     Array<type> *results)
+GRNXX_INSTANTIATE_EXPRESSION_EVALUATE(Bool);
+GRNXX_INSTANTIATE_EXPRESSION_EVALUATE(Int);
+GRNXX_INSTANTIATE_EXPRESSION_EVALUATE(Float);
+GRNXX_INSTANTIATE_EXPRESSION_EVALUATE(Time);
+GRNXX_INSTANTIATE_EXPRESSION_EVALUATE(GeoPoint);
+GRNXX_INSTANTIATE_EXPRESSION_EVALUATE(Text);
+#undef GRNXX_INSTANTIATE_EXPRESSION_EVALUATE
 
 template <typename T>
 bool Expression::evaluate(Error *error,
-                          const ArrayRef<Record> &records,
-                          ArrayRef<T> *results) {
+                          ArrayCRef<Record> records,
+                          ArrayRef<T> results) {
   if (TypeTraits<T>::data_type() != data_type()) {
     GRNXX_ERROR_SET(error, INVALID_ARGUMENT, "Invalid data type");
     return false;
   }
-  if (records.size() != results->size()) {
+  if (records.size() != results.size()) {
     GRNXX_ERROR_SET(error, INVALID_ARGUMENT, "Size conflict: "
                     "#records = %" PRIi64 ", #results = %" PRIi64,
-                    records.size(), results->size());
+                    records.size(), results.size());
     return false;
   }
-  ArrayRef<Record> input = records;
-  ArrayRef<T> output = *results;
-  while (input.size() > block_size()) {
-    ArrayRef<Record> ref = input.ref(0, block_size());
-    if (!evaluate_block(error, ref, &output)) {
+  auto typed_root = static_cast<TypedNode<T> *>(root_.get());
+  while (records.size() > block_size_) {
+    ArrayCRef<Record> input = records.ref(0, block_size_);
+    ArrayRef<T> output = results.ref(0, block_size_);
+    if (!typed_root->evaluate(error, input, output)) {
       return false;
     }
-    input = input.ref(block_size());
-    output = output.ref(block_size());
+    records = records.ref(block_size_);
+    results = results.ref(block_size_);
   }
-  return evaluate_block(error, input, &output);
+  return typed_root->evaluate(error, records, results);
 }
 
 unique_ptr<Expression> Expression::create(Error *error,
                                           const Table *table,
-                                          unique_ptr<ExpressionNode> &&root) {
+                                          unique_ptr<ExpressionNode> &&root,
+                                          const ExpressionOptions &options) {
+  if (options.block_size <= 0) {
+    GRNXX_ERROR_SET(error, INVALID_ARGUMENT,
+                    "Invalid argument: block_size = %" PRIi64,
+                    options.block_size);
+    return nullptr;
+  }
   unique_ptr<Expression> expression(
-      new (nothrow) Expression(table, std::move(root)));
+      new (nothrow) Expression(table, std::move(root), options.block_size));
   if (!expression) {
     GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
     return nullptr;
@@ -851,23 +2308,12 @@ unique_ptr<Expression> Expression::create(Error *error,
   return expression;
 }
 
-Expression::Expression(const Table *table, unique_ptr<ExpressionNode> &&root)
+Expression::Expression(const Table *table,
+                       unique_ptr<ExpressionNode> &&root,
+                       Int block_size)
     : table_(table),
-      root_(std::move(root)) {}
-
-template <typename T>
-bool Expression::evaluate_block(Error *error,
-                                const ArrayRef<Record> &records,
-                                ArrayRef<T> *results) {
-  Node<T> *node = static_cast<Node<T> *>(root_.get());
-  if (!node->evaluate(error, records)) {
-    return false;
-  }
-  for (Int i = 0; i < records.size(); ++i) {
-    results->set(i, node->get(i));
-  }
-  return true;
-}
+      root_(std::move(root)),
+      block_size_(block_size) {}
 
 // -- ExpressionBuilder --
 
@@ -889,96 +2335,22 @@ bool ExpressionBuilder::push_datum(Error *error, const Datum &datum) {
   if (!stack_.reserve(error, stack_.size() + 1)) {
     return false;
   }
-  unique_ptr<ExpressionNode> node;
-  switch (datum.type()) {
-    case BOOL_DATA: {
-      node.reset(new (nothrow) DatumNode<Bool>(datum.force_bool()));
-      break;
-    }
-    case INT_DATA: {
-      node.reset(new (nothrow) DatumNode<Int>(datum.force_int()));
-      break;
-    }
-    case FLOAT_DATA: {
-      node.reset(new (nothrow) DatumNode<Float>(datum.force_float()));
-      break;
-    }
-    case TIME_DATA: {
-      node.reset(new (nothrow) DatumNode<Time>(datum.force_time()));
-      break;
-    }
-    case GEO_POINT_DATA: {
-      node.reset(new (nothrow) DatumNode<GeoPoint>(datum.force_geo_point()));
-      break;
-    }
-    case TEXT_DATA: {
-      node.reset(new (nothrow) DatumNode<Text>(datum.force_text()));
-      break;
-    }
-    default: {
-      // TODO: Other types are not supported yet.
-      GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not supported yet");
-      return false;
-    }
-  }
+  unique_ptr<Node> node = create_datum_node(error, datum);
   if (!node) {
-    GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
     return false;
   }
   // This push_back() must not fail because a space is already reserved.
-  stack_.push_back(nullptr, std::move(node));
-  return true;
-}
-
-bool ExpressionBuilder::push_column(Error *error, String name) {
-  // Reserve a space for a new node.
-  if (!stack_.reserve(error, stack_.size() + 1)) {
-    return false;
-  }
-  unique_ptr<ExpressionNode> node;
-  if (name == "_id") {
-    node.reset(new (nothrow) RowIDNode());
-  } else if (name == "_score") {
-    node.reset(new (nothrow) ScoreNode());
-  } else {
-    Column *column = table_->find_column(error, name);
-    if (!column) {
-      return false;
-    }
-    switch (column->data_type()) {
-      case BOOL_DATA: {
-        node.reset(new (nothrow) ColumnNode<Bool>(column));
-        break;
-      }
-      case INT_DATA: {
-        node.reset(new (nothrow) ColumnNode<Int>(column));
-        break;
-      }
-      case FLOAT_DATA: {
-        node.reset(new (nothrow) ColumnNode<Float>(column));
-        break;
-      }
-      case TIME_DATA: {
-        node.reset(new (nothrow) ColumnNode<Time>(column));
-        break;
-      }
-      case GEO_POINT_DATA: {
-        node.reset(new (nothrow) ColumnNode<GeoPoint>(column));
-        break;
-      }
-      case TEXT_DATA: {
-        node.reset(new (nothrow) ColumnNode<Text>(column));
-        break;
-      }
-      default: {
-        // TODO: Other types are not supported yet.
-        GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not supported yet");
-        return false;
-      }
-    }
+  stack_.push_back(nullptr, std::move(node));
+  return true;
+}
+
+bool ExpressionBuilder::push_column(Error *error, String name) {
+  // Reserve a space for a new node.
+  if (!stack_.reserve(error, stack_.size() + 1)) {
+    return false;
   }
+  unique_ptr<ExpressionNode> node = create_column_node(error, name);
   if (!node) {
-    GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
     return false;
   }
   // This push_back() must not fail because a space is already reserved.
@@ -989,6 +2361,8 @@ bool ExpressionBuilder::push_column(Error *error, String name) {
 bool ExpressionBuilder::push_operator(Error *error,
                                       OperatorType operator_type) {
   switch (operator_type) {
+    case LOGICAL_NOT_OPERATOR:
+    case BITWISE_NOT_OPERATOR:
     case POSITIVE_OPERATOR:
     case NEGATIVE_OPERATOR:
     case TO_INT_OPERATOR:
@@ -1008,7 +2382,9 @@ bool ExpressionBuilder::push_operator(Error *error,
     case BITWISE_XOR_OPERATOR:
     case PLUS_OPERATOR:
     case MINUS_OPERATOR:
-    case MULTIPLICATION_OPERATOR: {
+    case MULTIPLICATION_OPERATOR:
+    case DIVISION_OPERATOR:
+    case MODULUS_OPERATOR: {
       return push_binary_operator(error, operator_type);
     }
     default: {
@@ -1023,17 +2399,106 @@ void ExpressionBuilder::clear() {
   stack_.clear();
 }
 
-unique_ptr<Expression> ExpressionBuilder::release(Error *error) {
+unique_ptr<Expression> ExpressionBuilder::release(
+    Error *error,
+    const ExpressionOptions &options) {
   if (stack_.size() != 1) {
     GRNXX_ERROR_SET(error, INVALID_ARGUMENT, "Incomplete expression");
     return nullptr;
   }
-  unique_ptr<ExpressionNode> root_node = std::move(stack_[0]);
+  unique_ptr<ExpressionNode> root = std::move(stack_[0]);
   stack_.clear();
-  return Expression::create(error, table_, std::move(root_node));
+  return Expression::create(error, table_, std::move(root), options);
+}
+
+ExpressionBuilder::ExpressionBuilder(const Table *table)
+    : table_(table),
+      stack_() {}
+
+unique_ptr<ExpressionNode> ExpressionBuilder::create_datum_node(
+    Error *error,
+    const Datum &datum) {
+  switch (datum.type()) {
+    case BOOL_DATA: {
+      return DatumNode<Bool>::create(error, datum.force_bool());
+    }
+    case INT_DATA: {
+      return DatumNode<Int>::create(error, datum.force_int());
+    }
+    case FLOAT_DATA: {
+      return DatumNode<Float>::create(error, datum.force_float());
+    }
+    case TIME_DATA: {
+      return DatumNode<Time>::create(error, datum.force_time());
+    }
+    case GEO_POINT_DATA: {
+      return DatumNode<GeoPoint>::create(error, datum.force_geo_point());
+    }
+    case TEXT_DATA: {
+      return DatumNode<Text>::create(error, datum.force_text());
+    }
+    default: {
+      // TODO: Other types are not supported yet.
+      GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not supported yet");
+      return nullptr;
+    }
+  }
 }
 
-ExpressionBuilder::ExpressionBuilder(const Table *table) : table_(table) {}
+unique_ptr<ExpressionNode> ExpressionBuilder::create_column_node(
+    Error *error,
+    String name) {
+  if (name == "_id") {
+    // Create a node associated with row IDs of records.
+    unique_ptr<Node> node(new (nothrow) RowIDNode());
+    if (!node) {
+      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
+      return nullptr;
+    }
+    return node;
+  }
+
+  if (name == "_score") {
+    // Create a node associated with scores of records.
+    unique_ptr<Node> node(new (nothrow) ScoreNode());
+    if (!node) {
+      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
+      return nullptr;
+    }
+    return node;
+  }
+
+  // Create a node associated with a column.
+  Column *column = table_->find_column(error, name);
+  if (!column) {
+    return nullptr;
+  }
+  switch (column->data_type()) {
+    case BOOL_DATA: {
+      return ColumnNode<Bool>::create(error, column);
+    }
+    case INT_DATA: {
+      return ColumnNode<Int>::create(error, column);
+    }
+    case FLOAT_DATA: {
+      return ColumnNode<Float>::create(error, column);
+    }
+    case TIME_DATA: {
+      return ColumnNode<Time>::create(error, column);
+    }
+    case GEO_POINT_DATA: {
+      return ColumnNode<GeoPoint>::create(error, column);
+    }
+    case TEXT_DATA: {
+      return ColumnNode<Text>::create(error, column);
+    }
+    default: {
+      // TODO: Other types are not supported yet.
+      GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not supported yet");
+      return nullptr;
+    }
+  }
+}
 
 bool ExpressionBuilder::push_unary_operator(Error *error,
                                             OperatorType operator_type) {
@@ -1041,400 +2506,341 @@ bool ExpressionBuilder::push_unary_operator(Error *error,
     GRNXX_ERROR_SET(error, INVALID_OPERAND, "Not enough operands");
     return false;
   }
+  unique_ptr<Node> arg = std::move(stack_[stack_.size() - 1]);
+  stack_.resize(nullptr, stack_.size() - 1);
+  unique_ptr<Node> node =
+      create_unary_node(error, operator_type, std::move(arg));
+  if (!node) {
+    return false;
+  }
+  stack_.push_back(error, std::move(node));
+  return true;
+}
+
+bool ExpressionBuilder::push_binary_operator(Error *error,
+                                             OperatorType operator_type) {
+  if (stack_.size() < 2) {
+    GRNXX_ERROR_SET(error, INVALID_OPERAND, "Not enough operands");
+    return false;
+  }
+  unique_ptr<Node> arg1 = std::move(stack_[stack_.size() - 2]);
+  unique_ptr<Node> arg2 = std::move(stack_[stack_.size() - 1]);
+  stack_.resize(nullptr, stack_.size() - 2);
+  unique_ptr<Node> node = create_binary_node(error, operator_type,
+                                             std::move(arg1), std::move(arg2));
+  if (!node) {
+    return false;
+  }
+  stack_.push_back(nullptr, std::move(node));
+  return true;
+}
+
+unique_ptr<ExpressionNode> ExpressionBuilder::create_unary_node(
+    Error *error,
+    OperatorType operator_type,
+    unique_ptr<ExpressionNode> &&arg) {
   switch (operator_type) {
+    case LOGICAL_NOT_OPERATOR: {
+      if (arg->data_type() != BOOL_DATA) {
+        GRNXX_ERROR_SET(error, INVALID_OPERAND, "Invalid data type");
+        return nullptr;
+      }
+      return LogicalNotNode::create(error, std::move(arg));
+    }
+    case BITWISE_NOT_OPERATOR: {
+      switch (arg->data_type()) {
+        case BOOL_DATA: {
+          return BitwiseNotNode<Bool>::create(error, std::move(arg));
+        }
+        case FLOAT_DATA: {
+          return BitwiseNotNode<Int>::create(error, std::move(arg));
+        }
+        default: {
+          GRNXX_ERROR_SET(error, INVALID_OPERAND, "Invalid data type");
+          return nullptr;
+        }
+      }
+    }
     case POSITIVE_OPERATOR: {
-      return push_positive_operator(error);
+      if ((arg->data_type() != INT_DATA) && (arg->data_type() != FLOAT_DATA)) {
+        GRNXX_ERROR_SET(error, INVALID_OPERAND, "Invalid data type");
+        return nullptr;
+      }
+      // Positive operator does nothing.
+      return std::move(arg);
     }
     case NEGATIVE_OPERATOR: {
-      return push_negative_operator(error);
+      switch (arg->data_type()) {
+        case INT_DATA: {
+          return NegativeNode<Int>::create(error, std::move(arg));
+        }
+        case FLOAT_DATA: {
+          return NegativeNode<Float>::create(error, std::move(arg));
+        }
+        default: {
+          GRNXX_ERROR_SET(error, INVALID_OPERAND, "Invalid data type");
+          return nullptr;
+        }
+      }
     }
     case TO_INT_OPERATOR: {
-      return push_to_int_operator(error);
+      if (arg->data_type() != FLOAT_DATA) {
+        GRNXX_ERROR_SET(error, INVALID_OPERAND, "Invalid data type");
+        return nullptr;
+      }
+      return ToIntNode::create(error, std::move(arg));
     }
     case TO_FLOAT_OPERATOR: {
-      return push_to_float_operator(error);
+      if (arg->data_type() != INT_DATA) {
+        GRNXX_ERROR_SET(error, INVALID_OPERAND, "Invalid data type");
+        return nullptr;
+      }
+      return ToFloatNode::create(error, std::move(arg));
     }
     default: {
       // TODO: Not supported yet.
       GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not supported yet");
-      return false;
+      return nullptr;
     }
   }
 }
 
-bool ExpressionBuilder::push_binary_operator(Error *error,
-                                             OperatorType operator_type) {
-  if (stack_.size() < 2) {
-    GRNXX_ERROR_SET(error, INVALID_OPERAND, "Not enough operands");
-    return false;
-  }
+unique_ptr<ExpressionNode> ExpressionBuilder::create_binary_node(
+    Error *error,
+    OperatorType operator_type,
+    unique_ptr<ExpressionNode> &&arg1,
+    unique_ptr<ExpressionNode> &&arg2) {
   switch (operator_type) {
     case LOGICAL_AND_OPERATOR: {
-      return push_logical_and_operator(error);
+      if ((arg1->data_type() != BOOL_DATA) ||
+          (arg2->data_type() != BOOL_DATA)) {
+        GRNXX_ERROR_SET(error, INVALID_OPERAND, "Invalid data type");
+        return nullptr;
+      }
+      return LogicalAndNode::create(error, std::move(arg1), std::move(arg2));
     }
     case LOGICAL_OR_OPERATOR: {
-      return push_logical_or_operator(error);
+      if ((arg1->data_type() != BOOL_DATA) ||
+          (arg2->data_type() != BOOL_DATA)) {
+        GRNXX_ERROR_SET(error, INVALID_OPERAND, "Invalid data type");
+        return nullptr;
+      }
+      return LogicalOrNode::create(error, std::move(arg1), std::move(arg2));
     }
     case EQUAL_OPERATOR: {
-      return push_equality_operator<Equal>(error);
+      return create_equality_test_node<Equal>(
+          error, std::move(arg1), std::move(arg2));
     }
     case NOT_EQUAL_OPERATOR: {
-      return push_equality_operator<NotEqual>(error);
+      return create_equality_test_node<NotEqual>(
+          error, std::move(arg1), std::move(arg2));
     }
     case LESS_OPERATOR: {
-      return push_comparison_operator<Less>(error);
+      return create_comparison_node<Less>(
+          error, std::move(arg1), std::move(arg2));
     }
     case LESS_EQUAL_OPERATOR: {
-      return push_comparison_operator<LessEqual>(error);
+      return create_comparison_node<LessEqual>(
+          error, std::move(arg1), std::move(arg2));
     }
     case GREATER_OPERATOR: {
-      return push_comparison_operator<Greater>(error);
+      return create_comparison_node<Greater>(
+          error, std::move(arg1), std::move(arg2));
     }
     case GREATER_EQUAL_OPERATOR: {
-      return push_comparison_operator<GreaterEqual>(error);
-    }
-    case BITWISE_AND_OPERATOR: {
-      return push_bitwise_operator<BitwiseAnd>(error);
-    }
-    case BITWISE_OR_OPERATOR: {
-      return push_bitwise_operator<BitwiseOr>(error);
+      return create_comparison_node<GreaterEqual>(
+          error, std::move(arg1), std::move(arg2));
     }
+    case BITWISE_AND_OPERATOR:
+    case BITWISE_OR_OPERATOR:
     case BITWISE_XOR_OPERATOR: {
-      return push_bitwise_operator<BitwiseXor>(error);
-    }
-    case PLUS_OPERATOR: {
-      return push_arithmetic_operator<Plus>(error);
+      switch (arg1->data_type()) {
+        case BOOL_DATA: {
+          return create_bitwise_node<Bool>(
+              error, operator_type, std::move(arg1), std::move(arg2));
+        }
+        case INT_DATA: {
+          return create_bitwise_node<Int>(
+              error, operator_type, std::move(arg1), std::move(arg2));
+        }
+        default: {
+          GRNXX_ERROR_SET(error, INVALID_OPERAND, "Invalid data type");
+          return nullptr;
+        }
+      }
     }
-    case MINUS_OPERATOR: {
-      return push_arithmetic_operator<Minus>(error);
+    case PLUS_OPERATOR:
+    case MINUS_OPERATOR:
+    case MULTIPLICATION_OPERATOR:
+    case DIVISION_OPERATOR: {
+      switch (arg1->data_type()) {
+        case INT_DATA: {
+          return create_arithmetic_node<Int>(
+              error, operator_type, std::move(arg1), std::move(arg2));
+        }
+        case FLOAT_DATA: {
+          return create_arithmetic_node<Float>(
+              error, operator_type, std::move(arg1), std::move(arg2));
+        }
+        default: {
+          GRNXX_ERROR_SET(error, INVALID_OPERAND, "Invalid data type");
+          return nullptr;
+        }
+      }
     }
-    case MULTIPLICATION_OPERATOR: {
-      return push_arithmetic_operator<Multiplication>(error);
+    case MODULUS_OPERATOR: {
+      if ((arg1->data_type() != INT_DATA) ||
+          (arg2->data_type() != INT_DATA)) {
+        GRNXX_ERROR_SET(error, INVALID_OPERAND, "Invalid data type");
+        return nullptr;
+      }
+      return ModulusNode<Int>::create(error, std::move(arg1), std::move(arg2));
     }
     default: {
       // TODO: Not supported yet.
       GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not supported yet");
-      return false;
-    }
-  }
-}
-
-bool ExpressionBuilder::push_positive_operator(Error *error) {
-  auto &arg = stack_[stack_.size() - 1];
-  switch (arg->data_type()) {
-    case INT_DATA:
-    case FLOAT_DATA: {
-      // Nothing to do because this operator does nothing.
-      return true;
-    }
-    default: {
-      GRNXX_ERROR_SET(error, INVALID_OPERAND, "Invalid data type");
-      return false;
-    }
-  }
-}
-
-bool ExpressionBuilder::push_negative_operator(Error *error) {
-  unique_ptr<ExpressionNode> node;
-  auto &arg = stack_[stack_.size() - 1];
-  switch (arg->data_type()) {
-    case INT_DATA: {
-      Negative::Functor<Int> functor;
-      node.reset(
-          new (nothrow) UnaryNode<decltype(functor)>(functor, std::move(arg)));
-      break;
-    }
-    case FLOAT_DATA: {
-      Negative::Functor<Float> functor;
-      node.reset(
-          new (nothrow) UnaryNode<decltype(functor)>(functor, std::move(arg)));
-      break;
+      return nullptr;
     }
-    default: {
-      GRNXX_ERROR_SET(error, INVALID_OPERAND, "Invalid data type");
-      return false;
-    }
-  }
-  if (!node) {
-    GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    return false;
-  }
-  stack_.back() = std::move(node);
-  return true;
-}
-
-bool ExpressionBuilder::push_to_int_operator(Error *error) {
-  unique_ptr<ExpressionNode> node;
-  auto &arg = stack_[stack_.size() - 1];
-  switch (arg->data_type()) {
-    case INT_DATA: {
-      // Nothing to do because this operator does nothing.
-      return true;
-    }
-    case FLOAT_DATA: {
-      Typecast<Int>::Functor<Float> functor;
-      node.reset(
-          new (nothrow) UnaryNode<decltype(functor)>(functor, std::move(arg)));
-      break;
-    }
-    default: {
-      GRNXX_ERROR_SET(error, INVALID_OPERAND, "Invalid data type");
-      return false;
-    }
-  }
-  if (!node) {
-    GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    return false;
-  }
-  stack_.back() = std::move(node);
-  return true;
-}
-
-bool ExpressionBuilder::push_to_float_operator(Error *error) {
-  unique_ptr<ExpressionNode> node;
-  auto &arg = stack_[stack_.size() - 1];
-  switch (arg->data_type()) {
-    case INT_DATA: {
-      Typecast<Float>::Functor<Int> functor;
-      node.reset(
-          new (nothrow) UnaryNode<decltype(functor)>(functor, std::move(arg)));
-      break;
-    }
-    case FLOAT_DATA: {
-      // Nothing to do because this operator does nothing.
-      return true;
-    }
-    default: {
-      GRNXX_ERROR_SET(error, INVALID_OPERAND, "Invalid data type");
-      return false;
-    }
-  }
-  if (!node) {
-    GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    return false;
-  }
-  stack_.back() = std::move(node);
-  return true;
-}
-
-bool ExpressionBuilder::push_logical_and_operator(Error *error) {
-  auto &lhs = stack_[stack_.size() - 2];
-  auto &rhs = stack_[stack_.size() - 1];
-  if ((lhs->data_type() != BOOL_DATA) ||
-      (rhs->data_type() != BOOL_DATA)) {
-    GRNXX_ERROR_SET(error, INVALID_OPERAND, "Invalid data type");
-    return false;
-  }
-  unique_ptr<ExpressionNode> node(
-      new (nothrow) LogicalAndNode(std::move(lhs), std::move(rhs)));
-  if (!node) {
-    GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    return false;
-  }
-  stack_.pop_back();
-  stack_.back() = std::move(node);
-  return true;
-}
-
-bool ExpressionBuilder::push_logical_or_operator(Error *error) {
-  auto &lhs = stack_[stack_.size() - 2];
-  auto &rhs = stack_[stack_.size() - 1];
-  if ((lhs->data_type() != BOOL_DATA) ||
-      (rhs->data_type() != BOOL_DATA)) {
-    GRNXX_ERROR_SET(error, INVALID_OPERAND, "Invalid data type");
-    return false;
   }
-  unique_ptr<ExpressionNode> node(
-      new (nothrow) LogicalOrNode(std::move(lhs), std::move(rhs)));
-  if (!node) {
-    GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    return false;
-  }
-  stack_.pop_back();
-  stack_.back() = std::move(node);
-  return true;
 }
 
 template <typename T>
-bool ExpressionBuilder::push_equality_operator(Error *error) {
-  auto &lhs = stack_[stack_.size() - 2];
-  auto &rhs = stack_[stack_.size() - 1];
-  if (lhs->data_type() != rhs->data_type()) {
+unique_ptr<ExpressionNode> ExpressionBuilder::create_equality_test_node(
+    Error *error,
+    unique_ptr<ExpressionNode> &&arg1,
+    unique_ptr<ExpressionNode> &&arg2) {
+  if (arg1->data_type() != arg2->data_type()) {
     GRNXX_ERROR_SET(error, INVALID_OPERAND, "Data type conflict");
-    return false;
+    return nullptr;
   }
-  unique_ptr<ExpressionNode> node;
-  switch (lhs->data_type()) {
+  switch (arg1->data_type()) {
     case BOOL_DATA: {
-      typename T::template Functor<Bool> functor;
-      node.reset(new (nothrow) BinaryNode<decltype(functor)>(
-          functor, std::move(lhs), std::move(rhs)));
-      break;
+      return ComparisonNode<typename T:: template Comparer<Bool>>::create(
+          error, std::move(arg1), std::move(arg2));
     }
     case INT_DATA: {
-      typename T::template Functor<Int> functor;
-      node.reset(new (nothrow) BinaryNode<decltype(functor)>(
-          functor, std::move(lhs), std::move(rhs)));
-      break;
+      return ComparisonNode<typename T:: template Comparer<Int>>::create(
+          error, std::move(arg1), std::move(arg2));
     }
     case FLOAT_DATA: {
-      typename T::template Functor<Float> functor;
-      node.reset(new (nothrow) BinaryNode<decltype(functor)>(
-          functor, std::move(lhs), std::move(rhs)));
-      break;
+      return ComparisonNode<typename T:: template Comparer<Float>>::create(
+          error, std::move(arg1), std::move(arg2));
     }
     case TIME_DATA: {
-      typename T::template Functor<Time> functor;
-      node.reset(new (nothrow) BinaryNode<decltype(functor)>(
-          functor, std::move(lhs), std::move(rhs)));
-      break;
+      return ComparisonNode<typename T:: template Comparer<Time>>::create(
+          error, std::move(arg1), std::move(arg2));
     }
     case GEO_POINT_DATA: {
-      typename T::template Functor<GeoPoint> functor;
-      node.reset(new (nothrow) BinaryNode<decltype(functor)>(
-          functor, std::move(lhs), std::move(rhs)));
-      break;
+      return ComparisonNode<typename T:: template Comparer<GeoPoint>>::create(
+          error, std::move(arg1), std::move(arg2));
     }
     case TEXT_DATA: {
-      typename T::template Functor<Text> functor;
-      node.reset(new (nothrow) BinaryNode<decltype(functor)>(
-          functor, std::move(lhs), std::move(rhs)));
-      break;
+      return ComparisonNode<typename T:: template Comparer<Text>>::create(
+          error, std::move(arg1), std::move(arg2));
     }
     // TODO: Support other types.
     default: {
       GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not supported yet");
-      return false;
+      return nullptr;
     }
   }
-  if (!node) {
-    GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    return false;
-  }
-  stack_.pop_back();
-  stack_.back() = std::move(node);
-  return true;
 }
 
 template <typename T>
-bool ExpressionBuilder::push_comparison_operator(Error *error) {
-  auto &lhs = stack_[stack_.size() - 2];
-  auto &rhs = stack_[stack_.size() - 1];
-  if (lhs->data_type() != rhs->data_type()) {
+unique_ptr<ExpressionNode> ExpressionBuilder::create_comparison_node(
+    Error *error,
+    unique_ptr<ExpressionNode> &&arg1,
+    unique_ptr<ExpressionNode> &&arg2) {
+  if (arg1->data_type() != arg2->data_type()) {
     GRNXX_ERROR_SET(error, INVALID_OPERAND, "Data type conflict");
-    return false;
+    return nullptr;
   }
-  unique_ptr<ExpressionNode> node;
-  switch (lhs->data_type()) {
+  switch (arg1->data_type()) {
     case INT_DATA: {
-      typename T::template Functor<Int> functor;
-      node.reset(new (nothrow) BinaryNode<decltype(functor)>(
-          functor, std::move(lhs), std::move(rhs)));
-      break;
+      return ComparisonNode<typename T:: template Comparer<Int>>::create(
+          error, std::move(arg1), std::move(arg2));
     }
     case FLOAT_DATA: {
-      typename T::template Functor<Float> functor;
-      node.reset(new (nothrow) BinaryNode<decltype(functor)>(
-          functor, std::move(lhs), std::move(rhs)));
-      break;
+      return ComparisonNode<typename T:: template Comparer<Float>>::create(
+          error, std::move(arg1), std::move(arg2));
     }
     case TIME_DATA: {
-      typename T::template Functor<Time> functor;
-      node.reset(new (nothrow) BinaryNode<decltype(functor)>(
-          functor, std::move(lhs), std::move(rhs)));
-      break;
+      return ComparisonNode<typename T:: template Comparer<Time>>::create(
+          error, std::move(arg1), std::move(arg2));
     }
     case TEXT_DATA: {
-      typename T::template Functor<Text> functor;
-      node.reset(new (nothrow) BinaryNode<decltype(functor)>(
-          functor, std::move(lhs), std::move(rhs)));
-      break;
+      return ComparisonNode<typename T:: template Comparer<Text>>::create(
+          error, std::move(arg1), std::move(arg2));
     }
-    // TODO: Support other comparable types.
     default: {
-      GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not supported yet");
-      return false;
+      GRNXX_ERROR_SET(error, INVALID_OPERAND, "Invalid data type");
+      return nullptr;
     }
   }
-  if (!node) {
-    GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    return false;
-  }
-  stack_.pop_back();
-  stack_.back() = std::move(node);
-  return true;
 }
 
 template <typename T>
-bool ExpressionBuilder::push_bitwise_operator(Error *error) {
-  auto &lhs = stack_[stack_.size() - 2];
-  auto &rhs = stack_[stack_.size() - 1];
-  if (lhs->data_type() != rhs->data_type()) {
+unique_ptr<ExpressionNode> ExpressionBuilder::create_bitwise_node(
+    Error *error,
+    OperatorType operator_type,
+    unique_ptr<ExpressionNode> &&arg1,
+    unique_ptr<ExpressionNode> &&arg2) {
+  if (arg1->data_type() != arg2->data_type()) {
     GRNXX_ERROR_SET(error, INVALID_OPERAND, "Data type conflict");
-    return false;
+    return nullptr;
   }
-  unique_ptr<ExpressionNode> node;
-  switch (lhs->data_type()) {
-    case BOOL_DATA: {
-      typename T::template Functor<Bool> functor;
-      node.reset(new (nothrow) BinaryNode<decltype(functor)>(
-          functor, std::move(lhs), std::move(rhs)));
-      break;
+  switch (operator_type) {
+    case BITWISE_AND_OPERATOR: {
+      return BitwiseAndNode<T>::create(
+          error, std::move(arg1), std::move(arg2));
     }
-    case INT_DATA: {
-      typename T::template Functor<Int> functor;
-      node.reset(new (nothrow) BinaryNode<decltype(functor)>(
-          functor, std::move(lhs), std::move(rhs)));
-      break;
+    case BITWISE_OR_OPERATOR: {
+      return BitwiseOrNode<T>::create(
+          error, std::move(arg1), std::move(arg2));
+    }
+    case BITWISE_XOR_OPERATOR: {
+      return BitwiseXorNode<T>::create(
+          error, std::move(arg1), std::move(arg2));
     }
     default: {
-      GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not supported yet");
-      return false;
+      GRNXX_ERROR_SET(error, INVALID_ARGUMENT, "Invalid operator");
+      return nullptr;
     }
   }
-  if (!node) {
-    GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    return false;
-  }
-  stack_.pop_back();
-  stack_.back() = std::move(node);
-  return true;
 }
 
 template <typename T>
-bool ExpressionBuilder::push_arithmetic_operator(Error *error) {
-  auto &lhs = stack_[stack_.size() - 2];
-  auto &rhs = stack_[stack_.size() - 1];
-  if (lhs->data_type() != rhs->data_type()) {
-    GRNXX_ERROR_SET(error, INVALID_OPERAND, "Type conflict");
-    return false;
+unique_ptr<ExpressionNode> ExpressionBuilder::create_arithmetic_node(
+    Error *error,
+    OperatorType operator_type,
+    unique_ptr<ExpressionNode> &&arg1,
+    unique_ptr<ExpressionNode> &&arg2) {
+  if (arg1->data_type() != arg2->data_type()) {
+    GRNXX_ERROR_SET(error, INVALID_OPERAND, "Data type conflict");
+    return nullptr;
   }
-  unique_ptr<ExpressionNode> node;
-  switch (lhs->data_type()) {
-    case INT_DATA: {
-      typename T::template Functor<Int> functor;
-      node.reset(new (nothrow) BinaryNode<decltype(functor)>(
-          functor, std::move(lhs), std::move(rhs)));
-      break;
+  switch (operator_type) {
+    case PLUS_OPERATOR: {
+      return PlusNode<T>::create(
+          error, std::move(arg1), std::move(arg2));
     }
-    case FLOAT_DATA: {
-      typename T::template Functor<Float> functor;
-      node.reset(new (nothrow) BinaryNode<decltype(functor)>(
-          functor, std::move(lhs), std::move(rhs)));
-      break;
+    case MINUS_OPERATOR: {
+      return MinusNode<T>::create(
+          error, std::move(arg1), std::move(arg2));
+    }
+    case MULTIPLICATION_OPERATOR: {
+      return MultiplicationNode<T>::create(
+          error, std::move(arg1), std::move(arg2));
+    }
+    case DIVISION_OPERATOR: {
+      return DivisionNode<T>::create(
+          error, std::move(arg1), std::move(arg2));
     }
     default: {
-      GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not supported yet");
-      return false;
+      GRNXX_ERROR_SET(error, INVALID_OPERAND, "Invalid data type");
+      return nullptr;
     }
   }
-  if (!node) {
-    GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    return false;
-  }
-  stack_.pop_back();
-  stack_.back() = std::move(node);
-  return true;
 }
 
 }  // namespace grnxx

  Deleted: lib/grnxx/expression2.cpp (+0 -2190) 100644
===================================================================
--- lib/grnxx/expression2.cpp    2014-08-12 16:14:13 +0900 (6521bce)
+++ /dev/null
@@ -1,2190 +0,0 @@
-#include "grnxx/expression.hpp"
-
-#include "grnxx/column_impl.hpp"
-#include "grnxx/datum.hpp"
-#include "grnxx/error.hpp"
-#include "grnxx/table.hpp"
-
-#include <iostream>  // For debugging.
-
-namespace grnxx {
-namespace expression {
-
-// TODO: Only CONSTANT_NODE and VARIABLE_NODE are required?
-enum NodeType {
-  DATUM_NODE,
-  ROW_ID_NODE,
-  SCORE_NODE,
-  COLUMN_NODE,
-  OPERATOR_NODE
-};
-
-// -- Node --
-
-class Node {
- public:
-  Node() {}
-  virtual ~Node() {}
-
-  // Return the node type.
-  virtual NodeType node_type() const = 0;
-  // Return the result data type.
-  virtual DataType data_type() const = 0;
-
-  // Extract true records.
-  //
-  // Evaluates the expression for "input_records" and appends records
-  // whose evaluation results are true into "*output_records".
-  // "*output_records" is truncated to the number of true records.
-  //
-  // On success, returns true.
-  // On failure, returns false and stores error information into "*error" if
-  // "error" != nullptr.
-  virtual bool filter(Error *error,
-                      ArrayCRef<Record> input_records,
-                      ArrayRef<Record> *output_records) = 0;
-
-  // Adjust scores of records.
-  //
-  // Evaluates the expression for the given record set and replaces their
-  // scores with the evaluation results.
-  //
-  // Returns true on success.
-  // On failure, returns false and stores error information into "*error" if
-  // "error" != nullptr.
-  virtual bool adjust(Error *error, ArrayRef<Record> records) = 0;
-};
-
-// -- TypedNode --
-
-template <typename T>
-class TypedNode : public Node {
- public:
-  using Value = T;
-
-  TypedNode() : Node() {}
-  virtual ~TypedNode() {}
-
-  DataType data_type() const {
-    return TypeTraits<Value>::data_type();
-  }
-
-  bool filter(Error *error,
-              ArrayCRef<Record> input_records,
-              ArrayRef<Record> *output_records) {
-    // Other than TypedNode<Bool> don't support filter().
-    GRNXX_ERROR_SET(error, INVALID_OPERATION, "Invalid operation");
-    return false;
-  }
-
-  bool adjust(Error *error, ArrayRef<Record> records) {
-    // Other than TypedNode<Float> don't support adjust().
-    GRNXX_ERROR_SET(error, INVALID_OPERATION, "Invalid operation");
-    return false;
-  }
-
-  // Evaluate the expression subtree.
-  //
-  // The evaluation results are stored into "*results".
-  //
-  // On success, returns true.
-  // On failure, returns false and stores error information into "*error" if
-  // "error" != nullptr.
-  virtual bool evaluate(Error *error,
-                        ArrayCRef<Record> records,
-                        ArrayRef<Value> results) = 0;
-};
-
-template <>
-class TypedNode<Bool> : public Node {
- public:
-  using Value = Bool;
-
-  TypedNode() : Node() {}
-  virtual ~TypedNode() {}
-
-  DataType data_type() const {
-    return TypeTraits<Value>::data_type();
-  }
-
-  // Derived classes must override this member function.
-  virtual bool filter(Error *error,
-                      ArrayCRef<Record> input_records,
-                      ArrayRef<Record> *output_records) = 0;
-
-  bool adjust(Error *error, ArrayRef<Record> records) {
-    // Other than TypedNode<Float> don't support adjust().
-    GRNXX_ERROR_SET(error, INVALID_OPERATION, "Invalid operation");
-    return false;
-  }
-
-  virtual bool evaluate(Error *error,
-                        ArrayCRef<Record> records,
-                        ArrayRef<Value> results) = 0;
-};
-
-//template <>
-//bool TypedNode<Bool>::filter(Error *error,
-//                             ArrayCRef<Record> input_records,
-//                             ArrayRef<Record> *output_records) {
-//  // TODO: This implementation should be overridden by derived classes.
-//  Array<Bool> results;
-//  if (!results.resize(error, input_records.size())) {
-//    return false;
-//  }
-//  if (!evaluate(error, input_records, results)) {
-//    return false;
-//  }
-//  Int count = 0;
-//  for (Int i = 0; i < input_records.size(); ++i) {
-//    if (results[i]) {
-//      output_records->set(count, input_records.get(i));
-//      ++count;
-//    }
-//  }
-//  *output_records = output_records->ref(0, count);
-//  return true;
-//}
-
-template <>
-class TypedNode<Float> : public Node {
- public:
-  using Value = Float;
-
-  TypedNode() : Node() {}
-  virtual ~TypedNode() {}
-
-  DataType data_type() const {
-    return TypeTraits<Value>::data_type();
-  }
-
-  bool filter(Error *error,
-              ArrayCRef<Record> input_records,
-              ArrayRef<Record> *output_records) {
-    // Other than TypedNode<Bool> don't support filter().
-    GRNXX_ERROR_SET(error, INVALID_OPERATION, "Invalid operation");
-    return false;
-  }
-
-  // Derived classes must override this member function.
-  virtual bool adjust(Error *error, ArrayRef<Record> records) = 0;
-
-  virtual bool evaluate(Error *error,
-                        ArrayCRef<Record> records,
-                        ArrayRef<Value> results) = 0;
-};
-
-//template <>
-//bool TypedNode<Float>::adjust(Error *error, ArrayRef<Record> records) {
-//  // TODO: This implementation should be overridden by derived classes.
-//  Array<Float> scores;
-//  if (!scores.resize(error, records.size())) {
-//    return false;
-//  }
-//  if (!evaluate(error, records, scores)) {
-//    return false;
-//  }
-//  for (Int i = 0; i < records.size(); ++i) {
-//    records.set_score(i, scores[i]);
-//  }
-//  return true;
-//}
-
-// -- DatumNode --
-
-template <typename T>
-class DatumNode : public TypedNode<T> {
- public:
-  using Value = T;
-
-  static unique_ptr<DatumNode> create(Error *error, Value datum) {
-    unique_ptr<DatumNode> node(new (nothrow) DatumNode(datum));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  explicit DatumNode(Value datum)
-      : TypedNode<Value>(),
-        datum_(datum) {}
-
-  NodeType node_type() const {
-    return DATUM_NODE;
-  }
-
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results) {
-    for (Int i = 0; i < records.size(); ++i) {
-      results[i] = datum_;
-    }
-    return true;
-  }
-
- private:
-  T datum_;
-};
-
-template <>
-class DatumNode<Bool> : public TypedNode<Bool> {
- public:
-  using Value = Bool;
-
-  static unique_ptr<DatumNode> create(Error *error, Value datum) {
-    unique_ptr<DatumNode> node(new (nothrow) DatumNode(datum));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  explicit DatumNode(Value datum)
-      : TypedNode<Value>(),
-        datum_(datum) {}
-
-  NodeType node_type() const {
-    return DATUM_NODE;
-  }
-
-  bool filter(Error *error,
-              ArrayCRef<Record> input_records,
-              ArrayRef<Record> *output_records);
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results);
-
- private:
-  Value datum_;
-};
-
-bool DatumNode<Bool>::filter(Error *error,
-                             ArrayCRef<Record> input_records,
-                             ArrayRef<Record> *output_records) {
-  if (datum_) {
-    if (input_records != *output_records) {
-      for (Int i = 0; i < input_records.size(); ++i) {
-        output_records->set(i, input_records.get(i));
-      }
-    }
-  } else {
-    *output_records = output_records->ref(0, 0);
-  }
-  return true;
-}
-
-bool DatumNode<Bool>::evaluate(Error *error,
-                               ArrayCRef<Record> records,
-                               ArrayRef<Value> results) {
-  // TODO: Fill results per 64 bits.
-  for (Int i = 0; i < records.size(); ++i) {
-    results.set(i, datum_);
-  }
-  return true;
-}
-
-template <>
-class DatumNode<Float> : public TypedNode<Float> {
- public:
-  using Value = Float;
-
-  static unique_ptr<DatumNode> create(Error *error, Value datum) {
-    unique_ptr<DatumNode> node(new (nothrow) DatumNode(datum));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  explicit DatumNode(Value datum)
-      : TypedNode<Float>(),
-        datum_(datum) {}
-
-  NodeType node_type() const {
-    return DATUM_NODE;
-  }
-
-  bool adjust(Error *error, ArrayRef<Record> records) {
-    for (Int i = 0; i < records.size(); ++i) {
-      records.set_score(i, datum_);
-    }
-    return true;
-  }
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results) {
-    for (Int i = 0; i < records.size(); ++i) {
-      results[i] = datum_;
-    }
-    return true;
-  }
-
- private:
-  Float datum_;
-};
-
-template <>
-class DatumNode<Text> : public TypedNode<Text> {
- public:
-  using Value = Text;
-
-  static unique_ptr<DatumNode> create(Error *error, Value datum) try {
-    return unique_ptr<DatumNode>(new DatumNode(datum));
-  } catch (...) {
-    GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    return nullptr;
-  }
-
-  explicit DatumNode(Value datum)
-      : TypedNode<Value>(),
-        datum_(datum.data(), datum.size()) {}
-
-  NodeType node_type() const {
-    return DATUM_NODE;
-  }
-
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results) {
-    Text datum(datum_.data(), datum_.size());
-    for (Int i = 0; i < records.size(); ++i) {
-      results[i] = datum;
-    }
-    return true;
-  }
-
- private:
-  std::string datum_;
-};
-
-// -- RowIDNode --
-
-class RowIDNode : public TypedNode<Int> {
- public:
-  using Value = Int;
-
-  static unique_ptr<RowIDNode> create(Error *error, Value datum) {
-    unique_ptr<RowIDNode> node(new (nothrow) RowIDNode);
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  RowIDNode() : TypedNode<Value>() {}
-
-  NodeType node_type() const {
-    return ROW_ID_NODE;
-  }
-
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results) {
-    for (Int i = 0; i < records.size(); ++i) {
-      results[i] = records.get_row_id(i);
-    }
-    return true;
-  }
-};
-
-// -- ScoreNode --
-
-class ScoreNode : public TypedNode<Float> {
- public:
-  using Value = Float;
-
-  static unique_ptr<ScoreNode> create(Error *error, Value datum) {
-    unique_ptr<ScoreNode> node(new (nothrow) ScoreNode);
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  ScoreNode() : TypedNode<Value>() {}
-
-  NodeType node_type() const {
-    return SCORE_NODE;
-  }
-
-  bool adjust(Error *error, ArrayRef<Record> records) {
-    // Nothing to do.
-    return true;
-  }
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results) {
-    for (Int i = 0; i < records.size(); ++i) {
-      results[i] = records.get_score(i);
-    }
-    return true;
-  }
-};
-
-// -- ColumnNode --
-
-template <typename T>
-class ColumnNode : public TypedNode<T> {
- public:
-  using Value = T;
-
-  static unique_ptr<ColumnNode> create(Error *error, const Column *column) {
-    unique_ptr<ColumnNode> node(new (nothrow) ColumnNode(column));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  explicit ColumnNode(const Column *column)
-      : TypedNode<Value>(),
-        column_(static_cast<const ColumnImpl<Value> *>(column)) {}
-
-  NodeType node_type() const {
-    return COLUMN_NODE;
-  }
-
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results) {
-    for (Int i = 0; i < records.size(); ++i) {
-      results[i] = column_->get(records.get_row_id(i));
-    }
-    return true;
-  }
-
- private:
-  const ColumnImpl<T> *column_;
-};
-
-template <>
-class ColumnNode<Bool> : public TypedNode<Bool> {
- public:
-  using Value = Bool;
-
-  static unique_ptr<ColumnNode> create(Error *error, const Column *column) {
-    unique_ptr<ColumnNode> node(new (nothrow) ColumnNode(column));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  explicit ColumnNode(const Column *column)
-      : TypedNode<Value>(),
-        column_(static_cast<const ColumnImpl<Value> *>(column)) {}
-
-  NodeType node_type() const {
-    return COLUMN_NODE;
-  }
-
-  bool filter(Error *error,
-              ArrayCRef<Record> input_records,
-              ArrayRef<Record> *output_records);
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results) {
-    for (Int i = 0; i < records.size(); ++i) {
-      results.set(i, column_->get(records.get_row_id(i)));
-    }
-    return true;
-  }
-
- private:
-  const ColumnImpl<Value> *column_;
-};
-
-bool ColumnNode<Bool>::filter(Error *error,
-                              ArrayCRef<Record> input_records,
-                              ArrayRef<Record> *output_records) {
-  Int dest = 0;
-  for (Int i = 0; i < input_records.size(); ++i) {
-    if (column_->get(input_records.get_row_id(i))) {
-      output_records->set(dest, input_records.get(i));
-      ++dest;
-    }
-  }
-  *output_records = output_records->ref(0, dest);
-  return true;
-}
-
-template <>
-class ColumnNode<Float> : public TypedNode<Float> {
- public:
-  using Value = Float;
-
-  static unique_ptr<ColumnNode> create(Error *error, const Column *column) {
-    unique_ptr<ColumnNode> node(new (nothrow) ColumnNode(column));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  explicit ColumnNode(const Column *column)
-      : TypedNode<Value>(),
-        column_(static_cast<const ColumnImpl<Value> *>(column)) {}
-
-  NodeType node_type() const {
-    return COLUMN_NODE;
-  }
-
-  bool adjust(Error *error, ArrayRef<Record> records) {
-    for (Int i = 0; i < records.size(); ++i) {
-      records.set_score(i, column_->get(records.get_row_id(i)));
-    }
-    return true;
-  }
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results) {
-    for (Int i = 0; i < records.size(); ++i) {
-      results[i] = column_->get(records.get_row_id(i));
-    }
-    return true;
-  }
-
- private:
-  const ColumnImpl<Value> *column_;
-};
-
-// -- OperatorNode --
-
-template <typename T>
-class OperatorNode : public TypedNode<T> {
- public:
-  using Value = T;
-
-  OperatorNode() : TypedNode<Value>() {}
-  virtual ~OperatorNode() {}
-
-  NodeType node_type() const {
-    return OPERATOR_NODE;
-  }
-};
-
-// Evaluate "*arg" for "records".
-//
-// The evaluation results are stored into "*arg_values".
-//
-// On success, returns true.
-// On failure, returns false and stores error information into "*error" if
-// "error" != nullptr.
-template <typename T>
-bool fill_node_arg_values(Error *error, ArrayCRef<Record> records,
-                          TypedNode<T> *arg, Array<T> *arg_values) {
-  Int old_size = arg_values->size();
-  if (old_size < records.size()) {
-    if (!arg_values->resize(error, records.size())) {
-      return false;
-    }
-  }
-  switch (arg->node_type()) {
-    case DATUM_NODE: {
-      if (old_size < records.size()) {
-        if (!arg->evaluate(error, records.ref(old_size),
-                           arg_values->ref(old_size))) {
-          return false;
-        }
-      }
-      break;
-    }
-    default: {
-      if (!arg->evaluate(error, records, arg_values->ref(0, records.size()))) {
-        return false;
-      }
-    }
-  }
-  return true;
-}
-
-// --- UnaryNode ---
-
-template <typename T, typename U>
-class UnaryNode : public OperatorNode<T> {
- public:
-  using Value = T;
-  using Arg = U;
-
-  explicit UnaryNode(unique_ptr<Node> &&arg)
-      : OperatorNode<Value>(),
-        arg_(static_cast<TypedNode<Arg> *>(arg.release())),
-        arg_values_() {}
-  virtual ~UnaryNode() {}
-
- protected:
-  unique_ptr<TypedNode<Arg>> arg_;
-  Array<Arg> arg_values_;
-
-  bool fill_arg_values(Error *error, ArrayCRef<Record> records) {
-    return fill_node_arg_values(error, records, arg_.get(), &arg_values_);
-  }
-};
-
-// ---- LogicalNotNode ----
-
-class LogicalNotNode : public UnaryNode<Bool, Bool> {
- public:
-  using Value = Bool;
-  using Arg = Bool;
-
-  static unique_ptr<LogicalNotNode> create(Error *error,
-                                           unique_ptr<Node> &&arg) {
-    unique_ptr<LogicalNotNode> node(
-        new (nothrow) LogicalNotNode(std::move(arg)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  explicit LogicalNotNode(unique_ptr<Node> &&arg)
-      : UnaryNode<Value, Arg>(std::move(arg)),
-        temp_records_() {}
-
-  bool filter(Error *error,
-              ArrayCRef<Record> input_records,
-              ArrayRef<Record> *output_records);
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results);
-
- private:
-  Array<Record> temp_records_;
-};
-
-bool LogicalNotNode::filter(Error *error,
-                            ArrayCRef<Record> input_records,
-                            ArrayRef<Record> *output_records) {
-  // Apply an argument filter to "input_records" and store the result to
-  // "temp_records_". Then, appends a sentinel to the end.
-  if (!temp_records_.resize(error, input_records.size() + 1)) {
-    return false;
-  }
-  ArrayRef<Record> ref = temp_records_;
-  if (!arg_->filter(error, input_records, &ref)) {
-    return false;
-  }
-  temp_records_.set_row_id(ref.size(), NULL_ROW_ID);
-
-  // Extract records which appear in "input_records" and don't appear in "ref".
-  Int count = 0;
-  for (Int i = 0, j = 0; i < input_records.size(); ++i) {
-    if (input_records.get_row_id(i) == ref.get_row_id(j)) {
-      ++j;
-      continue;
-    }
-    output_records->set(count, input_records.get(i));
-    ++count;
-  }
-  *output_records = output_records->ref(0, count);
-  return true;
-}
-
-bool LogicalNotNode::evaluate(Error *error,
-                              ArrayCRef<Record> records,
-                              ArrayRef<Value> results) {
-  // Apply an argument filter to "records" and store the result to
-  // "temp_records_". Then, appends a sentinel to the end.
-  if (!temp_records_.resize(error, records.size() + 1)) {
-    return false;
-  }
-  ArrayRef<Record> ref = temp_records_;
-  if (!arg_->filter(error, records, &ref)) {
-    return false;
-  }
-  temp_records_.set_row_id(ref.size(), NULL_ROW_ID);
-
-  // Compare records in "records" and "ref".
-  Int count = 0;
-  for (Int i = 0; i < records.size(); ++i) {
-    if (records.get_row_id(i) == ref.get_row_id(count)) {
-      results.set(i, false);
-      ++count;
-    } else {
-      results.set(i, true);
-    }
-  }
-  return true;
-}
-
-// ---- BitwiseNotNode ----
-
-template <typename T> class BitwiseNotNode;
-
-template <>
-class BitwiseNotNode<Bool> : public UnaryNode<Bool, Bool> {
- public:
-  using Value = Bool;
-  using Arg = Bool;
-
-  static unique_ptr<BitwiseNotNode> create(Error *error,
-                                           unique_ptr<Node> &&arg) {
-    unique_ptr<BitwiseNotNode> node(
-        new (nothrow) BitwiseNotNode(std::move(arg)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  explicit BitwiseNotNode(unique_ptr<Node> &&arg)
-      : UnaryNode<Value, Arg>(std::move(arg)) {}
-
-  bool filter(Error *error,
-              ArrayCRef<Record> input_records,
-              ArrayRef<Record> *output_records);
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results);
-};
-
-bool BitwiseNotNode<Bool>::filter(Error *error,
-                                  ArrayCRef<Record> input_records,
-                                  ArrayRef<Record> *output_records) {
-  if (!fill_arg_values(error, input_records)) {
-    return false;
-  }
-  Int count = 0;
-  for (Int i = 0; i < input_records.size(); ++i) {
-    if (arg_values_[i]) {
-      output_records->set(count, input_records.get(i));
-      ++count;
-    }
-  }
-  *output_records = output_records->ref(0, count);
-  return true;
-}
-
-bool BitwiseNotNode<Bool>::evaluate(Error *error,
-                                    ArrayCRef<Record> records,
-                                    ArrayRef<Value> results) {
-  if (!arg_->evaluate(error, records, results)) {
-    return false;
-  }
-  // TODO: Should be processed per 64 bits.
-  //       Check the 64-bit boundary and do it!
-  for (Int i = 0; i < records.size(); ++i) {
-    results.set(i, !results.get(i));
-  }
-  return true;
-}
-
-template <>
-class BitwiseNotNode<Int> : public UnaryNode<Int, Int> {
- public:
-  using Value = Int;
-  using Arg = Int;
-
-  static unique_ptr<BitwiseNotNode> create(Error *error,
-                                           unique_ptr<Node> &&arg) {
-    unique_ptr<BitwiseNotNode> node(
-        new (nothrow) BitwiseNotNode(std::move(arg)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  explicit BitwiseNotNode(unique_ptr<Node> &&arg)
-      : UnaryNode<Value, Arg>(std::move(arg)) {}
-
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results);
-};
-
-bool BitwiseNotNode<Int>::evaluate(Error *error,
-                                   ArrayCRef<Record> records,
-                                   ArrayRef<Value> results) {
-  if (!arg_->evaluate(error, records, results)) {
-    return false;
-  }
-  for (Int i = 0; i < records.size(); ++i) {
-    results.set(i, ~results.get(i));
-  }
-  return true;
-}
-
-// ---- PositiveNode ----
-
-// Nothing to do.
-
-// ---- NegativeNode ----
-
-template <typename T> class NegativeNode;
-
-template <>
-class NegativeNode<Int> : public UnaryNode<Int, Int> {
- public:
-  using Value = Int;
-  using Arg = Int;
-
-  static unique_ptr<NegativeNode> create(Error *error,
-                                         unique_ptr<Node> &&arg) {
-    unique_ptr<NegativeNode> node(new (nothrow) NegativeNode(std::move(arg)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  explicit NegativeNode(unique_ptr<Node> &&arg)
-      : UnaryNode<Value, Arg>(std::move(arg)) {}
-
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results);
-};
-
-bool NegativeNode<Int>::evaluate(Error *error,
-                                 ArrayCRef<Record> records,
-                                 ArrayRef<Value> results) {
-  if (!arg_->evaluate(error, records, results)) {
-    return false;
-  }
-  for (Int i = 0; i < records.size(); ++i) {
-    results.set(i, -results.get(i));
-  }
-  return true;
-}
-
-template <>
-class NegativeNode<Float> : public UnaryNode<Float, Float> {
- public:
-  using Value = Float;
-  using Arg = Float;
-
-  static unique_ptr<NegativeNode> create(Error *error,
-                                         unique_ptr<Node> &&arg) {
-    unique_ptr<NegativeNode> node(new (nothrow) NegativeNode(std::move(arg)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  explicit NegativeNode(unique_ptr<Node> &&arg)
-      : UnaryNode<Value, Arg>(std::move(arg)) {}
-
-  bool adjust(Error *error, ArrayRef<Record> records);
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results);
-};
-
-bool NegativeNode<Float>::adjust(Error *error, ArrayRef<Record> records) {
-  if (!fill_arg_values(error, records)) {
-    return false;
-  }
-  for (Int i = 0; i < records.size(); ++i) {
-    records.set_score(i, arg_values_[i]);
-  }
-  return true;
-}
-
-bool NegativeNode<Float>::evaluate(Error *error,
-                                   ArrayCRef<Record> records,
-                                   ArrayRef<Value> results) {
-  if (!arg_->evaluate(error, records, results)) {
-    return false;
-  }
-  for (Int i = 0; i < records.size(); ++i) {
-    results.set(i, -results.get(i));
-  }
-  return true;
-}
-
-// ---- ToIntNode ----
-
-class ToIntNode : public UnaryNode<Int, Float> {
- public:
-  using Value = Int;
-  using Arg = Float;
-
-  static unique_ptr<ToIntNode> create(Error *error, unique_ptr<Node> &&arg) {
-    unique_ptr<ToIntNode> node(new (nothrow) ToIntNode(std::move(arg)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  explicit ToIntNode(unique_ptr<Node> &&arg)
-      : UnaryNode<Value, Arg>(std::move(arg)) {}
-
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results);
-};
-
-bool ToIntNode::evaluate(Error *error,
-                         ArrayCRef<Record> records,
-                         ArrayRef<Value> results) {
-  if (!fill_arg_values(error, records)) {
-    return false;
-  }
-  for (Int i = 0; i < records.size(); ++i) {
-    results.set(i, static_cast<Value>(arg_values_[i]));
-  }
-  return true;
-}
-
-// ---- ToFloatNode ----
-
-class ToFloatNode : public UnaryNode<Float, Int> {
- public:
-  using Value = Float;
-  using Arg = Int;
-
-  static unique_ptr<ToFloatNode> create(Error *error, unique_ptr<Node> &&arg) {
-    unique_ptr<ToFloatNode> node(new (nothrow) ToFloatNode(std::move(arg)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  explicit ToFloatNode(unique_ptr<Node> &&arg)
-      : UnaryNode<Value, Arg>(std::move(arg)) {}
-
-  bool adjust(Error *error, ArrayRef<Record> records);
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results);
-};
-
-bool ToFloatNode::adjust(Error *error, ArrayRef<Record> records) {
-  if (!fill_arg_values(error, records)) {
-    return false;
-  }
-  for (Int i = 0; i < records.size(); ++i) {
-    records.set_score(i, static_cast<Value>(arg_values_[i]));
-  }
-  return true;
-}
-
-bool ToFloatNode::evaluate(Error *error,
-                           ArrayCRef<Record> records,
-                           ArrayRef<Value> results) {
-  if (!fill_arg_values(error, records)) {
-    return false;
-  }
-  for (Int i = 0; i < records.size(); ++i) {
-    results.set(i, static_cast<Value>(arg_values_[i]));
-  }
-  return true;
-}
-
-// --- BinaryNode ---
-
-template <typename T, typename U, typename V>
-class BinaryNode : public OperatorNode<T> {
- public:
-  using Value = T;
-  using Arg1 = U;
-  using Arg2 = V;
-
-  BinaryNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
-      : OperatorNode<Value>(),
-        arg1_(static_cast<TypedNode<Arg1> *>(arg1.release())),
-        arg2_(static_cast<TypedNode<Arg2> *>(arg2.release())),
-        arg1_values_(),
-        arg2_values_() {}
-  virtual ~BinaryNode() {}
-
- protected:
-  unique_ptr<TypedNode<Arg1>> arg1_;
-  unique_ptr<TypedNode<Arg2>> arg2_;
-  Array<Arg1> arg1_values_;
-  Array<Arg2> arg2_values_;
-
-  bool fill_arg1_values(Error *error, ArrayCRef<Record> records) {
-    return fill_node_arg_values(error, records, arg1_.get(), &arg1_values_);
-  }
-  bool fill_arg2_values(Error *error, ArrayCRef<Record> records) {
-    return fill_node_arg_values(error, records, arg2_.get(), &arg2_values_);
-  }
-};
-
-// ---- LogicalAndNode ----
-
-class LogicalAndNode : public BinaryNode<Bool, Bool, Bool> {
- public:
-  using Value = Bool;
-  using Arg1 = Bool;
-  using Arg2 = Bool;
-
-  static unique_ptr<LogicalAndNode> create(Error *error,
-                                           unique_ptr<Node> &&arg1,
-                                           unique_ptr<Node> &&arg2) {
-    unique_ptr<LogicalAndNode> node(
-        new (nothrow) LogicalAndNode(std::move(arg1), std::move(arg2)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  LogicalAndNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
-      : BinaryNode<Value, Arg1, Arg2>(std::move(arg1), std::move(arg2)),
-        temp_records_() {}
-
-  bool filter(Error *error,
-              ArrayCRef<Record> input_records,
-              ArrayRef<Record> *output_records) {
-    return arg1_->filter(error, input_records, output_records) &&
-           arg2_->filter(error, *output_records, output_records);
-  }
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results);
-
- private:
-  Array<Record> temp_records_;
-};
-
-bool LogicalAndNode::evaluate(Error *error,
-                              ArrayCRef<Record> records,
-                              ArrayRef<Value> results) {
-  // Apply argument filters to "records" and store the result to
-  // "temp_records_". Then, appends a sentinel to the end.
-  if (!temp_records_.resize(error, records.size() + 1)) {
-    return false;
-  }
-  ArrayRef<Record> ref = temp_records_;
-  if (!arg1_->filter(error, records, &ref) ||
-      !arg2_->filter(error, ref, &ref)) {
-    return false;
-  }
-  temp_records_.set_row_id(ref.size(), NULL_ROW_ID);
-
-  // Compare records in "records" and "ref".
-  Int count = 0;
-  for (Int i = 0; i < records.size(); ++i) {
-    if (records.get_row_id(i) == ref.get_row_id(count)) {
-      results.set(i, true);
-      ++count;
-    } else {
-      results.set(i, false);
-    }
-  }
-  return true;
-}
-
-// ---- LogicalOrNode ----
-
-class LogicalOrNode : public BinaryNode<Bool, Bool, Bool> {
- public:
-  using Value = Bool;
-  using Arg1 = Bool;
-  using Arg2 = Bool;
-
-  static unique_ptr<LogicalOrNode> create(Error *error,
-                                          unique_ptr<Node> &&arg1,
-                                          unique_ptr<Node> &&arg2) {
-    unique_ptr<LogicalOrNode> node(
-        new (nothrow) LogicalOrNode(std::move(arg1), std::move(arg2)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  LogicalOrNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
-      : BinaryNode<Value, Arg1, Arg2>(std::move(arg1), std::move(arg2)),
-        temp_records_() {}
-
-  bool filter(Error *error,
-              ArrayCRef<Record> input_records,
-              ArrayRef<Record> *output_records);
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results);
-
- private:
-  Array<Record> temp_records_;
-};
-
-bool LogicalOrNode::filter(Error *error,
-                            ArrayCRef<Record> input_records,
-                            ArrayRef<Record> *output_records) {
-  // Apply the 1st argument filter to "input_records" and store the result into
-  // "temp_records_", Then, appends a sentinel to the end.
-  if (!temp_records_.resize(error, input_records.size() + 2)) {
-    return false;
-  }
-  ArrayRef<Record> ref1 = temp_records_;
-  if (!arg1_->filter(error, input_records, &ref1)) {
-    return false;
-  }
-  if (ref1.size() == 0) {
-    // There are no arg1-true records.
-    return arg2_->filter(error, input_records, output_records);
-  } else if (ref1.size() == temp_records_.size()) {
-    // There are no arg1-false records.
-    if (input_records != *output_records) {
-      for (Int i = 0; i < input_records.size(); ++i) {
-        output_records->set(i, input_records.get(i));
-      }
-    }
-    return true;
-  }
-  temp_records_.set_row_id(ref1.size(), NULL_ROW_ID);
-
-  // Append arg1-false records to the end of "temp_records_".
-  // Then, applies the 2nd argument filter to it and appends a sentinel.
-  ArrayRef<Record> ref2 =
-      temp_records_.ref(ref1.size() + 1, input_records.size() - ref1.size());
-  Int arg1_count = 0;
-  Int arg2_count = 0;
-  for (Int i = 0; i < input_records.size(); ++i) {
-    if (input_records.get_row_id(i) == ref1.get_row_id(arg1_count)) {
-      ++arg1_count;
-    } else {
-      ref2.set(arg2_count, input_records.get(i));
-      ++arg2_count;
-    }
-  }
-  if (!arg2_->filter(error, ref2, &ref2)) {
-    return false;
-  }
-  if (ref2.size() == 0) {
-    // There are no arg2-true records.
-    for (Int i = 0; i < ref1.size(); ++i) {
-      output_records->set(i, ref1.get(i));
-    }
-    *output_records = output_records->ref(0, ref1.size());
-    return true;
-  } else if (ref2.size() == arg2_count) {
-    // There are no arg2-false records.
-    if (input_records != *output_records) {
-      for (Int i = 0; i < input_records.size(); ++i) {
-        output_records->set(i, input_records.get(i));
-      }
-      *output_records = output_records->ref(0, input_records.size());
-    }
-    return true;
-  }
-  temp_records_.set_row_id(ref1.size() + 1 + ref2.size(), NULL_ROW_ID);
-
-  // Merge the arg1-true records and the arg2-true records.
-  arg1_count = 0;
-  arg2_count = 0;
-  for (Int i = 0; i < input_records.size(); ++i) {
-    if (input_records.get_row_id(i) == ref1.get_row_id(arg1_count)) {
-      output_records->set(arg1_count + arg2_count, input_records.get(i));
-      ++arg1_count;
-    } else if (input_records.get_row_id(i) == ref2.get_row_id(arg2_count)) {
-      output_records->set(arg1_count + arg2_count, input_records.get(i));
-      ++arg2_count;
-    }
-  }
-  *output_records = output_records->ref(0, arg1_count + arg2_count);
-  return true;
-}
-
-bool LogicalOrNode::evaluate(Error *error,
-                              ArrayCRef<Record> records,
-                              ArrayRef<Value> results) {
-  // Apply the 1st argument filter to "records" and store the result into
-  // "temp_records_", Then, appends a sentinel to the end.
-  if (!temp_records_.resize(error, records.size() + 2)) {
-    return false;
-  }
-  ArrayRef<Record> ref1 = temp_records_;
-  if (!arg1_->filter(error, records, &ref1)) {
-    return false;
-  }
-  if (ref1.size() == 0) {
-    // There are no arg1-true records.
-    return arg2_->evaluate(error, records, results);
-  } else if (ref1.size() == temp_records_.size()) {
-    // There are no arg1-false records.
-    // TODO: Fill the array per 64 bits.
-    for (Int i = 0; i < records.size(); ++i) {
-      results.set(i, true);
-    }
-    return true;
-  }
-  temp_records_.set_row_id(ref1.size(), NULL_ROW_ID);
-
-  // Append arg1-false records to the end of "temp_records_".
-  // Then, applies the 2nd argument filter to it and appends a sentinel.
-  ArrayRef<Record> ref2 =
-      temp_records_.ref(ref1.size() + 1, records.size() - ref1.size());
-  Int arg1_count = 0;
-  Int arg2_count = 0;
-  for (Int i = 0; i < records.size(); ++i) {
-    if (records.get_row_id(i) == ref1.get_row_id(arg1_count)) {
-      ++arg1_count;
-    } else {
-      ref2.set(arg2_count, records.get(i));
-      ++arg2_count;
-    }
-  }
-  if (!arg2_->filter(error, ref2, &ref2)) {
-    return false;
-  }
-  if (ref2.size() == 0) {
-    // There are no arg2-true records.
-    arg1_count = 0;
-    for (Int i = 0; i < records.size(); ++i) {
-      if (records.get_row_id(i) == ref1.get_row_id(arg1_count)) {
-        results.set(i, true);
-        ++arg1_count;
-      } else {
-        results.set(i, false);
-      }
-    }
-    return true;
-  } else if (ref2.size() == arg2_count) {
-    // There are no arg2-false records.
-    // TODO: Fill the array per 64 bits.
-    for (Int i = 0; i < records.size(); ++i) {
-      results.set(i, true);
-    }
-    return true;
-  }
-  temp_records_.set_row_id(ref1.size() + 1 + ref2.size(), NULL_ROW_ID);
-
-  // Merge the arg1-true records and the arg2-true records.
-  arg1_count = 0;
-  arg2_count = 0;
-  for (Int i = 0; i < records.size(); ++i) {
-    if (records.get_row_id(i) == ref1.get_row_id(arg1_count)) {
-      results.set(i, true);
-      ++arg1_count;
-    } else if (records.get_row_id(i) == ref2.get_row_id(arg2_count)) {
-      results.set(i, true);
-      ++arg2_count;
-    } else {
-      results.set(i, false);
-    }
-  }
-  return true;
-}
-
-// ---- ComparisonNode ----
-
-template <typename T>
-class ComparisonNode
-    : public BinaryNode<Bool, typename T::Arg, typename T::Arg> {
- public:
-  using Comparer = T;
-  using Value = Bool;
-  using Arg1 = typename T::Arg;
-  using Arg2 = typename T::Arg;
-
-  static unique_ptr<ComparisonNode> create(Error *error,
-                                           unique_ptr<Node> &&arg1,
-                                           unique_ptr<Node> &&arg2) {
-    unique_ptr<ComparisonNode> node(
-        new (nothrow) ComparisonNode(std::move(arg1), std::move(arg2)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  ComparisonNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
-      : BinaryNode<Value, Arg1, Arg2>(std::move(arg1), std::move(arg2)),
-        comparer_() {}
-
-  bool filter(Error *error,
-              ArrayCRef<Record> input_records,
-              ArrayRef<Record> *output_records);
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results);
-
- protected:
-  Comparer comparer_;
-};
-
-template <typename T>
-bool ComparisonNode<T>::filter(Error *error,
-                               ArrayCRef<Record> input_records,
-                               ArrayRef<Record> *output_records) {
-  if (!this->fill_arg1_values(error, input_records) ||
-      !this->fill_arg2_values(error, input_records)) {
-    return false;
-  }
-  Int count = 0;
-  for (Int i = 0; i < input_records.size(); ++i) {
-    if (comparer_(this->arg1_values_[i], this->arg2_values_[i])) {
-      output_records->set(count, input_records.get(i));
-      ++count;
-    }
-  }
-  *output_records = output_records->ref(0, count);
-  return true;
-}
-
-template <typename T>
-bool ComparisonNode<T>::evaluate(Error *error,
-                                 ArrayCRef<Record> records,
-                                 ArrayRef<Value> results) {
-  if (!this->fill_arg1_values(error, records) ||
-      !this->fill_arg2_values(error, records)) {
-    return false;
-  }
-  for (Int i = 0; i < records.size(); ++i) {
-    results.set(i, comparer_(this->arg1_values_[i], this->arg2_values_[i]));
-  }
-  return true;
-}
-
-// ----- EqualNode -----
-
-struct Equal {
-  template <typename T>
-  struct Comparer {
-    using Arg = T;
-    Bool operator()(Arg arg1, Arg arg2) const {
-      return arg1 == arg2;
-    }
-  };
-};
-
-template <typename T>
-using EqualNode = ComparisonNode<Equal::Comparer<T>>;
-
-// ----- NotEqualNode -----
-
-struct NotEqual {
-  template <typename T>
-  struct Comparer {
-    using Arg = T;
-    Bool operator()(Arg arg1, Arg arg2) const {
-      return arg1 != arg2;
-    }
-  };
-};
-
-template <typename T>
-using NotEqualNode = ComparisonNode<NotEqual::Comparer<T>>;
-
-// ----- LessNode -----
-
-struct Less {
-  template <typename T>
-  struct Comparer {
-    using Arg = T;
-    Bool operator()(Arg arg1, Arg arg2) const {
-      return arg1 < arg2;
-    }
-  };
-};
-
-template <typename T>
-using LessNode = ComparisonNode<Less::Comparer<T>>;
-
-// ----- LessEqualNode -----
-
-struct LessEqual {
-  template <typename T>
-  struct Comparer {
-    using Arg = T;
-    Bool operator()(Arg arg1, Arg arg2) const {
-      return arg1 <= arg2;
-    }
-  };
-};
-
-template <typename T>
-using LessEqualNode = ComparisonNode<LessEqual::Comparer<T>>;
-
-// ----- GreaterNode -----
-
-struct Greater {
-  template <typename T>
-  struct Comparer {
-    using Arg = T;
-    Bool operator()(Arg arg1, Arg arg2) const {
-      return arg1 > arg2;
-    }
-  };
-};
-
-template <typename T>
-using GreaterNode = ComparisonNode<Greater::Comparer<T>>;
-
-// ----- GreaterEqualNode -----
-
-struct GreaterEqual {
-  template <typename T>
-  struct Comparer {
-    using Arg = T;
-    Bool operator()(Arg arg1, Arg arg2) const {
-      return arg1 >= arg2;
-    }
-  };
-};
-
-template <typename T>
-using GreaterEqualNode = ComparisonNode<GreaterEqual::Comparer<T>>;
-
-// ---- BitwiseAndNode ----
-
-// TODO: BitwiseAnd/Or/XorNode should be implemented on the same base class?
-
-template <typename T> class BitwiseAndNode;
-
-template <>
-class BitwiseAndNode<Bool> : public BinaryNode<Bool, Bool, Bool> {
- public:
-  using Value = Bool;
-  using Arg1 = Bool;
-  using Arg2 = Bool;
-
-  static unique_ptr<BitwiseAndNode> create(Error *error,
-                                           unique_ptr<Node> &&arg1,
-                                           unique_ptr<Node> &&arg2) {
-    unique_ptr<BitwiseAndNode> node(
-        new (nothrow) BitwiseAndNode(std::move(arg1), std::move(arg2)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  BitwiseAndNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
-      : BinaryNode<Value, Arg1, Arg2>(std::move(arg1), std::move(arg2)) {}
-
-  bool filter(Error *error,
-              ArrayCRef<Record> input_records,
-              ArrayRef<Record> *output_records);
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results);
-};
-
-bool BitwiseAndNode<Bool>::filter(Error *error,
-                                  ArrayCRef<Record> input_records,
-                                  ArrayRef<Record> *output_records) {
-  if (!fill_arg1_values(error, input_records) ||
-      !fill_arg2_values(error, input_records)) {
-    return false;
-  }
-  Int count = 0;
-  for (Int i = 0; i < input_records.size(); ++i) {
-    if (this->arg1_values_[i] & this->arg2_values_[i]) {
-      output_records->set(count, input_records.get(i));
-      ++count;
-    }
-  }
-  *output_records = output_records->ref(0, count);
-  return true;
-}
-
-bool BitwiseAndNode<Bool>::evaluate(Error *error,
-                                    ArrayCRef<Record> records,
-                                    ArrayRef<Value> results) {
-  if (!fill_arg1_values(error, records) ||
-      !fill_arg2_values(error, records)) {
-    return false;
-  }
-  // TODO: Should be processed per 64 bits.
-  //       Check the 64-bit boundary and do it!
-  for (Int i = 0; i < records.size(); ++i) {
-    results.set(i, this->arg1_values_[i] & this->arg2_values_[i]);
-  }
-  return true;
-}
-
-template <>
-class BitwiseAndNode<Int> : public BinaryNode<Int, Int, Int> {
- public:
-  using Value = Int;
-  using Arg1 = Int;
-  using Arg2 = Int;
-
-  static unique_ptr<BitwiseAndNode> create(Error *error,
-                                           unique_ptr<Node> &&arg1,
-                                           unique_ptr<Node> &&arg2) {
-    unique_ptr<BitwiseAndNode> node(
-        new (nothrow) BitwiseAndNode(std::move(arg1), std::move(arg2)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  BitwiseAndNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
-      : BinaryNode<Value, Arg1, Arg2>(std::move(arg1), std::move(arg2)) {}
-
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results);
-};
-
-bool BitwiseAndNode<Int>::evaluate(Error *error,
-                                   ArrayCRef<Record> records,
-                                   ArrayRef<Value> results) {
-  if (!fill_arg1_values(error, records) ||
-      !fill_arg2_values(error, records)) {
-    return false;
-  }
-  // TODO: Should be processed per 64 bits.
-  //       Check the 64-bit boundary and do it!
-  for (Int i = 0; i < records.size(); ++i) {
-    results.set(i, this->arg1_values_[i] & this->arg2_values_[i]);
-  }
-  return true;
-}
-
-// ---- BitwiseOrNode ----
-
-template <typename T> class BitwiseOrNode;
-
-template <>
-class BitwiseOrNode<Bool> : public BinaryNode<Bool, Bool, Bool> {
- public:
-  using Value = Bool;
-  using Arg1 = Bool;
-  using Arg2 = Bool;
-
-  static unique_ptr<BitwiseOrNode> create(Error *error,
-                                          unique_ptr<Node> &&arg1,
-                                          unique_ptr<Node> &&arg2) {
-    unique_ptr<BitwiseOrNode> node(
-        new (nothrow) BitwiseOrNode(std::move(arg1), std::move(arg2)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  BitwiseOrNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
-      : BinaryNode<Value, Arg1, Arg2>(std::move(arg1), std::move(arg2)) {}
-
-  bool filter(Error *error,
-              ArrayCRef<Record> input_records,
-              ArrayRef<Record> *output_records);
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results);
-};
-
-bool BitwiseOrNode<Bool>::filter(Error *error,
-                                 ArrayCRef<Record> input_records,
-                                 ArrayRef<Record> *output_records) {
-  if (!fill_arg1_values(error, input_records) ||
-      !fill_arg2_values(error, input_records)) {
-    return false;
-  }
-  Int count = 0;
-  for (Int i = 0; i < input_records.size(); ++i) {
-    if (this->arg1_values_[i] | this->arg2_values_[i]) {
-      output_records->set(count, input_records.get(i));
-      ++count;
-    }
-  }
-  *output_records = output_records->ref(0, count);
-  return true;
-}
-
-bool BitwiseOrNode<Bool>::evaluate(Error *error,
-                                   ArrayCRef<Record> records,
-                                   ArrayRef<Value> results) {
-  if (!fill_arg1_values(error, records) ||
-      !fill_arg2_values(error, records)) {
-    return false;
-  }
-  // TODO: Should be processed per 64 bits.
-  //       Check the 64-bit boundary and do it!
-  for (Int i = 0; i < records.size(); ++i) {
-    results.set(i, this->arg1_values_[i] | this->arg2_values_[i]);
-  }
-  return true;
-}
-
-template <>
-class BitwiseOrNode<Int> : public BinaryNode<Int, Int, Int> {
- public:
-  using Value = Int;
-  using Arg1 = Int;
-  using Arg2 = Int;
-
-  static unique_ptr<BitwiseOrNode> create(Error *error,
-                                          unique_ptr<Node> &&arg1,
-                                          unique_ptr<Node> &&arg2) {
-    unique_ptr<BitwiseOrNode> node(
-        new (nothrow) BitwiseOrNode(std::move(arg1), std::move(arg2)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  BitwiseOrNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
-      : BinaryNode<Value, Arg1, Arg2>(std::move(arg1), std::move(arg2)) {}
-
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results);
-};
-
-bool BitwiseOrNode<Int>::evaluate(Error *error,
-                                  ArrayCRef<Record> records,
-                                  ArrayRef<Value> results) {
-  if (!fill_arg1_values(error, records) ||
-      !fill_arg2_values(error, records)) {
-    return false;
-  }
-  // TODO: Should be processed per 64 bits.
-  //       Check the 64-bit boundary and do it!
-  for (Int i = 0; i < records.size(); ++i) {
-    results.set(i, this->arg1_values_[i] | this->arg2_values_[i]);
-  }
-  return true;
-}
-
-// ---- BitwiseXorNode ----
-
-template <typename T> class BitwiseXorNode;
-
-template <>
-class BitwiseXorNode<Bool> : public BinaryNode<Bool, Bool, Bool> {
- public:
-  using Value = Bool;
-  using Arg1 = Bool;
-  using Arg2 = Bool;
-
-  static unique_ptr<BitwiseXorNode> create(Error *error,
-                                           unique_ptr<Node> &&arg1,
-                                           unique_ptr<Node> &&arg2) {
-    unique_ptr<BitwiseXorNode> node(
-        new (nothrow) BitwiseXorNode(std::move(arg1), std::move(arg2)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  BitwiseXorNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
-      : BinaryNode<Value, Arg1, Arg2>(std::move(arg1), std::move(arg2)) {}
-
-  bool filter(Error *error,
-              ArrayCRef<Record> input_records,
-              ArrayRef<Record> *output_records);
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results);
-};
-
-bool BitwiseXorNode<Bool>::filter(Error *error,
-                                  ArrayCRef<Record> input_records,
-                                  ArrayRef<Record> *output_records) {
-  if (!fill_arg1_values(error, input_records) ||
-      !fill_arg2_values(error, input_records)) {
-    return false;
-  }
-  Int count = 0;
-  for (Int i = 0; i < input_records.size(); ++i) {
-    if (this->arg1_values_[i] ^ this->arg2_values_[i]) {
-      output_records->set(count, input_records.get(i));
-      ++count;
-    }
-  }
-  *output_records = output_records->ref(0, count);
-  return true;
-}
-
-bool BitwiseXorNode<Bool>::evaluate(Error *error,
-                                    ArrayCRef<Record> records,
-                                    ArrayRef<Value> results) {
-  if (!fill_arg1_values(error, records) ||
-      !fill_arg2_values(error, records)) {
-    return false;
-  }
-  // TODO: Should be processed per 64 bits.
-  //       Check the 64-bit boundary and do it!
-  for (Int i = 0; i < records.size(); ++i) {
-    results.set(i, this->arg1_values_[i] ^ this->arg2_values_[i]);
-  }
-  return true;
-}
-
-template <>
-class BitwiseXorNode<Int> : public BinaryNode<Int, Int, Int> {
- public:
-  using Value = Int;
-  using Arg1 = Int;
-  using Arg2 = Int;
-
-  static unique_ptr<BitwiseXorNode> create(Error *error,
-                                           unique_ptr<Node> &&arg1,
-                                           unique_ptr<Node> &&arg2) {
-    unique_ptr<BitwiseXorNode> node(
-        new (nothrow) BitwiseXorNode(std::move(arg1), std::move(arg2)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  BitwiseXorNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
-      : BinaryNode<Value, Arg1, Arg2>(std::move(arg1), std::move(arg2)) {}
-
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results);
-};
-
-bool BitwiseXorNode<Int>::evaluate(Error *error,
-                                   ArrayCRef<Record> records,
-                                   ArrayRef<Value> results) {
-  if (!fill_arg1_values(error, records) ||
-      !fill_arg2_values(error, records)) {
-    return false;
-  }
-  // TODO: Should be processed per 64 bits.
-  //       Check the 64-bit boundary and do it!
-  for (Int i = 0; i < records.size(); ++i) {
-    results.set(i, this->arg1_values_[i] ^ this->arg2_values_[i]);
-  }
-  return true;
-}
-
-// ---- PlusOperator ----
-
-template <typename T> class PlusNode;
-
-template <>
-class PlusNode<Int> : public BinaryNode<Int, Int, Int> {
- public:
-  using Value = Int;
-  using Arg1 = Int;
-  using Arg2 = Int;
-
-  static unique_ptr<PlusNode> create(Error *error,
-                                     unique_ptr<Node> &&arg1,
-                                     unique_ptr<Node> &&arg2) {
-    unique_ptr<PlusNode> node(
-        new (nothrow) PlusNode(std::move(arg1), std::move(arg2)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  PlusNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
-      : BinaryNode<Value, Arg1, Arg2>(std::move(arg1), std::move(arg2)) {}
-
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results);
-};
-
-bool PlusNode<Int>::evaluate(Error *error,
-                             ArrayCRef<Record> records,
-                             ArrayRef<Value> results) {
-  if (!fill_arg1_values(error, records) ||
-      !fill_arg2_values(error, records)) {
-    return false;
-  }
-  for (Int i = 0; i < records.size(); ++i) {
-    results.set(i, this->arg1_values_[i] + this->arg2_values_[i]);
-  }
-  return true;
-}
-
-template <>
-class PlusNode<Float> : public BinaryNode<Float, Float, Float> {
- public:
-  using Value = Float;
-  using Arg1 = Float;
-  using Arg2 = Float;
-
-  static unique_ptr<PlusNode> create(Error *error,
-                                     unique_ptr<Node> &&arg1,
-                                     unique_ptr<Node> &&arg2) {
-    unique_ptr<PlusNode> node(
-        new (nothrow) PlusNode(std::move(arg1), std::move(arg2)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  PlusNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
-      : BinaryNode<Value, Arg1, Arg2>(std::move(arg1), std::move(arg2)) {}
-
-  bool adjust(Error *error, ArrayRef<Record> records);
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results);
-};
-
-bool PlusNode<Float>::adjust(Error *error, ArrayRef<Record> records) {
-  if (!fill_arg1_values(error, records) ||
-      !fill_arg2_values(error, records)) {
-    return false;
-  }
-  for (Int i = 0; i < records.size(); ++i) {
-    records.set_score(i, this->arg1_values_[i] + this->arg2_values_[i]);
-  }
-  return true;
-}
-
-bool PlusNode<Float>::evaluate(Error *error,
-                               ArrayCRef<Record> records,
-                               ArrayRef<Value> results) {
-  if (!fill_arg1_values(error, records) ||
-      !fill_arg2_values(error, records)) {
-    return false;
-  }
-  for (Int i = 0; i < records.size(); ++i) {
-    results.set(i, this->arg1_values_[i] + this->arg2_values_[i]);
-  }
-  return true;
-}
-
-// ---- MinusOperator ----
-
-template <typename T> class MinusNode;
-
-template <>
-class MinusNode<Int> : public BinaryNode<Int, Int, Int> {
- public:
-  using Value = Int;
-  using Arg1 = Int;
-  using Arg2 = Int;
-
-  static unique_ptr<MinusNode> create(Error *error,
-                                      unique_ptr<Node> &&arg1,
-                                      unique_ptr<Node> &&arg2) {
-    unique_ptr<MinusNode> node(
-        new (nothrow) MinusNode(std::move(arg1), std::move(arg2)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  MinusNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
-      : BinaryNode<Value, Arg1, Arg2>(std::move(arg1), std::move(arg2)) {}
-
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results);
-};
-
-bool MinusNode<Int>::evaluate(Error *error,
-                              ArrayCRef<Record> records,
-                              ArrayRef<Value> results) {
-  if (!fill_arg1_values(error, records) ||
-      !fill_arg2_values(error, records)) {
-    return false;
-  }
-  for (Int i = 0; i < records.size(); ++i) {
-    results.set(i, this->arg1_values_[i] - this->arg2_values_[i]);
-  }
-  return true;
-}
-
-template <>
-class MinusNode<Float> : public BinaryNode<Float, Float, Float> {
- public:
-  using Value = Float;
-  using Arg1 = Float;
-  using Arg2 = Float;
-
-  static unique_ptr<MinusNode> create(Error *error,
-                                      unique_ptr<Node> &&arg1,
-                                      unique_ptr<Node> &&arg2) {
-    unique_ptr<MinusNode> node(
-        new (nothrow) MinusNode(std::move(arg1), std::move(arg2)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  MinusNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
-      : BinaryNode<Value, Arg1, Arg2>(std::move(arg1), std::move(arg2)) {}
-
-  bool adjust(Error *error, ArrayRef<Record> records);
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results);
-};
-
-bool MinusNode<Float>::adjust(Error *error, ArrayRef<Record> records) {
-  if (!fill_arg1_values(error, records) ||
-      !fill_arg2_values(error, records)) {
-    return false;
-  }
-  for (Int i = 0; i < records.size(); ++i) {
-    records.set_score(i, this->arg1_values_[i] - this->arg2_values_[i]);
-  }
-  return true;
-}
-
-bool MinusNode<Float>::evaluate(Error *error,
-                                ArrayCRef<Record> records,
-                                ArrayRef<Value> results) {
-  if (!fill_arg1_values(error, records) ||
-      !fill_arg2_values(error, records)) {
-    return false;
-  }
-  for (Int i = 0; i < records.size(); ++i) {
-    results.set(i, this->arg1_values_[i] - this->arg2_values_[i]);
-  }
-  return true;
-}
-
-// ---- MultiplicationOperator ----
-
-template <typename T> class MultiplicationNode;
-
-template <>
-class MultiplicationNode<Int> : public BinaryNode<Int, Int, Int> {
- public:
-  using Value = Int;
-  using Arg1 = Int;
-  using Arg2 = Int;
-
-  static unique_ptr<MultiplicationNode> create(Error *error,
-                                               unique_ptr<Node> &&arg1,
-                                               unique_ptr<Node> &&arg2) {
-    unique_ptr<MultiplicationNode> node(
-        new (nothrow) MultiplicationNode(std::move(arg1), std::move(arg2)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  MultiplicationNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
-      : BinaryNode<Value, Arg1, Arg2>(std::move(arg1), std::move(arg2)) {}
-
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results);
-};
-
-bool MultiplicationNode<Int>::evaluate(Error *error,
-                                       ArrayCRef<Record> records,
-                                       ArrayRef<Value> results) {
-  if (!fill_arg1_values(error, records) ||
-      !fill_arg2_values(error, records)) {
-    return false;
-  }
-  for (Int i = 0; i < records.size(); ++i) {
-    results.set(i, this->arg1_values_[i] * this->arg2_values_[i]);
-  }
-  return true;
-}
-
-template <>
-class MultiplicationNode<Float> : public BinaryNode<Float, Float, Float> {
- public:
-  using Value = Float;
-  using Arg1 = Float;
-  using Arg2 = Float;
-
-  static unique_ptr<MultiplicationNode> create(Error *error,
-                                               unique_ptr<Node> &&arg1,
-                                               unique_ptr<Node> &&arg2) {
-    unique_ptr<MultiplicationNode> node(
-        new (nothrow) MultiplicationNode(std::move(arg1), std::move(arg2)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  MultiplicationNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
-      : BinaryNode<Value, Arg1, Arg2>(std::move(arg1), std::move(arg2)) {}
-
-  bool adjust(Error *error, ArrayRef<Record> records);
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results);
-};
-
-bool MultiplicationNode<Float>::adjust(Error *error,
-                                       ArrayRef<Record> records) {
-  if (!fill_arg1_values(error, records) ||
-      !fill_arg2_values(error, records)) {
-    return false;
-  }
-  for (Int i = 0; i < records.size(); ++i) {
-    records.set_score(i, this->arg1_values_[i] * this->arg2_values_[i]);
-  }
-  return true;
-}
-
-bool MultiplicationNode<Float>::evaluate(Error *error,
-                                         ArrayCRef<Record> records,
-                                         ArrayRef<Value> results) {
-  if (!fill_arg1_values(error, records) ||
-      !fill_arg2_values(error, records)) {
-    return false;
-  }
-  for (Int i = 0; i < records.size(); ++i) {
-    results.set(i, this->arg1_values_[i] * this->arg2_values_[i]);
-  }
-  return true;
-}
-
-// ---- DivisionOperator ----
-
-template <typename T> class DivisionNode;
-
-template <>
-class DivisionNode<Int> : public BinaryNode<Int, Int, Int> {
- public:
-  using Value = Int;
-  using Arg1 = Int;
-  using Arg2 = Int;
-
-  static unique_ptr<DivisionNode> create(Error *error,
-                                         unique_ptr<Node> &&arg1,
-                                         unique_ptr<Node> &&arg2) {
-    unique_ptr<DivisionNode> node(
-        new (nothrow) DivisionNode(std::move(arg1), std::move(arg2)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  DivisionNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
-      : BinaryNode<Value, Arg1, Arg2>(std::move(arg1), std::move(arg2)) {}
-
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results);
-};
-
-bool DivisionNode<Int>::evaluate(Error *error,
-                                 ArrayCRef<Record> records,
-                                 ArrayRef<Value> results) {
-  if (!fill_arg1_values(error, records) ||
-      !fill_arg2_values(error, records)) {
-    return false;
-  }
-  for (Int i = 0; i < records.size(); ++i) {
-    if (this->arg2_values_[i] == 0) {
-      GRNXX_ERROR_SET(error, DIVISION_BY_ZERO, "Division by zero");
-      return false;
-    } else if ((this->arg2_values_[i] == -1) &&
-               (this->arg1_values_[i] == numeric_limits<Int>::min())) {
-      GRNXX_ERROR_SET(error, DIVISION_OVERFLOW, "Division overflow");
-      return false;
-    }
-    results.set(i, this->arg1_values_[i] / this->arg2_values_[i]);
-  }
-  return true;
-}
-
-template <>
-class DivisionNode<Float> : public BinaryNode<Float, Float, Float> {
- public:
-  using Value = Float;
-  using Arg1 = Float;
-  using Arg2 = Float;
-
-  static unique_ptr<DivisionNode> create(Error *error,
-                                         unique_ptr<Node> &&arg1,
-                                         unique_ptr<Node> &&arg2) {
-    unique_ptr<DivisionNode> node(
-        new (nothrow) DivisionNode(std::move(arg1), std::move(arg2)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  DivisionNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
-      : BinaryNode<Value, Arg1, Arg2>(std::move(arg1), std::move(arg2)) {}
-
-  bool adjust(Error *error, ArrayRef<Record> records);
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results);
-};
-
-bool DivisionNode<Float>::adjust(Error *error,
-                                 ArrayRef<Record> records) {
-  if (!fill_arg1_values(error, records) ||
-      !fill_arg2_values(error, records)) {
-    return false;
-  }
-  for (Int i = 0; i < records.size(); ++i) {
-    records.set_score(i, this->arg1_values_[i] / this->arg2_values_[i]);
-  }
-  return true;
-}
-
-bool DivisionNode<Float>::evaluate(Error *error,
-                                   ArrayCRef<Record> records,
-                                   ArrayRef<Value> results) {
-  if (!fill_arg1_values(error, records) ||
-      !fill_arg2_values(error, records)) {
-    return false;
-  }
-  for (Int i = 0; i < records.size(); ++i) {
-    results.set(i, this->arg1_values_[i] / this->arg2_values_[i]);
-  }
-  return true;
-}
-
-// ---- ModulusOperator ----
-
-template <typename T> class ModulusNode;
-
-template <>
-class ModulusNode<Int> : public BinaryNode<Int, Int, Int> {
- public:
-  using Value = Int;
-  using Arg1 = Int;
-  using Arg2 = Int;
-
-  static unique_ptr<ModulusNode> create(Error *error,
-                                        unique_ptr<Node> &&arg1,
-                                        unique_ptr<Node> &&arg2) {
-    unique_ptr<ModulusNode> node(
-        new (nothrow) ModulusNode(std::move(arg1), std::move(arg2)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  ModulusNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
-      : BinaryNode<Value, Arg1, Arg2>(std::move(arg1), std::move(arg2)) {}
-
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results);
-};
-
-bool ModulusNode<Int>::evaluate(Error *error,
-                                ArrayCRef<Record> records,
-                                ArrayRef<Value> results) {
-  if (!fill_arg1_values(error, records) ||
-      !fill_arg2_values(error, records)) {
-    return false;
-  }
-  for (Int i = 0; i < records.size(); ++i) {
-    if (this->arg2_values_[i] == 0) {
-      GRNXX_ERROR_SET(error, DIVISION_BY_ZERO, "Division by zero");
-      return false;
-    } else if ((this->arg2_values_[i] == -1) &&
-               (this->arg1_values_[i] == numeric_limits<Int>::min())) {
-      GRNXX_ERROR_SET(error, DIVISION_OVERFLOW, "Division overflow");
-      return false;
-    }
-    results.set(i, this->arg1_values_[i] % this->arg2_values_[i]);
-  }
-  return true;
-}
-
-}  // namespace expression
-
-}  // namespace grnxx

  Modified: lib/grnxx/types.cpp (+3 -0)
===================================================================
--- lib/grnxx/types.cpp    2014-08-12 16:14:13 +0900 (7ec2757)
+++ lib/grnxx/types.cpp    2014-08-12 19:05:59 +0900 (ddad422)
@@ -53,6 +53,9 @@ CursorOptions::CursorOptions()
       limit(numeric_limits<Int>::max()),
       order_type(REGULAR_ORDER) {}
 
+ExpressionOptions::ExpressionOptions()
+    : block_size(1024) {}
+
 SorterOptions::SorterOptions()
     : offset(0),
       limit(numeric_limits<Int>::max()) {}




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