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/08/20 09:48:39 UTC

[2/2] git commit: TAJO-1008: Protocol buffer De/Serialization for EvalNode.

TAJO-1008: Protocol buffer De/Serialization for EvalNode.


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

Branch: refs/heads/master
Commit: ea5ce54d812ac38dc23683c48d0ca24fb122a7ba
Parents: 2d6bff7
Author: Hyunsik Choi <hy...@apache.org>
Authored: Wed Aug 20 16:46:00 2014 +0900
Committer: Hyunsik Choi <hy...@apache.org>
Committed: Wed Aug 20 16:47:15 2014 +0900

----------------------------------------------------------------------
 CHANGES                                         |   2 +
 .../main/java/org/apache/tajo/datum/Datum.java  |   3 +-
 tajo-core/pom.xml                               |   1 +
 .../apache/tajo/engine/eval/AlgebraicUtil.java  |   6 +-
 .../tajo/engine/eval/BetweenPredicateEval.java  |  26 ++
 .../org/apache/tajo/engine/eval/BinaryEval.java |   6 +
 .../apache/tajo/engine/eval/CaseWhenEval.java   |  38 ++-
 .../org/apache/tajo/engine/eval/ConstEval.java  |  12 +-
 .../org/apache/tajo/engine/eval/EvalNode.java   |   4 +
 .../apache/tajo/engine/eval/EvalTreeUtil.java   |   2 +-
 .../org/apache/tajo/engine/eval/EvalType.java   |  46 ++-
 .../org/apache/tajo/engine/eval/FieldEval.java  |  12 +-
 .../apache/tajo/engine/eval/FunctionEval.java   |  14 +
 .../tajo/engine/eval/RowConstantEval.java       |  10 +
 .../tajo/engine/eval/SimpleEvalNodeVisitor.java |  24 +-
 .../org/apache/tajo/engine/eval/UnaryEval.java  |  11 +
 .../engine/plan/EvalTreeProtoDeserializer.java  | 218 +++++++++++++
 .../engine/plan/EvalTreeProtoSerializer.java    | 308 +++++++++++++++++++
 .../tajo/engine/planner/ExprAnnotator.java      |   2 +-
 tajo-core/src/main/proto/Plan.proto             | 209 +++++++++++++
 .../apache/tajo/engine/eval/ExprTestBase.java   |  21 ++
 .../apache/tajo/engine/eval/TestEvalTree.java   |  21 +-
 22 files changed, 967 insertions(+), 29 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tajo/blob/ea5ce54d/CHANGES
----------------------------------------------------------------------
diff --git a/CHANGES b/CHANGES
index a4160aa..07119bd 100644
--- a/CHANGES
+++ b/CHANGES
@@ -31,6 +31,8 @@ Release 0.9.0 - unreleased
 
   IMPROVEMENT
 
+    TAJO-1008: Protocol buffer De/Serialization for EvalNode. (hyunsik)
+
     TAJO-984: Improve the default data type handling in RowStoreUtil.
     (jihoon via hyunsik)
 

http://git-wip-us.apache.org/repos/asf/tajo/blob/ea5ce54d/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 874004b..f21e3d7 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
@@ -69,9 +69,8 @@ public abstract class Datum implements Comparable<Datum>, GsonObject {
     throw new InvalidCastException(type, Type.INT2);
   }
   public int asInt4() {
-    throw new InvalidCastException(type, Type.INT1);
+    throw new InvalidCastException(type, Type.INT4);
   }
-
   public long asInt8() {
     throw new InvalidCastException(type, Type.INT8);
   }

http://git-wip-us.apache.org/repos/asf/tajo/blob/ea5ce54d/tajo-core/pom.xml
----------------------------------------------------------------------
diff --git a/tajo-core/pom.xml b/tajo-core/pom.xml
index 32ae266..364c428 100644
--- a/tajo-core/pom.xml
+++ b/tajo-core/pom.xml
@@ -144,6 +144,7 @@
                 <argument>src/main/proto/TajoMasterProtocol.proto</argument>
                 <argument>src/main/proto/TajoWorkerProtocol.proto</argument>
                 <argument>src/main/proto/InternalTypes.proto</argument>
+                <argument>src/main/proto/Plan.proto</argument>
               </arguments>
             </configuration>
             <goals>

http://git-wip-us.apache.org/repos/asf/tajo/blob/ea5ce54d/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 a72e2a8..518b72f 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
@@ -72,7 +72,7 @@ public class AlgebraicUtil {
       EvalNode lTerm = null;
       EvalNode rTerm = null;
 
-      if (EvalType.isArithmeticOperator(left)) { // we can ensure that left is binary.
+      if (EvalType.isArithmeticOperator(left.getType())) { // 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)) {
@@ -234,7 +234,7 @@ public class AlgebraicUtil {
    */
   public static PartialBinaryExpr splitLeftTerm(BinaryEval binary) {
     
-    if (!(EvalType.isArithmeticOperator(binary))) {
+    if (!(EvalType.isArithmeticOperator(binary.getType()))) {
       throw new AlgebraicException("Invalid algebraic operation: " + binary);
     }
     
@@ -259,7 +259,7 @@ public class AlgebraicUtil {
    */
   public static PartialBinaryExpr splitRightTerm(BinaryEval binary) {
     
-    if (!(EvalType.isArithmeticOperator(binary))) {
+    if (!(EvalType.isArithmeticOperator(binary.getType()))) {
       throw new AlgebraicException("Invalid algebraic operation: " + binary);
     }
     

http://git-wip-us.apache.org/repos/asf/tajo/blob/ea5ce54d/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 0b9c7c1..07f9a6f 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
@@ -46,6 +46,14 @@ public class BetweenPredicateEval extends EvalNode implements Cloneable {
     this.end = end;
   }
 
+  public boolean isNot() {
+    return not;
+  }
+
+  public boolean isSymmetric() {
+    return symmetric;
+  }
+
   public void setPredicand(EvalNode predicand) {
     this.predicand = predicand;
   }
@@ -170,6 +178,24 @@ public class BetweenPredicateEval extends EvalNode implements Cloneable {
   }
 
   @Override
+  public int childNum() {
+    return 3;
+  }
+
+  @Override
+  public EvalNode getChild(int idx) {
+    if (idx == 0) {
+      return predicand;
+    } else if (idx == 1) {
+      return begin;
+    } else if (idx == 2) {
+      return end;
+    } else {
+      throw new ArrayIndexOutOfBoundsException(idx);
+    }
+  }
+
+  @Override
   public String getName() {
     return "between";
   }

http://git-wip-us.apache.org/repos/asf/tajo/blob/ea5ce54d/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 2430020..4c94f4a 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
@@ -88,6 +88,12 @@ public class BinaryEval extends EvalNode implements Cloneable {
     return (T) this.rightExpr;
   }
 
+  @Override
+  public int childNum() {
+    return 2;
+  }
+
+  @Override
   public EvalNode getChild(int id) {
     if (id == 0) {
       return this.leftExpr;

http://git-wip-us.apache.org/repos/asf/tajo/blob/ea5ce54d/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 cf1acdf..3eb3a69 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
@@ -43,7 +43,11 @@ public class CaseWhenEval extends EvalNode implements GsonObject {
     super(EvalType.CASE);
   }
 
-  public void addWhen(EvalNode condition, EvalNode result) {
+  public void addIfCond(IfThenEval ifCond) {
+    whens.add(ifCond);
+  }
+
+  public void addIfCond(EvalNode condition, EvalNode result) {
     whens.add(new IfThenEval(condition, result));
   }
 
@@ -80,6 +84,22 @@ public class CaseWhenEval extends EvalNode implements GsonObject {
   }
 
   @Override
+  public int childNum() {
+    return whens.size() + (elseResult != null ? 1 : 0);
+  }
+
+  @Override
+  public EvalNode getChild(int idx) {
+    if (idx < whens.size()) {
+      return whens.get(idx);
+    } else if (idx == whens.size()) {
+      return elseResult;
+    } else {
+      throw new ArrayIndexOutOfBoundsException(idx);
+    }
+  }
+
+  @Override
   public String getName() {
     return "?";
   }
@@ -175,6 +195,22 @@ public class CaseWhenEval extends EvalNode implements GsonObject {
     }
 
     @Override
+    public int childNum() {
+      return 2;
+    }
+
+    @Override
+    public EvalNode getChild(int idx) {
+      if (idx == 0) {
+        return condition;
+      } else if (idx == 1) {
+        return result;
+      } else {
+        throw new ArrayIndexOutOfBoundsException(idx);
+      }
+    }
+
+    @Override
     public String getName() {
       return "when?";
     }

http://git-wip-us.apache.org/repos/asf/tajo/blob/ea5ce54d/tajo-core/src/main/java/org/apache/tajo/engine/eval/ConstEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/eval/ConstEval.java b/tajo-core/src/main/java/org/apache/tajo/engine/eval/ConstEval.java
index 2cb530d..323a4e9 100644
--- a/tajo-core/src/main/java/org/apache/tajo/engine/eval/ConstEval.java
+++ b/tajo-core/src/main/java/org/apache/tajo/engine/eval/ConstEval.java
@@ -52,7 +52,17 @@ public class ConstEval extends EvalNode implements Comparable<ConstEval>, Clonea
     return CatalogUtil.newSimpleDataType(datum.type());
 	}
 
-	@Override
+  @Override
+  public int childNum() {
+    return 0;
+  }
+
+  @Override
+  public EvalNode getChild(int idx) {
+    return null;
+  }
+
+  @Override
 	public String getName() {
 		return this.datum.toString();
 	}

http://git-wip-us.apache.org/repos/asf/tajo/blob/ea5ce54d/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 a30d27f..48ab516 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
@@ -46,6 +46,10 @@ public abstract class EvalNode implements Cloneable, GsonObject {
 	}
 	
 	public abstract DataType getValueType();
+
+  public abstract int childNum();
+
+  public abstract EvalNode getChild(int idx);
 	
 	public abstract String getName();
 

http://git-wip-us.apache.org/repos/asf/tajo/blob/ea5ce54d/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 3e7a05b..0035636 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
@@ -283,7 +283,7 @@ public class EvalTreeUtil {
     if (expr instanceof BinaryEval) {
       boolean joinComparator;
       if (includeThetaJoin) {
-        joinComparator = EvalType.isComparisonOperator(expr);
+        joinComparator = EvalType.isComparisonOperator(expr.getType());
       } else {
         joinComparator = expr.getType() == EvalType.EQUAL;
       }

http://git-wip-us.apache.org/repos/asf/tajo/blob/ea5ce54d/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 549f8d0..500928a 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
@@ -79,8 +79,34 @@ public enum EvalType {
     this.operatorName = text;
   }
 
-  public static boolean isLogicalOperator(EvalNode evalNode) {
-    EvalType type = evalNode.getType();
+  public static boolean isUnaryOperator(EvalType type) {
+    boolean match = false;
+
+    match |= type == CAST;
+    match |= type == IS_NULL;
+    match |= type == NOT;
+    match |= type == SIGNED;
+
+    return match;
+  }
+
+  public static boolean isBinaryOperator(EvalType type) {
+    boolean match = false;
+
+    match |= isArithmeticOperator(type);
+    match |= isLogicalOperator(type) && type != NOT;
+    match |= isComparisonOperator(type) && type != BETWEEN;
+
+    match |= type == CONCATENATE;
+    match |= type == IN;
+    match |= type == LIKE;
+    match |= type == REGEX;
+    match |= type == SIMILAR_TO;
+
+    return match;
+  }
+
+  public static boolean isLogicalOperator(EvalType type) {
     boolean match = false;
 
     match |= type == AND;
@@ -90,8 +116,7 @@ public enum EvalType {
     return match;
   }
 
-  public static boolean isComparisonOperator(EvalNode evalNode) {
-    EvalType type = evalNode.getType();
+  public static boolean isComparisonOperator(EvalType type) {
     boolean match = false;
 
     match |= type == EQUAL;
@@ -105,8 +130,7 @@ public enum EvalType {
     return match;
   }
 
-  public static boolean isArithmeticOperator(EvalNode evalNode) {
-    EvalType type = evalNode.getType();
+  public static boolean isArithmeticOperator(EvalType type) {
     boolean match = false;
 
     match |= type == PLUS;
@@ -118,6 +142,16 @@ public enum EvalType {
     return match;
   }
 
+  public static boolean isFunction(EvalType type) {
+    boolean match = false;
+
+    match |= type == FUNCTION;
+    match |= type == AGG_FUNCTION;
+    match |= type == WINDOW_FUNCTION;
+
+    return match;
+  }
+
   public String getOperatorName() {
     return operatorName != null ? operatorName : name();
   }

http://git-wip-us.apache.org/repos/asf/tajo/blob/ea5ce54d/tajo-core/src/main/java/org/apache/tajo/engine/eval/FieldEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/eval/FieldEval.java b/tajo-core/src/main/java/org/apache/tajo/engine/eval/FieldEval.java
index 20af854..5cedbca 100644
--- a/tajo-core/src/main/java/org/apache/tajo/engine/eval/FieldEval.java
+++ b/tajo-core/src/main/java/org/apache/tajo/engine/eval/FieldEval.java
@@ -59,7 +59,17 @@ public class FieldEval extends EvalNode implements Cloneable {
 	public DataType getValueType() {
 		return column.getDataType();
 	}
-	
+
+  @Override
+  public int childNum() {
+    return 0;
+  }
+
+  @Override
+  public EvalNode getChild(int idx) {
+    return null;
+  }
+
   public Column getColumnRef() {
     return column;
   }

http://git-wip-us.apache.org/repos/asf/tajo/blob/ea5ce54d/tajo-core/src/main/java/org/apache/tajo/engine/eval/FunctionEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/eval/FunctionEval.java b/tajo-core/src/main/java/org/apache/tajo/engine/eval/FunctionEval.java
index 376ee2e..9447ef2 100644
--- a/tajo-core/src/main/java/org/apache/tajo/engine/eval/FunctionEval.java
+++ b/tajo-core/src/main/java/org/apache/tajo/engine/eval/FunctionEval.java
@@ -79,6 +79,20 @@ public abstract class FunctionEval extends EvalNode implements Cloneable {
     this.argEvals = args;
   }
 
+  @Override
+  public int childNum() {
+    if (argEvals != null) {
+      return argEvals.length;
+    } else {
+      return 0;
+    }
+  }
+
+  @Override
+  public EvalNode getChild(int idx) {
+    return argEvals[idx];
+  }
+
 	public DataType getValueType() {
 		return this.funcDesc.getReturnType();
 	}

http://git-wip-us.apache.org/repos/asf/tajo/blob/ea5ce54d/tajo-core/src/main/java/org/apache/tajo/engine/eval/RowConstantEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/eval/RowConstantEval.java b/tajo-core/src/main/java/org/apache/tajo/engine/eval/RowConstantEval.java
index ffaf6b5..5b21be0 100644
--- a/tajo-core/src/main/java/org/apache/tajo/engine/eval/RowConstantEval.java
+++ b/tajo-core/src/main/java/org/apache/tajo/engine/eval/RowConstantEval.java
@@ -42,6 +42,16 @@ public class RowConstantEval extends EvalNode {
   }
 
   @Override
+  public int childNum() {
+    return 0;
+  }
+
+  @Override
+  public EvalNode getChild(int idx) {
+    return null;
+  }
+
+  @Override
   public String getName() {
     return "ROW";
   }

http://git-wip-us.apache.org/repos/asf/tajo/blob/ea5ce54d/tajo-core/src/main/java/org/apache/tajo/engine/eval/SimpleEvalNodeVisitor.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/eval/SimpleEvalNodeVisitor.java b/tajo-core/src/main/java/org/apache/tajo/engine/eval/SimpleEvalNodeVisitor.java
index 93f1f74..15e34de 100644
--- a/tajo-core/src/main/java/org/apache/tajo/engine/eval/SimpleEvalNodeVisitor.java
+++ b/tajo-core/src/main/java/org/apache/tajo/engine/eval/SimpleEvalNodeVisitor.java
@@ -26,7 +26,7 @@ import java.util.Stack;
  * It provides simple visitor methods for an expression tree. Since <code>SimpleEvalNodeVisitor</code> provides
  * fewer visitor methods, it allows users to write a simple rewriter for expression trees.
  */
-public class SimpleEvalNodeVisitor<CONTEXT> {
+public abstract class SimpleEvalNodeVisitor<CONTEXT> {
 
   public EvalNode visit(CONTEXT context, EvalNode evalNode, Stack<EvalNode> stack) {
     EvalNode result;
@@ -83,14 +83,14 @@ public class SimpleEvalNodeVisitor<CONTEXT> {
     return result;
   }
 
-  public EvalNode visitUnaryEval(CONTEXT context, Stack<EvalNode> stack, UnaryEval unaryEval) {
+  protected EvalNode visitUnaryEval(CONTEXT context, Stack<EvalNode> stack, UnaryEval unaryEval) {
     stack.push(unaryEval);
     visit(context, unaryEval.getChild(), stack);
     stack.pop();
     return unaryEval;
   }
 
-  public EvalNode visitBinaryEval(CONTEXT context, Stack<EvalNode> stack, BinaryEval binaryEval) {
+  protected EvalNode visitBinaryEval(CONTEXT context, Stack<EvalNode> stack, BinaryEval binaryEval) {
     stack.push(binaryEval);
     visit(context, binaryEval.getLeftExpr(), stack);
     visit(context, binaryEval.getRightExpr(), stack);
@@ -98,7 +98,7 @@ public class SimpleEvalNodeVisitor<CONTEXT> {
     return binaryEval;
   }
 
-  private EvalNode visitDefaultFunctionEval(CONTEXT context, Stack<EvalNode> stack, FunctionEval functionEval) {
+  protected EvalNode visitDefaultFunctionEval(CONTEXT context, Stack<EvalNode> stack, FunctionEval functionEval) {
     stack.push(functionEval);
     if (functionEval.getArgs() != null) {
       for (EvalNode arg : functionEval.getArgs()) {
@@ -113,15 +113,15 @@ public class SimpleEvalNodeVisitor<CONTEXT> {
   // Value and Literal
   ///////////////////////////////////////////////////////////////////////////////////////////////
 
-  public EvalNode visitConst(CONTEXT context, ConstEval evalNode, Stack<EvalNode> stack) {
+  protected EvalNode visitConst(CONTEXT context, ConstEval evalNode, Stack<EvalNode> stack) {
     return evalNode;
   }
 
-  public EvalNode visitRowConstant(CONTEXT context, RowConstantEval evalNode, Stack<EvalNode> stack) {
+  protected EvalNode visitRowConstant(CONTEXT context, RowConstantEval evalNode, Stack<EvalNode> stack) {
     return evalNode;
   }
 
-  public EvalNode visitField(CONTEXT context, Stack<EvalNode> stack, FieldEval evalNode) {
+  protected EvalNode visitField(CONTEXT context, Stack<EvalNode> stack, FieldEval evalNode) {
     return evalNode;
   }
 
@@ -130,7 +130,7 @@ public class SimpleEvalNodeVisitor<CONTEXT> {
   // SQL standard predicates
   ///////////////////////////////////////////////////////////////////////////////////////////////
 
-  public EvalNode visitBetween(CONTEXT context, BetweenPredicateEval evalNode, Stack<EvalNode> stack) {
+  protected EvalNode visitBetween(CONTEXT context, BetweenPredicateEval evalNode, Stack<EvalNode> stack) {
     stack.push(evalNode);
     visit(context, evalNode.getPredicand(), stack);
     visit(context, evalNode.getBegin(), stack);
@@ -138,7 +138,7 @@ public class SimpleEvalNodeVisitor<CONTEXT> {
     return evalNode;
   }
 
-  public EvalNode visitCaseWhen(CONTEXT context, CaseWhenEval evalNode, Stack<EvalNode> stack) {
+  protected EvalNode visitCaseWhen(CONTEXT context, CaseWhenEval evalNode, Stack<EvalNode> stack) {
     stack.push(evalNode);
     for (CaseWhenEval.IfThenEval ifThenEval : evalNode.getIfThenEvals()) {
       visitIfThen(context, ifThenEval, stack);
@@ -150,7 +150,7 @@ public class SimpleEvalNodeVisitor<CONTEXT> {
     return evalNode;
   }
 
-  public EvalNode visitIfThen(CONTEXT context, CaseWhenEval.IfThenEval evalNode, Stack<EvalNode> stack) {
+  protected EvalNode visitIfThen(CONTEXT context, CaseWhenEval.IfThenEval evalNode, Stack<EvalNode> stack) {
     stack.push(evalNode);
     visit(context, evalNode.getCondition(), stack);
     visit(context, evalNode.getResult(), stack);
@@ -158,7 +158,7 @@ public class SimpleEvalNodeVisitor<CONTEXT> {
     return evalNode;
   }
 
-  public EvalNode visitInPredicate(CONTEXT context, InEval evalNode, Stack<EvalNode> stack) {
+  protected EvalNode visitInPredicate(CONTEXT context, InEval evalNode, Stack<EvalNode> stack) {
     return visitBinaryEval(context, stack, evalNode);
   }
 
@@ -166,7 +166,7 @@ public class SimpleEvalNodeVisitor<CONTEXT> {
   // Functions
   ///////////////////////////////////////////////////////////////////////////////////////////////
 
-  public EvalNode visitFuncCall(CONTEXT context, FunctionEval evalNode, Stack<EvalNode> stack) {
+  protected EvalNode visitFuncCall(CONTEXT context, FunctionEval evalNode, Stack<EvalNode> stack) {
     return visitDefaultFunctionEval(context, stack, evalNode);
   }
 }

http://git-wip-us.apache.org/repos/asf/tajo/blob/ea5ce54d/tajo-core/src/main/java/org/apache/tajo/engine/eval/UnaryEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/eval/UnaryEval.java b/tajo-core/src/main/java/org/apache/tajo/engine/eval/UnaryEval.java
index 7c6833f..e7ae112 100644
--- a/tajo-core/src/main/java/org/apache/tajo/engine/eval/UnaryEval.java
+++ b/tajo-core/src/main/java/org/apache/tajo/engine/eval/UnaryEval.java
@@ -19,6 +19,7 @@
 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.Schema;
 import org.apache.tajo.common.TajoDataTypes;
@@ -37,6 +38,16 @@ public abstract class UnaryEval extends EvalNode implements Cloneable {
     this.child = child;
   }
 
+  @Override
+  public int childNum() {
+    return 1;
+  }
+
+  public EvalNode getChild(int idx) {
+    Preconditions.checkArgument(idx == 0, "UnaryEval always has one child.");
+    return child;
+  }
+
   public void setChild(EvalNode child) {
     this.child = child;
   }

http://git-wip-us.apache.org/repos/asf/tajo/blob/ea5ce54d/tajo-core/src/main/java/org/apache/tajo/engine/plan/EvalTreeProtoDeserializer.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/plan/EvalTreeProtoDeserializer.java b/tajo-core/src/main/java/org/apache/tajo/engine/plan/EvalTreeProtoDeserializer.java
new file mode 100644
index 0000000..0fa6dbb
--- /dev/null
+++ b/tajo-core/src/main/java/org/apache/tajo/engine/plan/EvalTreeProtoDeserializer.java
@@ -0,0 +1,218 @@
+/*
+ * Lisensed 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.engine.plan;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import org.apache.tajo.catalog.Column;
+import org.apache.tajo.catalog.FunctionDesc;
+import org.apache.tajo.catalog.exception.NoSuchFunctionException;
+import org.apache.tajo.catalog.proto.CatalogProtos;
+import org.apache.tajo.datum.*;
+import org.apache.tajo.engine.eval.*;
+import org.apache.tajo.engine.function.AggFunction;
+import org.apache.tajo.engine.function.GeneralFunction;
+import org.apache.tajo.engine.plan.proto.PlanProto;
+import org.apache.tajo.exception.InternalException;
+
+import java.util.*;
+
+/**
+ * It deserializes a serialized eval tree consisting of a number of EvalNodes.
+ *
+ * {@link org.apache.tajo.engine.plan.EvalTreeProtoSerializer} serializes an eval tree in a postfix traverse order.
+ * So, this class firstly sorts all serialized eval nodes in ascending order of their sequence IDs. Then,
+ * it sequentially restores each serialized node to EvalNode instance.
+ *
+ * @see org.apache.tajo.engine.plan.EvalTreeProtoSerializer
+ */
+public class EvalTreeProtoDeserializer {
+
+  public static EvalNode deserialize(PlanProto.EvalTree tree) {
+    Map<Integer, EvalNode> evalNodeMap = Maps.newHashMap();
+
+    // sort serialized eval nodes in an ascending order of their IDs.
+    List<PlanProto.EvalNode> nodeList = Lists.newArrayList(tree.getNodesList());
+    Collections.sort(nodeList, new Comparator<PlanProto.EvalNode>() {
+      @Override
+      public int compare(PlanProto.EvalNode o1, PlanProto.EvalNode o2) {
+        return o1.getId() - o2.getId();
+      }
+    });
+
+    EvalNode current = null;
+
+    // The sorted order is the same of a postfix traverse order.
+    // So, it sequentially transforms each serialized node into a EvalNode instance in a postfix order of
+    // the original eval tree.
+
+    Iterator<PlanProto.EvalNode> it = nodeList.iterator();
+    while (it.hasNext()) {
+      PlanProto.EvalNode protoNode = it.next();
+
+      EvalType type = EvalType.valueOf(protoNode.getType().name());
+
+      if (EvalType.isUnaryOperator(type)) {
+        PlanProto.UnaryEval unaryProto = protoNode.getUnary();
+        EvalNode child = evalNodeMap.get(unaryProto.getChildId());
+
+        switch (type) {
+        case NOT:
+          current = new NotEval(child);
+          break;
+        case IS_NULL:
+          current = new IsNullEval(unaryProto.getNegative(), child);
+          break;
+        case CAST:
+          current = new CastEval(child, unaryProto.getCastingType());
+          break;
+        case SIGNED:
+          current = new SignedEval(unaryProto.getNegative(), child);
+          break;
+        default:
+          throw new RuntimeException("Unknown EvalType: " + type.name());
+        }
+
+      } else if (EvalType.isBinaryOperator(type)) {
+        PlanProto.BinaryEval binProto = protoNode.getBinary();
+        EvalNode lhs = evalNodeMap.get(binProto.getLhsId());
+        EvalNode rhs = evalNodeMap.get(binProto.getRhsId());
+
+        switch (type) {
+        case IN:
+          current = new InEval(lhs, (RowConstantEval) rhs, binProto.getNegative());
+          break;
+        default:
+          current = new BinaryEval(type, lhs, rhs);
+        }
+
+      } else if (type == EvalType.CONST) {
+        PlanProto.ConstEval constProto = protoNode.getConst();
+        current = new ConstEval(deserialize(constProto.getValue()));
+
+      } else if (type == EvalType.ROW_CONSTANT) {
+        PlanProto.RowConstEval rowConstProto = protoNode.getRowConst();
+        Datum[] values = new Datum[rowConstProto.getValuesCount()];
+        for (int i = 0; i < rowConstProto.getValuesCount(); i++) {
+          values[i] = deserialize(rowConstProto.getValues(i));
+        }
+        current = new RowConstantEval(values);
+
+      } else if (type == EvalType.FIELD) {
+        CatalogProtos.ColumnProto columnProto = protoNode.getField();
+        current = new FieldEval(new Column(columnProto));
+
+      } else if (type == EvalType.BETWEEN) {
+        PlanProto.BetweenEval betweenProto = protoNode.getBetween();
+        current = new BetweenPredicateEval(betweenProto.getNegative(), betweenProto.getSymmetric(),
+            evalNodeMap.get(betweenProto.getPredicand()),
+            evalNodeMap.get(betweenProto.getBegin()),
+            evalNodeMap.get(betweenProto.getEnd()));
+
+      } else if (type == EvalType.CASE) {
+        PlanProto.CaseWhenEval caseWhenProto = protoNode.getCasewhen();
+        CaseWhenEval caseWhenEval = new CaseWhenEval();
+        for (int i = 0; i < caseWhenProto.getIfCondsCount(); i++) {
+          caseWhenEval.addIfCond((CaseWhenEval.IfThenEval) evalNodeMap.get(caseWhenProto.getIfConds(i)));
+        }
+        if (caseWhenProto.hasElse()) {
+          caseWhenEval.setElseResult(evalNodeMap.get(caseWhenProto.getElse()));
+        }
+        current = caseWhenEval;
+
+      } else if (type == EvalType.IF_THEN) {
+        PlanProto.IfCondEval ifCondProto = protoNode.getIfCond();
+        current = new CaseWhenEval.IfThenEval(evalNodeMap.get(ifCondProto.getCondition()),
+            evalNodeMap.get(ifCondProto.getThen()));
+
+      } else if (EvalType.isFunction(type)) {
+        PlanProto.FunctionEval funcProto = protoNode.getFunction();
+
+        EvalNode [] params = new EvalNode[funcProto.getParamIdsCount()];
+        for (int i = 0; i < funcProto.getParamIdsCount(); i++) {
+          params[i] = evalNodeMap.get(funcProto.getParamIds(i));
+        }
+
+        FunctionDesc funcDesc = null;
+        try {
+          funcDesc = new FunctionDesc(funcProto.getFuncion());
+          if (type == EvalType.FUNCTION) {
+            GeneralFunction instance = (GeneralFunction) funcDesc.newInstance();
+            current = new GeneralFunctionEval(new FunctionDesc(funcProto.getFuncion()), instance, params);
+          } else if (type == EvalType.AGG_FUNCTION || type == EvalType.WINDOW_FUNCTION) {
+            AggFunction instance = (AggFunction) funcDesc.newInstance();
+            if (type == EvalType.AGG_FUNCTION) {
+              current = new AggregationFunctionCallEval(new FunctionDesc(funcProto.getFuncion()), instance, params);
+            } else {
+              current = new WindowFunctionEval(new FunctionDesc(funcProto.getFuncion()), instance, params, null);
+            }
+          }
+        } catch (ClassNotFoundException cnfe) {
+          throw new NoSuchFunctionException(funcDesc.getSignature(), funcDesc.getParamTypes());
+        } catch (InternalException ie) {
+          throw new NoSuchFunctionException(funcDesc.getSignature(), funcDesc.getParamTypes());
+        }
+      } else {
+        throw new RuntimeException("Unknown EvalType: " + type.name());
+      }
+
+      evalNodeMap.put(protoNode.getId(), current);
+    }
+
+    return current;
+  }
+
+  public static Datum deserialize(PlanProto.Datum datum) {
+    switch (datum.getType()) {
+    case BOOLEAN:
+      return DatumFactory.createBool(datum.getBoolean());
+    case CHAR:
+      return DatumFactory.createChar(datum.getText());
+    case INT1:
+    case INT2:
+      return DatumFactory.createInt2((short) datum.getInt4());
+    case INT4:
+      return DatumFactory.createInt4(datum.getInt4());
+    case INT8:
+      return DatumFactory.createInt8(datum.getInt8());
+    case FLOAT4:
+      return DatumFactory.createFloat4(datum.getFloat4());
+    case FLOAT8:
+      return DatumFactory.createFloat8(datum.getFloat8());
+    case VARCHAR:
+    case TEXT:
+      return DatumFactory.createText(datum.getText());
+    case TIMESTAMP:
+      return new TimestampDatum(datum.getInt8());
+    case DATE:
+      return DatumFactory.createDate(datum.getInt4());
+    case TIME:
+      return DatumFactory.createTime(datum.getInt8());
+    case BINARY:
+    case BLOB:
+      return DatumFactory.createBlob(datum.getBlob().toByteArray());
+    case INTERVAL:
+      return new IntervalDatum(datum.getInterval().getMonth(), datum.getInterval().getMsec());
+    case NULL_TYPE:
+      return NullDatum.get();
+    default:
+      throw new RuntimeException("Unknown data type: " + datum.getType().name());
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/ea5ce54d/tajo-core/src/main/java/org/apache/tajo/engine/plan/EvalTreeProtoSerializer.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/plan/EvalTreeProtoSerializer.java b/tajo-core/src/main/java/org/apache/tajo/engine/plan/EvalTreeProtoSerializer.java
new file mode 100644
index 0000000..d2b6fd7
--- /dev/null
+++ b/tajo-core/src/main/java/org/apache/tajo/engine/plan/EvalTreeProtoSerializer.java
@@ -0,0 +1,308 @@
+/*
+ * Lisensed 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.engine.plan;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Maps;
+import com.google.protobuf.ByteString;
+import org.apache.tajo.datum.Datum;
+import org.apache.tajo.datum.IntervalDatum;
+import org.apache.tajo.engine.eval.*;
+import org.apache.tajo.engine.plan.proto.PlanProto;
+
+import java.util.Map;
+import java.util.Stack;
+
+/**
+ * It traverses an eval tree consisting of a number of {@link org.apache.tajo.engine.eval.EvalNode}
+ * in a postfix traverse order. The postfix traverse order guarantees that all child nodes of some node N
+ * were already visited when the node N is visited. This manner makes tree serialization possible in a simple logic.
+ */
+public class EvalTreeProtoSerializer
+    extends SimpleEvalNodeVisitor<EvalTreeProtoSerializer.EvalTreeProtoBuilderContext> {
+
+  private static final EvalTreeProtoSerializer instance;
+
+  static {
+    instance = new EvalTreeProtoSerializer();
+  }
+
+  public static class EvalTreeProtoBuilderContext {
+    private int seqId = 0;
+    private Map<EvalNode, Integer> idMap = Maps.newHashMap();
+    private PlanProto.EvalTree.Builder treeBuilder = PlanProto.EvalTree.newBuilder();
+  }
+
+  public static PlanProto.EvalTree serialize(EvalNode evalNode) {
+    EvalTreeProtoSerializer.EvalTreeProtoBuilderContext context =
+        new EvalTreeProtoSerializer.EvalTreeProtoBuilderContext();
+    instance.visit(context, evalNode, new Stack<EvalNode>());
+    return context.treeBuilder.build();
+  }
+
+  /**
+   * Return child's serialization IDs. Usually, 0 is used for a child id of unary node or left child of
+   * binary node. 1 is used for right child of binary node. Between will use 0 as predicand, 1 as begin, and 2 as
+   * end eval node. For more detail, you should refer to each EvalNode implementation.
+   *
+   * @param context Context
+   * @param evalNode EvalNode
+   * @return The array of IDs which points to stored EvalNode.
+   * @see org.apache.tajo.engine.eval.EvalNode
+   */
+  private int [] registerGetChildIds(EvalTreeProtoBuilderContext context, EvalNode evalNode) {
+    int [] childIds = new int[evalNode.childNum()];
+    for (int i = 0; i < evalNode.childNum(); i++) {
+      if (context.idMap.containsKey(evalNode.getChild(i))) {
+        childIds[i] = context.idMap.get(evalNode.getChild(i));
+      } else {
+        childIds[i] = context.seqId++;
+      }
+    }
+    return childIds;
+  }
+
+  private PlanProto.EvalNode.Builder createEvalBuilder(EvalTreeProtoBuilderContext context, EvalNode node) {
+    int sid; // serialization sequence id
+    if (context.idMap.containsKey(node)) {
+      sid = context.idMap.get(node);
+    } else {
+      sid = context.seqId++;
+      context.idMap.put(node, sid);
+    }
+
+    PlanProto.EvalNode.Builder nodeBuilder = PlanProto.EvalNode.newBuilder();
+    nodeBuilder.setId(sid);
+    nodeBuilder.setDataType(node.getValueType());
+    nodeBuilder.setType(PlanProto.EvalType.valueOf(node.getType().name()));
+    return nodeBuilder;
+  }
+
+  @Override
+  public EvalNode visitUnaryEval(EvalTreeProtoBuilderContext context, Stack<EvalNode> stack, UnaryEval unary) {
+    // visiting and registering childs
+    super.visitUnaryEval(context, stack, unary);
+    int [] childIds = registerGetChildIds(context, unary);
+
+    // building itself
+    PlanProto.UnaryEval.Builder unaryBuilder = PlanProto.UnaryEval.newBuilder();
+    unaryBuilder.setChildId(childIds[0]);
+    if (unary.getType() == EvalType.IS_NULL) {
+      IsNullEval isNullEval = (IsNullEval) unary;
+      unaryBuilder.setNegative(isNullEval.isNot());
+    } else if (unary.getType() == EvalType.SIGNED) {
+      SignedEval signedEval = (SignedEval) unary;
+      unaryBuilder.setNegative(signedEval.isNegative());
+    } else if (unary.getType() == EvalType.CAST) {
+      CastEval castEval = (CastEval) unary;
+      unaryBuilder.setCastingType(castEval.getValueType());
+    }
+
+    // registering itself and building EvalNode
+    PlanProto.EvalNode.Builder builder = createEvalBuilder(context, unary);
+    builder.setUnary(unaryBuilder);
+    context.treeBuilder.addNodes(builder);
+    return unary;
+  }
+
+  @Override
+  public EvalNode visitBinaryEval(EvalTreeProtoBuilderContext context, Stack<EvalNode> stack, BinaryEval binary) {
+    // visiting and registering childs
+    super.visitBinaryEval(context, stack, binary);
+    int [] childIds = registerGetChildIds(context, binary);
+
+    // building itself
+    PlanProto.BinaryEval.Builder binaryBuilder = PlanProto.BinaryEval.newBuilder();
+    binaryBuilder.setLhsId(childIds[0]);
+    binaryBuilder.setRhsId(childIds[1]);
+
+    // registering itself and building EvalNode
+    PlanProto.EvalNode.Builder builder = createEvalBuilder(context, binary);
+    builder.setBinary(binaryBuilder);
+    context.treeBuilder.addNodes(builder);
+    return binary;
+  }
+
+  @Override
+  public EvalNode visitConst(EvalTreeProtoBuilderContext context, ConstEval constant, Stack<EvalNode> stack) {
+    PlanProto.EvalNode.Builder builder = createEvalBuilder(context, constant);
+    builder.setConst(PlanProto.ConstEval.newBuilder().setValue(serialize(constant.getValue())));
+    context.treeBuilder.addNodes(builder);
+    return constant;
+  }
+
+  @Override
+  public EvalNode visitRowConstant(EvalTreeProtoBuilderContext context, RowConstantEval rowConst,
+                                   Stack<EvalNode> stack) {
+
+    PlanProto.RowConstEval.Builder rowConstBuilder = PlanProto.RowConstEval.newBuilder();
+    for (Datum d : rowConst.getValues()) {
+      rowConstBuilder.addValues(serialize(d));
+    }
+
+    PlanProto.EvalNode.Builder builder = createEvalBuilder(context, rowConst);
+    builder.setRowConst(rowConstBuilder);
+    context.treeBuilder.addNodes(builder);
+    return rowConst;
+  }
+
+  public EvalNode visitField(EvalTreeProtoBuilderContext context, Stack<EvalNode> stack, FieldEval field) {
+    PlanProto.EvalNode.Builder builder = createEvalBuilder(context, field);
+    builder.setField(field.getColumnRef().getProto());
+    context.treeBuilder.addNodes(builder);
+    return field;
+  }
+
+  public EvalNode visitBetween(EvalTreeProtoBuilderContext context, BetweenPredicateEval between,
+                               Stack<EvalNode> stack) {
+    // visiting and registering childs
+    super.visitBetween(context, between, stack);
+    int [] childIds = registerGetChildIds(context, between);
+    Preconditions.checkState(childIds.length == 3, "Between must have three childs, but there are " + childIds.length
+        + " child nodes");
+
+    // building itself
+    PlanProto.BetweenEval.Builder betweenBuilder = PlanProto.BetweenEval.newBuilder();
+    betweenBuilder.setNegative(between.isNot());
+    betweenBuilder.setSymmetric(between.isSymmetric());
+    betweenBuilder.setPredicand(childIds[0]);
+    betweenBuilder.setBegin(childIds[1]);
+    betweenBuilder.setEnd(childIds[2]);
+
+    // registering itself and building EvalNode
+    PlanProto.EvalNode.Builder builder = createEvalBuilder(context, between);
+    builder.setBetween(betweenBuilder);
+    context.treeBuilder.addNodes(builder);
+    return between;
+  }
+
+  public EvalNode visitCaseWhen(EvalTreeProtoBuilderContext context, CaseWhenEval caseWhen, Stack<EvalNode> stack) {
+    // visiting and registering childs
+    super.visitCaseWhen(context, caseWhen, stack);
+    int [] childIds = registerGetChildIds(context, caseWhen);
+    Preconditions.checkState(childIds.length > 0, "Case When must have at least one child, but there is no child");
+
+    // building itself
+    PlanProto.CaseWhenEval.Builder caseWhenBuilder = PlanProto.CaseWhenEval.newBuilder();
+    int ifCondsNum = childIds.length - (caseWhen.hasElse() ? 1 : 0);
+    for (int i = 0; i < ifCondsNum; i++) {
+      caseWhenBuilder.addIfConds(childIds[i]);
+    }
+    if (caseWhen.hasElse()) {
+      caseWhenBuilder.setElse(childIds[childIds.length - 1]);
+    }
+
+    // registering itself and building EvalNode
+    PlanProto.EvalNode.Builder builder = createEvalBuilder(context, caseWhen);
+    builder.setCasewhen(caseWhenBuilder);
+    context.treeBuilder.addNodes(builder);
+
+    return caseWhen;
+  }
+
+  public EvalNode visitIfThen(EvalTreeProtoBuilderContext context, CaseWhenEval.IfThenEval ifCond,
+                              Stack<EvalNode> stack) {
+    // visiting and registering childs
+    super.visitIfThen(context, ifCond, stack);
+    int [] childIds = registerGetChildIds(context, ifCond);
+
+    // building itself
+    PlanProto.IfCondEval.Builder ifCondBuilder = PlanProto.IfCondEval.newBuilder();
+    ifCondBuilder.setCondition(childIds[0]);
+    ifCondBuilder.setThen(childIds[1]);
+
+    // registering itself and building EvalNode
+    PlanProto.EvalNode.Builder builder = createEvalBuilder(context, ifCond);
+    builder.setIfCond(ifCondBuilder);
+    context.treeBuilder.addNodes(builder);
+
+    return ifCond;
+  }
+
+  public EvalNode visitFuncCall(EvalTreeProtoBuilderContext context, FunctionEval function, Stack<EvalNode> stack) {
+    // visiting and registering childs
+    super.visitFuncCall(context, function, stack);
+    int [] childIds = registerGetChildIds(context, function);
+
+    // building itself
+    PlanProto.FunctionEval.Builder funcBuilder = PlanProto.FunctionEval.newBuilder();
+    funcBuilder.setFuncion(function.getFuncDesc().getProto());
+    for (int i = 0; i < childIds.length; i++) {
+      funcBuilder.addParamIds(childIds[i]);
+    }
+
+    // registering itself and building EvalNode
+    PlanProto.EvalNode.Builder builder = createEvalBuilder(context, function);
+    builder.setFunction(funcBuilder);
+    context.treeBuilder.addNodes(builder);
+
+    return function;
+  }
+
+  public static PlanProto.Datum serialize(Datum datum) {
+    PlanProto.Datum.Builder builder = PlanProto.Datum.newBuilder();
+
+    builder.setType(datum.type());
+
+    switch (datum.type()) {
+    case NULL_TYPE:
+      break;
+    case BOOLEAN:
+      builder.setBoolean(datum.asBool());
+      break;
+    case INT1:
+    case INT2:
+    case INT4:
+    case DATE:
+      builder.setInt4(datum.asInt4());
+      break;
+    case INT8:
+    case TIMESTAMP:
+    case TIME:
+      builder.setInt8(datum.asInt8());
+      break;
+    case FLOAT4:
+      builder.setFloat4(datum.asFloat4());
+      break;
+    case FLOAT8:
+      builder.setFloat8(datum.asFloat8());
+      break;
+    case CHAR:
+    case VARCHAR:
+    case TEXT:
+      builder.setText(datum.asChars());
+      break;
+    case BINARY:
+    case BLOB:
+      builder.setBlob(ByteString.copyFrom(datum.asByteArray()));
+      break;
+    case INTERVAL:
+      IntervalDatum interval = (IntervalDatum) datum;
+      PlanProto.Interval.Builder intervalBuilder = PlanProto.Interval.newBuilder();
+      intervalBuilder.setMonth(interval.getMonths());
+      intervalBuilder.setMsec(interval.getMilliSeconds());
+      builder.setInterval(intervalBuilder);
+      break;
+    default:
+      throw new RuntimeException("Unknown data type: " + datum.type().name());
+    }
+
+    return builder.build();
+  }
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/ea5ce54d/tajo-core/src/main/java/org/apache/tajo/engine/planner/ExprAnnotator.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/planner/ExprAnnotator.java b/tajo-core/src/main/java/org/apache/tajo/engine/planner/ExprAnnotator.java
index 87e54de..6a3af98 100644
--- a/tajo-core/src/main/java/org/apache/tajo/engine/planner/ExprAnnotator.java
+++ b/tajo-core/src/main/java/org/apache/tajo/engine/planner/ExprAnnotator.java
@@ -352,7 +352,7 @@ public class ExprAnnotator extends BaseAlgebraVisitor<ExprAnnotator.Context, Eva
     for (CaseWhenPredicate.WhenExpr when : caseWhen.getWhens()) {
       condition = visit(ctx, stack, when.getCondition());
       result = visit(ctx, stack, when.getResult());
-      caseWhenEval.addWhen(condition, result);
+      caseWhenEval.addIfCond(condition, result);
     }
 
     if (caseWhen.hasElseResult()) {

http://git-wip-us.apache.org/repos/asf/tajo/blob/ea5ce54d/tajo-core/src/main/proto/Plan.proto
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/proto/Plan.proto b/tajo-core/src/main/proto/Plan.proto
new file mode 100644
index 0000000..fa8cbb8
--- /dev/null
+++ b/tajo-core/src/main/proto/Plan.proto
@@ -0,0 +1,209 @@
+/**
+ * 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 tajo.plan;
+option cc_generic_services = false;
+option java_package = "org.apache.tajo.engine.plan.proto";
+option java_outer_classname = "PlanProto";
+option java_generic_services = false;
+option java_generate_equals_and_hash = true;
+
+import "PrimitiveProtos.proto";
+import "CatalogProtos.proto";
+import "DataTypes.proto";
+
+enum NodeType {
+  BST_INDEX_SCAN = 0;
+  EXCEPT = 1;
+  EXPRS = 2;
+  DISTINCT_GROUP_BY = 3;
+  GROUP_BY = 4;
+  HAVING = 5;
+  JOIN = 6;
+  INSERT = 7;
+  INTERSECT = 8;
+  LIMIT = 9;
+  PARTITIONS_SCAN = 10;
+  PROJECTION = 11;
+  ROOT = 12;
+  SCAN = 13;
+  SELECTION = 14;
+  SORT = 15;
+  STORE = 16;
+  TABLE_SUBQUERY = 17;
+  UNION = 18;
+  WINDOW_AGG = 19;
+
+  CREATE_DATABASE = 20;
+  DROP_DATABASE = 21;
+  CREATE_TABLE = 22;
+  DROP_TABLE = 23;
+  ALTER_TABLESPACE = 24;
+  ALTER_TABLE = 25;
+  TRUNCATE_TABLE = 26;
+}
+
+message LogicalPlan {
+  required KeyValueSetProto adjacentList = 1;
+}
+
+message LogicalNode {
+  required int32 pid = 1;
+  required NodeType type = 2;
+  required SchemaProto in_schema = 3;
+  required SchemaProto out_schema = 4;
+  required NodeSpec spec = 5;
+}
+
+message NodeSpec {
+  optional ScanNode scan = 1;
+}
+
+message ScanNode {
+  required TableDescProto table = 1;
+  optional string alias = 2;
+  required SchemaProto schema = 3;
+}
+
+
+enum EvalType {
+  NOT = 0;
+  AND = 1;
+  OR = 2;
+  EQUAL = 3;
+  IS_NULL = 4;
+  NOT_EQUAL = 5;
+  LTH = 6;
+  LEQ = 7;
+  GTH = 8;
+  GEQ = 9;
+  PLUS = 10;
+  MINUS = 11;
+  MODULAR = 12;
+  MULTIPLY = 13;
+  DIVIDE = 14;
+
+  // Binary Bitwise expressions
+  BIT_AND = 15;
+  BIT_OR = 16;
+  BIT_XOR = 17;
+
+  // Function
+  WINDOW_FUNCTION = 18;
+  AGG_FUNCTION = 19;
+  FUNCTION = 20;
+
+  // String operator or pattern matching predicates
+  LIKE = 21;
+  SIMILAR_TO = 22;
+  REGEX = 23;
+  CONCATENATE = 24;
+
+  // Other predicates
+  BETWEEN = 25;
+  CASE = 26;
+  IF_THEN = 27;
+  IN = 28;
+
+  // Value or Reference
+  SIGNED = 29;
+  CAST = 30;
+  ROW_CONSTANT = 31;
+  FIELD = 32;
+  CONST = 33;
+}
+
+message EvalTree {
+  repeated EvalNode nodes = 1;
+}
+
+message EvalNode {
+  required int32 id = 1;
+  required EvalType type = 2;
+  required DataType data_type = 3;
+
+  optional UnaryEval unary = 4; // NOT
+  optional BinaryEval binary = 5;
+  optional ConstEval const = 6;
+  optional ColumnProto field = 7; // field eval
+  optional FunctionEval function = 8;
+  optional RowConstEval rowConst = 9;
+  optional BetweenEval between = 10;
+  optional CaseWhenEval casewhen = 11;
+  optional IfCondEval ifCond = 12;
+}
+
+message UnaryEval {
+  required int32 child_id = 1;
+  optional DataType castingType = 2;
+  optional bool negative = 3;
+}
+
+message BinaryEval {
+  required int32 lhs_id = 1;
+  required int32 rhs_id = 2;
+  optional bool negative = 3 [default = false];
+}
+
+message BetweenEval {
+  required int32 predicand = 1;
+  required int32 begin = 2;
+  required int32 end = 3;
+  optional bool negative = 4 [default = false];
+  optional bool symmetric = 5 [default = false];
+}
+
+message CaseWhenEval {
+  repeated int32 ifConds = 1;
+  optional int32 else = 2;
+}
+
+message IfCondEval {
+  required int32 condition = 1;
+  required int32 then = 2;
+}
+
+message ConstEval {
+  required Datum value = 1;
+}
+
+message RowConstEval {
+  repeated Datum values = 1;
+}
+
+message FunctionEval {
+  required FunctionDescProto funcion = 1;
+  repeated int32 paramIds = 2;
+}
+
+message Datum {
+  required Type type = 1;
+  optional bool boolean = 2;
+  optional int32 int4 = 3;    // int4, date
+  optional int64 int8 = 4;    // int8, timestamp, and time
+  optional float float4 = 5;
+  optional double float8 = 6;
+  optional string text = 7;
+  optional bytes blob = 8;
+  optional Interval interval = 12;
+}
+
+message Interval {
+  optional int32 month = 1 [default = 0];
+  optional int64 msec = 2;
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tajo/blob/ea5ce54d/tajo-core/src/test/java/org/apache/tajo/engine/eval/ExprTestBase.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/test/java/org/apache/tajo/engine/eval/ExprTestBase.java b/tajo-core/src/test/java/org/apache/tajo/engine/eval/ExprTestBase.java
index 7f9436a..3bee4f3 100644
--- a/tajo-core/src/test/java/org/apache/tajo/engine/eval/ExprTestBase.java
+++ b/tajo-core/src/test/java/org/apache/tajo/engine/eval/ExprTestBase.java
@@ -31,6 +31,9 @@ import org.apache.tajo.conf.TajoConf;
 import org.apache.tajo.datum.*;
 import org.apache.tajo.engine.json.CoreGsonHelper;
 import org.apache.tajo.engine.parser.SQLAnalyzer;
+import org.apache.tajo.engine.plan.EvalTreeProtoDeserializer;
+import org.apache.tajo.engine.plan.EvalTreeProtoSerializer;
+import org.apache.tajo.engine.plan.proto.PlanProto;
 import org.apache.tajo.engine.planner.*;
 import org.apache.tajo.engine.query.QueryContext;
 import org.apache.tajo.engine.utils.SchemaUtil;
@@ -53,6 +56,7 @@ import static org.apache.tajo.TajoConstants.DEFAULT_DATABASE_NAME;
 import static org.apache.tajo.TajoConstants.DEFAULT_TABLESPACE_NAME;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.fail;
 
 public class ExprTestBase {
   private static TajoTestingCluster util;
@@ -135,9 +139,21 @@ public class ExprTestBase {
     if (targets == null) {
       throw new PlanningException("Wrong query statement or query plan: " + parsedResults.get(0).getHistoryStatement());
     }
+
+    // Trying regression test for cloning, (de)serialization for json and protocol buffer
+    for (Target t : targets) {
+      try {
+        assertEquals(t.getEvalTree(), t.getEvalTree().clone());
+      } catch (CloneNotSupportedException e) {
+        fail(e.getMessage());
+      }
+    }
     for (Target t : targets) {
       assertJsonSerDer(t.getEvalTree());
     }
+    for (Target t : targets) {
+      assertEvalTreeProtoSerDer(t.getEvalTree());
+    }
     return targets;
   }
 
@@ -226,4 +242,9 @@ public class ExprTestBase {
       }
     }
   }
+
+  public static void assertEvalTreeProtoSerDer(EvalNode evalNode) {
+    PlanProto.EvalTree converted = EvalTreeProtoSerializer.serialize(evalNode);
+    assertEquals(evalNode, EvalTreeProtoDeserializer.deserialize(converted));
+  }
 }

http://git-wip-us.apache.org/repos/asf/tajo/blob/ea5ce54d/tajo-core/src/test/java/org/apache/tajo/engine/eval/TestEvalTree.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/test/java/org/apache/tajo/engine/eval/TestEvalTree.java b/tajo-core/src/test/java/org/apache/tajo/engine/eval/TestEvalTree.java
index da43025..beeb1c6 100644
--- a/tajo-core/src/test/java/org/apache/tajo/engine/eval/TestEvalTree.java
+++ b/tajo-core/src/test/java/org/apache/tajo/engine/eval/TestEvalTree.java
@@ -31,7 +31,7 @@ import org.junit.Test;
 import static org.apache.tajo.common.TajoDataTypes.Type.*;
 import static org.junit.Assert.*;
 
-public class TestEvalTree extends ExprTestBase{
+public class TestEvalTree extends ExprTestBase {
   @Test
   public void testTupleEval() throws CloneNotSupportedException {
     ConstEval e1 = new ConstEval(DatumFactory.createInt4(1));
@@ -89,6 +89,15 @@ public class TestEvalTree extends ExprTestBase{
       return CatalogUtil.newSimpleDataType(BOOLEAN);
     }
 
+    @Override
+    public int childNum() {
+      return 0;
+    }
+
+    @Override
+    public EvalNode getChild(int idx) {
+      return null;
+    }
   }
 
   public static class MockFalseExpr extends EvalNode {
@@ -126,6 +135,16 @@ public class TestEvalTree extends ExprTestBase{
     public DataType getValueType() {
       return CatalogUtil.newSimpleDataType(BOOLEAN);
     }
+
+    @Override
+    public int childNum() {
+      return 0;
+    }
+
+    @Override
+    public EvalNode getChild(int idx) {
+      return null;
+    }
   }
 
   @Test