You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tajo.apache.org by hy...@apache.org on 2014/04/30 13:01:52 UTC

[3/3] git commit: TAJO-797: Implicit type conversion support. (hyunsik)

TAJO-797: Implicit type conversion support. (hyunsik)


Project: http://git-wip-us.apache.org/repos/asf/tajo/repo
Commit: http://git-wip-us.apache.org/repos/asf/tajo/commit/bd032094
Tree: http://git-wip-us.apache.org/repos/asf/tajo/tree/bd032094
Diff: http://git-wip-us.apache.org/repos/asf/tajo/diff/bd032094

Branch: refs/heads/master
Commit: bd032094caa0f54ddfbee2ee5eb6ab46824a9afa
Parents: cde1bca
Author: Hyunsik Choi <hy...@apache.org>
Authored: Wed Apr 30 19:57:29 2014 +0900
Committer: Hyunsik Choi <hy...@apache.org>
Committed: Wed Apr 30 19:57:29 2014 +0900

----------------------------------------------------------------------
 CHANGES                                         |   2 +
 .../org/apache/tajo/catalog/CatalogUtil.java    |  15 +-
 .../org/apache/tajo/catalog/FunctionDesc.java   |   2 +-
 .../java/org/apache/tajo/datum/BitDatum.java    |   2 +-
 .../java/org/apache/tajo/datum/BlobDatum.java   |   2 +-
 .../org/apache/tajo/datum/BooleanDatum.java     |  11 +-
 .../java/org/apache/tajo/datum/CharDatum.java   |   2 +-
 .../java/org/apache/tajo/datum/DateDatum.java   |   4 +-
 .../main/java/org/apache/tajo/datum/Datum.java  |  24 +-
 .../org/apache/tajo/datum/DatumFactory.java     |  14 +-
 .../java/org/apache/tajo/datum/Float4Datum.java |  30 +-
 .../java/org/apache/tajo/datum/Float8Datum.java |   2 +-
 .../java/org/apache/tajo/datum/Inet4Datum.java  |   2 +-
 .../java/org/apache/tajo/datum/Int2Datum.java   |   2 +-
 .../java/org/apache/tajo/datum/Int4Datum.java   |   2 +-
 .../java/org/apache/tajo/datum/Int8Datum.java   |   4 +-
 .../org/apache/tajo/datum/IntervalDatum.java    |   2 +-
 .../java/org/apache/tajo/datum/NullDatum.java   |   4 +-
 .../java/org/apache/tajo/datum/TextDatum.java   |   4 +-
 .../java/org/apache/tajo/datum/TimeDatum.java   |   4 +-
 .../org/apache/tajo/datum/TimestampDatum.java   |   2 +-
 .../datum/exception/InvalidCastException.java   |  33 -
 .../exception/InvalidOperationException.java    |  42 -
 .../tajo/exception/InvalidCastException.java    |  36 +
 .../exception/InvalidOperationException.java    |  42 +
 .../main/java/org/apache/tajo/util/TUtil.java   |  22 +
 .../org/apache/tajo/datum/TestDateDatum.java    |   2 +-
 .../apache/tajo/datum/TestIntervalDatum.java    |   2 +-
 .../org/apache/tajo/datum/TestTimeDatum.java    |   2 +-
 .../apache/tajo/datum/TestTimestampDatum.java   |   2 +-
 .../apache/tajo/engine/eval/AlgebraicUtil.java  | 261 +++---
 .../tajo/engine/eval/BasicEvalNodeVisitor.java  |  78 +-
 .../tajo/engine/eval/BetweenPredicateEval.java  |  13 +-
 .../org/apache/tajo/engine/eval/BinaryEval.java |  86 +-
 .../apache/tajo/engine/eval/CaseWhenEval.java   |  20 +
 .../org/apache/tajo/engine/eval/CastEval.java   |  29 +-
 .../org/apache/tajo/engine/eval/EvalNode.java   |  74 +-
 .../apache/tajo/engine/eval/EvalTreeUtil.java   |  75 +-
 .../org/apache/tajo/engine/eval/EvalType.java   |  44 ++
 .../tajo/engine/eval/InvalidCastException.java  |  36 -
 .../org/apache/tajo/engine/eval/IsNullEval.java |   8 +-
 .../org/apache/tajo/engine/eval/NotEval.java    |  50 +-
 .../tajo/engine/eval/PartialBinaryExpr.java     |  13 +-
 .../tajo/engine/eval/RowConstantEval.java       |  10 +
 .../org/apache/tajo/engine/eval/SignedEval.java |  47 +-
 .../tajo/engine/eval/SimpleEvalNodeVisitor.java | 173 ++++
 .../org/apache/tajo/engine/eval/UnaryEval.java  |  96 +++
 .../tajo/engine/planner/ExprAnnotator.java      | 269 ++++++-
 .../tajo/engine/planner/ExprsVerifier.java      |   8 +-
 .../apache/tajo/engine/planner/PlannerUtil.java |   3 +-
 .../tajo/engine/planner/logical/JoinNode.java   |   3 +-
 .../engine/planner/logical/join/JoinGraph.java  |   5 +-
 .../planner/rewrite/FilterPushDownRule.java     |   9 +-
 .../rewrite/PartitionedTableRewriter.java       |   9 +-
 .../java/org/apache/tajo/util/ClassUtil.java    |   7 +-
 .../java/org/apache/tajo/util/IndexUtil.java    |  19 +-
 .../apache/tajo/engine/eval/TestEvalTree.java   |  34 +-
 .../tajo/engine/eval/TestEvalTreeUtil.java      |  12 +-
 .../tajo/engine/eval/TestIntervalType.java      |   2 +-
 .../tajo/engine/eval/TestSQLExpression.java     | 784 ++++++++++++++++++-
 .../tajo/engine/function/TestMathFunctions.java |   4 +-
 .../tajo/engine/planner/TestExprAnnotator.java  |  46 ++
 .../storage/TextSerializerDeserializer.java     |   1 +
 .../java/org/apache/tajo/storage/VTuple.java    |  10 +-
 64 files changed, 2004 insertions(+), 653 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tajo/blob/bd032094/CHANGES
----------------------------------------------------------------------
diff --git a/CHANGES b/CHANGES
index b71cbc6..7ac546e 100644
--- a/CHANGES
+++ b/CHANGES
@@ -12,6 +12,8 @@ Release 0.9.0 - unreleased
 
   IMPROVEMENT
 
+    TAJO-797: Implicit type conversion support. (hyunsik)
+
     TAJO-804: Bump up Parquet version to 1.4.2. (hyunsik)
 
     TAJO-425: RAWFILE_SYNC_INTERVAL has not default value. (jinho)

http://git-wip-us.apache.org/repos/asf/tajo/blob/bd032094/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/CatalogUtil.java
----------------------------------------------------------------------
diff --git a/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/CatalogUtil.java b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/CatalogUtil.java
index 1dd33b2..c363eb0 100644
--- a/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/CatalogUtil.java
+++ b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/CatalogUtil.java
@@ -27,7 +27,7 @@ import org.apache.tajo.catalog.proto.CatalogProtos.SchemaProto;
 import org.apache.tajo.catalog.proto.CatalogProtos.TableDescProto;
 import org.apache.tajo.common.TajoDataTypes;
 import org.apache.tajo.common.TajoDataTypes.DataType;
-import org.apache.tajo.datum.exception.InvalidOperationException;
+import org.apache.tajo.exception.InvalidOperationException;
 import org.apache.tajo.util.StringUtils;
 
 import java.sql.Connection;
@@ -550,6 +550,10 @@ public class CatalogUtil {
    * @return True if the parameter definition can be variable length.
    */
   public static boolean checkIfVariableLengthParamDefinition(List<DataType> definedTypes) {
+    if (definedTypes.size() < 1) { // if no parameter function
+      return false;
+    }
+
     // Get the last param type of the function definition.
     Type lastDefinedParamType = definedTypes.get(definedTypes.size() - 1).getType();
 
@@ -558,8 +562,11 @@ public class CatalogUtil {
     return CatalogUtil.isArrayType(lastDefinedParamType);
   }
 
-  public static Type getPrimitiveTypeOf(Type arrayType) {
-    switch (arrayType) {
+  public static Type getPrimitiveTypeOf(Type type) {
+    if (!isArrayType(type)) { // If the type is already primitive, it will just return the type.
+      return type;
+    }
+    switch (type) {
     case BOOLEAN_ARRAY: return Type.BOOLEAN;
     case UINT1_ARRAY: return Type.UINT1;
     case UINT2_ARRAY: return Type.UINT2;
@@ -583,7 +590,7 @@ public class CatalogUtil {
     case TIMESTAMP_ARRAY: return Type.TIMESTAMP;
     case TIMESTAMPZ_ARRAY: return Type.TIMESTAMPZ;
     case INTERVAL_ARRAY: return Type.INTERVAL;
-    default: throw new InvalidOperationException("Invalid array type: " + arrayType.name());
+    default: throw new InvalidOperationException("Invalid array type: " + type.name());
     }
   }
 

http://git-wip-us.apache.org/repos/asf/tajo/blob/bd032094/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/FunctionDesc.java
----------------------------------------------------------------------
diff --git a/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/FunctionDesc.java b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/FunctionDesc.java
index d6d9290..bed4f08 100644
--- a/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/FunctionDesc.java
+++ b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/FunctionDesc.java
@@ -196,7 +196,7 @@ public class FunctionDesc implements ProtoObject<FunctionDescProto>, Cloneable,
   
   @Override
   public String toString() {
-	  return getProto().toString();
+	  return getHelpSignature();
   }
   
   public String toJson() {

http://git-wip-us.apache.org/repos/asf/tajo/blob/bd032094/tajo-common/src/main/java/org/apache/tajo/datum/BitDatum.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/java/org/apache/tajo/datum/BitDatum.java b/tajo-common/src/main/java/org/apache/tajo/datum/BitDatum.java
index 5194420..8ada5e8 100644
--- a/tajo-common/src/main/java/org/apache/tajo/datum/BitDatum.java
+++ b/tajo-common/src/main/java/org/apache/tajo/datum/BitDatum.java
@@ -20,7 +20,7 @@ package org.apache.tajo.datum;
 
 import com.google.gson.annotations.Expose;
 import org.apache.tajo.common.TajoDataTypes;
-import org.apache.tajo.datum.exception.InvalidOperationException;
+import org.apache.tajo.exception.InvalidOperationException;
 import org.apache.tajo.util.NumberUtil;
 
 public class BitDatum extends Datum {

http://git-wip-us.apache.org/repos/asf/tajo/blob/bd032094/tajo-common/src/main/java/org/apache/tajo/datum/BlobDatum.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/java/org/apache/tajo/datum/BlobDatum.java b/tajo-common/src/main/java/org/apache/tajo/datum/BlobDatum.java
index 13b845b..a0ceb95 100644
--- a/tajo-common/src/main/java/org/apache/tajo/datum/BlobDatum.java
+++ b/tajo-common/src/main/java/org/apache/tajo/datum/BlobDatum.java
@@ -22,7 +22,7 @@
 package org.apache.tajo.datum;
 
 import com.google.gson.annotations.Expose;
-import org.apache.tajo.datum.exception.InvalidOperationException;
+import org.apache.tajo.exception.InvalidOperationException;
 
 import java.nio.ByteBuffer;
 import java.nio.charset.Charset;

http://git-wip-us.apache.org/repos/asf/tajo/blob/bd032094/tajo-common/src/main/java/org/apache/tajo/datum/BooleanDatum.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/java/org/apache/tajo/datum/BooleanDatum.java b/tajo-common/src/main/java/org/apache/tajo/datum/BooleanDatum.java
index 33a2a69..93933a8 100644
--- a/tajo-common/src/main/java/org/apache/tajo/datum/BooleanDatum.java
+++ b/tajo-common/src/main/java/org/apache/tajo/datum/BooleanDatum.java
@@ -20,7 +20,7 @@ package org.apache.tajo.datum;
 
 import com.google.gson.annotations.Expose;
 import org.apache.tajo.common.TajoDataTypes;
-import org.apache.tajo.datum.exception.InvalidOperationException;
+import org.apache.tajo.exception.InvalidOperationException;
 
 public class BooleanDatum extends Datum {
   @Expose private final boolean val;
@@ -29,9 +29,10 @@ public class BooleanDatum extends Datum {
   public static final BooleanDatum TRUE = new BooleanDatum(true);
   public static final BooleanDatum FALSE = new BooleanDatum(false);
 
-  public static final int UNKNOWN_INT = 0;
-  public static final int TRUE_INT = 1;
-  public static final int FALSE_INT = 2;
+  // Three-valued Login Constants
+  public static final byte UNKNOWN_INT = 0;
+  public static final byte TRUE_INT = 1;
+  public static final byte FALSE_INT = 2;
   public static final byte [] TRUE_BYTES = new byte[] {TRUE_INT};
   public static final byte [] FALSE_BYTES = new byte[] {FALSE_INT};
 
@@ -54,7 +55,7 @@ public class BooleanDatum extends Datum {
       new Datum [] {NullDatum.get(), TRUE, FALSE          }  // false
   };
 
-  protected BooleanDatum(boolean val) {
+  private BooleanDatum(boolean val) {
     super(TajoDataTypes.Type.BOOLEAN);
     this.val = val;
   }

http://git-wip-us.apache.org/repos/asf/tajo/blob/bd032094/tajo-common/src/main/java/org/apache/tajo/datum/CharDatum.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/java/org/apache/tajo/datum/CharDatum.java b/tajo-common/src/main/java/org/apache/tajo/datum/CharDatum.java
index e31f59e..444ca66 100644
--- a/tajo-common/src/main/java/org/apache/tajo/datum/CharDatum.java
+++ b/tajo-common/src/main/java/org/apache/tajo/datum/CharDatum.java
@@ -20,7 +20,7 @@ package org.apache.tajo.datum;
 
 import com.google.common.primitives.UnsignedBytes;
 import com.google.gson.annotations.Expose;
-import org.apache.tajo.datum.exception.InvalidOperationException;
+import org.apache.tajo.exception.InvalidOperationException;
 
 import java.util.Arrays;
 

http://git-wip-us.apache.org/repos/asf/tajo/blob/bd032094/tajo-common/src/main/java/org/apache/tajo/datum/DateDatum.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/java/org/apache/tajo/datum/DateDatum.java b/tajo-common/src/main/java/org/apache/tajo/datum/DateDatum.java
index 6b155ac..ad68303 100644
--- a/tajo-common/src/main/java/org/apache/tajo/datum/DateDatum.java
+++ b/tajo-common/src/main/java/org/apache/tajo/datum/DateDatum.java
@@ -19,8 +19,8 @@
 package org.apache.tajo.datum;
 
 import org.apache.tajo.common.TajoDataTypes;
-import org.apache.tajo.datum.exception.InvalidCastException;
-import org.apache.tajo.datum.exception.InvalidOperationException;
+import org.apache.tajo.exception.InvalidCastException;
+import org.apache.tajo.exception.InvalidOperationException;
 import org.apache.tajo.util.Bytes;
 import org.joda.time.*;
 import org.joda.time.format.DateTimeFormat;

http://git-wip-us.apache.org/repos/asf/tajo/blob/bd032094/tajo-common/src/main/java/org/apache/tajo/datum/Datum.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/java/org/apache/tajo/datum/Datum.java b/tajo-common/src/main/java/org/apache/tajo/datum/Datum.java
index aee5621..af88ebe 100644
--- a/tajo-common/src/main/java/org/apache/tajo/datum/Datum.java
+++ b/tajo-common/src/main/java/org/apache/tajo/datum/Datum.java
@@ -19,8 +19,8 @@
 package org.apache.tajo.datum;
 
 import com.google.gson.annotations.Expose;
-import org.apache.tajo.datum.exception.InvalidCastException;
-import org.apache.tajo.datum.exception.InvalidOperationException;
+import org.apache.tajo.exception.InvalidCastException;
+import org.apache.tajo.exception.InvalidOperationException;
 import org.apache.tajo.json.CommonGsonHelper;
 import org.apache.tajo.json.GsonObject;
 
@@ -46,42 +46,42 @@ public abstract class Datum implements Comparable<Datum>, GsonObject {
   }
 
   public boolean asBool() {
-    throw new InvalidCastException(type + " cannot be casted to BOOL type");
+    throw new InvalidCastException(type, Type.BOOLEAN);
   }
 
   public byte asByte() {
-    throw new InvalidCastException(type + " cannot be casted to BYTE type");
+    throw new InvalidCastException(type, Type.BIT);
   }
 
   public char asChar() {
-    throw new InvalidCastException(type + " cannot be casted to CHAR type");
+    throw new InvalidCastException(type, Type.CHAR);
   }
 
   public short asInt2() {
-    throw new InvalidCastException(type + " cannot be casted to SHORT type");
+    throw new InvalidCastException(type, Type.INT2);
   }
   public int asInt4() {
-    throw new InvalidCastException(type + " cannot be casted to INT type");
+    throw new InvalidCastException(type, Type.INT1);
   }
 
   public long asInt8() {
-    throw new InvalidCastException(type + " cannot be casted to LONG type");
+    throw new InvalidCastException(type, Type.INT8);
   }
 
   public byte [] asByteArray() {
-    throw new InvalidCastException(type + " cannot be casted to BYTES type");
+    throw new InvalidCastException(type, Type.BLOB);
   }
 
   public float asFloat4() {
-    throw new InvalidCastException(type + " cannot be casted to FLOAT type");
+    throw new InvalidCastException(type, Type.FLOAT4);
   }
 
   public double asFloat8() {
-    throw new InvalidCastException(type + " cannot be casted to DOUBLE type");
+    throw new InvalidCastException(type, Type.FLOAT8);
   }
 
   public String asChars() {
-    throw new InvalidCastException(type + " cannot be casted to STRING type");
+    throw new InvalidCastException(type, Type.TEXT);
   }
 
   public byte[] asTextBytes() {

http://git-wip-us.apache.org/repos/asf/tajo/blob/bd032094/tajo-common/src/main/java/org/apache/tajo/datum/DatumFactory.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/java/org/apache/tajo/datum/DatumFactory.java b/tajo-common/src/main/java/org/apache/tajo/datum/DatumFactory.java
index 4eacfc3..dad4eda 100644
--- a/tajo-common/src/main/java/org/apache/tajo/datum/DatumFactory.java
+++ b/tajo-common/src/main/java/org/apache/tajo/datum/DatumFactory.java
@@ -21,7 +21,7 @@ package org.apache.tajo.datum;
 import com.google.protobuf.Message;
 import org.apache.tajo.common.TajoDataTypes.DataType;
 import org.apache.tajo.common.TajoDataTypes.Type;
-import org.apache.tajo.datum.exception.InvalidCastException;
+import org.apache.tajo.exception.InvalidCastException;
 import org.apache.tajo.util.Bytes;
 import org.joda.time.DateTime;
 import org.joda.time.LocalDate;
@@ -186,6 +186,10 @@ public class DatumFactory {
     return BooleanDatum.THREE_VALUES[(int)val];
   }
 
+  public static Datum createBool(int val) {
+    return BooleanDatum.THREE_VALUES[val];
+  }
+
   public static BooleanDatum createBool(boolean val) {
     return val ? BooleanDatum.TRUE : BooleanDatum.FALSE;
   }
@@ -301,7 +305,7 @@ public class DatumFactory {
     case DATE:
       return (DateDatum) datum;
     default:
-      throw new InvalidCastException(datum.type() + " cannot be casted to DATE type");
+      throw new InvalidCastException(datum.type(), Type.DATE);
     }
   }
 
@@ -314,7 +318,7 @@ public class DatumFactory {
     case TIME:
       return (TimeDatum) datum;
     default:
-      throw new InvalidCastException(datum.type() + " cannot be casted to TIME type");
+      throw new InvalidCastException(datum.type(), Type.TIME);
     }
   }
 
@@ -325,7 +329,7 @@ public class DatumFactory {
       case TIMESTAMP:
         return (TimestampDatum) datum;
       default:
-        throw new InvalidCastException(datum.type() + " cannot be casted to TIMESTAMP type");
+        throw new InvalidCastException(datum.type(), Type.TIMESTAMP);
     }
   }
 
@@ -381,7 +385,7 @@ public class DatumFactory {
     case BLOB:
       return DatumFactory.createBlob(operandDatum.asByteArray());
     default:
-      throw new InvalidCastException("Cannot cast " + operandDatum.type() + " to " + target.getType());
+      throw new InvalidCastException(operandDatum.type(), target.getType());
     }
   }
 }

http://git-wip-us.apache.org/repos/asf/tajo/blob/bd032094/tajo-common/src/main/java/org/apache/tajo/datum/Float4Datum.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/java/org/apache/tajo/datum/Float4Datum.java b/tajo-common/src/main/java/org/apache/tajo/datum/Float4Datum.java
index b042f2d..35dca00 100644
--- a/tajo-common/src/main/java/org/apache/tajo/datum/Float4Datum.java
+++ b/tajo-common/src/main/java/org/apache/tajo/datum/Float4Datum.java
@@ -20,8 +20,8 @@ package org.apache.tajo.datum;
 
 import com.google.gson.annotations.Expose;
 import org.apache.tajo.common.TajoDataTypes;
-import org.apache.tajo.datum.exception.InvalidCastException;
-import org.apache.tajo.datum.exception.InvalidOperationException;
+import org.apache.tajo.exception.InvalidCastException;
+import org.apache.tajo.exception.InvalidOperationException;
 import org.apache.tajo.util.NumberUtil;
 
 import java.nio.ByteBuffer;
@@ -205,9 +205,9 @@ public class Float4Datum extends NumericDatum {
     case INT4:
       return DatumFactory.createFloat4(val + datum.asInt4());
     case INT8:
-      return DatumFactory.createFloat8(val + datum.asInt8());
+      return DatumFactory.createFloat4(val + datum.asInt8());
     case FLOAT4:
-      return DatumFactory.createFloat8(val + datum.asFloat4());
+      return DatumFactory.createFloat4(val + datum.asFloat4());
     case FLOAT8:
       return DatumFactory.createFloat8(val + datum.asFloat8());
     case DATE:
@@ -227,9 +227,9 @@ public class Float4Datum extends NumericDatum {
     case INT4:
       return DatumFactory.createFloat4(val - datum.asInt4());
     case INT8:
-      return DatumFactory.createFloat8(val - datum.asInt8());
+      return DatumFactory.createFloat4(val - datum.asInt8());
     case FLOAT4:
-      return DatumFactory.createFloat8(val - datum.asFloat4());
+      return DatumFactory.createFloat4(val - datum.asFloat4());
     case FLOAT8:
       return DatumFactory.createFloat8(val - datum.asFloat8());
     case DATE:
@@ -249,9 +249,9 @@ public class Float4Datum extends NumericDatum {
     case INT4:
       return DatumFactory.createFloat4(val * datum.asInt4());
     case INT8:
-      return DatumFactory.createFloat8(val * datum.asInt8());
+      return DatumFactory.createFloat4(val * datum.asInt8());
     case FLOAT4:
-      return DatumFactory.createFloat8(val * datum.asFloat4());
+      return DatumFactory.createFloat4(val * datum.asFloat4());
     case FLOAT8:
       return DatumFactory.createFloat8(val * datum.asFloat8());
     case INTERVAL:
@@ -272,9 +272,9 @@ public class Float4Datum extends NumericDatum {
     case INT4:
       return DatumFactory.createFloat4(val / datum.asInt4());
     case INT8:
-      return DatumFactory.createFloat8(val / datum.asInt8());
+      return DatumFactory.createFloat4(val / datum.asInt8());
     case FLOAT4:
-      return DatumFactory.createFloat8(val / datum.asFloat4());
+      return DatumFactory.createFloat4(val / datum.asFloat4());
     case FLOAT8:
       return DatumFactory.createFloat8(val / datum.asFloat8());
     case NULL_TYPE:
@@ -288,15 +288,15 @@ public class Float4Datum extends NumericDatum {
   public Datum modular(Datum datum) {
     switch (datum.type()) {
       case INT2:
-        return DatumFactory.createFloat4(val / datum.asInt2());
+        return DatumFactory.createFloat4(val % datum.asInt2());
       case INT4:
-        return DatumFactory.createFloat4(val / datum.asInt4());
+        return DatumFactory.createFloat4(val % datum.asInt4());
       case INT8:
-        return DatumFactory.createFloat4(val / datum.asInt8());
+        return DatumFactory.createFloat4(val % datum.asInt8());
       case FLOAT4:
-        return DatumFactory.createFloat4(val / datum.asFloat4());
+        return DatumFactory.createFloat4(val % datum.asFloat4());
       case FLOAT8:
-        return DatumFactory.createFloat8(val / datum.asFloat8());
+        return DatumFactory.createFloat8(val % datum.asFloat8());
       case NULL_TYPE:
         return datum;
       default:

http://git-wip-us.apache.org/repos/asf/tajo/blob/bd032094/tajo-common/src/main/java/org/apache/tajo/datum/Float8Datum.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/java/org/apache/tajo/datum/Float8Datum.java b/tajo-common/src/main/java/org/apache/tajo/datum/Float8Datum.java
index 55b079f..b7d8cf4 100644
--- a/tajo-common/src/main/java/org/apache/tajo/datum/Float8Datum.java
+++ b/tajo-common/src/main/java/org/apache/tajo/datum/Float8Datum.java
@@ -20,7 +20,7 @@ package org.apache.tajo.datum;
 
 import com.google.gson.annotations.Expose;
 import org.apache.tajo.common.TajoDataTypes;
-import org.apache.tajo.datum.exception.InvalidOperationException;
+import org.apache.tajo.exception.InvalidOperationException;
 import org.apache.tajo.util.Bytes;
 import org.apache.tajo.util.NumberUtil;
 

http://git-wip-us.apache.org/repos/asf/tajo/blob/bd032094/tajo-common/src/main/java/org/apache/tajo/datum/Inet4Datum.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/java/org/apache/tajo/datum/Inet4Datum.java b/tajo-common/src/main/java/org/apache/tajo/datum/Inet4Datum.java
index 991fa70..08b76f0 100644
--- a/tajo-common/src/main/java/org/apache/tajo/datum/Inet4Datum.java
+++ b/tajo-common/src/main/java/org/apache/tajo/datum/Inet4Datum.java
@@ -20,7 +20,7 @@ package org.apache.tajo.datum;
 
 import com.google.common.base.Preconditions;
 import com.google.gson.annotations.Expose;
-import org.apache.tajo.datum.exception.InvalidOperationException;
+import org.apache.tajo.exception.InvalidOperationException;
 import org.apache.tajo.util.Bytes;
 
 import static org.apache.tajo.common.TajoDataTypes.Type;

http://git-wip-us.apache.org/repos/asf/tajo/blob/bd032094/tajo-common/src/main/java/org/apache/tajo/datum/Int2Datum.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/java/org/apache/tajo/datum/Int2Datum.java b/tajo-common/src/main/java/org/apache/tajo/datum/Int2Datum.java
index 46616e7..731ccdc 100644
--- a/tajo-common/src/main/java/org/apache/tajo/datum/Int2Datum.java
+++ b/tajo-common/src/main/java/org/apache/tajo/datum/Int2Datum.java
@@ -20,7 +20,7 @@ package org.apache.tajo.datum;
 
 import com.google.gson.annotations.Expose;
 import org.apache.tajo.common.TajoDataTypes;
-import org.apache.tajo.datum.exception.InvalidOperationException;
+import org.apache.tajo.exception.InvalidOperationException;
 import org.apache.tajo.util.NumberUtil;
 
 import java.nio.ByteBuffer;

http://git-wip-us.apache.org/repos/asf/tajo/blob/bd032094/tajo-common/src/main/java/org/apache/tajo/datum/Int4Datum.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/java/org/apache/tajo/datum/Int4Datum.java b/tajo-common/src/main/java/org/apache/tajo/datum/Int4Datum.java
index 8296a0f..5b60e9e 100644
--- a/tajo-common/src/main/java/org/apache/tajo/datum/Int4Datum.java
+++ b/tajo-common/src/main/java/org/apache/tajo/datum/Int4Datum.java
@@ -20,7 +20,7 @@ package org.apache.tajo.datum;
 
 import com.google.gson.annotations.Expose;
 import org.apache.tajo.common.TajoDataTypes.Type;
-import org.apache.tajo.datum.exception.InvalidOperationException;
+import org.apache.tajo.exception.InvalidOperationException;
 import org.apache.tajo.util.NumberUtil;
 
 import java.nio.ByteBuffer;

http://git-wip-us.apache.org/repos/asf/tajo/blob/bd032094/tajo-common/src/main/java/org/apache/tajo/datum/Int8Datum.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/java/org/apache/tajo/datum/Int8Datum.java b/tajo-common/src/main/java/org/apache/tajo/datum/Int8Datum.java
index 6d3e5b2..0367f9c 100644
--- a/tajo-common/src/main/java/org/apache/tajo/datum/Int8Datum.java
+++ b/tajo-common/src/main/java/org/apache/tajo/datum/Int8Datum.java
@@ -20,8 +20,8 @@ package org.apache.tajo.datum;
 
 import com.google.gson.annotations.Expose;
 import org.apache.tajo.common.TajoDataTypes;
-import org.apache.tajo.datum.exception.InvalidCastException;
-import org.apache.tajo.datum.exception.InvalidOperationException;
+import org.apache.tajo.exception.InvalidCastException;
+import org.apache.tajo.exception.InvalidOperationException;
 import org.apache.tajo.util.NumberUtil;
 
 import java.nio.ByteBuffer;

http://git-wip-us.apache.org/repos/asf/tajo/blob/bd032094/tajo-common/src/main/java/org/apache/tajo/datum/IntervalDatum.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/java/org/apache/tajo/datum/IntervalDatum.java b/tajo-common/src/main/java/org/apache/tajo/datum/IntervalDatum.java
index 029203e..b6904a9 100644
--- a/tajo-common/src/main/java/org/apache/tajo/datum/IntervalDatum.java
+++ b/tajo-common/src/main/java/org/apache/tajo/datum/IntervalDatum.java
@@ -20,7 +20,7 @@ package org.apache.tajo.datum;
 
 import com.google.common.base.Objects;
 import org.apache.tajo.common.TajoDataTypes;
-import org.apache.tajo.datum.exception.InvalidOperationException;
+import org.apache.tajo.exception.InvalidOperationException;
 import org.joda.time.DateTime;
 import org.joda.time.LocalDate;
 import org.joda.time.LocalTime;

http://git-wip-us.apache.org/repos/asf/tajo/blob/bd032094/tajo-common/src/main/java/org/apache/tajo/datum/NullDatum.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/java/org/apache/tajo/datum/NullDatum.java b/tajo-common/src/main/java/org/apache/tajo/datum/NullDatum.java
index a2b42c4..9842490 100644
--- a/tajo-common/src/main/java/org/apache/tajo/datum/NullDatum.java
+++ b/tajo-common/src/main/java/org/apache/tajo/datum/NullDatum.java
@@ -18,7 +18,7 @@
 
 package org.apache.tajo.datum;
 
-import org.apache.tajo.datum.exception.InvalidCastException;
+import org.apache.tajo.exception.InvalidCastException;
 
 import static org.apache.tajo.common.TajoDataTypes.Type;
 
@@ -45,7 +45,7 @@ public class NullDatum extends Datum {
 
   @Override
   public boolean asBool() {
-    throw new InvalidCastException("NULL cannot be casted as a bool type value.");
+    throw new InvalidCastException(Type.NULL_TYPE, Type.BOOLEAN);
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/tajo/blob/bd032094/tajo-common/src/main/java/org/apache/tajo/datum/TextDatum.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/java/org/apache/tajo/datum/TextDatum.java b/tajo-common/src/main/java/org/apache/tajo/datum/TextDatum.java
index 669933f..313b905 100644
--- a/tajo-common/src/main/java/org/apache/tajo/datum/TextDatum.java
+++ b/tajo-common/src/main/java/org/apache/tajo/datum/TextDatum.java
@@ -21,8 +21,8 @@ package org.apache.tajo.datum;
 import com.google.common.primitives.UnsignedBytes;
 import com.google.gson.annotations.Expose;
 import org.apache.tajo.common.TajoDataTypes;
-import org.apache.tajo.datum.exception.InvalidCastException;
-import org.apache.tajo.datum.exception.InvalidOperationException;
+import org.apache.tajo.exception.InvalidCastException;
+import org.apache.tajo.exception.InvalidOperationException;
 
 import java.util.Arrays;
 import java.util.Comparator;

http://git-wip-us.apache.org/repos/asf/tajo/blob/bd032094/tajo-common/src/main/java/org/apache/tajo/datum/TimeDatum.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/java/org/apache/tajo/datum/TimeDatum.java b/tajo-common/src/main/java/org/apache/tajo/datum/TimeDatum.java
index e7f1684..70f62c2 100644
--- a/tajo-common/src/main/java/org/apache/tajo/datum/TimeDatum.java
+++ b/tajo-common/src/main/java/org/apache/tajo/datum/TimeDatum.java
@@ -19,8 +19,8 @@
 package org.apache.tajo.datum;
 
 import org.apache.tajo.common.TajoDataTypes;
-import org.apache.tajo.datum.exception.InvalidCastException;
-import org.apache.tajo.datum.exception.InvalidOperationException;
+import org.apache.tajo.exception.InvalidCastException;
+import org.apache.tajo.exception.InvalidOperationException;
 import org.apache.tajo.util.Bytes;
 import org.joda.time.DateTime;
 import org.joda.time.LocalTime;

http://git-wip-us.apache.org/repos/asf/tajo/blob/bd032094/tajo-common/src/main/java/org/apache/tajo/datum/TimestampDatum.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/java/org/apache/tajo/datum/TimestampDatum.java b/tajo-common/src/main/java/org/apache/tajo/datum/TimestampDatum.java
index 219d5ca..879428b 100644
--- a/tajo-common/src/main/java/org/apache/tajo/datum/TimestampDatum.java
+++ b/tajo-common/src/main/java/org/apache/tajo/datum/TimestampDatum.java
@@ -21,7 +21,7 @@ package org.apache.tajo.datum;
 import com.google.common.base.Objects;
 import org.apache.commons.lang.StringUtils;
 import org.apache.tajo.common.TajoDataTypes;
-import org.apache.tajo.datum.exception.InvalidOperationException;
+import org.apache.tajo.exception.InvalidOperationException;
 import org.apache.tajo.util.Bytes;
 import org.joda.time.DateTime;
 import org.joda.time.format.DateTimeFormat;

http://git-wip-us.apache.org/repos/asf/tajo/blob/bd032094/tajo-common/src/main/java/org/apache/tajo/datum/exception/InvalidCastException.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/java/org/apache/tajo/datum/exception/InvalidCastException.java b/tajo-common/src/main/java/org/apache/tajo/datum/exception/InvalidCastException.java
deleted file mode 100644
index 445c9e2..0000000
--- a/tajo-common/src/main/java/org/apache/tajo/datum/exception/InvalidCastException.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.tajo.datum.exception;
-
-public class InvalidCastException extends RuntimeException {
-	private static final long serialVersionUID = -7689027447969916148L;
-
-	public InvalidCastException() {
-	}
-
-	/**
-	 * @param message
-	 */
-	public InvalidCastException(String message) {
-		super(message);
-	}
-}

http://git-wip-us.apache.org/repos/asf/tajo/blob/bd032094/tajo-common/src/main/java/org/apache/tajo/datum/exception/InvalidOperationException.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/java/org/apache/tajo/datum/exception/InvalidOperationException.java b/tajo-common/src/main/java/org/apache/tajo/datum/exception/InvalidOperationException.java
deleted file mode 100644
index 4610a38..0000000
--- a/tajo-common/src/main/java/org/apache/tajo/datum/exception/InvalidOperationException.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.tajo.datum.exception;
-
-import static org.apache.tajo.common.TajoDataTypes.Type;
-
-public class InvalidOperationException extends RuntimeException {
-	private static final long serialVersionUID = -7689027447969916148L;
-
-	/**
-	 * 
-	 */
-	public InvalidOperationException() {
-	}
-
-	/**
-	 * @param message
-	 */
-	public InvalidOperationException(String message) {
-		super(message);
-	}
-	
-	public InvalidOperationException(Type type) {
-	  super("Cannot compare to " + type + " type datum");
-	}
-}

http://git-wip-us.apache.org/repos/asf/tajo/blob/bd032094/tajo-common/src/main/java/org/apache/tajo/exception/InvalidCastException.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/java/org/apache/tajo/exception/InvalidCastException.java b/tajo-common/src/main/java/org/apache/tajo/exception/InvalidCastException.java
new file mode 100644
index 0000000..f562924
--- /dev/null
+++ b/tajo-common/src/main/java/org/apache/tajo/exception/InvalidCastException.java
@@ -0,0 +1,36 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.tajo.exception;
+
+import org.apache.tajo.common.TajoDataTypes;
+
+public class InvalidCastException extends RuntimeException {
+	private static final long serialVersionUID = -7689027447969916148L;
+
+	public InvalidCastException() {
+	}
+
+	public InvalidCastException(TajoDataTypes.DataType src, TajoDataTypes.DataType target) {
+		super(src.getType().name() + " value cannot be casted to " + target.getType().name());
+	}
+
+  public InvalidCastException(TajoDataTypes.Type src, TajoDataTypes.Type target) {
+    super(src.name() + " value cannot be casted to " + target.name());
+  }
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/bd032094/tajo-common/src/main/java/org/apache/tajo/exception/InvalidOperationException.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/java/org/apache/tajo/exception/InvalidOperationException.java b/tajo-common/src/main/java/org/apache/tajo/exception/InvalidOperationException.java
new file mode 100644
index 0000000..f5de632
--- /dev/null
+++ b/tajo-common/src/main/java/org/apache/tajo/exception/InvalidOperationException.java
@@ -0,0 +1,42 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.tajo.exception;
+
+import static org.apache.tajo.common.TajoDataTypes.Type;
+
+public class InvalidOperationException extends RuntimeException {
+	private static final long serialVersionUID = -7689027447969916148L;
+
+	/**
+	 * 
+	 */
+	public InvalidOperationException() {
+	}
+
+	/**
+	 * @param message
+	 */
+	public InvalidOperationException(String message) {
+		super(message);
+	}
+	
+	public InvalidOperationException(Type type) {
+	  super("Cannot compare to " + type + " type datum");
+	}
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/bd032094/tajo-common/src/main/java/org/apache/tajo/util/TUtil.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/java/org/apache/tajo/util/TUtil.java b/tajo-common/src/main/java/org/apache/tajo/util/TUtil.java
index e116000..431c930 100644
--- a/tajo-common/src/main/java/org/apache/tajo/util/TUtil.java
+++ b/tajo-common/src/main/java/org/apache/tajo/util/TUtil.java
@@ -177,6 +177,28 @@ public class TUtil {
     }
   }
 
+  /**
+   * It checks if an item is included in Map<KEY1, Map<KEY2, VALUE>>.
+   *
+   * @return True if the item is included in the nested map.
+   */
+  public static <KEY1, KEY2, VALUE> boolean containsInNestedMap(Map<KEY1, Map<KEY2, VALUE>> map, KEY1 k1, KEY2 k2) {
+    return map.containsKey(k1) && map.get(k1).containsKey(k2);
+  }
+
+  /**
+   * Get an item in Map<KEY1, Map<KEY2, VALUE>>.
+   *
+   * @return a VALUE
+   */
+  public static <KEY1, KEY2, VALUE> VALUE getFromNestedMap(Map<KEY1, Map<KEY2, VALUE>> map, KEY1 k1, KEY2 k2) {
+    if (map.containsKey(k1)) {
+      return map.get(k1).get(k2);
+    } else {
+      return null;
+    }
+  }
+
   public static String collectionToString(Collection objects) {
     boolean first = true;
     StringBuilder sb = new StringBuilder();

http://git-wip-us.apache.org/repos/asf/tajo/blob/bd032094/tajo-common/src/test/java/org/apache/tajo/datum/TestDateDatum.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/test/java/org/apache/tajo/datum/TestDateDatum.java b/tajo-common/src/test/java/org/apache/tajo/datum/TestDateDatum.java
index dd915f5..2123dc5 100644
--- a/tajo-common/src/test/java/org/apache/tajo/datum/TestDateDatum.java
+++ b/tajo-common/src/test/java/org/apache/tajo/datum/TestDateDatum.java
@@ -19,7 +19,7 @@
 package org.apache.tajo.datum;
 
 import org.apache.tajo.common.TajoDataTypes.Type;
-import org.apache.tajo.datum.exception.InvalidCastException;
+import org.apache.tajo.exception.InvalidCastException;
 import org.apache.tajo.json.CommonGsonHelper;
 import org.junit.Test;
 

http://git-wip-us.apache.org/repos/asf/tajo/blob/bd032094/tajo-common/src/test/java/org/apache/tajo/datum/TestIntervalDatum.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/test/java/org/apache/tajo/datum/TestIntervalDatum.java b/tajo-common/src/test/java/org/apache/tajo/datum/TestIntervalDatum.java
index 5936c31..3bce64c 100644
--- a/tajo-common/src/test/java/org/apache/tajo/datum/TestIntervalDatum.java
+++ b/tajo-common/src/test/java/org/apache/tajo/datum/TestIntervalDatum.java
@@ -19,7 +19,7 @@
 package org.apache.tajo.datum;
 
 import org.apache.tajo.common.TajoDataTypes;
-import org.apache.tajo.datum.exception.InvalidOperationException;
+import org.apache.tajo.exception.InvalidOperationException;
 import org.joda.time.DateTime;
 import org.joda.time.LocalTime;
 import org.junit.Test;

http://git-wip-us.apache.org/repos/asf/tajo/blob/bd032094/tajo-common/src/test/java/org/apache/tajo/datum/TestTimeDatum.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/test/java/org/apache/tajo/datum/TestTimeDatum.java b/tajo-common/src/test/java/org/apache/tajo/datum/TestTimeDatum.java
index 63f8252..c405d68 100644
--- a/tajo-common/src/test/java/org/apache/tajo/datum/TestTimeDatum.java
+++ b/tajo-common/src/test/java/org/apache/tajo/datum/TestTimeDatum.java
@@ -20,7 +20,7 @@ package org.apache.tajo.datum;
 
 import org.apache.tajo.common.TajoDataTypes.Type;
 import org.apache.tajo.common.TajoDataTypes.DataType;
-import org.apache.tajo.datum.exception.InvalidCastException;
+import org.apache.tajo.exception.InvalidCastException;
 import org.apache.tajo.json.CommonGsonHelper;
 import org.junit.Test;
 

http://git-wip-us.apache.org/repos/asf/tajo/blob/bd032094/tajo-common/src/test/java/org/apache/tajo/datum/TestTimestampDatum.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/test/java/org/apache/tajo/datum/TestTimestampDatum.java b/tajo-common/src/test/java/org/apache/tajo/datum/TestTimestampDatum.java
index 7aa01ac..6551077 100644
--- a/tajo-common/src/test/java/org/apache/tajo/datum/TestTimestampDatum.java
+++ b/tajo-common/src/test/java/org/apache/tajo/datum/TestTimestampDatum.java
@@ -19,7 +19,7 @@
 package org.apache.tajo.datum;
 
 import org.apache.tajo.common.TajoDataTypes.Type;
-import org.apache.tajo.datum.exception.InvalidCastException;
+import org.apache.tajo.exception.InvalidCastException;
 import org.apache.tajo.json.CommonGsonHelper;
 import org.junit.BeforeClass;
 import org.junit.Test;

http://git-wip-us.apache.org/repos/asf/tajo/blob/bd032094/tajo-core/src/main/java/org/apache/tajo/engine/eval/AlgebraicUtil.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/eval/AlgebraicUtil.java b/tajo-core/src/main/java/org/apache/tajo/engine/eval/AlgebraicUtil.java
index 6bb0160..1cb37db 100644
--- a/tajo-core/src/main/java/org/apache/tajo/engine/eval/AlgebraicUtil.java
+++ b/tajo-core/src/main/java/org/apache/tajo/engine/eval/AlgebraicUtil.java
@@ -23,6 +23,7 @@ import org.apache.tajo.catalog.Column;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.Stack;
 
 public class AlgebraicUtil {
   
@@ -31,61 +32,69 @@ public class AlgebraicUtil {
    * where the variable corresponding to the target is placed 
    * on the left-hand side.
    * 
-   * @param expr
+   * @param evalNode
    * @param target
    * @return Transposed expression
    */
-  public static EvalNode transpose(EvalNode expr, Column target) {
-    EvalNode commutated = null;
-    // If the variable is in the right term, inverse the expr.
-    if (!EvalTreeUtil.containColumnRef(expr.getLeftExpr(), target)) {
-      // the commutate method works with a copy of the expr
-      commutated = commutate(expr);
-    } else {
-      try {
-        commutated = (EvalNode) expr.clone();
-      } catch (CloneNotSupportedException e) {
-        throw new AlgebraicException(e);
+  public static EvalNode transpose(EvalNode evalNode, Column target) {
+    BinaryEval commutated = null;
+
+    if (evalNode instanceof BinaryEval) { // if it is binary
+      BinaryEval binaryEval = (BinaryEval) evalNode;
+      // If the variable is in the right term, inverse the expr.
+      if (!EvalTreeUtil.containColumnRef(binaryEval.getLeftExpr(), target)) {
+        // the commutate method works with a copy of the expr
+        commutated = commutate(binaryEval);
+      } else {
+        try {
+          commutated = (BinaryEval) evalNode.clone();
+        } catch (CloneNotSupportedException e) {
+          throw new AlgebraicException(e);
+        }
       }
-    }
 
-    return _transpose(commutated, target);
+      return _transpose(commutated, target);
+    } else {
+      return evalNode;
+    }
   }
   
-  private static EvalNode _transpose(EvalNode _expr, Column target) {
+  private static EvalNode _transpose(BinaryEval _expr, Column target) {
      EvalNode expr = eliminateConstantExprs(_expr);
-     
-     if (isSingleVar(expr.getLeftExpr())) {
-       return expr;
-     }
-     
-     EvalNode left = expr.getLeftExpr();     
-     EvalNode lTerm = null;
-     EvalNode rTerm = null;
-     
-    if (left.getType() == EvalType.PLUS
-        || left.getType() == EvalType.MINUS
-        || left.getType() == EvalType.MULTIPLY
-        || left.getType() == EvalType.DIVIDE) {
-      
-      // If the left-left term is a variable, the left-right term is transposed.
-      if(EvalTreeUtil.containColumnRef(left.getLeftExpr(), target)) {
-        PartialBinaryExpr tmpTerm = splitRightTerm(left);
-        tmpTerm.type = inverseOperator(tmpTerm.type);
-        tmpTerm.setLeftExpr(expr.getRightExpr());
-        lTerm = left.getLeftExpr();
-        rTerm = new BinaryEval(tmpTerm);
-      } else { 
-        // Otherwise, the left-right term is transposed into the left-left term.
-        PartialBinaryExpr tmpTerm = splitLeftTerm(left);
-        tmpTerm.type = inverseOperator(tmpTerm.type);
-        tmpTerm.setLeftExpr(expr.getRightExpr());        
-        lTerm = left.getRightExpr();
-        rTerm = new BinaryEval(tmpTerm);    
+
+    if (expr instanceof BinaryEval) { // only if expr is a binary operator
+      BinaryEval binaryEval = (BinaryEval) expr;
+      if (isSingleVar(binaryEval.getLeftExpr())) {
+        return expr;
       }
+
+      EvalNode left = binaryEval.getLeftExpr();
+      EvalNode lTerm = null;
+      EvalNode rTerm = null;
+
+      if (EvalType.isArithmeticOperator(left)) { // we can ensure that left is binary.
+
+        // If the left-left term is a variable, the left-right term is transposed.
+        if (EvalTreeUtil.containColumnRef(((BinaryEval)left).getLeftExpr(), target)) {
+          PartialBinaryExpr tmpTerm = splitRightTerm((BinaryEval) left);
+          tmpTerm.type = inverseOperator(tmpTerm.type);
+          tmpTerm.setLeftExpr(((BinaryEval)expr).getRightExpr());
+          lTerm = ((BinaryEval)left).getLeftExpr();
+          rTerm = new BinaryEval(tmpTerm);
+        } else {
+          // Otherwise, the left-right term is transposed into the left-left term.
+          PartialBinaryExpr tmpTerm = splitLeftTerm((BinaryEval) left);
+          tmpTerm.type = inverseOperator(tmpTerm.type);
+          tmpTerm.setLeftExpr(((BinaryEval)expr).getRightExpr());
+          lTerm = ((BinaryEval)left).getRightExpr();
+          rTerm = new BinaryEval(tmpTerm);
+        }
+      }
+
+      return _transpose(new BinaryEval(expr.getType(), lTerm, rTerm), target);
+    } else {
+      return _expr;
     }
-    
-    return _transpose(new BinaryEval(expr.getType(), lTerm, rTerm), target);
   }
   
   /**
@@ -122,6 +131,59 @@ public class AlgebraicUtil {
       return false;
     }
   }
+
+  private static class AlgebraicOptimizer extends SimpleEvalNodeVisitor<Object> {
+
+    @Override
+    public EvalNode visitBinaryEval(Object context, Stack<EvalNode> stack, BinaryEval binaryEval) {
+      stack.push(binaryEval);
+      EvalNode lhs = visit(context, binaryEval.getLeftExpr(), stack);
+      EvalNode rhs = visit(context, binaryEval.getRightExpr(), stack);
+      stack.pop();
+
+      if (!binaryEval.getLeftExpr().equals(lhs)) {
+        binaryEval.setLeftExpr(lhs);
+      }
+      if (!binaryEval.getRightExpr().equals(rhs)) {
+        binaryEval.setRightExpr(rhs);
+      }
+
+      if (lhs.getType() == EvalType.CONST && rhs.getType() == EvalType.CONST) {
+        return new ConstEval(binaryEval.eval(null, null));
+      }
+
+      return binaryEval;
+    }
+
+    @Override
+    public EvalNode visitUnaryEval(Object context, Stack<EvalNode> stack, UnaryEval unaryEval) {
+      stack.push(unaryEval);
+      EvalNode child = visit(context, unaryEval.getChild(), stack);
+      stack.pop();
+
+      if (child.getType() == EvalType.CONST) {
+        return new ConstEval(unaryEval.eval(null, null));
+      }
+
+      return unaryEval;
+    }
+
+    public EvalNode visitFuncCall(Object context, GeneralFunctionEval evalNode, Stack<EvalNode> stack) {
+      boolean constant = true;
+
+      for (EvalNode arg : evalNode.getArgs()) {
+        constant &= (arg.getType() == EvalType.CONST);
+      }
+
+      if (constant) {
+        return new ConstEval(evalNode.eval(null, null));
+      } else {
+        return evalNode;
+      }
+    }
+  }
+
+  private final static AlgebraicOptimizer algebraicOptimizer = new AlgebraicOptimizer();
   
   /**
    * Simplify the given expr. That is, all subexprs consisting of only constants
@@ -131,43 +193,7 @@ public class AlgebraicUtil {
    * @return the simplified expr
    */
   public static EvalNode eliminateConstantExprs(EvalNode expr) {
-
-    if (expr.getType() == EvalType.FIELD) {
-      return expr;
-    }
-
-    EvalNode left = expr.getLeftExpr();
-    EvalNode right = expr.getRightExpr();
-    
-    switch (expr.getType()) {
-    case AND:
-    case OR:
-    case EQUAL:
-    case NOT_EQUAL:
-    case LTH:
-    case LEQ:
-    case GTH:
-    case GEQ:
-    case PLUS:
-    case MINUS:
-    case MULTIPLY:
-    case DIVIDE:
-    case MODULAR:
-      left = eliminateConstantExprs(left);
-      right = eliminateConstantExprs(right);
-
-      if (left.getType() == EvalType.CONST && right.getType() == EvalType.CONST) {
-        return new ConstEval(expr.eval(null, null));
-      } else {
-        return new BinaryEval(expr.getType(), left, right);
-      }
-
-    case CONST:
-      return expr;
-      
-    default: new AlgebraicException("Wrong expression: " + expr);
-    }
-    return expr;
+    return algebraicOptimizer.visit(null, expr, new Stack<EvalNode>());
   }
   
   /** 
@@ -192,56 +218,50 @@ public class AlgebraicUtil {
   /**
    * Split the left term and transform it into the right deep expression.
    * 
-   * @param expr - notice the left term of this expr will be eliminated 
+   * @param binary - notice the left term of this expr will be eliminated
    * after done.
    * @return the separated expression changed into the right deep expression.  
    * For example, the expr 'x * y' is transformed into '* x'.  
    *
    */
-  public static PartialBinaryExpr splitLeftTerm(EvalNode expr) {
+  public static PartialBinaryExpr splitLeftTerm(BinaryEval binary) {
     
-    if (!(expr.getType() == EvalType.PLUS
-        || expr.getType() == EvalType.MINUS
-        || expr.getType() == EvalType.MULTIPLY
-        || expr.getType() == EvalType.DIVIDE)) {
-      throw new AlgebraicException("Invalid algebraic operation: " + expr);
+    if (!(EvalType.isArithmeticOperator(binary))) {
+      throw new AlgebraicException("Invalid algebraic operation: " + binary);
     }
     
-    if (expr.getLeftExpr().getType() != EvalType.CONST) {
-      return splitLeftTerm(expr.getLeftExpr());
+    if (binary.getLeftExpr() instanceof BinaryEval) {
+      return splitLeftTerm((BinaryEval) binary.getLeftExpr());
     }
     
     PartialBinaryExpr splitted = 
-        new PartialBinaryExpr(expr.getType(), null, expr.getLeftExpr());
-    expr.setLeftExpr(null);
+        new PartialBinaryExpr(binary.getType(), null, binary.getLeftExpr());
+    binary.setLeftExpr(null);
     return splitted;
   }
   
   /**
    * Split the left term and transform it into the right deep expression.
    * 
-   * @param expr - to be splited
+   * @param binary - to be splited
    * @return the separated expression changed into the right deep expression.
    * For example, the expr 'x * y' is transformed into '* y'. 
    *
    * @throws CloneNotSupportedException
    */
-  public static PartialBinaryExpr splitRightTerm(EvalNode expr) {
+  public static PartialBinaryExpr splitRightTerm(BinaryEval binary) {
     
-    if (!(expr.getType() == EvalType.PLUS
-        || expr.getType() == EvalType.MINUS
-        || expr.getType() == EvalType.MULTIPLY
-        || expr.getType() == EvalType.DIVIDE)) {
-      throw new AlgebraicException("Invalid algebraic operation: " + expr);
+    if (!(EvalType.isArithmeticOperator(binary))) {
+      throw new AlgebraicException("Invalid algebraic operation: " + binary);
     }
     
-    if (expr.getRightExpr().getType() != EvalType.CONST) {
-      return splitRightTerm(expr.getRightExpr());
+    if (binary.getRightExpr() instanceof BinaryEval) {
+      return splitRightTerm((BinaryEval) binary.getRightExpr());
     }
     
     PartialBinaryExpr splitted = 
-        new PartialBinaryExpr(expr.getType(), null, expr.getRightExpr());
-    expr.setRightExpr(null);
+        new PartialBinaryExpr(binary.getType(), null, binary.getRightExpr());
+    binary.setRightExpr(null);
     return splitted;
   }
   
@@ -251,8 +271,8 @@ public class AlgebraicUtil {
    * @param inputExpr
    * @return
    */
-  public static EvalNode commutate(EvalNode inputExpr) {
-    EvalNode expr;
+  public static BinaryEval commutate(BinaryEval inputExpr) {
+    BinaryEval rewritten;
     switch (inputExpr.getType()) {
     case AND:
     case OR:
@@ -260,24 +280,24 @@ public class AlgebraicUtil {
     case PLUS:
     case MINUS:
     case MULTIPLY: // these types can be commutated w/o any change
-      expr = EvalTreeFactory.create(inputExpr.getType(),
+      rewritten = EvalTreeFactory.create(inputExpr.getType(),
           inputExpr.getRightExpr(), inputExpr.getLeftExpr());
       break;
       
     case GTH:
-      expr = EvalTreeFactory.create(EvalType.LTH,
+      rewritten = EvalTreeFactory.create(EvalType.LTH,
           inputExpr.getRightExpr(), inputExpr.getLeftExpr());
       break;
     case GEQ:
-      expr = EvalTreeFactory.create(EvalType.LEQ,
+      rewritten = EvalTreeFactory.create(EvalType.LEQ,
           inputExpr.getRightExpr(), inputExpr.getLeftExpr());
       break;
     case LTH:
-      expr = EvalTreeFactory.create(EvalType.GTH,
+      rewritten = EvalTreeFactory.create(EvalType.GTH,
           inputExpr.getRightExpr(), inputExpr.getLeftExpr());
       break;
     case LEQ:
-      expr = EvalTreeFactory.create(EvalType.GEQ,
+      rewritten = EvalTreeFactory.create(EvalType.GEQ,
           inputExpr.getRightExpr(), inputExpr.getLeftExpr());
       break;
       
@@ -285,16 +305,7 @@ public class AlgebraicUtil {
       throw new AlgebraicException("Cannot commutate the expr: " + inputExpr);
     }
     
-    return expr;
-  }
-
-  public static boolean isComparisonOperator(EvalNode expr) {
-    return expr.getType() == EvalType.EQUAL ||
-        expr.getType() == EvalType.LEQ ||
-        expr.getType() == EvalType.LTH ||
-        expr.getType() == EvalType.GEQ ||
-        expr.getType() == EvalType.GTH ||
-        expr.getType() == EvalType.BETWEEN;
+    return rewritten;
   }
 
   public static boolean isIndexableOperator(EvalNode expr) {
@@ -344,8 +355,8 @@ public class AlgebraicUtil {
 
   private static void toConjunctiveNormalFormArrayRecursive(EvalNode node, List<EvalNode> found) {
     if (node.getType() == EvalType.AND) {
-      toConjunctiveNormalFormArrayRecursive(node.getLeftExpr(), found);
-      toConjunctiveNormalFormArrayRecursive(node.getRightExpr(), found);
+      toConjunctiveNormalFormArrayRecursive(((BinaryEval)node).getLeftExpr(), found);
+      toConjunctiveNormalFormArrayRecursive(((BinaryEval)node).getRightExpr(), found);
     } else {
       found.add(node);
     }
@@ -389,8 +400,8 @@ public class AlgebraicUtil {
 
   private static void toDisjunctiveNormalFormArrayRecursive(EvalNode node, List<EvalNode> found) {
     if (node.getType() == EvalType.OR) {
-      toDisjunctiveNormalFormArrayRecursive(node.getLeftExpr(), found);
-      toDisjunctiveNormalFormArrayRecursive(node.getRightExpr(), found);
+      toDisjunctiveNormalFormArrayRecursive(((BinaryEval)node).getLeftExpr(), found);
+      toDisjunctiveNormalFormArrayRecursive(((BinaryEval)node).getRightExpr(), found);
     } else {
       found.add(node);
     }

http://git-wip-us.apache.org/repos/asf/tajo/blob/bd032094/tajo-core/src/main/java/org/apache/tajo/engine/eval/BasicEvalNodeVisitor.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/eval/BasicEvalNodeVisitor.java b/tajo-core/src/main/java/org/apache/tajo/engine/eval/BasicEvalNodeVisitor.java
index 015e9db..6e83c70 100644
--- a/tajo-core/src/main/java/org/apache/tajo/engine/eval/BasicEvalNodeVisitor.java
+++ b/tajo-core/src/main/java/org/apache/tajo/engine/eval/BasicEvalNodeVisitor.java
@@ -18,6 +18,8 @@
 
 package org.apache.tajo.engine.eval;
 
+import org.apache.tajo.exception.UnsupportedException;
+
 import java.util.Stack;
 
 public class BasicEvalNodeVisitor<CONTEXT, RESULT> implements EvalNodeVisitor2<CONTEXT, RESULT> {
@@ -132,13 +134,20 @@ public class BasicEvalNodeVisitor<CONTEXT, RESULT> implements EvalNodeVisitor2<C
         break;
 
       default:
-        throw new InvalidEvalException("Unknown EvalNode: " + evalNode);
+        throw new UnsupportedException("Unknown EvalType: " + evalNode);
     }
 
     return result;
   }
 
-  private RESULT visitDefaultBinaryEval(CONTEXT context, Stack<EvalNode> stack, BinaryEval binaryEval) {
+  private RESULT visitDefaultUnaryEval(CONTEXT context, UnaryEval unaryEval, Stack<EvalNode> stack) {
+    stack.push(unaryEval);
+    RESULT result = visitChild(context, unaryEval.getChild(), stack);
+    stack.pop();
+    return result;
+  }
+
+  private RESULT visitDefaultBinaryEval(CONTEXT context, BinaryEval binaryEval, Stack<EvalNode> stack) {
     stack.push(binaryEval);
     RESULT result = visitChild(context, binaryEval.getLeftExpr(), stack);
     visitChild(context, binaryEval.getRightExpr(), stack);
@@ -146,7 +155,7 @@ public class BasicEvalNodeVisitor<CONTEXT, RESULT> implements EvalNodeVisitor2<C
     return result;
   }
 
-  private RESULT visitDefaultFunctionEval(CONTEXT context, Stack<EvalNode> stack, FunctionEval functionEval) {
+  private RESULT visitDefaultFunctionEval(CONTEXT context, FunctionEval functionEval, Stack<EvalNode> stack) {
     RESULT result = null;
     stack.push(functionEval);
     if (functionEval.getArgs() != null) {
@@ -175,82 +184,77 @@ public class BasicEvalNodeVisitor<CONTEXT, RESULT> implements EvalNodeVisitor2<C
 
   @Override
   public RESULT visitPlus(CONTEXT context, BinaryEval evalNode, Stack<EvalNode> stack) {
-    return visitDefaultBinaryEval(context, stack, evalNode);
+    return visitDefaultBinaryEval(context, evalNode, stack);
   }
 
   @Override
   public RESULT visitMinus(CONTEXT context, BinaryEval evalNode, Stack<EvalNode> stack) {
-    return visitDefaultBinaryEval(context, stack, evalNode);
+    return visitDefaultBinaryEval(context, evalNode, stack);
   }
 
   @Override
   public RESULT visitMultiply(CONTEXT context, BinaryEval evalNode, Stack<EvalNode> stack) {
-    return visitDefaultBinaryEval(context, stack, evalNode);
+    return visitDefaultBinaryEval(context, evalNode, stack);
   }
 
   @Override
   public RESULT visitDivide(CONTEXT context, BinaryEval evalNode, Stack<EvalNode> stack) {
-    return visitDefaultBinaryEval(context, stack, evalNode);
+    return visitDefaultBinaryEval(context, evalNode, stack);
   }
 
   @Override
   public RESULT visitModular(CONTEXT context, BinaryEval evalNode, Stack<EvalNode> stack) {
-    return visitDefaultBinaryEval(context, stack, evalNode);
+    return visitDefaultBinaryEval(context, evalNode, stack);
   }
 
   @Override
   public RESULT visitAnd(CONTEXT context, BinaryEval evalNode, Stack<EvalNode> stack) {
-    return visitDefaultBinaryEval(context, stack, evalNode);
+    return visitDefaultBinaryEval(context, evalNode, stack);
   }
 
   @Override
   public RESULT visitOr(CONTEXT context, BinaryEval evalNode, Stack<EvalNode> stack) {
-    return visitDefaultBinaryEval(context, stack, evalNode);
+    return visitDefaultBinaryEval(context, evalNode, stack);
   }
 
   @Override
   public RESULT visitNot(CONTEXT context, NotEval evalNode, Stack<EvalNode> stack) {
-    RESULT result;
-    stack.push(evalNode);
-    result = visitChild(context, evalNode.getChild(), stack);
-    stack.pop();
-
-    return result;
+    return visitDefaultUnaryEval(context, evalNode, stack);
   }
 
   @Override
   public RESULT visitEqual(CONTEXT context, BinaryEval evalNode, Stack<EvalNode> stack) {
-    return visitDefaultBinaryEval(context, stack, evalNode);
+    return visitDefaultBinaryEval(context, evalNode, stack);
   }
 
   @Override
   public RESULT visitNotEqual(CONTEXT context, BinaryEval evalNode, Stack<EvalNode> stack) {
-    return visitDefaultBinaryEval(context, stack, evalNode);
+    return visitDefaultBinaryEval(context, evalNode, stack);
   }
 
   @Override
   public RESULT visitLessThan(CONTEXT context, BinaryEval evalNode, Stack<EvalNode> stack) {
-    return visitDefaultBinaryEval(context, stack, evalNode);
+    return visitDefaultBinaryEval(context, evalNode, stack);
   }
 
   @Override
   public RESULT visitLessThanOrEqual(CONTEXT context, BinaryEval evalNode, Stack<EvalNode> stack) {
-    return visitDefaultBinaryEval(context, stack, evalNode);
+    return visitDefaultBinaryEval(context, evalNode, stack);
   }
 
   @Override
   public RESULT visitGreaterThan(CONTEXT context, BinaryEval evalNode, Stack<EvalNode> stack) {
-    return visitDefaultBinaryEval(context, stack, evalNode);
+    return visitDefaultBinaryEval(context, evalNode, stack);
   }
 
   @Override
   public RESULT visitGreaterThanOrEqual(CONTEXT context, BinaryEval evalNode, Stack<EvalNode> stack) {
-    return visitDefaultBinaryEval(context, stack, evalNode);
+    return visitDefaultBinaryEval(context, evalNode, stack);
   }
 
   @Override
   public RESULT visitIsNull(CONTEXT context, IsNullEval evalNode, Stack<EvalNode> stack) {
-    return visitDefaultBinaryEval(context, stack, evalNode);
+    return visitDefaultUnaryEval(context, evalNode, stack);
   }
 
   @Override
@@ -288,54 +292,46 @@ public class BasicEvalNodeVisitor<CONTEXT, RESULT> implements EvalNodeVisitor2<C
 
   @Override
   public RESULT visitInPredicate(CONTEXT context, InEval evalNode, Stack<EvalNode> stack) {
-    return visitDefaultBinaryEval(context, stack, evalNode);
+    return visitDefaultBinaryEval(context, evalNode, stack);
   }
 
   @Override
   public RESULT visitLike(CONTEXT context, LikePredicateEval evalNode, Stack<EvalNode> stack) {
-    return visitDefaultBinaryEval(context, stack, evalNode);
+    return visitDefaultBinaryEval(context, evalNode, stack);
   }
 
   @Override
   public RESULT visitSimilarTo(CONTEXT context, SimilarToPredicateEval evalNode, Stack<EvalNode> stack) {
-    return visitDefaultBinaryEval(context, stack, evalNode);
+    return visitDefaultBinaryEval(context, evalNode, stack);
   }
 
   @Override
   public RESULT visitRegex(CONTEXT context, RegexPredicateEval evalNode, Stack<EvalNode> stack) {
-    return visitDefaultBinaryEval(context, stack, evalNode);
+    return visitDefaultBinaryEval(context, evalNode, stack);
   }
 
   @Override
   public RESULT visitConcatenate(CONTEXT context, BinaryEval evalNode, Stack<EvalNode> stack) {
-    return visitDefaultBinaryEval(context, stack, evalNode);
+    return visitDefaultBinaryEval(context, evalNode, stack);
   }
 
   @Override
   public RESULT visitFuncCall(CONTEXT context, GeneralFunctionEval evalNode, Stack<EvalNode> stack) {
-    return visitDefaultFunctionEval(context, stack, evalNode);
+    return visitDefaultFunctionEval(context, evalNode, stack);
   }
 
   @Override
   public RESULT visitAggrFuncCall(CONTEXT context, AggregationFunctionCallEval evalNode, Stack<EvalNode> stack) {
-    return visitDefaultFunctionEval(context, stack, evalNode);
+    return visitDefaultFunctionEval(context, evalNode, stack);
   }
 
   @Override
   public RESULT visitSigned(CONTEXT context, SignedEval signedEval, Stack<EvalNode> stack) {
-    RESULT result;
-    stack.push(signedEval);
-    result = visitChild(context, signedEval.getChild(), stack);
-    stack.pop();
-    return result;
+    return visitDefaultUnaryEval(context, signedEval, stack);
   }
 
   @Override
-  public RESULT visitCast(CONTEXT context, CastEval signedEval, Stack<EvalNode> stack) {
-    RESULT result;
-    stack.push(signedEval);
-    result = visitChild(context, signedEval.getOperand(), stack);
-    stack.pop();
-    return result;
+  public RESULT visitCast(CONTEXT context, CastEval castEval, Stack<EvalNode> stack) {
+    return visitDefaultUnaryEval(context, castEval, stack);
   }
 }

http://git-wip-us.apache.org/repos/asf/tajo/blob/bd032094/tajo-core/src/main/java/org/apache/tajo/engine/eval/BetweenPredicateEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/eval/BetweenPredicateEval.java b/tajo-core/src/main/java/org/apache/tajo/engine/eval/BetweenPredicateEval.java
index 80e6494..0b9c7c1 100644
--- a/tajo-core/src/main/java/org/apache/tajo/engine/eval/BetweenPredicateEval.java
+++ b/tajo-core/src/main/java/org/apache/tajo/engine/eval/BetweenPredicateEval.java
@@ -27,7 +27,7 @@ import org.apache.tajo.datum.DatumFactory;
 import org.apache.tajo.datum.NullDatum;
 import org.apache.tajo.storage.Tuple;
 
-public class BetweenPredicateEval extends EvalNode {
+public class BetweenPredicateEval extends EvalNode implements Cloneable {
   private static final TajoDataTypes.DataType RES_TYPE = CatalogUtil.newSimpleDataType(TajoDataTypes.Type.BOOLEAN);
   @Expose private boolean not;
   @Expose private boolean symmetric;
@@ -228,4 +228,15 @@ public class BetweenPredicateEval extends EvalNode {
     end.postOrder(visitor);
     visitor.visit(this);
   }
+
+  @Override
+  public Object clone() throws CloneNotSupportedException {
+    BetweenPredicateEval newBetween = (BetweenPredicateEval) super.clone();
+    newBetween.not = not;
+    newBetween.symmetric = symmetric;
+    newBetween.predicand = predicand;
+    newBetween.begin = begin;
+    newBetween.end = end;
+    return newBetween;
+  }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tajo/blob/bd032094/tajo-core/src/main/java/org/apache/tajo/engine/eval/BinaryEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/eval/BinaryEval.java b/tajo-core/src/main/java/org/apache/tajo/engine/eval/BinaryEval.java
index f3e145a..bafce91 100644
--- a/tajo-core/src/main/java/org/apache/tajo/engine/eval/BinaryEval.java
+++ b/tajo-core/src/main/java/org/apache/tajo/engine/eval/BinaryEval.java
@@ -19,7 +19,6 @@
 package org.apache.tajo.engine.eval;
 
 import com.google.common.base.Objects;
-import com.google.common.base.Preconditions;
 import com.google.gson.annotations.Expose;
 import org.apache.tajo.catalog.CatalogUtil;
 import org.apache.tajo.catalog.Schema;
@@ -27,21 +26,23 @@ import org.apache.tajo.common.TajoDataTypes.DataType;
 import org.apache.tajo.datum.Datum;
 import org.apache.tajo.datum.DatumFactory;
 import org.apache.tajo.datum.NullDatum;
+import org.apache.tajo.exception.InvalidOperationException;
 import org.apache.tajo.storage.Tuple;
 
 import static org.apache.tajo.common.TajoDataTypes.Type;
 
 public class BinaryEval extends EvalNode implements Cloneable {
-  @Expose private DataType returnType = null;
+  @Expose protected EvalNode leftExpr;
+  @Expose protected EvalNode rightExpr;
+
+  protected BinaryEval(EvalType type) {
+    super(type);
+  }
 
-  /**
-   * @param type
-   */
   public BinaryEval(EvalType type, EvalNode left, EvalNode right) {
-    super(type, left, right);
-    Preconditions.checkNotNull(type);
-    Preconditions.checkNotNull(left);
-    Preconditions.checkNotNull(right);
+    super(type);
+    this.leftExpr = left;
+    this.rightExpr = right;
 
     if(
         type == EvalType.AND ||
@@ -70,13 +71,43 @@ public class BinaryEval extends EvalNode implements Cloneable {
     this(expr.type, expr.leftExpr, expr.rightExpr);
   }
 
+  public void setLeftExpr(EvalNode expr) {
+    this.leftExpr = expr;
+  }
+
+  public <T extends EvalNode> T getLeftExpr() {
+    return (T) this.leftExpr;
+  }
+
+  public void setRightExpr(EvalNode expr) {
+    this.rightExpr = expr;
+  }
+
+  public <T extends EvalNode> T getRightExpr() {
+    return (T) this.rightExpr;
+  }
+
+  public EvalNode getExpr(int id) {
+    if (id == 0) {
+      return this.leftExpr;
+    } else if (id == 1) {
+      return this.rightExpr;
+    } else {
+      throw new ArrayIndexOutOfBoundsException("only 0 or 1 is available (" + id + " is not available)");
+    }
+  }
+
   /**
    * This is verified by ExprsVerifier.checkArithmeticOperand().
    */
   private DataType determineType(DataType left, DataType right) throws InvalidEvalException {
     switch (left.getType()) {
+
+    case INT1:
+    case INT2:
     case INT4: {
       switch(right.getType()) {
+      case INT1:
       case INT2:
       case INT4: return CatalogUtil.newSimpleDataType(Type.INT4);
       case INT8: return CatalogUtil.newSimpleDataType(Type.INT8);
@@ -89,10 +120,11 @@ public class BinaryEval extends EvalNode implements Cloneable {
 
     case INT8: {
       switch(right.getType()) {
+      case INT1:
       case INT2:
       case INT4:
       case INT8: return CatalogUtil.newSimpleDataType(Type.INT8);
-      case FLOAT4:
+      case FLOAT4: return CatalogUtil.newSimpleDataType(Type.FLOAT4);
       case FLOAT8: return CatalogUtil.newSimpleDataType(Type.FLOAT8);
       case DATE: return CatalogUtil.newSimpleDataType(Type.DATE);
       case INTERVAL: return CatalogUtil.newSimpleDataType(Type.INTERVAL);
@@ -101,10 +133,11 @@ public class BinaryEval extends EvalNode implements Cloneable {
 
     case FLOAT4: {
       switch(right.getType()) {
+      case INT1:
       case INT2:
-      case INT4:
-      case INT8:
-      case FLOAT4:
+      case INT4: return CatalogUtil.newSimpleDataType(Type.FLOAT4);
+      case INT8: return CatalogUtil.newSimpleDataType(Type.FLOAT4);
+      case FLOAT4: return CatalogUtil.newSimpleDataType(Type.FLOAT4);
       case FLOAT8: return CatalogUtil.newSimpleDataType(Type.FLOAT8);
       case INTERVAL: return CatalogUtil.newSimpleDataType(Type.INTERVAL);
       }
@@ -112,6 +145,7 @@ public class BinaryEval extends EvalNode implements Cloneable {
 
     case FLOAT8: {
       switch(right.getType()) {
+      case INT1:
       case INT2:
       case INT4:
       case INT8:
@@ -200,7 +234,7 @@ public class BinaryEval extends EvalNode implements Cloneable {
       }
       return DatumFactory.createText(lhs.asChars() + rhs.asChars());
     default:
-      throw new InvalidEvalException("We does not support " + type + " expression yet");
+      throw new InvalidOperationException("Unknown binary operation: " + type);
     }
   }
 
@@ -214,8 +248,22 @@ public class BinaryEval extends EvalNode implements Cloneable {
 	  return returnType;
 	}
 
+  @Deprecated
+  public void preOrder(EvalNodeVisitor visitor) {
+    visitor.visit(this);
+    leftExpr.preOrder(visitor);
+    rightExpr.preOrder(visitor);
+  }
+
+  @Deprecated
+  public void postOrder(EvalNodeVisitor visitor) {
+    leftExpr.postOrder(visitor);
+    rightExpr.postOrder(visitor);
+    visitor.visit(this);
+  }
+
 	public String toString() {
-		return leftExpr +" " + type.getOperatorName() + " "+rightExpr;
+		return leftExpr +" " + type.getOperatorName() + " "+ rightExpr;
 	}
 
   @Override
@@ -237,9 +285,11 @@ public class BinaryEval extends EvalNode implements Cloneable {
 
   @Override
   public Object clone() throws CloneNotSupportedException {
-    BinaryEval eval = (BinaryEval) super.clone();
-    eval.returnType = returnType;
+    BinaryEval node = (BinaryEval) super.clone();
+    node.type = type;
+    node.leftExpr = leftExpr != null ? (EvalNode) leftExpr.clone() : null;
+    node.rightExpr = rightExpr != null ? (EvalNode) rightExpr.clone() : null;
 
-    return eval;
+    return node;
   }
 }

http://git-wip-us.apache.org/repos/asf/tajo/blob/bd032094/tajo-core/src/main/java/org/apache/tajo/engine/eval/CaseWhenEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/eval/CaseWhenEval.java b/tajo-core/src/main/java/org/apache/tajo/engine/eval/CaseWhenEval.java
index 0883e5c..6b330f5 100644
--- a/tajo-core/src/main/java/org/apache/tajo/engine/eval/CaseWhenEval.java
+++ b/tajo-core/src/main/java/org/apache/tajo/engine/eval/CaseWhenEval.java
@@ -31,6 +31,7 @@ import org.apache.tajo.json.GsonObject;
 import org.apache.tajo.storage.Tuple;
 import org.apache.tajo.util.TUtil;
 
+import java.util.ArrayList;
 import java.util.List;
 
 public class CaseWhenEval extends EvalNode implements GsonObject {
@@ -120,6 +121,17 @@ public class CaseWhenEval extends EvalNode implements GsonObject {
   }
 
   @Override
+  public Object clone() throws CloneNotSupportedException {
+    CaseWhenEval caseWhenEval = (CaseWhenEval) super.clone();
+    caseWhenEval.whens = new ArrayList<IfThenEval>();
+    for (IfThenEval ifThenEval : whens) {
+      caseWhenEval.whens.add((IfThenEval) ifThenEval.clone());
+    }
+    caseWhenEval.elseResult = elseResult;
+    return caseWhenEval;
+  }
+
+  @Override
   public boolean equals(Object obj) {
     if (obj instanceof CaseWhenEval) {
       CaseWhenEval other = (CaseWhenEval) obj;
@@ -212,5 +224,13 @@ public class CaseWhenEval extends EvalNode implements GsonObject {
       result.postOrder(visitor);
       visitor.visit(this);
     }
+
+    @Override
+    public Object clone() throws CloneNotSupportedException {
+      IfThenEval ifThenEval = (IfThenEval) super.clone();
+      ifThenEval.condition = condition;
+      ifThenEval.result = result;
+      return ifThenEval;
+    }
   }
 }

http://git-wip-us.apache.org/repos/asf/tajo/blob/bd032094/tajo-core/src/main/java/org/apache/tajo/engine/eval/CastEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/eval/CastEval.java b/tajo-core/src/main/java/org/apache/tajo/engine/eval/CastEval.java
index 24a0409..d996385 100644
--- a/tajo-core/src/main/java/org/apache/tajo/engine/eval/CastEval.java
+++ b/tajo-core/src/main/java/org/apache/tajo/engine/eval/CastEval.java
@@ -26,22 +26,16 @@ import org.apache.tajo.storage.Tuple;
 
 import static org.apache.tajo.common.TajoDataTypes.DataType;
 
-public class CastEval extends EvalNode {
-  @Expose private EvalNode operand;
+public class CastEval extends UnaryEval {
   @Expose private DataType target;
 
   public CastEval(EvalNode operand, DataType target) {
-    super(EvalType.CAST);
-    this.operand = operand;
+    super(EvalType.CAST, operand);
     this.target = target;
   }
 
-  public void setOperand(EvalNode operand) {
-    this.operand = operand;
-  }
-
   public EvalNode getOperand() {
-    return operand;
+    return child;
   }
 
   @Override
@@ -55,7 +49,7 @@ public class CastEval extends EvalNode {
   }
 
   public Datum eval(Schema schema, Tuple tuple) {
-    Datum operandDatum = operand.eval(schema, tuple);
+    Datum operandDatum = child.eval(schema, tuple);
     if (operandDatum.isNull()) {
       return operandDatum;
     }
@@ -64,7 +58,7 @@ public class CastEval extends EvalNode {
   }
 
   public String toString() {
-    return "CAST (" + operand + " AS " + target.getType() + ")";
+    return "CAST (" + child + " AS " + target.getType() + ")";
   }
 
   @Override
@@ -72,20 +66,9 @@ public class CastEval extends EvalNode {
     boolean valid = obj != null && obj instanceof CastEval;
     if (valid) {
       CastEval another = (CastEval) obj;
-      return operand.equals(another.operand) && target.equals(another.target);
+      return child.equals(another.child) && target.equals(another.target);
     } else {
       return false;
     }
   }
-
-  @Override
-  public void preOrder(EvalNodeVisitor visitor) {
-    visitor.visit(this);
-    operand.preOrder(visitor);
-  }
-
-  public void postOrder(EvalNodeVisitor visitor) {
-    operand.postOrder(visitor);
-    visitor.visit(this);
-  }
 }

http://git-wip-us.apache.org/repos/asf/tajo/blob/bd032094/tajo-core/src/main/java/org/apache/tajo/engine/eval/EvalNode.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/eval/EvalNode.java b/tajo-core/src/main/java/org/apache/tajo/engine/eval/EvalNode.java
index 1180bde..a30d27f 100644
--- a/tajo-core/src/main/java/org/apache/tajo/engine/eval/EvalNode.java
+++ b/tajo-core/src/main/java/org/apache/tajo/engine/eval/EvalNode.java
@@ -32,56 +32,22 @@ import org.apache.tajo.storage.Tuple;
  */
 public abstract class EvalNode implements Cloneable, GsonObject {
 	@Expose protected EvalType type;
-	@Expose protected EvalNode leftExpr;
-	@Expose protected EvalNode rightExpr;
-	
+  @Expose protected DataType returnType = null;
+
+  public EvalNode() {
+  }
+
 	public EvalNode(EvalType type) {
 		this.type = type;
 	}
 	
-	public EvalNode(EvalType type, EvalNode left, EvalNode right) {
-		this(type);
-		this.leftExpr = left;
-		this.rightExpr = right;
-	}
-	
 	public EvalType getType() {
 		return this.type;
 	}
 	
-	public void setLeftExpr(EvalNode expr) {
-		this.leftExpr = expr;
-	}
-	
-	public <T extends EvalNode> T getLeftExpr() {
-		return (T) this.leftExpr;
-	}
-	
-	public void setRightExpr(EvalNode expr) {
-		this.rightExpr = expr;
-	}
-	
-	public <T extends EvalNode> T getRightExpr() {
-		return (T) this.rightExpr;
-	}
-
-  public EvalNode getExpr(int id) {
-    if (id == 0) {
-      return this.leftExpr;
-    } else if (id == 1) {
-      return this.rightExpr;
-    } else {
-      throw new ArrayIndexOutOfBoundsException("only 0 or 1 is available (" + id + " is not available)");
-    }
-  }
-	
 	public abstract DataType getValueType();
 	
 	public abstract String getName();
-	
-	public String toString() {
-		return "(" + this.type + "(" + leftExpr.toString() + " " + rightExpr.toString() + "))";
-	}
 
   @Override
 	public String toJson() {
@@ -91,28 +57,16 @@ public abstract class EvalNode implements Cloneable, GsonObject {
 	public abstract <T extends Datum> T eval(Schema schema, Tuple tuple);
 
   @Deprecated
-	public void preOrder(EvalNodeVisitor visitor) {
-	  visitor.visit(this);
-	  leftExpr.preOrder(visitor);
-	  rightExpr.preOrder(visitor);
-	}
+  public abstract  void preOrder(EvalNodeVisitor visitor);
 
   @Deprecated
-	public void postOrder(EvalNodeVisitor visitor) {
-	  leftExpr.postOrder(visitor);
-	  rightExpr.postOrder(visitor);	  	  
-	  visitor.visit(this);
-	}
+  public abstract void postOrder(EvalNodeVisitor visitor);
 
-  public abstract boolean equals(Object obj);
-	
-	@Override
-	public Object clone() throws CloneNotSupportedException {
-	  EvalNode node = (EvalNode) super.clone();
-	  node.type = type;
-	  node.leftExpr = leftExpr != null ? (EvalNode) leftExpr.clone() : null;
-	  node.rightExpr = rightExpr != null ? (EvalNode) rightExpr.clone() : null;
-	  
-	  return node;
-	}
+  @Override
+  public Object clone() throws CloneNotSupportedException {
+    EvalNode evalNode = (EvalNode) super.clone();
+    evalNode.type = type;
+    evalNode.returnType = returnType;
+    return evalNode;
+  }
 }

http://git-wip-us.apache.org/repos/asf/tajo/blob/bd032094/tajo-core/src/main/java/org/apache/tajo/engine/eval/EvalTreeUtil.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/eval/EvalTreeUtil.java b/tajo-core/src/main/java/org/apache/tajo/engine/eval/EvalTreeUtil.java
index 38c7e1f..2417193 100644
--- a/tajo-core/src/main/java/org/apache/tajo/engine/eval/EvalTreeUtil.java
+++ b/tajo-core/src/main/java/org/apache/tajo/engine/eval/EvalTreeUtil.java
@@ -85,12 +85,6 @@ public class EvalTreeUtil {
           if (ifThen.getResult().equals(evalNode)) {
             ifThen.setResult(tobeReplaced);
           }
-        } else if (parent instanceof CastEval) {
-          CastEval cast = (CastEval) parent;
-          if (cast.getOperand().equals(evalNode)) {
-            cast.setOperand(tobeReplaced);
-          }
-
        } else if (parent instanceof FunctionEval) {
           FunctionEval functionEval = (FunctionEval) parent;
           EvalNode [] arguments = functionEval.getArgs();
@@ -101,24 +95,17 @@ public class EvalTreeUtil {
           }
           functionEval.setArgs(arguments);
 
-        } else if (parent instanceof NotEval) {
-          NotEval not = (NotEval) parent;
-          if (not.getChild().equals(evalNode)) {
-            not.setChild(tobeReplaced);
+        } else if (parent instanceof UnaryEval) {
+          if (((UnaryEval)parent).getChild().equals(evalNode)) {
+            ((UnaryEval)parent).setChild(tobeReplaced);
           }
-
-        } else if (parent instanceof SignedEval) {
-          SignedEval sign = (SignedEval) parent;
-          if (sign.getChild().equals(evalNode)) {
-            sign.setChild(tobeReplaced);
-          }
-
-        } else {
-          if (parent.getLeftExpr() != null && parent.getLeftExpr().equals(evalNode)) {
-            parent.setLeftExpr(tobeReplaced);
+        } else if (parent instanceof BinaryEval) {
+          BinaryEval binary = (BinaryEval) parent;
+          if (binary.getLeftExpr() != null && binary.getLeftExpr().equals(evalNode)) {
+            binary.setLeftExpr(tobeReplaced);
           }
-          if (parent.getRightExpr() != null && parent.getRightExpr().equals(evalNode)) {
-            parent.setRightExpr(tobeReplaced);
+          if (binary.getRightExpr() != null && binary.getRightExpr().equals(evalNode)) {
+            binary.setRightExpr(tobeReplaced);
           }
         }
       }
@@ -228,27 +215,8 @@ public class EvalTreeUtil {
    * to the target column
    */
   public static boolean containColumnRef(EvalNode expr, Column target) {
-    Set<EvalNode> exprSet = Sets.newHashSet();
-    _containColumnRef(expr, target, exprSet);
-    
-    return exprSet.size() > 0;
-  }
-  
-  private static void _containColumnRef(EvalNode expr, Column target, 
-      Set<EvalNode> exprSet) {
-    switch (expr.getType()) {
-    case FIELD:
-      FieldEval field = (FieldEval) expr;
-      if (field.getColumnName().equals(target.getSimpleName())) {
-        exprSet.add(field);
-      }
-      break;
-    case CONST:
-      return;
-    default: 
-      _containColumnRef(expr.getLeftExpr(), target, exprSet);
-      _containColumnRef(expr.getRightExpr(), target, exprSet);
-    }    
+    Set<Column> exprSet = findUniqueColumns(expr);
+    return exprSet.contains(target);
   }
 
   /**
@@ -260,15 +228,22 @@ public class EvalTreeUtil {
    * @return True if it is join condition.
    */
   public static boolean isJoinQual(EvalNode expr, boolean includeThetaJoin) {
-    boolean joinComparator;
-    if (includeThetaJoin) {
-      joinComparator = AlgebraicUtil.isComparisonOperator(expr);
+    if (expr instanceof BinaryEval) {
+      boolean joinComparator;
+      if (includeThetaJoin) {
+        joinComparator = EvalType.isComparisonOperator(expr);
+      } else {
+        joinComparator = expr.getType() == EvalType.EQUAL;
+      }
+
+      BinaryEval binaryEval = (BinaryEval) expr;
+      boolean isBothTermFields =
+          binaryEval.getLeftExpr().getType() == EvalType.FIELD &&
+          binaryEval.getRightExpr().getType() == EvalType.FIELD;
+      return joinComparator && isBothTermFields;
     } else {
-      joinComparator = expr.getType() == EvalType.EQUAL;
+      return false;
     }
-
-    return joinComparator && expr.getLeftExpr().getType() == EvalType.FIELD &&
-        expr.getRightExpr().getType() == EvalType.FIELD;
   }
   
   public static class ChangeColumnRefVisitor implements EvalNodeVisitor {    

http://git-wip-us.apache.org/repos/asf/tajo/blob/bd032094/tajo-core/src/main/java/org/apache/tajo/engine/eval/EvalType.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/eval/EvalType.java b/tajo-core/src/main/java/org/apache/tajo/engine/eval/EvalType.java
index 71db934..14367f4 100644
--- a/tajo-core/src/main/java/org/apache/tajo/engine/eval/EvalType.java
+++ b/tajo-core/src/main/java/org/apache/tajo/engine/eval/EvalType.java
@@ -38,6 +38,11 @@ public enum EvalType {
   MULTIPLY(BinaryEval.class, "*"),
   DIVIDE(BinaryEval.class, "/"),
 
+  // Binary Bitwise expressions
+  BIT_AND(BinaryEval.class, "&"),
+  BIT_OR(BinaryEval.class, "|"),
+  BIT_XOR(BinaryEval.class, "|"),
+
   // Function
   AGG_FUNCTION(AggregationFunctionCallEval.class),
   FUNCTION(GeneralFunctionEval.class),
@@ -73,6 +78,45 @@ public enum EvalType {
     this.operatorName = text;
   }
 
+  public static boolean isLogicalOperator(EvalNode evalNode) {
+    EvalType type = evalNode.getType();
+    boolean match = false;
+
+    match |= type == AND;
+    match |= type == OR;
+    match |= type == NOT;
+
+    return match;
+  }
+
+  public static boolean isComparisonOperator(EvalNode evalNode) {
+    EvalType type = evalNode.getType();
+    boolean match = false;
+
+    match |= type == EQUAL;
+    match |= type == NOT_EQUAL;
+    match |= type == LTH;
+    match |= type == LEQ;
+    match |= type == GTH;
+    match |= type == GEQ;
+    match |= type == BETWEEN;
+
+    return match;
+  }
+
+  public static boolean isArithmeticOperator(EvalNode evalNode) {
+    EvalType type = evalNode.getType();
+    boolean match = false;
+
+    match |= type == PLUS;
+    match |= type == MINUS;
+    match |= type == MULTIPLY;
+    match |= type == DIVIDE;
+    match |= type == MODULAR;
+
+    return match;
+  }
+
   public String getOperatorName() {
     return operatorName != null ? operatorName : name();
   }