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/01/17 10:23:38 UTC

[08/12] TAJO-501: Rewrite the projection part of logical planning.

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/BinaryEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/BinaryEval.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/BinaryEval.java
index a67ca7a..ba21b4a 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/BinaryEval.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/BinaryEval.java
@@ -52,6 +52,7 @@ public class BinaryEval extends EvalNode implements Cloneable {
         type == EvalType.AND ||
             type == EvalType.OR ||
             type == EvalType.EQUAL ||
+            type == EvalType.NOT_EQUAL ||
             type == EvalType.LTH ||
             type == EvalType.GTH ||
             type == EvalType.LEQ ||
@@ -187,7 +188,7 @@ public class BinaryEval extends EvalNode implements Cloneable {
 
   @Override
 	public String getName() {
-		return "?";
+		return type.name();
 	}
 
 	@Override

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/CaseWhenEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/CaseWhenEval.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/CaseWhenEval.java
index c519250..9bbf4b4 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/CaseWhenEval.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/CaseWhenEval.java
@@ -104,12 +104,12 @@ public class CaseWhenEval extends EvalNode implements GsonObject {
 
   @Override
   public String toString() {
-    StringBuilder sb = new StringBuilder("CASE\n");
+    StringBuilder sb = new StringBuilder("CASE ");
     for (IfThenEval when : whens) {
-     sb.append(when).append("\n");
+     sb.append(when).append(" ");
     }
 
-    sb.append("ELSE ").append(elseResult).append(" END\n");
+    sb.append("ELSE ").append(elseResult).append(" END");
 
     return sb.toString();
   }
@@ -199,8 +199,7 @@ public class CaseWhenEval extends EvalNode implements GsonObject {
     public boolean equals(Object object) {
       if (object instanceof IfThenEval) {
         IfThenEval other = (IfThenEval) object;
-        return condition.equals(other.condition) &&
-            result.equals(other.result);
+        return condition.equals(other.condition) && result.equals(other.result);
       } else {
         return false;
       }

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalTreeUtil.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalTreeUtil.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalTreeUtil.java
index d262bc3..4044217 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalTreeUtil.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalTreeUtil.java
@@ -26,6 +26,7 @@ import org.apache.tajo.catalog.Schema;
 import org.apache.tajo.common.TajoDataTypes.DataType;
 import org.apache.tajo.engine.planner.Target;
 import org.apache.tajo.exception.InternalException;
+import org.apache.tajo.util.TUtil;
 
 import java.util.*;
 
@@ -124,16 +125,16 @@ public class EvalTreeUtil {
           + expr.getType().toString());
     }
   }
-  
+
   /**
    * Return all exprs to refer columns corresponding to the target.
-   * 
-   * @param expr 
+   *
+   * @param expr
    * @param target to be found
    * @return a list of exprs
    */
   public static Collection<EvalNode> getContainExpr(EvalNode expr, Column target) {
-    Set<EvalNode> exprSet = Sets.newHashSet();    
+    Set<EvalNode> exprSet = Sets.newHashSet();
     getContainExpr(expr, target, exprSet);
     return exprSet;
   }
@@ -298,4 +299,30 @@ public class EvalTreeUtil {
       return this.aggFucntions;
     }
   }
+
+  public static <T extends EvalNode> Collection<T> findEvalsByType(EvalNode evalNode, EvalType type) {
+    EvalFinder finder = new EvalFinder(type);
+    finder.visitChild(null, evalNode, new Stack<EvalNode>());
+    return (Collection<T>) finder.evalNodes;
+  }
+
+  public static class EvalFinder extends BasicEvalNodeVisitor<Object, Object> {
+    private EvalType targetType;
+    List<EvalNode> evalNodes = TUtil.newList();
+
+    public EvalFinder(EvalType targetType) {
+      this.targetType = targetType;
+    }
+
+    @Override
+    public Object visitChild(Object context, EvalNode evalNode, Stack<EvalNode> stack) {
+      super.visitChild(context, evalNode, stack);
+
+      if (evalNode.type == targetType) {
+        evalNodes.add(evalNode);
+      }
+
+      return evalNode;
+    }
+  }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/FieldEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/FieldEval.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/FieldEval.java
index 6a840e4..dd29a3b 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/FieldEval.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/FieldEval.java
@@ -42,17 +42,10 @@ public class FieldEval extends EvalNode implements Cloneable {
 	@Override
 	public void eval(EvalContext ctx, Schema schema, Tuple tuple) {
 	  if (fieldId == -1) {
-	    if(schema.contains(column.getQualifiedName())) {
-	     fieldId = schema.getColumnId(column.getQualifiedName());
-	    } else {
-	      if(schema.getColumnNum() != 0) {
-	        String schemaColQualName = schema.getColumn(0).getQualifier() +
-	            "." +  column.getColumnName();
-	        fieldId = schema.getColumnId(schemaColQualName);
-	      } else {
-	        fieldId = schema.getColumnId(column.getQualifiedName());
-	      }
-	    }
+	    fieldId = schema.getColumnId(column.getQualifiedName());
+      if (fieldId == -1) {
+        throw new IllegalStateException("No Such Column Reference: " + column + ", schema: " + schema);
+      }
 	  }
     FieldEvalContext fieldCtx = (FieldEvalContext) ctx;
 	  fieldCtx.datum = tuple.get(fieldId);

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/InEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/InEval.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/InEval.java
index 1e26e14..e113326 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/InEval.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/InEval.java
@@ -25,6 +25,7 @@ import org.apache.tajo.catalog.Schema;
 import org.apache.tajo.common.TajoDataTypes;
 import org.apache.tajo.datum.Datum;
 import org.apache.tajo.datum.DatumFactory;
+import org.apache.tajo.datum.NullDatum;
 import org.apache.tajo.storage.Tuple;
 
 public class InEval extends BinaryEval {
@@ -69,6 +70,12 @@ public class InEval extends BinaryEval {
     boolean isIncluded = false;
 
     Datum value = tuple.get(fieldId);
+
+    if (value.isNull()) {
+      isNullCtx.isNull = true;
+      return;
+    }
+
     for (Datum datum : values) {
       if (value.equalsTo(datum).asBool()) {
         isIncluded = true;
@@ -80,6 +87,9 @@ public class InEval extends BinaryEval {
 
   @Override
   public Datum terminate(EvalContext ctx) {
+    if (((InEvalCtx)ctx).isNull) {
+      return NullDatum.get();
+    }
     return DatumFactory.createBool(not ^ ((InEvalCtx)ctx).result);
   }
 
@@ -97,6 +107,7 @@ public class InEval extends BinaryEval {
   }
 
   private class InEvalCtx implements EvalContext {
+    boolean isNull;
     boolean result;
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/IsNullEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/IsNullEval.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/IsNullEval.java
index 029f4f4..8bb4d95 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/IsNullEval.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/IsNullEval.java
@@ -59,6 +59,11 @@ public class IsNullEval extends BinaryEval {
   }
 
   @Override
+  public String toString() {
+    return leftExpr + " IS " + (isNot ? "NOT NULL" : "NULL");
+  }
+
+  @Override
   public void eval(EvalContext ctx, Schema schema, Tuple tuple) {
     IsNullEvalCtx isNullCtx = (IsNullEvalCtx) ctx;
     leftExpr.eval(isNullCtx.predicandContext, schema, tuple);

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/NotEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/NotEval.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/NotEval.java
index a45e96d..677708d 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/NotEval.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/NotEval.java
@@ -64,7 +64,8 @@ public class NotEval extends EvalNode implements Cloneable {
 
   @Override
   public Datum terminate(EvalContext ctx) {
-    return DatumFactory.createBool(!childEval.terminate(((NotEvalCtx) ctx).childExprCtx).asBool());
+    Datum datum = childEval.terminate(((NotEvalCtx) ctx).childExprCtx);
+    return !datum.isNull() ? DatumFactory.createBool(!datum.asBool()) : datum;
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/exception/NoSuchColumnException.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/exception/NoSuchColumnException.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/exception/NoSuchColumnException.java
index 968bf3e..70191a9 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/exception/NoSuchColumnException.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/exception/NoSuchColumnException.java
@@ -20,6 +20,6 @@ package org.apache.tajo.engine.exception;
 
 public class NoSuchColumnException extends VerifyException {
   public NoSuchColumnException(String columnName) {
-    super("ERROR: no such column '" + columnName + "'");
+    super("ERROR: no such a column '" + columnName + "'");
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/HiveConverter.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/HiveConverter.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/HiveConverter.java
index 308faf0..a8a555b 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/HiveConverter.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/HiveConverter.java
@@ -153,7 +153,7 @@ public class HiveConverter extends HiveParserBaseVisitor<Expr> {
     }
 
     Projection projection = new Projection();
-    projection.setTargets(select.getTargets());
+    projection.setNamedExprs(select.getNamedExprs());
 
     if (current != null)
       projection.setChild(current);
@@ -253,7 +253,7 @@ public class HiveConverter extends HiveParserBaseVisitor<Expr> {
       }
 
       Projection projection = new Projection();
-      projection.setTargets(select.getTargets());
+      projection.setNamedExprs(select.getNamedExprs());
 
       if (current != null)
         projection.setChild(current);
@@ -368,7 +368,7 @@ public class HiveConverter extends HiveParserBaseVisitor<Expr> {
     }
 
     Projection projection = new Projection();
-    projection.setTargets(select.getTargets());
+    projection.setNamedExprs(select.getNamedExprs());
 
     if (current != null)
       projection.setChild(current);
@@ -542,7 +542,7 @@ public class HiveConverter extends HiveParserBaseVisitor<Expr> {
   public Expr visitSelectList(HiveParser.SelectListContext ctx) {
     Expr current = null;
     Projection projection = new Projection();
-    TargetExpr[] targets = new TargetExpr[ctx.selectItem().size()];
+    NamedExpr[] targets = new NamedExpr[ctx.selectItem().size()];
     for (int i = 0; i < targets.length; i++) {
       targets[i] = visitSelectItem(ctx.selectItem(i));
     }
@@ -557,16 +557,16 @@ public class HiveConverter extends HiveParserBaseVisitor<Expr> {
     }
 
     if (!projection.isAllProjected())
-      projection.setTargets(targets);
+      projection.setNamedExprs(targets);
 
     current = projection;
     return current;
   }
 
   @Override
-  public TargetExpr visitSelectItem(HiveParser.SelectItemContext ctx) {
+  public NamedExpr visitSelectItem(HiveParser.SelectItemContext ctx) {
     ColumnReferenceExpr columnReference;
-    TargetExpr target = null;
+    NamedExpr target = null;
 
     String tableName = "", itemName = "", alias = "";
 
@@ -587,9 +587,9 @@ public class HiveConverter extends HiveParserBaseVisitor<Expr> {
 
     if (ctx.selectExpression() != null) {
       if (ctx.selectExpression().expression() != null) {
-        target = new TargetExpr(visitSelectExpression(ctx.selectExpression()));
+        target = new NamedExpr(visitSelectExpression(ctx.selectExpression()));
       } else {
-        target = new TargetExpr(columnReference);
+        target = new NamedExpr(columnReference);
       }
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/SQLAnalyzer.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/SQLAnalyzer.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/SQLAnalyzer.java
index 2555b9c..48d9e4d 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/SQLAnalyzer.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/SQLAnalyzer.java
@@ -37,9 +37,6 @@ import java.util.Map;
 
 import static org.apache.tajo.algebra.Aggregation.GroupElement;
 import static org.apache.tajo.algebra.CreateTable.*;
-
-import org.apache.tajo.algebra.DateValue;
-import org.apache.tajo.algebra.TimeValue;
 import static org.apache.tajo.common.TajoDataTypes.Type;
 import static org.apache.tajo.engine.parser.SQLParser.*;
 
@@ -229,11 +226,11 @@ public class SQLAnalyzer extends SQLParserBaseVisitor<Expr> {
     if (ctx.MULTIPLY() != null) {
       projection.setAll();
     } else {
-      TargetExpr[] targets = new TargetExpr[ctx.select_sublist().size()];
+      NamedExpr[] targets = new NamedExpr[ctx.select_sublist().size()];
       for (int i = 0; i < targets.length; i++) {
         targets[i] = visitSelect_sublist(ctx.select_sublist(i));
       }
-      projection.setTargets(targets);
+      projection.setNamedExprs(targets);
     }
 
     return projection;
@@ -250,9 +247,9 @@ public class SQLAnalyzer extends SQLParserBaseVisitor<Expr> {
    * @return
    */
   @Override
-  public TargetExpr visitSelect_sublist(SQLParser.Select_sublistContext ctx) {
+  public NamedExpr visitSelect_sublist(SQLParser.Select_sublistContext ctx) {
     if (ctx.asterisked_qualifier != null) {
-      return new TargetExpr(new ColumnReferenceExpr(ctx.asterisked_qualifier.getText(), "*"));
+      return new NamedExpr(new ColumnReferenceExpr(ctx.asterisked_qualifier.getText(), "*"));
     } else {
       return visitDerived_column(ctx.derived_column());
     }
@@ -285,13 +282,13 @@ public class SQLAnalyzer extends SQLParserBaseVisitor<Expr> {
             ctx.grouping_element_list().grouping_element().get(i);
         if (element.ordinary_grouping_set() != null) {
           groups[i] = new GroupElement(GroupType.OrdinaryGroup,
-              getColumnReferences(element.ordinary_grouping_set().column_reference_list()));
+              getRowValuePredicands(element.ordinary_grouping_set().row_value_predicand_list()));
         } else if (element.rollup_list() != null) {
           groups[i] = new GroupElement(GroupType.Rollup,
-              getColumnReferences(element.rollup_list().c.column_reference_list()));
+              getRowValuePredicands(element.rollup_list().c.row_value_predicand_list()));
         } else if (element.cube_list() != null) {
           groups[i] = new GroupElement(GroupType.Cube,
-              getColumnReferences(element.cube_list().c.column_reference_list()));
+              getRowValuePredicands(element.cube_list().c.row_value_predicand_list()));
         }
       }
       clause.setGroups(groups);
@@ -306,7 +303,7 @@ public class SQLAnalyzer extends SQLParserBaseVisitor<Expr> {
     Sort.SortSpec specs [] = new Sort.SortSpec[size];
     for (int i = 0; i < size; i++) {
       SQLParser.Sort_specifierContext specContext = ctx.sort_specifier_list().sort_specifier(i);
-      ColumnReferenceExpr column = visitColumn_reference(specContext.column);
+      Expr column = visitRow_value_predicand(specContext.key);
       specs[i] = new Sort.SortSpec(column);
       if (specContext.order_specification() != null) {
         if (specContext.order.DESC() != null) {
@@ -387,6 +384,14 @@ public class SQLAnalyzer extends SQLParserBaseVisitor<Expr> {
     return join;
   }
 
+  private Expr [] getRowValuePredicands(Row_value_predicand_listContext ctx) {
+    Expr [] rowValuePredicands = new Expr[ctx.row_value_predicand().size()];
+    for (int i = 0; i < rowValuePredicands.length; i++) {
+      rowValuePredicands[i] = visitRow_value_predicand(ctx.row_value_predicand(i));
+    }
+    return rowValuePredicands;
+  }
+
   private ColumnReferenceExpr [] getColumnReferences(Column_reference_listContext ctx) {
     ColumnReferenceExpr [] columnRefs = new ColumnReferenceExpr[ctx.column_reference().size()];
     for (int i = 0; i < columnRefs.length; i++) {
@@ -490,9 +495,9 @@ public class SQLAnalyzer extends SQLParserBaseVisitor<Expr> {
 
     Expr left;
     Expr right;
-    for (int i = 0; i < ctx.boolean_value_expression().size(); i++) {
+    for (int i = 0; i < ctx.or_predicate().size(); i++) {
       left = current;
-      right = visitBoolean_value_expression(ctx.boolean_value_expression(i));
+      right = visitOr_predicate(ctx.or_predicate(i));
       current = new BinaryOperator(OpType.Or, left, right);
     }
 
@@ -505,9 +510,9 @@ public class SQLAnalyzer extends SQLParserBaseVisitor<Expr> {
 
     Expr left;
     Expr right;
-    for (int i = 0; i < ctx.boolean_value_expression().size(); i++) {
+    for (int i = 0; i < ctx.and_predicate().size(); i++) {
       left = current;
-      right = visitBoolean_value_expression(ctx.boolean_value_expression(i));
+      right = visitAnd_predicate(ctx.and_predicate(i));
       current = new BinaryOperator(OpType.And, left, right);
     }
 
@@ -821,8 +826,8 @@ public class SQLAnalyzer extends SQLParserBaseVisitor<Expr> {
   }
 
   @Override
-  public TargetExpr visitDerived_column(SQLParser.Derived_columnContext ctx) {
-    TargetExpr target = new TargetExpr(visitValue_expression(ctx.value_expression()));
+  public NamedExpr visitDerived_column(SQLParser.Derived_columnContext ctx) {
+    NamedExpr target = new NamedExpr(visitValue_expression(ctx.value_expression()));
     if (ctx.as_clause() != null) {
       target.setAlias(ctx.as_clause().Identifier().getText());
     }

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/AlgebraVisitor.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/AlgebraVisitor.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/AlgebraVisitor.java
index 26a1ba4..1c710dc 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/AlgebraVisitor.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/AlgebraVisitor.java
@@ -24,83 +24,83 @@ import java.util.Stack;
 
 public interface AlgebraVisitor<CONTEXT, RESULT> {
   // Relational Operators
-  RESULT visitProjection(CONTEXT ctx, Stack<OpType> stack, Projection expr) throws PlanningException;
-  RESULT visitLimit(CONTEXT ctx, Stack<OpType> stack, Limit expr) throws PlanningException;
-  RESULT visitSort(CONTEXT ctx, Stack<OpType> stack, Sort expr) throws PlanningException;
-  RESULT visitHaving(CONTEXT ctx, Stack<OpType> stack, Having expr) throws PlanningException;
-  RESULT visitGroupBy(CONTEXT ctx, Stack<OpType> stack, Aggregation expr) throws PlanningException;
-  RESULT visitJoin(CONTEXT ctx, Stack<OpType> stack, Join expr) throws PlanningException;
-  RESULT visitFilter(CONTEXT ctx, Stack<OpType> stack, Selection expr) throws PlanningException;
-  RESULT visitUnion(CONTEXT ctx, Stack<OpType> stack, SetOperation expr) throws PlanningException;
-  RESULT visitExcept(CONTEXT ctx, Stack<OpType> stack, SetOperation expr) throws PlanningException;
-  RESULT visitIntersect(CONTEXT ctx, Stack<OpType> stack, SetOperation expr) throws PlanningException;
-  RESULT visitSimpleTableSubQuery(CONTEXT ctx, Stack<OpType> stack, SimpleTableSubQuery expr) throws PlanningException;
-  RESULT visitTableSubQuery(CONTEXT ctx, Stack<OpType> stack, TablePrimarySubQuery expr) throws PlanningException;
-  RESULT visitRelationList(CONTEXT ctx, Stack<OpType> stack, RelationList expr) throws PlanningException;
-  RESULT visitRelation(CONTEXT ctx, Stack<OpType> stack, Relation expr) throws PlanningException;
-  RESULT visitScalarSubQuery(CONTEXT ctx, Stack<OpType> stack, ScalarSubQuery expr) throws PlanningException;
+  RESULT visitProjection(CONTEXT ctx, Stack<Expr> stack, Projection expr) throws PlanningException;
+  RESULT visitLimit(CONTEXT ctx, Stack<Expr> stack, Limit expr) throws PlanningException;
+  RESULT visitSort(CONTEXT ctx, Stack<Expr> stack, Sort expr) throws PlanningException;
+  RESULT visitHaving(CONTEXT ctx, Stack<Expr> stack, Having expr) throws PlanningException;
+  RESULT visitGroupBy(CONTEXT ctx, Stack<Expr> stack, Aggregation expr) throws PlanningException;
+  RESULT visitJoin(CONTEXT ctx, Stack<Expr> stack, Join expr) throws PlanningException;
+  RESULT visitFilter(CONTEXT ctx, Stack<Expr> stack, Selection expr) throws PlanningException;
+  RESULT visitUnion(CONTEXT ctx, Stack<Expr> stack, SetOperation expr) throws PlanningException;
+  RESULT visitExcept(CONTEXT ctx, Stack<Expr> stack, SetOperation expr) throws PlanningException;
+  RESULT visitIntersect(CONTEXT ctx, Stack<Expr> stack, SetOperation expr) throws PlanningException;
+  RESULT visitSimpleTableSubQuery(CONTEXT ctx, Stack<Expr> stack, SimpleTableSubQuery expr) throws PlanningException;
+  RESULT visitTableSubQuery(CONTEXT ctx, Stack<Expr> stack, TablePrimarySubQuery expr) throws PlanningException;
+  RESULT visitRelationList(CONTEXT ctx, Stack<Expr> stack, RelationList expr) throws PlanningException;
+  RESULT visitRelation(CONTEXT ctx, Stack<Expr> stack, Relation expr) throws PlanningException;
+  RESULT visitScalarSubQuery(CONTEXT ctx, Stack<Expr> stack, ScalarSubQuery expr) throws PlanningException;
 
   // Data definition language
-  RESULT visitCreateTable(CONTEXT ctx, Stack<OpType> stack, CreateTable expr) throws PlanningException;
-  RESULT visitDropTable(CONTEXT ctx, Stack<OpType> stack, DropTable expr) throws PlanningException;
+  RESULT visitCreateTable(CONTEXT ctx, Stack<Expr> stack, CreateTable expr) throws PlanningException;
+  RESULT visitDropTable(CONTEXT ctx, Stack<Expr> stack, DropTable expr) throws PlanningException;
 
   // Insert or Update
-  RESULT visitInsert(CONTEXT ctx, Stack<OpType> stack, Insert expr) throws PlanningException;
+  RESULT visitInsert(CONTEXT ctx, Stack<Expr> stack, Insert expr) throws PlanningException;
 
   // Logical operators
-  RESULT visitAnd(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException;
-  RESULT visitOr(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException;
-  RESULT visitNot(CONTEXT ctx, Stack<OpType> stack, NotExpr expr) throws PlanningException;
+  RESULT visitAnd(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException;
+  RESULT visitOr(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException;
+  RESULT visitNot(CONTEXT ctx, Stack<Expr> stack, NotExpr expr) throws PlanningException;
 
   // comparison predicates
-  RESULT visitEquals(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException;
-  RESULT visitNotEquals(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException;
-  RESULT visitLessThan(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException;
-  RESULT visitLessThanOrEquals(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException;
-  RESULT visitGreaterThan(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException;
-  RESULT visitGreaterThanOrEquals(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException;
+  RESULT visitEquals(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException;
+  RESULT visitNotEquals(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException;
+  RESULT visitLessThan(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException;
+  RESULT visitLessThanOrEquals(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException;
+  RESULT visitGreaterThan(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException;
+  RESULT visitGreaterThanOrEquals(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException;
 
   // Other Predicates
-  RESULT visitBetween(CONTEXT ctx, Stack<OpType> stack, BetweenPredicate expr) throws PlanningException;
-  RESULT visitCaseWhen(CONTEXT ctx, Stack<OpType> stack, CaseWhenPredicate expr) throws PlanningException;
-  RESULT visitIsNullPredicate(CONTEXT ctx, Stack<OpType> stack, IsNullPredicate expr) throws PlanningException;
-  RESULT visitInPredicate(CONTEXT ctx, Stack<OpType> stack, InPredicate expr) throws PlanningException;
-  RESULT visitValueListExpr(CONTEXT ctx, Stack<OpType> stack, ValueListExpr expr) throws PlanningException;
-  RESULT visitExistsPredicate(CONTEXT ctx, Stack<OpType> stack, ExistsPredicate expr) throws PlanningException;
+  RESULT visitBetween(CONTEXT ctx, Stack<Expr> stack, BetweenPredicate expr) throws PlanningException;
+  RESULT visitCaseWhen(CONTEXT ctx, Stack<Expr> stack, CaseWhenPredicate expr) throws PlanningException;
+  RESULT visitIsNullPredicate(CONTEXT ctx, Stack<Expr> stack, IsNullPredicate expr) throws PlanningException;
+  RESULT visitInPredicate(CONTEXT ctx, Stack<Expr> stack, InPredicate expr) throws PlanningException;
+  RESULT visitValueListExpr(CONTEXT ctx, Stack<Expr> stack, ValueListExpr expr) throws PlanningException;
+  RESULT visitExistsPredicate(CONTEXT ctx, Stack<Expr> stack, ExistsPredicate expr) throws PlanningException;
 
   // String Operator or Pattern Matching Predicates
-  RESULT visitLikePredicate(CONTEXT ctx, Stack<OpType> stack, PatternMatchPredicate expr) throws PlanningException;
-  RESULT visitSimilarToPredicate(CONTEXT ctx, Stack<OpType> stack, PatternMatchPredicate expr) throws PlanningException;
-  RESULT visitRegexpPredicate(CONTEXT ctx, Stack<OpType> stack, PatternMatchPredicate expr) throws PlanningException;
-  RESULT visitConcatenate(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException;
+  RESULT visitLikePredicate(CONTEXT ctx, Stack<Expr> stack, PatternMatchPredicate expr) throws PlanningException;
+  RESULT visitSimilarToPredicate(CONTEXT ctx, Stack<Expr> stack, PatternMatchPredicate expr) throws PlanningException;
+  RESULT visitRegexpPredicate(CONTEXT ctx, Stack<Expr> stack, PatternMatchPredicate expr) throws PlanningException;
+  RESULT visitConcatenate(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException;
 
   // arithmetic operators
-  RESULT visitPlus(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException;
-  RESULT visitMinus(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException;
-  RESULT visitMultiply(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException;
-  RESULT visitDivide(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException;
-  RESULT visitModular(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException;
+  RESULT visitPlus(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException;
+  RESULT visitMinus(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException;
+  RESULT visitMultiply(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException;
+  RESULT visitDivide(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException;
+  RESULT visitModular(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException;
 
   // other expressions
-  RESULT visitSign(CONTEXT ctx, Stack<OpType> stack, SignedExpr expr) throws PlanningException;
-  RESULT visitColumnReference(CONTEXT ctx, Stack<OpType> stack, ColumnReferenceExpr expr) throws PlanningException;
-  RESULT visitTargetExpr(CONTEXT ctx, Stack<OpType> stack, TargetExpr expr) throws PlanningException;
-  RESULT visitFunction(CONTEXT ctx, Stack<OpType> stack, FunctionExpr expr) throws PlanningException;
+  RESULT visitSign(CONTEXT ctx, Stack<Expr> stack, SignedExpr expr) throws PlanningException;
+  RESULT visitColumnReference(CONTEXT ctx, Stack<Expr> stack, ColumnReferenceExpr expr) throws PlanningException;
+  RESULT visitTargetExpr(CONTEXT ctx, Stack<Expr> stack, NamedExpr expr) throws PlanningException;
+  RESULT visitFunction(CONTEXT ctx, Stack<Expr> stack, FunctionExpr expr) throws PlanningException;
 
   // set functions
-  RESULT visitCountRowsFunction(CONTEXT ctx, Stack<OpType> stack, CountRowsFunctionExpr expr) throws PlanningException;
-  RESULT visitGeneralSetFunction(CONTEXT ctx, Stack<OpType> stack, GeneralSetFunctionExpr expr)
+  RESULT visitCountRowsFunction(CONTEXT ctx, Stack<Expr> stack, CountRowsFunctionExpr expr) throws PlanningException;
+  RESULT visitGeneralSetFunction(CONTEXT ctx, Stack<Expr> stack, GeneralSetFunctionExpr expr)
       throws PlanningException;
 
   // Literal
-  RESULT visitCastExpr(CONTEXT ctx, Stack<OpType> stack, CastExpr expr) throws PlanningException;
-
-  RESULT visitDataType(CONTEXT ctx, Stack<OpType> stack, DataTypeExpr expr) throws PlanningException;
-  RESULT visitLiteral(CONTEXT ctx, Stack<OpType> stack, LiteralValue expr) throws PlanningException;
-  RESULT visitNullLiteral(CONTEXT ctx, Stack<OpType> stack, NullLiteral expr) throws PlanningException;
-  RESULT visitTimestampLiteral(CONTEXT ctx, Stack<OpType> stack, TimestampLiteral expr) throws PlanningException;
-  RESULT visitTimeLiteral(CONTEXT ctx, Stack<OpType> stack, TimeLiteral expr) throws PlanningException;
-  RESULT visitDateLiteral(CONTEXT ctx, Stack<OpType> stack, DateLiteral expr) throws PlanningException;
+  RESULT visitCastExpr(CONTEXT ctx, Stack<Expr> stack, CastExpr expr) throws PlanningException;
+
+  RESULT visitDataType(CONTEXT ctx, Stack<Expr> stack, DataTypeExpr expr) throws PlanningException;
+  RESULT visitLiteral(CONTEXT ctx, Stack<Expr> stack, LiteralValue expr) throws PlanningException;
+  RESULT visitNullLiteral(CONTEXT ctx, Stack<Expr> stack, NullLiteral expr) throws PlanningException;
+  RESULT visitTimestampLiteral(CONTEXT ctx, Stack<Expr> stack, TimestampLiteral expr) throws PlanningException;
+  RESULT visitTimeLiteral(CONTEXT ctx, Stack<Expr> stack, TimeLiteral expr) throws PlanningException;
+  RESULT visitDateLiteral(CONTEXT ctx, Stack<Expr> stack, DateLiteral expr) throws PlanningException;
 
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/BaseAlgebraVisitor.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/BaseAlgebraVisitor.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/BaseAlgebraVisitor.java
index 880a874..a9c026d 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/BaseAlgebraVisitor.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/BaseAlgebraVisitor.java
@@ -27,14 +27,14 @@ public class BaseAlgebraVisitor<CONTEXT, RESULT> implements AlgebraVisitor<CONTE
   /**
    * The prehook is called before each expression is visited.
    */
-  public void preHook(CONTEXT ctx, Stack<OpType> stack, Expr expr) throws PlanningException {
+  public void preHook(CONTEXT ctx, Stack<Expr> stack, Expr expr) throws PlanningException {
   }
 
 
   /**
    * The posthook is called before each expression is visited.
    */
-  public RESULT postHook(CONTEXT ctx, Stack<OpType> stack, Expr expr, RESULT current) throws PlanningException {
+  public RESULT postHook(CONTEXT ctx, Stack<Expr> stack, Expr expr, RESULT current) throws PlanningException {
     return current;
   }
 
@@ -44,7 +44,7 @@ public class BaseAlgebraVisitor<CONTEXT, RESULT> implements AlgebraVisitor<CONTE
    * @param stack The stack contains the upper operators' type.
    * @param expr The visiting relational operator
    */
-  public RESULT visit(CONTEXT ctx, Stack<OpType> stack, Expr expr) throws PlanningException {
+  public RESULT visit(CONTEXT ctx, Stack<Expr> stack, Expr expr) throws PlanningException {
     preHook(ctx, stack, expr);
 
     RESULT current;
@@ -196,7 +196,7 @@ public class BaseAlgebraVisitor<CONTEXT, RESULT> implements AlgebraVisitor<CONTE
       current = visitColumnReference(ctx, stack, (ColumnReferenceExpr) expr);
       break;
     case Target:
-      current = visitTargetExpr(ctx, stack, (TargetExpr) expr);
+      current = visitTargetExpr(ctx, stack, (NamedExpr) expr);
       break;
     case Function:
       current = visitFunction(ctx, stack, (FunctionExpr) expr);
@@ -222,30 +222,44 @@ public class BaseAlgebraVisitor<CONTEXT, RESULT> implements AlgebraVisitor<CONTE
     case NullLiteral:
       current = visitNullLiteral(ctx, stack, (NullLiteral) expr);
       break;
+    case DateLiteral:
+      current = visitDateLiteral(ctx, stack, (DateLiteral) expr);
+      break;
+    case TimeLiteral:
+      current = visitTimeLiteral(ctx, stack, (TimeLiteral) expr);
+      break;
     case TimestampLiteral:
       current = visitTimestampLiteral(ctx, stack, (TimestampLiteral) expr);
       break;
 
 
+
     default:
       throw new PlanningException("Cannot support this type algebra \"" + expr.getType() + "\"");
     }
 
-    postHook(ctx, stack, expr, current);
+    // skip postHook against only one relation
+    if (expr.getType() == OpType.RelationList) {
+      RelationList relationList = (RelationList)expr;
+      if (relationList.size() == 1 && relationList.getRelations()[0].getType() == OpType.Relation) {
+        return current;
+      }
+    }
 
+    postHook(ctx, stack, expr, current);
     return current;
   }
 
-  private RESULT visitDefaultUnaryExpr(CONTEXT ctx, Stack<OpType> stack, UnaryOperator expr) throws PlanningException {
-    stack.push(expr.getType());
+  private RESULT visitDefaultUnaryExpr(CONTEXT ctx, Stack<Expr> stack, UnaryOperator expr) throws PlanningException {
+    stack.push(expr);
     RESULT child = visit(ctx, stack, expr.getChild());
     stack.pop();
     return child;
   }
 
-  private RESULT visitDefaultBinaryExpr(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr)
+  private RESULT visitDefaultBinaryExpr(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr)
       throws PlanningException {
-    stack.push(expr.getType());
+    stack.push(expr);
     RESULT child = visit(ctx, stack, expr.getLeft());
     visit(ctx, stack, expr.getRight());
     stack.pop();
@@ -253,76 +267,113 @@ public class BaseAlgebraVisitor<CONTEXT, RESULT> implements AlgebraVisitor<CONTE
   }
 
   @Override
-  public RESULT visitProjection(CONTEXT ctx, Stack<OpType> stack, Projection expr) throws PlanningException {
-    return visitDefaultUnaryExpr(ctx, stack, expr);
+  public RESULT visitProjection(CONTEXT ctx, Stack<Expr> stack, Projection expr) throws PlanningException {
+    stack.push(expr);
+    for (NamedExpr target : expr.getNamedExprs()) {
+      visit(ctx, stack, target);
+    }
+    RESULT result = visit(ctx, stack, expr.getChild());
+    stack.pop();
+    return result;
   }
 
   @Override
-  public RESULT visitLimit(CONTEXT ctx, Stack<OpType> stack, Limit expr) throws PlanningException {
-    return visitDefaultUnaryExpr(ctx, stack, expr);
+  public RESULT visitLimit(CONTEXT ctx, Stack<Expr> stack, Limit expr) throws PlanningException {
+    stack.push(expr);
+    visit(ctx, stack, expr.getFetchFirstNum());
+    RESULT result = visit(ctx, stack, expr.getChild());
+    stack.pop();
+    return result;
   }
 
   @Override
-  public RESULT visitSort(CONTEXT ctx, Stack<OpType> stack, Sort expr) throws PlanningException {
-    return visitDefaultUnaryExpr(ctx, stack, expr);
+  public RESULT visitSort(CONTEXT ctx, Stack<Expr> stack, Sort expr) throws PlanningException {
+    stack.push(expr);
+    for (Sort.SortSpec sortSpec : expr.getSortSpecs()) {
+      visit(ctx, stack, sortSpec.getKey());
+    }
+    RESULT result = visit(ctx, stack, expr.getChild());
+    return result;
   }
 
   @Override
-  public RESULT visitHaving(CONTEXT ctx, Stack<OpType> stack, Having expr) throws PlanningException {
-    return visitDefaultUnaryExpr(ctx, stack, expr);
+  public RESULT visitHaving(CONTEXT ctx, Stack<Expr> stack, Having expr) throws PlanningException {
+    stack.push(expr);
+    visit(ctx, stack, expr.getQual());
+    RESULT result = visit(ctx, stack, expr.getChild());
+    stack.pop();
+    return result;
   }
 
   @Override
-  public RESULT visitGroupBy(CONTEXT ctx, Stack<OpType> stack, Aggregation expr) throws PlanningException {
-    return visitDefaultUnaryExpr(ctx, stack, expr);
+  public RESULT visitGroupBy(CONTEXT ctx, Stack<Expr> stack, Aggregation expr) throws PlanningException {
+    stack.push(expr);
+
+    if (expr.hasHavingCondition()) {
+      visit(ctx, stack, expr.getHavingCondition());
+    }
+    for (org.apache.tajo.algebra.Aggregation.GroupElement groupElement : expr.getGroupSet()) {
+      for (Expr groupingSet : groupElement.getGroupingSets()) {
+        visit(ctx, stack, groupingSet);
+      }
+    }
+    RESULT result = visit(ctx, stack, expr.getChild());
+    stack.pop();
+    return result;
   }
 
   @Override
-  public RESULT visitJoin(CONTEXT ctx, Stack<OpType> stack, Join expr) throws PlanningException {
-    return visitDefaultBinaryExpr(ctx, stack, expr);
+  public RESULT visitJoin(CONTEXT ctx, Stack<Expr> stack, Join expr) throws PlanningException {
+    stack.push(expr);
+    visit(ctx, stack, expr.getQual());
+    visit(ctx, stack, expr.getLeft());
+    RESULT result = visit(ctx, stack, expr.getRight());
+    stack.pop();
+    return result;
   }
 
   @Override
-  public RESULT visitFilter(CONTEXT ctx, Stack<OpType> stack, Selection expr) throws PlanningException {
-    return visitDefaultUnaryExpr(ctx, stack, expr);
+  public RESULT visitFilter(CONTEXT ctx, Stack<Expr> stack, Selection expr) throws PlanningException {
+    stack.push(expr);
+    visit(ctx, stack, expr.getQual());
+    RESULT result = visit(ctx, stack, expr.getChild());
+    stack.pop();
+    return result;
   }
 
   @Override
-  public RESULT visitUnion(CONTEXT ctx, Stack<OpType> stack, SetOperation expr) throws PlanningException {
+  public RESULT visitUnion(CONTEXT ctx, Stack<Expr> stack, SetOperation expr) throws PlanningException {
     return visitDefaultBinaryExpr(ctx, stack, expr);
   }
 
   @Override
-  public RESULT visitExcept(CONTEXT ctx, Stack<OpType> stack, SetOperation expr) throws PlanningException {
+  public RESULT visitExcept(CONTEXT ctx, Stack<Expr> stack, SetOperation expr) throws PlanningException {
     return visitDefaultBinaryExpr(ctx, stack, expr);
   }
 
   @Override
-  public RESULT visitIntersect(CONTEXT ctx, Stack<OpType> stack, SetOperation expr) throws PlanningException {
+  public RESULT visitIntersect(CONTEXT ctx, Stack<Expr> stack, SetOperation expr) throws PlanningException {
     return visitDefaultBinaryExpr(ctx, stack, expr);
   }
 
   @Override
-  public RESULT visitSimpleTableSubQuery(CONTEXT ctx, Stack<OpType> stack, SimpleTableSubQuery expr)
+  public RESULT visitSimpleTableSubQuery(CONTEXT ctx, Stack<Expr> stack, SimpleTableSubQuery expr)
       throws PlanningException {
-    stack.push(expr.getType());
-    RESULT child = visit(ctx, stack, expr.getSubQuery());
-    stack.pop();
-    return child;
+    return visitDefaultUnaryExpr(ctx, stack, expr);
   }
 
   @Override
-  public RESULT visitTableSubQuery(CONTEXT ctx, Stack<OpType> stack, TablePrimarySubQuery expr)
+  public RESULT visitTableSubQuery(CONTEXT ctx, Stack<Expr> stack, TablePrimarySubQuery expr)
       throws PlanningException {
-    stack.push(expr.getType());
+    stack.push(expr);
     RESULT child = visit(ctx, stack, expr.getSubQuery());
     stack.pop();
     return child;
   }
 
   @Override
-  public RESULT visitRelationList(CONTEXT ctx, Stack<OpType> stack, RelationList expr) throws PlanningException {
-    stack.push(expr.getType());
+  public RESULT visitRelationList(CONTEXT ctx, Stack<Expr> stack, RelationList expr) throws PlanningException {
+    stack.push(expr);
     RESULT child = null;
     for (Expr e : expr.getRelations()) {
       child = visit(ctx, stack, e);
@@ -332,16 +383,13 @@ public class BaseAlgebraVisitor<CONTEXT, RESULT> implements AlgebraVisitor<CONTE
   }
 
   @Override
-  public RESULT visitRelation(CONTEXT ctx, Stack<OpType> stack, Relation expr) throws PlanningException {
+  public RESULT visitRelation(CONTEXT ctx, Stack<Expr> stack, Relation expr) throws PlanningException {
     return null;
   }
 
   @Override
-  public RESULT visitScalarSubQuery(CONTEXT ctx, Stack<OpType> stack, ScalarSubQuery expr) throws PlanningException {
-    stack.push(OpType.ScalarSubQuery);
-    RESULT result = visit(ctx, stack, expr.getSubQuery());
-    stack.pop();
-    return result;
+  public RESULT visitScalarSubQuery(CONTEXT ctx, Stack<Expr> stack, ScalarSubQuery expr) throws PlanningException {
+    return visitDefaultUnaryExpr(ctx, stack, expr);
   }
 
   ///////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -349,8 +397,8 @@ public class BaseAlgebraVisitor<CONTEXT, RESULT> implements AlgebraVisitor<CONTE
   ///////////////////////////////////////////////////////////////////////////////////////////////////////////
 
   @Override
-  public RESULT visitCreateTable(CONTEXT ctx, Stack<OpType> stack, CreateTable expr) throws PlanningException {
-    stack.push(expr.getType());
+  public RESULT visitCreateTable(CONTEXT ctx, Stack<Expr> stack, CreateTable expr) throws PlanningException {
+    stack.push(expr);
     RESULT child = null;
     if (expr.hasSubQuery()) {
       child = visit(ctx, stack, expr.getSubQuery());
@@ -360,7 +408,7 @@ public class BaseAlgebraVisitor<CONTEXT, RESULT> implements AlgebraVisitor<CONTE
   }
 
   @Override
-  public RESULT visitDropTable(CONTEXT ctx, Stack<OpType> stack, DropTable expr) throws PlanningException {
+  public RESULT visitDropTable(CONTEXT ctx, Stack<Expr> stack, DropTable expr) throws PlanningException {
     return null;
   }
 
@@ -368,8 +416,8 @@ public class BaseAlgebraVisitor<CONTEXT, RESULT> implements AlgebraVisitor<CONTE
   // Insert or Update Section
   ///////////////////////////////////////////////////////////////////////////////////////////////////////////
 
-  public RESULT visitInsert(CONTEXT ctx, Stack<OpType> stack, Insert expr) throws PlanningException {
-    stack.push(expr.getType());
+  public RESULT visitInsert(CONTEXT ctx, Stack<Expr> stack, Insert expr) throws PlanningException {
+    stack.push(expr);
     RESULT child = visit(ctx, stack, expr.getSubQuery());
     stack.pop();
     return child;
@@ -380,17 +428,17 @@ public class BaseAlgebraVisitor<CONTEXT, RESULT> implements AlgebraVisitor<CONTE
   ///////////////////////////////////////////////////////////////////////////////////////////////////////////
 
   @Override
-  public RESULT visitAnd(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException {
+  public RESULT visitAnd(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
     return visitDefaultBinaryExpr(ctx, stack, expr);
   }
 
   @Override
-  public RESULT visitOr(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException {
+  public RESULT visitOr(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
     return visitDefaultBinaryExpr(ctx, stack, expr);
   }
 
   @Override
-  public RESULT visitNot(CONTEXT ctx, Stack<OpType> stack, NotExpr expr) throws PlanningException {
+  public RESULT visitNot(CONTEXT ctx, Stack<Expr> stack, NotExpr expr) throws PlanningException {
     return visitDefaultUnaryExpr(ctx, stack, expr);
   }
 
@@ -398,32 +446,32 @@ public class BaseAlgebraVisitor<CONTEXT, RESULT> implements AlgebraVisitor<CONTE
   // Comparison Predicates Section
   ///////////////////////////////////////////////////////////////////////////////////////////////////////////
   @Override
-  public RESULT visitEquals(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException {
+  public RESULT visitEquals(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
     return visitDefaultBinaryExpr(ctx, stack, expr);
   }
 
   @Override
-  public RESULT visitNotEquals(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException {
+  public RESULT visitNotEquals(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
     return visitDefaultBinaryExpr(ctx, stack, expr);
   }
 
   @Override
-  public RESULT visitLessThan(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException {
+  public RESULT visitLessThan(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
     return visitDefaultBinaryExpr(ctx, stack, expr);
   }
 
   @Override
-  public RESULT visitLessThanOrEquals(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException {
+  public RESULT visitLessThanOrEquals(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
     return visitDefaultBinaryExpr(ctx, stack, expr);
   }
 
   @Override
-  public RESULT visitGreaterThan(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException {
+  public RESULT visitGreaterThan(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
     return visitDefaultBinaryExpr(ctx, stack, expr);
   }
 
   @Override
-  public RESULT visitGreaterThanOrEquals(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr)
+  public RESULT visitGreaterThanOrEquals(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr)
       throws PlanningException {
     return visitDefaultBinaryExpr(ctx, stack, expr);
   }
@@ -433,8 +481,8 @@ public class BaseAlgebraVisitor<CONTEXT, RESULT> implements AlgebraVisitor<CONTE
   ///////////////////////////////////////////////////////////////////////////////////////////////////////////
 
   @Override
-  public RESULT visitBetween(CONTEXT ctx, Stack<OpType> stack, BetweenPredicate expr) throws PlanningException {
-    stack.push(OpType.Between);
+  public RESULT visitBetween(CONTEXT ctx, Stack<Expr> stack, BetweenPredicate expr) throws PlanningException {
+    stack.push(expr);
     RESULT result = visit(ctx, stack, expr.predicand());
     visit(ctx, stack, expr.begin());
     visit(ctx, stack, expr.end());
@@ -443,8 +491,8 @@ public class BaseAlgebraVisitor<CONTEXT, RESULT> implements AlgebraVisitor<CONTE
   }
 
   @Override
-  public RESULT visitCaseWhen(CONTEXT ctx, Stack<OpType> stack, CaseWhenPredicate expr) throws PlanningException {
-    stack.push(OpType.CaseWhen);
+  public RESULT visitCaseWhen(CONTEXT ctx, Stack<Expr> stack, CaseWhenPredicate expr) throws PlanningException {
+    stack.push(expr);
     RESULT result = null;
     for (CaseWhenPredicate.WhenExpr when : expr.getWhens()) {
       result = visit(ctx, stack, when.getCondition());
@@ -458,21 +506,18 @@ public class BaseAlgebraVisitor<CONTEXT, RESULT> implements AlgebraVisitor<CONTE
   }
 
   @Override
-  public RESULT visitIsNullPredicate(CONTEXT ctx, Stack<OpType> stack, IsNullPredicate expr) throws PlanningException {
-    stack.push(OpType.IsNullPredicate);
-    RESULT result = visit(ctx, stack, expr.getPredicand());
-    stack.pop();
-    return result;
+  public RESULT visitIsNullPredicate(CONTEXT ctx, Stack<Expr> stack, IsNullPredicate expr) throws PlanningException {
+    return visitDefaultUnaryExpr(ctx, stack, expr);
   }
 
   @Override
-  public RESULT visitInPredicate(CONTEXT ctx, Stack<OpType> stack, InPredicate expr) throws PlanningException {
+  public RESULT visitInPredicate(CONTEXT ctx, Stack<Expr> stack, InPredicate expr) throws PlanningException {
     return visitDefaultBinaryExpr(ctx, stack, expr);
   }
 
   @Override
-  public RESULT visitValueListExpr(CONTEXT ctx, Stack<OpType> stack, ValueListExpr expr) throws PlanningException {
-    stack.push(OpType.ValueList);
+  public RESULT visitValueListExpr(CONTEXT ctx, Stack<Expr> stack, ValueListExpr expr) throws PlanningException {
+    stack.push(expr);
     RESULT result = null;
     for (Expr value : expr.getValues()) {
       result = visit(ctx, stack, value);
@@ -482,45 +527,33 @@ public class BaseAlgebraVisitor<CONTEXT, RESULT> implements AlgebraVisitor<CONTE
   }
 
   @Override
-  public RESULT visitExistsPredicate(CONTEXT ctx, Stack<OpType> stack, ExistsPredicate expr) throws PlanningException {
-    stack.push(OpType.ExistsPredicate);
-    RESULT result = visit(ctx, stack, expr.getSubQuery());
-    stack.pop();
-    return result;
+  public RESULT visitExistsPredicate(CONTEXT ctx, Stack<Expr> stack, ExistsPredicate expr) throws PlanningException {
+    return visitDefaultUnaryExpr(ctx, stack, expr);
   }
 
   ///////////////////////////////////////////////////////////////////////////////////////////////////////////
   // String Operator or Pattern Matching Predicates Section
   ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-  private RESULT visitPatternMatchPredicate(CONTEXT ctx, Stack<OpType> stack, PatternMatchPredicate expr)
-      throws PlanningException {
-    stack.push(expr.getType());
-    RESULT result = visit(ctx, stack, expr.getPredicand());
-    visit(ctx, stack, expr.getPattern());
-    stack.pop();
-    return result;
-  }
   @Override
-  public RESULT visitLikePredicate(CONTEXT ctx, Stack<OpType> stack, PatternMatchPredicate expr)
+  public RESULT visitLikePredicate(CONTEXT ctx, Stack<Expr> stack, PatternMatchPredicate expr)
       throws PlanningException {
-    return visitPatternMatchPredicate(ctx, stack, expr);
+    return visitDefaultBinaryExpr(ctx, stack, expr);
   }
 
   @Override
-  public RESULT visitSimilarToPredicate(CONTEXT ctx, Stack<OpType> stack, PatternMatchPredicate expr)
+  public RESULT visitSimilarToPredicate(CONTEXT ctx, Stack<Expr> stack, PatternMatchPredicate expr)
       throws PlanningException {
-    return visitPatternMatchPredicate(ctx, stack, expr);
+    return visitDefaultBinaryExpr(ctx, stack, expr);
   }
 
   @Override
-  public RESULT visitRegexpPredicate(CONTEXT ctx, Stack<OpType> stack, PatternMatchPredicate expr)
+  public RESULT visitRegexpPredicate(CONTEXT ctx, Stack<Expr> stack, PatternMatchPredicate expr)
       throws PlanningException {
-    return visitPatternMatchPredicate(ctx, stack, expr);
+    return visitDefaultBinaryExpr(ctx, stack, expr);
   }
 
   @Override
-  public RESULT visitConcatenate(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException {
+  public RESULT visitConcatenate(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
     return visitDefaultBinaryExpr(ctx, stack, expr);
   }
 
@@ -529,27 +562,27 @@ public class BaseAlgebraVisitor<CONTEXT, RESULT> implements AlgebraVisitor<CONTE
   ///////////////////////////////////////////////////////////////////////////////////////////////////////////
 
   @Override
-  public RESULT visitPlus(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException {
+  public RESULT visitPlus(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
     return visitDefaultBinaryExpr(ctx, stack, expr);
   }
 
   @Override
-  public RESULT visitMinus(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException {
+  public RESULT visitMinus(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
     return visitDefaultBinaryExpr(ctx, stack, expr);
   }
 
   @Override
-  public RESULT visitMultiply(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException {
+  public RESULT visitMultiply(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
     return visitDefaultBinaryExpr(ctx, stack, expr);
   }
 
   @Override
-  public RESULT visitDivide(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException {
+  public RESULT visitDivide(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
     return visitDefaultBinaryExpr(ctx, stack, expr);
   }
 
   @Override
-  public RESULT visitModular(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException {
+  public RESULT visitModular(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
     return visitDefaultBinaryExpr(ctx, stack, expr);
   }
 
@@ -558,27 +591,24 @@ public class BaseAlgebraVisitor<CONTEXT, RESULT> implements AlgebraVisitor<CONTE
   ///////////////////////////////////////////////////////////////////////////////////////////////////////////
 
   @Override
-  public RESULT visitSign(CONTEXT ctx, Stack<OpType> stack, SignedExpr expr) throws PlanningException {
+  public RESULT visitSign(CONTEXT ctx, Stack<Expr> stack, SignedExpr expr) throws PlanningException {
     return visitDefaultUnaryExpr(ctx, stack, expr);
   }
 
   @Override
-  public RESULT visitColumnReference(CONTEXT ctx, Stack<OpType> stack, ColumnReferenceExpr expr)
+  public RESULT visitColumnReference(CONTEXT ctx, Stack<Expr> stack, ColumnReferenceExpr expr)
       throws PlanningException {
     return null;
   }
 
   @Override
-  public RESULT visitTargetExpr(CONTEXT ctx, Stack<OpType> stack, TargetExpr expr) throws PlanningException {
-    stack.push(OpType.Target);
-    RESULT result = visit(ctx, stack, expr.getExpr());
-    stack.pop();
-    return result;
+  public RESULT visitTargetExpr(CONTEXT ctx, Stack<Expr> stack, NamedExpr expr) throws PlanningException {
+    return visitDefaultUnaryExpr(ctx, stack, expr);
   }
 
   @Override
-  public RESULT visitFunction(CONTEXT ctx, Stack<OpType> stack, FunctionExpr expr) throws PlanningException {
-    stack.push(OpType.Function);
+  public RESULT visitFunction(CONTEXT ctx, Stack<Expr> stack, FunctionExpr expr) throws PlanningException {
+    stack.push(expr);
     RESULT result = null;
     for (Expr param : expr.getParams()) {
       result = visit(ctx, stack, param);
@@ -592,15 +622,15 @@ public class BaseAlgebraVisitor<CONTEXT, RESULT> implements AlgebraVisitor<CONTE
   ///////////////////////////////////////////////////////////////////////////////////////////////////////////
 
   @Override
-  public RESULT visitCountRowsFunction(CONTEXT ctx, Stack<OpType> stack, CountRowsFunctionExpr expr)
+  public RESULT visitCountRowsFunction(CONTEXT ctx, Stack<Expr> stack, CountRowsFunctionExpr expr)
       throws PlanningException {
     return null;
   }
 
   @Override
-  public RESULT visitGeneralSetFunction(CONTEXT ctx, Stack<OpType> stack, GeneralSetFunctionExpr expr)
+  public RESULT visitGeneralSetFunction(CONTEXT ctx, Stack<Expr> stack, GeneralSetFunctionExpr expr)
       throws PlanningException {
-    stack.push(OpType.GeneralSetFunction);
+    stack.push(expr);
     RESULT result = null;
     for (Expr param : expr.getParams()) {
       result = visit(ctx, stack, param);
@@ -614,40 +644,40 @@ public class BaseAlgebraVisitor<CONTEXT, RESULT> implements AlgebraVisitor<CONTE
   ///////////////////////////////////////////////////////////////////////////////////////////////////////////
 
   @Override
-  public RESULT visitDataType(CONTEXT ctx, Stack<OpType> stack, DataTypeExpr expr) throws PlanningException {
+  public RESULT visitDataType(CONTEXT ctx, Stack<Expr> stack, DataTypeExpr expr) throws PlanningException {
     return null;
   }
 
   @Override
-  public RESULT visitCastExpr(CONTEXT ctx, Stack<OpType> stack, CastExpr expr) throws PlanningException {
-    stack.push(OpType.Cast);
+  public RESULT visitCastExpr(CONTEXT ctx, Stack<Expr> stack, CastExpr expr) throws PlanningException {
+    stack.push(expr);
     RESULT result = visit(ctx, stack, expr.getOperand());
     stack.pop();
     return result;
   }
 
   @Override
-  public RESULT visitLiteral(CONTEXT ctx, Stack<OpType> stack, LiteralValue expr) throws PlanningException {
+  public RESULT visitLiteral(CONTEXT ctx, Stack<Expr> stack, LiteralValue expr) throws PlanningException {
     return null;
   }
 
   @Override
-  public RESULT visitNullLiteral(CONTEXT ctx, Stack<OpType> stack, NullLiteral expr) throws PlanningException {
+  public RESULT visitNullLiteral(CONTEXT ctx, Stack<Expr> stack, NullLiteral expr) throws PlanningException {
     return null;
   }
 
   @Override
-  public RESULT visitTimestampLiteral(CONTEXT ctx, Stack<OpType> stack, TimestampLiteral expr) throws PlanningException {
+  public RESULT visitTimestampLiteral(CONTEXT ctx, Stack<Expr> stack, TimestampLiteral expr) throws PlanningException {
     return null;
   }
 
   @Override
-  public RESULT visitTimeLiteral(CONTEXT ctx, Stack<OpType> stack, TimeLiteral expr) throws PlanningException {
+  public RESULT visitTimeLiteral(CONTEXT ctx, Stack<Expr> stack, TimeLiteral expr) throws PlanningException {
     return null;
   }
 
   @Override
-  public RESULT visitDateLiteral(CONTEXT ctx, Stack<OpType> stack, DateLiteral expr) throws PlanningException {
+  public RESULT visitDateLiteral(CONTEXT ctx, Stack<Expr> stack, DateLiteral expr) throws PlanningException {
     return null;
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/BasicLogicalPlanVisitor.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/BasicLogicalPlanVisitor.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/BasicLogicalPlanVisitor.java
index 9cbb0ad..59c6872 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/BasicLogicalPlanVisitor.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/BasicLogicalPlanVisitor.java
@@ -68,6 +68,9 @@ public class BasicLogicalPlanVisitor<CONTEXT, RESULT> implements LogicalPlanVisi
       case SORT:
         current = visitSort(context, plan, block, (SortNode) node, stack);
         break;
+      case HAVING:
+        current = visitHaving(context, plan, block, (HavingNode) node, stack);
+        break;
       case GROUP_BY:
         current = visitGroupBy(context, plan, block, (GroupbyNode) node, stack);
         break;
@@ -152,6 +155,15 @@ public class BasicLogicalPlanVisitor<CONTEXT, RESULT> implements LogicalPlanVisi
   }
 
   @Override
+  public RESULT visitHaving(CONTEXT context, LogicalPlan plan, LogicalPlan.QueryBlock block, HavingNode node,
+                            Stack<LogicalNode> stack) throws PlanningException {
+    stack.push(node);
+    RESULT result = visit(context, plan, block, node.getChild(), stack);
+    stack.pop();
+    return result;
+  }
+
+  @Override
   public RESULT visitGroupBy(CONTEXT context, LogicalPlan plan, LogicalPlan.QueryBlock block, GroupbyNode node,
                              Stack<LogicalNode> stack) throws PlanningException {
     stack.push(node);

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/ExplainLogicalPlanVisitor.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/ExplainLogicalPlanVisitor.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/ExplainLogicalPlanVisitor.java
index fd8a6e1..4cd40f7 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/ExplainLogicalPlanVisitor.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/ExplainLogicalPlanVisitor.java
@@ -96,6 +96,11 @@ public class ExplainLogicalPlanVisitor extends BasicLogicalPlanVisitor<ExplainLo
     return visitUnaryNode(context, plan, block, node, stack);
   }
 
+  public LogicalNode visitHaving(Context context, LogicalPlan plan, LogicalPlan.QueryBlock block, HavingNode node,
+                                  Stack<LogicalNode> stack) throws PlanningException {
+    return visitUnaryNode(context, plan, block, node, stack);
+  }
+
   @Override
   public LogicalNode visitGroupBy(Context context, LogicalPlan plan, LogicalPlan.QueryBlock block, GroupbyNode node,
                                   Stack<LogicalNode> stack) throws PlanningException {

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/ExprAnnotator.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/ExprAnnotator.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/ExprAnnotator.java
new file mode 100644
index 0000000..cd49c73
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/ExprAnnotator.java
@@ -0,0 +1,622 @@
+/**
+ * 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.engine.planner;
+
+import org.apache.tajo.algebra.*;
+import org.apache.tajo.catalog.CatalogService;
+import org.apache.tajo.catalog.CatalogUtil;
+import org.apache.tajo.catalog.Column;
+import org.apache.tajo.catalog.FunctionDesc;
+import org.apache.tajo.catalog.proto.CatalogProtos;
+import org.apache.tajo.common.TajoDataTypes;
+import org.apache.tajo.datum.*;
+import org.apache.tajo.engine.eval.*;
+import org.apache.tajo.engine.exception.UndefinedFunctionException;
+import org.apache.tajo.engine.function.AggFunction;
+import org.apache.tajo.engine.function.GeneralFunction;
+import org.apache.tajo.engine.planner.logical.NodeType;
+import org.apache.tajo.exception.InternalException;
+import org.joda.time.DateTime;
+
+import java.util.Stack;
+
+/**
+ * <code>ExprAnnotator</code> makes an annotated expression called <code>EvalNode</code> from an
+ * {@link org.apache.tajo.algebra.Expr}. It visits descendants recursively from a given expression, and finally
+ * it returns an EvalNode.
+ */
+public class ExprAnnotator extends BaseAlgebraVisitor<ExprAnnotator.Context, EvalNode> {
+  private CatalogService catalog;
+
+  public ExprAnnotator(CatalogService catalog) {
+    this.catalog = catalog;
+  }
+
+  static class Context {
+    LogicalPlan plan;
+    LogicalPlan.QueryBlock currentBlock;
+
+    public Context(LogicalPlan plan, LogicalPlan.QueryBlock block) {
+      this.plan = plan;
+      this.currentBlock = block;
+    }
+  }
+
+  public EvalNode createEvalNode(LogicalPlan plan, LogicalPlan.QueryBlock block, Expr expr)
+      throws PlanningException {
+    Context context = new Context(plan, block);
+    return visit(context, new Stack<Expr>(), expr);
+  }
+
+  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+  // Logical Operator Section
+  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+  @Override
+  public EvalNode visitAnd(Context ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
+    stack.push(expr);
+    EvalNode left = visit(ctx, stack, expr.getLeft());
+    EvalNode right = visit(ctx, stack, expr.getRight());
+    stack.pop();
+
+    return new BinaryEval(EvalType.AND, left, right);
+  }
+
+  @Override
+  public EvalNode visitOr(Context ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
+    stack.push(expr);
+    EvalNode left = visit(ctx, stack, expr.getLeft());
+    EvalNode right = visit(ctx, stack, expr.getRight());
+    stack.pop();
+
+    return new BinaryEval(EvalType.OR, left, right);
+  }
+
+  @Override
+  public EvalNode visitNot(Context ctx, Stack<Expr> stack, NotExpr expr) throws PlanningException {
+    stack.push(expr);
+    EvalNode child = visit(ctx, stack, expr.getChild());
+    stack.pop();
+    return new NotEval(child);
+  }
+
+  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+  // Comparison Predicates Section
+  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+  @Override
+  public EvalNode visitEquals(Context ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
+    return visitCommonComparison(ctx, stack, expr);
+  }
+
+  @Override
+  public EvalNode visitNotEquals(Context ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
+    return visitCommonComparison(ctx, stack, expr);
+  }
+
+  @Override
+  public EvalNode visitLessThan(Context ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
+    return visitCommonComparison(ctx, stack, expr);
+  }
+
+  @Override
+  public EvalNode visitLessThanOrEquals(Context ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
+    return visitCommonComparison(ctx, stack, expr);
+  }
+
+  @Override
+  public EvalNode visitGreaterThan(Context ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
+    return visitCommonComparison(ctx, stack, expr);
+  }
+
+  @Override
+  public EvalNode visitGreaterThanOrEquals(Context ctx, Stack<Expr> stack, BinaryOperator expr)
+      throws PlanningException {
+    return visitCommonComparison(ctx, stack, expr);
+  }
+
+  public EvalNode visitCommonComparison(Context ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
+    stack.push(expr);
+    EvalNode left = visit(ctx, stack, expr.getLeft());
+    EvalNode right = visit(ctx, stack, expr.getRight());
+    stack.pop();
+
+    EvalType evalType;
+    switch (expr.getType()) {
+      case Equals:
+        evalType = EvalType.EQUAL;
+        break;
+      case NotEquals:
+        evalType = EvalType.NOT_EQUAL;
+        break;
+      case LessThan:
+        evalType = EvalType.LTH;
+        break;
+      case LessThanOrEquals:
+        evalType = EvalType.LEQ;
+        break;
+      case GreaterThan:
+        evalType = EvalType.GTH;
+        break;
+      case GreaterThanOrEquals:
+        evalType = EvalType.GEQ;
+        break;
+      default:
+      throw new IllegalStateException("Wrong Expr Type: " + expr.getType());
+    }
+
+    return new BinaryEval(evalType, left, right);
+  }
+
+  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+  // Other Predicates Section
+  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+  @Override
+  public EvalNode visitBetween(Context ctx, Stack<Expr> stack, BetweenPredicate between) throws PlanningException {
+    stack.push(between);
+    EvalNode predicand = visit(ctx, stack, between.predicand());
+    EvalNode begin = visit(ctx, stack, between.begin());
+    EvalNode end = visit(ctx, stack, between.end());
+    stack.pop();
+
+    BetweenPredicateEval betweenEval = new BetweenPredicateEval(
+        between.isNot(),
+        between.isSymmetric(),
+        predicand, begin, end);
+    return betweenEval;
+  }
+
+  @Override
+  public EvalNode visitCaseWhen(Context ctx, Stack<Expr> stack, CaseWhenPredicate caseWhen) throws PlanningException {
+    CaseWhenEval caseWhenEval = new CaseWhenEval();
+
+    EvalNode condition;
+    EvalNode result;
+    for (CaseWhenPredicate.WhenExpr when : caseWhen.getWhens()) {
+      condition = visit(ctx, stack, when.getCondition());
+      result = visit(ctx, stack, when.getResult());
+      caseWhenEval.addWhen(condition, result);
+    }
+
+    if (caseWhen.hasElseResult()) {
+      caseWhenEval.setElseResult(visit(ctx, stack, caseWhen.getElseResult()));
+    }
+
+    return caseWhenEval;
+  }
+
+  @Override
+  public EvalNode visitIsNullPredicate(Context ctx, Stack<Expr> stack, IsNullPredicate expr) throws PlanningException {
+    stack.push(expr);
+    EvalNode child = visit(ctx, stack, expr.getPredicand());
+    stack.pop();
+    return new IsNullEval(expr.isNot(), child);
+  }
+
+  @Override
+  public EvalNode visitInPredicate(Context ctx, Stack<Expr> stack, InPredicate expr) throws PlanningException {
+    stack.push(expr);
+    Column predicandColumn = ctx.plan.resolveColumn(ctx.currentBlock, (ColumnReferenceExpr) expr.getPredicand());
+    FieldEval predicand = new FieldEval(predicandColumn);
+    RowConstantEval rowConstantEval = (RowConstantEval) visit(ctx, stack, expr.getInValue());
+    stack.pop();
+    return new InEval(predicand, rowConstantEval, expr.isNot());
+  }
+
+  @Override
+  public EvalNode visitValueListExpr(Context ctx, Stack<Expr> stack, ValueListExpr expr) throws PlanningException {
+    Datum[] values = new Datum[expr.getValues().length];
+    ConstEval [] constEvals = new ConstEval[expr.getValues().length];
+    for (int i = 0; i < expr.getValues().length; i++) {
+      constEvals[i] = (ConstEval) visit(ctx, stack, expr.getValues()[i]);
+      values[i] = constEvals[i].getValue();
+    }
+    return new RowConstantEval(values);
+  }
+
+  @Override
+  public EvalNode visitExistsPredicate(Context ctx, Stack<Expr> stack, ExistsPredicate expr) throws PlanningException {
+    throw new PlanningException("Cannot support EXISTS clause yet");
+  }
+
+  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+  // String Operator or Pattern Matching Predicates Section
+  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+  @Override
+  public EvalNode visitLikePredicate(Context ctx, Stack<Expr> stack, PatternMatchPredicate expr)
+      throws PlanningException {
+    return visitPatternMatchPredicate(ctx, stack, expr);
+  }
+
+  @Override
+  public EvalNode visitSimilarToPredicate(Context ctx, Stack<Expr> stack, PatternMatchPredicate expr)
+      throws PlanningException {
+    return visitPatternMatchPredicate(ctx, stack, expr);
+  }
+
+  @Override
+  public EvalNode visitRegexpPredicate(Context ctx, Stack<Expr> stack, PatternMatchPredicate expr)
+      throws PlanningException {
+    return visitPatternMatchPredicate(ctx, stack, expr);
+  }
+
+  @Override
+  public EvalNode visitConcatenate(Context ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
+    stack.push(expr);
+    EvalNode left = visit(ctx, stack, expr.getLeft());
+    EvalNode right = visit(ctx, stack, expr.getRight());
+    stack.pop();
+
+    return new BinaryEval(EvalType.CONCATENATE, left, right);
+  }
+
+  private EvalNode visitPatternMatchPredicate(Context ctx, Stack<Expr> stack, PatternMatchPredicate expr)
+      throws PlanningException {
+    EvalNode field = visit(ctx, stack, expr.getPredicand());
+    ConstEval pattern = (ConstEval) visit(ctx, stack, expr.getPattern());
+
+    // A pattern is a const value in pattern matching predicates.
+    // In a binary expression, the result is always null if a const value in left or right side is null.
+    if (pattern.getValue() instanceof NullDatum) {
+      return new ConstEval(NullDatum.get());
+    } else {
+      if (expr.getType() == OpType.LikePredicate) {
+        return new LikePredicateEval(expr.isNot(), field, pattern, expr.isCaseInsensitive());
+      } else if (expr.getType() == OpType.SimilarToPredicate) {
+        return new SimilarToPredicateEval(expr.isNot(), field, pattern);
+      } else {
+        return new RegexPredicateEval(expr.isNot(), field, pattern, expr.isCaseInsensitive());
+      }
+    }
+  }
+
+  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+  // Arithmetic Operators
+  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+  @Override
+  public EvalNode visitPlus(Context ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
+    stack.push(expr);
+    EvalNode left = visit(ctx, stack, expr.getLeft());
+    EvalNode right = visit(ctx, stack, expr.getRight());
+    stack.pop();
+
+    return new BinaryEval(EvalType.PLUS, left, right);
+  }
+
+  @Override
+  public EvalNode visitMinus(Context ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
+    stack.push(expr);
+    EvalNode left = visit(ctx, stack, expr.getLeft());
+    EvalNode right = visit(ctx, stack, expr.getRight());
+    stack.pop();
+
+    return new BinaryEval(EvalType.MINUS, left, right);
+  }
+
+  @Override
+  public EvalNode visitMultiply(Context ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
+    stack.push(expr);
+    EvalNode left = visit(ctx, stack, expr.getLeft());
+    EvalNode right = visit(ctx, stack, expr.getRight());
+    stack.pop();
+
+    return new BinaryEval(EvalType.MULTIPLY, left, right);
+  }
+
+  @Override
+  public EvalNode visitDivide(Context ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
+    stack.push(expr);
+    EvalNode left = visit(ctx, stack, expr.getLeft());
+    EvalNode right = visit(ctx, stack, expr.getRight());
+    stack.pop();
+
+    return new BinaryEval(EvalType.DIVIDE, left, right);
+  }
+
+  @Override
+  public EvalNode visitModular(Context ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
+    stack.push(expr);
+    EvalNode left = visit(ctx, stack, expr.getLeft());
+    EvalNode right = visit(ctx, stack, expr.getRight());
+    stack.pop();
+
+    return new BinaryEval(EvalType.MODULAR, left, right);
+  }
+
+  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+  // Other Expressions
+  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+  @Override
+  public EvalNode visitSign(Context ctx, Stack<Expr> stack, SignedExpr expr) throws PlanningException {
+    stack.push(expr);
+    EvalNode numericExpr = visit(ctx, stack, expr.getChild());
+    stack.pop();
+
+    if (expr.isNegative()) {
+      return new SignedEval(expr.isNegative(), numericExpr);
+    } else {
+      return numericExpr;
+    }
+  }
+
+  @Override
+  public EvalNode visitColumnReference(Context ctx, Stack<Expr> stack, ColumnReferenceExpr expr)
+      throws PlanningException {
+    Column column = ctx.plan.resolveColumn(ctx.currentBlock, expr);
+    return new FieldEval(column);
+  }
+
+  @Override
+  public EvalNode visitTargetExpr(Context ctx, Stack<Expr> stack, NamedExpr expr) throws PlanningException {
+    throw new PlanningException("ExprAnnotator cannot take NamedExpr");
+  }
+
+  @Override
+  public EvalNode visitFunction(Context ctx, Stack<Expr> stack, FunctionExpr expr) throws PlanningException {
+    stack.push(expr); // <--- Push
+
+    // Given parameters
+    Expr[] params = expr.getParams();
+    if (params == null) {
+      params = new Expr[1];
+      params[0] = new NullLiteral();
+    }
+
+    EvalNode[] givenArgs = new EvalNode[params.length];
+    TajoDataTypes.DataType[] paramTypes = new TajoDataTypes.DataType[params.length];
+
+    for (int i = 0; i < params.length; i++) {
+      givenArgs[i] = visit(ctx, stack, params[i]);
+      paramTypes[i] = givenArgs[i].getValueType();
+    }
+
+    stack.pop(); // <--- Pop
+
+    if (!catalog.containFunction(expr.getSignature(), paramTypes)) {
+      throw new UndefinedFunctionException(CatalogUtil.getCanonicalName(expr.getSignature(), paramTypes));
+    }
+
+    FunctionDesc funcDesc = catalog.getFunction(expr.getSignature(), paramTypes);
+
+    try {
+    CatalogProtos.FunctionType functionType = funcDesc.getFuncType();
+    if (functionType == CatalogProtos.FunctionType.GENERAL
+        || functionType == CatalogProtos.FunctionType.UDF) {
+      return new GeneralFunctionEval(funcDesc, (GeneralFunction) funcDesc.newInstance(), givenArgs);
+    } else if (functionType == CatalogProtos.FunctionType.AGGREGATION
+        || functionType == CatalogProtos.FunctionType.UDA) {
+      if (!ctx.currentBlock.hasNode(NodeType.GROUP_BY)) {
+        ctx.currentBlock.setAggregationRequire();
+      }
+      return new AggregationFunctionCallEval(funcDesc, (AggFunction) funcDesc.newInstance(), givenArgs);
+    } else if (functionType == CatalogProtos.FunctionType.DISTINCT_AGGREGATION
+        || functionType == CatalogProtos.FunctionType.DISTINCT_UDA) {
+      throw new PlanningException("Unsupported function: " + funcDesc.toString());
+    } else {
+      throw new PlanningException("Unsupported Function Type: " + functionType.name());
+    }
+    } catch (InternalException e) {
+      throw new PlanningException(e);
+    }
+  }
+
+  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+  // General Set Section
+  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+  @Override
+  public EvalNode visitCountRowsFunction(Context ctx, Stack<Expr> stack, CountRowsFunctionExpr expr)
+      throws PlanningException {
+    FunctionDesc countRows = catalog.getFunction("count", CatalogProtos.FunctionType.AGGREGATION,
+        new TajoDataTypes.DataType[] {});
+
+    try {
+      ctx.currentBlock.setAggregationRequire();
+
+      return new AggregationFunctionCallEval(countRows, (AggFunction) countRows.newInstance(),
+          new EvalNode[] {});
+    } catch (InternalException e) {
+      throw new UndefinedFunctionException(CatalogUtil.
+          getCanonicalName(countRows.getSignature(), new TajoDataTypes.DataType[]{}));
+    }
+  }
+
+  @Override
+  public EvalNode visitGeneralSetFunction(Context ctx, Stack<Expr> stack, GeneralSetFunctionExpr setFunction)
+      throws PlanningException {
+
+    Expr[] params = setFunction.getParams();
+    EvalNode[] givenArgs = new EvalNode[params.length];
+    TajoDataTypes.DataType[] paramTypes = new TajoDataTypes.DataType[params.length];
+
+    CatalogProtos.FunctionType functionType = setFunction.isDistinct() ?
+        CatalogProtos.FunctionType.DISTINCT_AGGREGATION : CatalogProtos.FunctionType.AGGREGATION;
+    givenArgs[0] = visit(ctx, stack, params[0]);
+    if (setFunction.getSignature().equalsIgnoreCase("count")) {
+      paramTypes[0] = CatalogUtil.newSimpleDataType(TajoDataTypes.Type.ANY);
+    } else {
+      paramTypes[0] = givenArgs[0].getValueType();
+    }
+
+    if (!catalog.containFunction(setFunction.getSignature(), functionType, paramTypes)) {
+      throw new UndefinedFunctionException(CatalogUtil. getCanonicalName(setFunction.getSignature(), paramTypes));
+    }
+
+    FunctionDesc funcDesc = catalog.getFunction(setFunction.getSignature(), functionType, paramTypes);
+    if (!ctx.currentBlock.hasNode(NodeType.GROUP_BY)) {
+      ctx.currentBlock.setAggregationRequire();
+    }
+
+    try {
+      return new AggregationFunctionCallEval(funcDesc, (AggFunction) funcDesc.newInstance(), givenArgs);
+    } catch (InternalException e) {
+      throw new PlanningException(e);
+    }
+  }
+
+  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+  // Literal Section
+  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+  @Override
+  public EvalNode visitDataType(Context ctx, Stack<Expr> stack, DataTypeExpr expr) throws PlanningException {
+    return super.visitDataType(ctx, stack, expr);
+  }
+
+  @Override
+  public EvalNode visitCastExpr(Context ctx, Stack<Expr> stack, CastExpr expr) throws PlanningException {
+    EvalNode child = super.visitCastExpr(ctx, stack, expr);
+    return new CastEval(child, LogicalPlanner.convertDataType(expr.getTarget()));
+  }
+
+  @Override
+  public EvalNode visitLiteral(Context ctx, Stack<Expr> stack, LiteralValue expr) throws PlanningException {
+    switch (expr.getValueType()) {
+    case Boolean:
+      return new ConstEval(DatumFactory.createBool(((BooleanLiteral) expr).isTrue()));
+    case String:
+      return new ConstEval(DatumFactory.createText(expr.getValue()));
+    case Unsigned_Integer:
+      return new ConstEval(DatumFactory.createInt4(expr.getValue()));
+    case Unsigned_Large_Integer:
+      return new ConstEval(DatumFactory.createInt8(expr.getValue()));
+    case Unsigned_Float:
+      return new ConstEval(DatumFactory.createFloat8(expr.getValue()));
+    default:
+      throw new RuntimeException("Unsupported type: " + expr.getValueType());
+    }
+  }
+
+  @Override
+  public EvalNode visitNullLiteral(Context ctx, Stack<Expr> stack, NullLiteral expr) throws PlanningException {
+    return new ConstEval(NullDatum.get());
+  }
+
+  @Override
+  public EvalNode visitDateLiteral(Context context, Stack<Expr> stack, DateLiteral expr) throws PlanningException {
+    DateValue dateValue = expr.getDate();
+    int [] dates = dateToIntArray(dateValue.getYears(), dateValue.getMonths(), dateValue.getDays());
+    return new ConstEval(new DateDatum(dates[0], dates[1], dates[2]));
+  }
+
+  @Override
+  public EvalNode visitTimestampLiteral(Context ctx, Stack<Expr> stack, TimestampLiteral expr)
+      throws PlanningException {
+    DateValue dateValue = expr.getDate();
+    TimeValue timeValue = expr.getTime();
+
+    int [] dates = dateToIntArray(dateValue.getYears(),
+        dateValue.getMonths(),
+        dateValue.getDays());
+    int [] times = timeToIntArray(timeValue.getHours(),
+        timeValue.getMinutes(),
+        timeValue.getSeconds(),
+        timeValue.getSecondsFraction());
+    DateTime dateTime;
+    if (timeValue.hasSecondsFraction()) {
+      dateTime = new DateTime(dates[0], dates[1], dates[2], times[0], times[1], times[2], times[3]);
+    } else {
+      dateTime = new DateTime(dates[0], dates[1], dates[2], times[0], times[1], times[2]);
+    }
+
+    return new ConstEval(new TimestampDatum(dateTime));
+  }
+
+  @Override
+  public EvalNode visitTimeLiteral(Context ctx, Stack<Expr> stack, TimeLiteral expr) throws PlanningException {
+    TimeValue timeValue = expr.getTime();
+    int [] times = timeToIntArray(timeValue.getHours(),
+        timeValue.getMinutes(),
+        timeValue.getSeconds(),
+        timeValue.getSecondsFraction());
+
+    TimeDatum datum;
+    if (timeValue.hasSecondsFraction()) {
+      datum = new TimeDatum(times[0], times[1], times[2], times[3]);
+    } else {
+      datum = new TimeDatum(times[0], times[1], times[2]);
+    }
+    return new ConstEval(datum);
+  }
+
+  public static int [] dateToIntArray(String years, String months, String days)
+      throws PlanningException {
+    int year = Integer.valueOf(years);
+    int month = Integer.valueOf(months);
+    int day = Integer.valueOf(days);
+
+    if (!(1 <= year && year <= 9999)) {
+      throw new PlanningException(String.format("Years (%d) must be between 1 and 9999 integer value", year));
+    }
+
+    if (!(1 <= month && month <= 12)) {
+      throw new PlanningException(String.format("Months (%d) must be between 1 and 12 integer value", month));
+    }
+
+    if (!(1<= day && day <= 31)) {
+      throw new PlanningException(String.format("Days (%d) must be between 1 and 31 integer value", day));
+    }
+
+    int [] results = new int[3];
+    results[0] = year;
+    results[1] = month;
+    results[2] = day;
+
+    return results;
+  }
+
+  public static int [] timeToIntArray(String hours, String minutes, String seconds, String fractionOfSecond)
+      throws PlanningException {
+    int hour = Integer.valueOf(hours);
+    int minute = Integer.valueOf(minutes);
+    int second = Integer.valueOf(seconds);
+    int fraction = 0;
+    if (fractionOfSecond != null) {
+      fraction = Integer.valueOf(fractionOfSecond);
+    }
+
+    if (!(0 <= hour && hour <= 23)) {
+      throw new PlanningException(String.format("Hours (%d) must be between 0 and 24 integer value", hour));
+    }
+
+    if (!(0 <= minute && minute <= 59)) {
+      throw new PlanningException(String.format("Minutes (%d) must be between 0 and 59 integer value", minute));
+    }
+
+    if (!(0 <= second && second <= 59)) {
+      throw new PlanningException(String.format("Seconds (%d) must be between 0 and 59 integer value", second));
+    }
+
+    if (fraction != 0) {
+      if (!(0 <= fraction && fraction <= 999)) {
+        throw new PlanningException(String.format("Seconds (%d) must be between 0 and 999 integer value", fraction));
+      }
+    }
+
+    int [] results = new int[4];
+    results[0] = hour;
+    results[1] = minute;
+    results[2] = second;
+    results[3] = fraction;
+
+    return results;
+  }
+}