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 2013/09/21 04:02:45 UTC

[2/2] git commit: TAJO-46: The "having" clause does not work properly. (hyunsik)

TAJO-46: The "having" clause does not work properly. (hyunsik)


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

Branch: refs/heads/master
Commit: e595384bace80341c23575a554cd21a95fb19738
Parents: bd1619d
Author: Hyunsik Choi <hy...@apache.org>
Authored: Sat Sep 21 11:01:50 2013 +0900
Committer: Hyunsik Choi <hy...@apache.org>
Committed: Sat Sep 21 11:01:50 2013 +0900

----------------------------------------------------------------------
 CHANGES.txt                                     |   5 +-
 .../org/apache/tajo/algebra/LiteralValue.java   |   1 +
 .../java/org/apache/tajo/algebra/Target.java    |   7 +-
 .../main/java/org/apache/tajo/util/TUtil.java   |  22 ++
 .../tajo/engine/eval/BasicEvalNodeVisitor.java  | 280 +++++++++++++++++++
 .../apache/tajo/engine/eval/CaseWhenEval.java   |  36 ++-
 .../tajo/engine/eval/EvalNodeVisitor.java       |   1 +
 .../tajo/engine/eval/EvalNodeVisitor2.java      |  61 ++++
 .../apache/tajo/engine/eval/EvalTreeUtil.java   |  37 ++-
 .../org/apache/tajo/engine/eval/EvalType.java   |   4 +-
 .../org/apache/tajo/engine/eval/InEval.java     |   4 +-
 .../org/apache/tajo/engine/eval/NotEval.java    |   7 +-
 .../apache/tajo/engine/eval/RowConstant.java    |  89 ------
 .../tajo/engine/eval/RowConstantEval.java       |  89 ++++++
 .../tajo/engine/parser/HiveConverter.java       |  16 +-
 .../apache/tajo/engine/parser/SQLAnalyzer.java  |   4 +-
 .../tajo/engine/planner/AlgebraVisitor.java     |  31 +-
 .../tajo/engine/planner/BaseAlgebraVisitor.java |  13 +-
 .../engine/planner/BasicLogicalPlanVisitor.java |  62 ++--
 .../planner/ExplainLogicalPlanVisitor.java      |   8 +-
 .../apache/tajo/engine/planner/LogicalPlan.java |  88 ++++--
 .../tajo/engine/planner/LogicalPlanVisitor.java |  30 +-
 .../tajo/engine/planner/LogicalPlanner.java     |  32 ++-
 .../engine/planner/PhysicalPlannerImpl.java     |  52 ++--
 .../org/apache/tajo/engine/planner/Target.java  |   2 +-
 .../engine/planner/logical/GroupbyNode.java     |  34 ++-
 .../planner/physical/AggregationExec.java       |  23 +-
 .../planner/physical/HashAggregateExec.java     |  30 +-
 .../planner/rewrite/ProjectionPushDownRule.java |  10 +-
 .../org/apache/tajo/master/GlobalPlanner.java   | 140 +++++-----
 .../tajo/engine/query/TestGroupByQuery.java     |  41 ++-
 .../apache/tajo/master/TestGlobalPlanner.java   |   6 +-
 32 files changed, 924 insertions(+), 341 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e595384b/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index 32d7713..af1a245 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -25,7 +25,8 @@ Release 0.2.0 - unreleased
 
   IMPROVEMENTS
 
-    TAJO-183: Creating too many TableMetaProto objects might lead a potential memory leak. (jihoon)
+    TAJO-183: Creating too many TableMetaProto objects might lead a potential 
+    memory leak. (jihoon)
 
     TAJO-184: Refactor GlobalPlanner and global plan data structure. (hyunsik)
 
@@ -142,6 +143,8 @@ Release 0.2.0 - unreleased
 
   BUG FIXES
 
+    TAJO-46: The "having" clause does not work properly. (hyunsik)
+
     TAJO-186: Improve column resolving method. (hyunsik)
 
     TAJO-168: infinite loop occurs when QueryMaster is stopping. (jinho)

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e595384b/tajo-algebra/src/main/java/org/apache/tajo/algebra/LiteralValue.java
----------------------------------------------------------------------
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/LiteralValue.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/LiteralValue.java
index 02445f0..d713d00 100644
--- a/tajo-algebra/src/main/java/org/apache/tajo/algebra/LiteralValue.java
+++ b/tajo-algebra/src/main/java/org/apache/tajo/algebra/LiteralValue.java
@@ -23,6 +23,7 @@ public class LiteralValue extends Expr {
   private LiteralType valueType;
 
   public static enum LiteralType {
+    Boolean,
     String,
     Unsigned_Integer,
     Unsigned_Float,

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e595384b/tajo-algebra/src/main/java/org/apache/tajo/algebra/Target.java
----------------------------------------------------------------------
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/Target.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/Target.java
index 2de5057..9172d6c 100644
--- a/tajo-algebra/src/main/java/org/apache/tajo/algebra/Target.java
+++ b/tajo-algebra/src/main/java/org/apache/tajo/algebra/Target.java
@@ -26,7 +26,12 @@ public class Target extends Expr {
 
   public Target(Expr expr) {
     super(OpType.Target);
-   this.expr = expr;
+    this.expr = expr;
+  }
+
+  public Target(Expr expr, String alias) {
+    this(expr);
+    setAlias(alias);
   }
 
   public Expr getExpr() {

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e595384b/tajo-common/src/main/java/org/apache/tajo/util/TUtil.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/java/org/apache/tajo/util/TUtil.java b/tajo-common/src/main/java/org/apache/tajo/util/TUtil.java
index 373292b..3931709 100644
--- a/tajo-common/src/main/java/org/apache/tajo/util/TUtil.java
+++ b/tajo-common/src/main/java/org/apache/tajo/util/TUtil.java
@@ -67,6 +67,20 @@ public class TUtil {
     return result;
   }
 
+  public static <T> T[] concatAll(T[] first, T[]... rest) {
+    int totalLength = first.length;
+    for (T[] array : rest) {
+      totalLength += array.length;
+    }
+    T[] result = Arrays.copyOf(first, totalLength);
+    int offset = first.length;
+    for (T[] array : rest) {
+      System.arraycopy(array, 0, result, offset, array.length);
+      offset += array.length;
+    }
+    return result;
+  }
+
   public static <T> Set<T> newHashSet() {
     return new HashSet<T>();
   }
@@ -135,6 +149,14 @@ public class TUtil {
     return reference;
   }
 
+  public static <KEY1, VALUE> void putToNestedList(Map<KEY1, List<VALUE>> map, KEY1 k1, VALUE value) {
+    if (map.containsKey(k1)) {
+      map.get(k1).add(value);
+    } else {
+      map.put(k1, TUtil.newList(value));
+    }
+  }
+
   public static <KEY1, KEY2, VALUE> void putToNestedMap(Map<KEY1, Map<KEY2, VALUE>> map, KEY1 k1, KEY2 k2,
                                                         VALUE value) {
     if (map.containsKey(k1)) {

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e595384b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/BasicEvalNodeVisitor.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/BasicEvalNodeVisitor.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/BasicEvalNodeVisitor.java
new file mode 100644
index 0000000..8d6e250
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/BasicEvalNodeVisitor.java
@@ -0,0 +1,280 @@
+/**
+ * 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.eval;
+
+import java.util.Stack;
+
+public class BasicEvalNodeVisitor<CONTEXT, RESULT> implements EvalNodeVisitor2<CONTEXT, RESULT> {
+  @Override
+  public RESULT visitChild(CONTEXT context, Stack<EvalNode> stack, EvalNode evalNode) {
+    RESULT result;
+    switch (evalNode.getType()) {
+      // Column and Value reference expressions
+      case CONST:
+        result = visitConst(context, stack, (ConstEval) evalNode);
+        break;
+      case ROW_CONSTANT:
+        result = visitRowConstant(context, stack, (RowConstantEval) evalNode);
+        break;
+      case FIELD:
+        result = visitField(context, stack, (FieldEval) evalNode);
+        break;
+
+      // Arithmetic expression
+      case PLUS:
+        result = visitPlus(context, stack, (BinaryEval) evalNode);
+        break;
+      case MINUS:
+        result = visitMinus(context, stack, (BinaryEval) evalNode);
+        break;
+      case MULTIPLY:
+        result = visitMultiply(context, stack, (BinaryEval) evalNode);
+        break;
+      case DIVIDE:
+        result = visitDivide(context, stack, (BinaryEval) evalNode);
+        break;
+      case MODULAR:
+        result = visitModular(context, stack, (BinaryEval) evalNode);
+        break;
+
+      // Logical Predicates
+      case AND:
+        result = visitAnd(context, stack, (BinaryEval) evalNode);
+        break;
+      case OR:
+        result = visitOr(context, stack, (BinaryEval) evalNode);
+        break;
+      case NOT:
+        result = visitNot(context, stack, (NotEval) evalNode);
+        break;
+
+      // Comparison Predicates
+      case EQUAL:
+        result = visitEqual(context, stack, (BinaryEval) evalNode);
+        break;
+      case NOT_EQUAL:
+        result = visitNotEqual(context, stack, (BinaryEval) evalNode);
+        break;
+      case LTH:
+        result = visitLessThan(context, stack, (BinaryEval) evalNode);
+        break;
+      case LEQ:
+        result = visitLessThanOrEqual(context, stack, (BinaryEval) evalNode);
+        break;
+      case GTH:
+        result = visitGreaterThan(context, stack, (BinaryEval) evalNode);
+        break;
+      case GEQ:
+        result = visitGreaterThanOrEqual(context, stack, (BinaryEval) evalNode);
+        break;
+
+      // Other Predicates
+      case IS_NULL:
+        result = visitIsNull(context, stack, (IsNullEval) evalNode);
+        break;
+      case CASE:
+        result = visitCaseWhen(context, stack, (CaseWhenEval) evalNode);
+        break;
+      case IF_THEN:
+        result = visitIfThen(context, stack, (CaseWhenEval.IfThenEval) evalNode);
+        break;
+      case IN:
+        result = visitInPredicate(context, stack, (InEval) evalNode);
+        break;
+      case LIKE:
+        result = visitLike(context, stack, (LikeEval) evalNode);
+        break;
+
+      // Functions
+      case FUNCTION:
+        result = visitFuncCall(context, stack, (FuncCallEval) evalNode);
+        break;
+      case AGG_FUNCTION:
+        result = visitAggrFuncCall(context, stack, (AggFuncCallEval) evalNode);
+        break;
+
+      default:
+        throw new InvalidEvalException("Unknown EvalNode: " + evalNode);
+    }
+
+    return result;
+  }
+
+  private RESULT visitDefaultBinaryEval(CONTEXT context, Stack<EvalNode> stack, BinaryEval binaryEval) {
+    stack.push(binaryEval);
+    RESULT result = visitChild(context, stack, binaryEval.getLeftExpr());
+    visitChild(context, stack, binaryEval.getRightExpr());
+    stack.pop();
+    return result;
+  }
+
+  private RESULT visitDefaultFunctionEval(CONTEXT context, Stack<EvalNode> stack, FuncEval functionEval) {
+    RESULT result = null;
+    stack.push(functionEval);
+    for (EvalNode arg : functionEval.getArgs()) {
+      result = visitChild(context, stack, arg);
+    }
+    stack.pop();
+    return result;
+  }
+
+  @Override
+  public RESULT visitConst(CONTEXT context, Stack<EvalNode> stack, ConstEval evalNode) {
+    return null;
+  }
+
+  @Override
+  public RESULT visitRowConstant(CONTEXT context, Stack<EvalNode> stack, RowConstantEval evalNode) {
+    return null;
+  }
+
+  @Override
+  public RESULT visitField(CONTEXT context, Stack<EvalNode> stack, FieldEval evalNode) {
+    return null;
+  }
+
+  @Override
+  public RESULT visitPlus(CONTEXT context, Stack<EvalNode> stack, BinaryEval evalNode) {
+    return visitDefaultBinaryEval(context, stack, evalNode);
+  }
+
+  @Override
+  public RESULT visitMinus(CONTEXT context, Stack<EvalNode> stack, BinaryEval evalNode) {
+    return visitDefaultBinaryEval(context, stack, evalNode);
+  }
+
+  @Override
+  public RESULT visitMultiply(CONTEXT context, Stack<EvalNode> stack, BinaryEval evalNode) {
+    return visitDefaultBinaryEval(context, stack, evalNode);
+  }
+
+  @Override
+  public RESULT visitDivide(CONTEXT context, Stack<EvalNode> stack, BinaryEval evalNode) {
+    return visitDefaultBinaryEval(context, stack, evalNode);
+  }
+
+  @Override
+  public RESULT visitModular(CONTEXT context, Stack<EvalNode> stack, BinaryEval evalNode) {
+    return visitDefaultBinaryEval(context, stack, evalNode);
+  }
+
+  @Override
+  public RESULT visitAnd(CONTEXT context, Stack<EvalNode> stack, BinaryEval evalNode) {
+    return visitDefaultBinaryEval(context, stack, evalNode);
+  }
+
+  @Override
+  public RESULT visitOr(CONTEXT context, Stack<EvalNode> stack, BinaryEval evalNode) {
+    return visitDefaultBinaryEval(context, stack, evalNode);
+  }
+
+  @Override
+  public RESULT visitNot(CONTEXT context, Stack<EvalNode> stack, NotEval evalNode) {
+    RESULT result;
+    stack.push(evalNode);
+    if (evalNode.getChild() instanceof NotEval) {
+      result = visitChild(context, stack, evalNode);
+    } else {
+      result = visitChild(context, stack, evalNode.getLeftExpr());
+      visitChild(context, stack, evalNode.getRightExpr());
+    }
+    stack.pop();
+
+    return result;
+  }
+
+  @Override
+  public RESULT visitEqual(CONTEXT context, Stack<EvalNode> stack, BinaryEval evalNode) {
+    return visitDefaultBinaryEval(context, stack, evalNode);
+  }
+
+  @Override
+  public RESULT visitNotEqual(CONTEXT context, Stack<EvalNode> stack, BinaryEval evalNode) {
+    return visitDefaultBinaryEval(context, stack, evalNode);
+  }
+
+  @Override
+  public RESULT visitLessThan(CONTEXT context, Stack<EvalNode> stack, BinaryEval evalNode) {
+    return visitDefaultBinaryEval(context, stack, evalNode);
+  }
+
+  @Override
+  public RESULT visitLessThanOrEqual(CONTEXT context, Stack<EvalNode> stack, BinaryEval evalNode) {
+    return visitDefaultBinaryEval(context, stack, evalNode);
+  }
+
+  @Override
+  public RESULT visitGreaterThan(CONTEXT context, Stack<EvalNode> stack, BinaryEval evalNode) {
+    return visitDefaultBinaryEval(context, stack, evalNode);
+  }
+
+  @Override
+  public RESULT visitGreaterThanOrEqual(CONTEXT context, Stack<EvalNode> stack, BinaryEval evalNode) {
+    return visitDefaultBinaryEval(context, stack, evalNode);
+  }
+
+  @Override
+  public RESULT visitIsNull(CONTEXT context, Stack<EvalNode> stack, IsNullEval evalNode) {
+    return visitDefaultBinaryEval(context, stack, evalNode);
+  }
+
+  @Override
+  public RESULT visitCaseWhen(CONTEXT context, Stack<EvalNode> stack, CaseWhenEval evalNode) {
+    RESULT result = null;
+    stack.push(evalNode);
+    for (CaseWhenEval.IfThenEval ifThenEval : evalNode.getIfThenEvals()) {
+      result = visitIfThen(context, stack, ifThenEval);
+    }
+    if (evalNode.hasElse()) {
+      result = visitChild(context, stack, evalNode.getElse());
+    }
+    stack.pop();
+    return result;
+  }
+
+  @Override
+  public RESULT visitIfThen(CONTEXT context, Stack<EvalNode> stack, CaseWhenEval.IfThenEval evalNode) {
+    RESULT result;
+    stack.push(evalNode);
+    result = visitChild(context, stack, evalNode.getConditionExpr());
+    visitChild(context, stack, evalNode.getResultExpr());
+    stack.pop();
+    return result;
+  }
+
+  @Override
+  public RESULT visitInPredicate(CONTEXT context, Stack<EvalNode> stack, InEval evalNode) {
+    return visitDefaultBinaryEval(context, stack, evalNode);
+  }
+
+  @Override
+  public RESULT visitLike(CONTEXT context, Stack<EvalNode> stack, LikeEval evalNode) {
+    return visitDefaultBinaryEval(context, stack, evalNode);
+  }
+
+  @Override
+  public RESULT visitFuncCall(CONTEXT context, Stack<EvalNode> stack, FuncCallEval evalNode) {
+    return visitDefaultFunctionEval(context, stack, evalNode);
+  }
+
+  @Override
+  public RESULT visitAggrFuncCall(CONTEXT context, Stack<EvalNode> stack, AggFuncCallEval evalNode) {
+    return visitDefaultFunctionEval(context, stack, evalNode);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e595384b/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 1cb24d2..e2ab0b9 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
@@ -34,7 +34,7 @@ import org.apache.tajo.util.TUtil;
 import java.util.List;
 
 public class CaseWhenEval extends EvalNode implements GsonObject {
-  @Expose private List<WhenEval> whens = Lists.newArrayList();
+  @Expose private List<IfThenEval> whens = Lists.newArrayList();
   @Expose private EvalNode elseResult;
 
   public CaseWhenEval() {
@@ -42,7 +42,19 @@ public class CaseWhenEval extends EvalNode implements GsonObject {
   }
 
   public void addWhen(EvalNode condition, EvalNode result) {
-    whens.add(new WhenEval(condition, result));
+    whens.add(new IfThenEval(condition, result));
+  }
+
+  public List<IfThenEval> getIfThenEvals() {
+    return whens;
+  }
+
+  public boolean hasElse() {
+    return this.elseResult != null;
+  }
+
+  public EvalNode getElse() {
+    return elseResult;
   }
 
   public void setElseResult(EvalNode elseResult) {
@@ -93,7 +105,7 @@ public class CaseWhenEval extends EvalNode implements GsonObject {
   @Override
   public String toString() {
     StringBuilder sb = new StringBuilder("CASE\n");
-    for (WhenEval when : whens) {
+    for (IfThenEval when : whens) {
      sb.append(when).append("\n");
     }
 
@@ -105,7 +117,7 @@ public class CaseWhenEval extends EvalNode implements GsonObject {
   @Override
   public void preOrder(EvalNodeVisitor visitor) {
     visitor.visit(this);
-    for (WhenEval when : whens) {
+    for (IfThenEval when : whens) {
       when.preOrder(visitor);
     }
     if (elseResult != null) { // without else clause
@@ -115,7 +127,7 @@ public class CaseWhenEval extends EvalNode implements GsonObject {
 
   @Override
   public void postOrder(EvalNodeVisitor visitor) {
-    for (WhenEval when : whens) {
+    for (IfThenEval when : whens) {
       when.postOrder(visitor);
     }
     if (elseResult != null) { // without else clause
@@ -140,12 +152,12 @@ public class CaseWhenEval extends EvalNode implements GsonObject {
     }
   }
 
-  public static class WhenEval extends EvalNode implements GsonObject {
+  public static class IfThenEval extends EvalNode implements GsonObject {
     @Expose private EvalNode condition;
     @Expose private EvalNode result;
 
-    public WhenEval(EvalNode condition, EvalNode result) {
-      super(EvalType.WHEN);
+    public IfThenEval(EvalNode condition, EvalNode result) {
+      super(EvalType.IF_THEN);
       this.condition = condition;
       this.result = result;
     }
@@ -185,8 +197,8 @@ public class CaseWhenEval extends EvalNode implements GsonObject {
 
     @Override
     public boolean equals(Object object) {
-      if (object instanceof WhenEval) {
-        WhenEval other = (WhenEval) object;
+      if (object instanceof IfThenEval) {
+        IfThenEval other = (IfThenEval) object;
         return condition.equals(other.condition) &&
             result.equals(other.result);
       } else {
@@ -201,7 +213,7 @@ public class CaseWhenEval extends EvalNode implements GsonObject {
 
     @Override
     public String toJson() {
-      return CoreGsonHelper.toJson(WhenEval.this, WhenEval.class);
+      return CoreGsonHelper.toJson(IfThenEval.this, IfThenEval.class);
     }
 
     private class WhenContext implements EvalContext {
@@ -237,7 +249,7 @@ public class CaseWhenEval extends EvalNode implements GsonObject {
     EvalContext [] contexts;
     EvalContext elseCtx;
 
-    CaseContext(List<WhenEval> whens, EvalContext elseCtx) {
+    CaseContext(List<IfThenEval> whens, EvalContext elseCtx) {
       contexts = new EvalContext[whens.size()];
       for (int i = 0; i < whens.size(); i++) {
         contexts[i] = whens.get(i).newContext();

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e595384b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalNodeVisitor.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalNodeVisitor.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalNodeVisitor.java
index 2cac5da..1680b31 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalNodeVisitor.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalNodeVisitor.java
@@ -18,6 +18,7 @@
 
 package org.apache.tajo.engine.eval;
 
+@Deprecated
 public interface EvalNodeVisitor {
   public void visit(EvalNode node);
 }

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e595384b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalNodeVisitor2.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalNodeVisitor2.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalNodeVisitor2.java
new file mode 100644
index 0000000..abb6b51
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalNodeVisitor2.java
@@ -0,0 +1,61 @@
+/**
+ * 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.eval;
+
+import java.util.Stack;
+
+public interface EvalNodeVisitor2<CONTEXT, RESULT> {
+  RESULT visitChild(CONTEXT context, Stack<EvalNode> stack, EvalNode evalNode);
+
+  // Column and Value reference expressions
+  RESULT visitConst(CONTEXT context, Stack<EvalNode> stack, ConstEval evalNode);
+  RESULT visitRowConstant(CONTEXT context, Stack<EvalNode> stack, RowConstantEval evalNode);
+  RESULT visitField(CONTEXT context, Stack<EvalNode> stack, FieldEval evalNode);
+
+  // Arithmetic expression
+  RESULT visitPlus(CONTEXT context, Stack<EvalNode> stack, BinaryEval evalNode);
+  RESULT visitMinus(CONTEXT context, Stack<EvalNode> stack, BinaryEval evalNode);
+  RESULT visitMultiply(CONTEXT context, Stack<EvalNode> stack, BinaryEval evalNode);
+  RESULT visitDivide(CONTEXT context, Stack<EvalNode> stack, BinaryEval evalNode);
+  RESULT visitModular(CONTEXT context, Stack<EvalNode> stack, BinaryEval evalNode);
+
+  // Logical Predicates
+  RESULT visitAnd(CONTEXT context, Stack<EvalNode> stack, BinaryEval evalNode);
+  RESULT visitOr(CONTEXT context, Stack<EvalNode> stack, BinaryEval evalNode);
+  RESULT visitNot(CONTEXT context, Stack<EvalNode> stack, NotEval evalNode);
+
+  // Comparison Predicates
+  RESULT visitEqual(CONTEXT context, Stack<EvalNode> stack, BinaryEval evalNode);
+  RESULT visitNotEqual(CONTEXT context, Stack<EvalNode> stack, BinaryEval evalNode);
+  RESULT visitLessThan(CONTEXT context, Stack<EvalNode> stack, BinaryEval evalNode);
+  RESULT visitLessThanOrEqual(CONTEXT context, Stack<EvalNode> stack, BinaryEval evalNode);
+  RESULT visitGreaterThan(CONTEXT context, Stack<EvalNode> stack, BinaryEval evalNode);
+  RESULT visitGreaterThanOrEqual(CONTEXT context, Stack<EvalNode> stack, BinaryEval evalNode);
+
+  // Other Predicates
+  RESULT visitIsNull(CONTEXT context, Stack<EvalNode> stack, IsNullEval evalNode);
+  RESULT visitCaseWhen(CONTEXT context, Stack<EvalNode> stack, CaseWhenEval evalNode);
+  RESULT visitIfThen(CONTEXT context, Stack<EvalNode> stack, CaseWhenEval.IfThenEval evalNode);
+  RESULT visitInPredicate(CONTEXT context, Stack<EvalNode> stack, InEval evalNode);
+  RESULT visitLike(CONTEXT context, Stack<EvalNode> stack, LikeEval evalNode);
+
+  // Functions
+  RESULT visitFuncCall(CONTEXT context, Stack<EvalNode> stack, FuncCallEval evalNode);
+  RESULT visitAggrFuncCall(CONTEXT context, Stack<EvalNode> stack, AggFuncCallEval evalNode);
+}

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e595384b/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 e6bd733..6be0996 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
@@ -35,6 +35,39 @@ public class EvalTreeUtil {
       String newName) {
     node.postOrder(new ChangeColumnRefVisitor(oldName, newName));
   }
+
+  public static void replace(EvalNode expr, EvalNode targetExpr, EvalNode tobeReplaced) {
+    EvalReplaceVisitor replacer = new EvalReplaceVisitor(targetExpr, tobeReplaced);
+    replacer.visitChild(null, new Stack<EvalNode>(), expr);
+  }
+
+  public static class EvalReplaceVisitor extends BasicEvalNodeVisitor<EvalNode, EvalNode> {
+    private EvalNode target;
+    private EvalNode tobeReplaced;
+
+    public EvalReplaceVisitor(EvalNode target, EvalNode tobeReplaced) {
+      this.target = target;
+      this.tobeReplaced = tobeReplaced;
+    }
+
+    @Override
+    public EvalNode visitChild(EvalNode context, Stack<EvalNode> stack, EvalNode evalNode) {
+      super.visitChild(context, stack, evalNode);
+
+      if (evalNode.equals(target)) {
+        EvalNode parent = stack.peek();
+
+        if (parent.getLeftExpr().equals(evalNode)) {
+          parent.setLeftExpr(tobeReplaced);
+        }
+        if (parent.getRightExpr().equals(evalNode)) {
+          parent.setRightExpr(tobeReplaced);
+        }
+      }
+
+      return evalNode;
+    }
+  }
   
   public static Set<Column> findDistinctRefColumns(EvalNode node) {
     DistinctColumnRefFinder finder = new DistinctColumnRefFinder();
@@ -214,10 +247,6 @@ public class EvalTreeUtil {
         expr.getLeftExpr().getType() == EvalType.FIELD &&
         expr.getRightExpr().getType() == EvalType.FIELD;
   }
-
-  public static boolean isLogicalOperator(EvalNode expr) {
-    return expr.getType() == EvalType.AND || expr.getType() == EvalType.OR;
-  }
   
   public static class ChangeColumnRefVisitor implements EvalNodeVisitor {    
     private final String findColumn;

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e595384b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalType.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalType.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalType.java
index a3fcf40..2e6742f 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalType.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalType.java
@@ -45,13 +45,13 @@ public enum EvalType {
   // Predicate
   LIKE(LikeEval.class),
   CASE(CaseWhenEval.class),
-  WHEN(CaseWhenEval.WhenEval.class),
+  IF_THEN(CaseWhenEval.IfThenEval.class),
   IN(InEval.class),
 
   // Value or Reference
   FIELD(FieldEval.class),
   CONST(ConstEval.class),
-  ROW_CONSTANT(RowConstant.class);
+  ROW_CONSTANT(RowConstantEval.class);
 
   private Class<? extends EvalNode> baseClass;
 

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e595384b/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 6b04948..60dea3b 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
@@ -36,7 +36,7 @@ public class InEval extends BinaryEval {
   private Integer fieldId = null;
   Datum [] values;
 
-  public InEval(FieldEval columnRef, RowConstant valueList, boolean not) {
+  public InEval(FieldEval columnRef, RowConstantEval valueList, boolean not) {
     super(EvalType.IN, columnRef, valueList);
     this.not = not;
   }
@@ -65,7 +65,7 @@ public class InEval extends BinaryEval {
     InEvalCtx isNullCtx = (InEvalCtx) ctx;
     if (fieldId == null) {
       fieldId = schema.getColumnId(((FieldEval)leftExpr).getColumnRef().getQualifiedName());
-      values = ((RowConstant)rightExpr).getValues();
+      values = ((RowConstantEval)rightExpr).getValues();
     }
 
     boolean isIncluded = false;

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e595384b/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 296850c..9fe4679 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
@@ -35,8 +35,7 @@ public class NotEval extends EvalNode implements Cloneable {
 
   public NotEval(EvalNode subExpr) {
     super(EvalType.NOT);
-    Preconditions.checkArgument(
-        subExpr instanceof BinaryEval || subExpr instanceof NotEval);
+    Preconditions.checkArgument(subExpr instanceof BinaryEval || subExpr instanceof NotEval);
     this.subExpr = subExpr;
   }
 
@@ -47,6 +46,10 @@ public class NotEval extends EvalNode implements Cloneable {
     return newCtx;
   }
 
+  public EvalNode getChild() {
+    return subExpr;
+  }
+
   @Override
   public DataType [] getValueType() {
     return RES_TYPE;

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e595384b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/RowConstant.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/RowConstant.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/RowConstant.java
deleted file mode 100644
index 4e473ed..0000000
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/RowConstant.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.tajo.engine.eval;
-
-import com.google.gson.annotations.Expose;
-import org.apache.tajo.catalog.CatalogUtil;
-import org.apache.tajo.common.TajoDataTypes;
-import org.apache.tajo.datum.ArrayDatum;
-import org.apache.tajo.datum.Datum;
-import org.apache.tajo.util.TUtil;
-
-public class RowConstant extends EvalNode {
-  @Expose ArrayDatum values;
-
-  public RowConstant(Datum [] values) {
-    super(EvalType.ROW_CONSTANT);
-    this.values = new ArrayDatum(values);
-  }
-
-  @Override
-  public EvalContext newContext() {
-    return null;
-  }
-
-  @Override
-  public TajoDataTypes.DataType[] getValueType() {
-    return new TajoDataTypes.DataType[] {CatalogUtil.newDataTypeWithoutLen(values.get(0).type())};
-  }
-
-  @Override
-  public String getName() {
-    return "ROW";
-  }
-
-  @Override
-  public Datum terminate(EvalContext ctx) {
-    return values;
-  }
-
-  @Override
-  public boolean equals(Object obj) {
-    if (obj instanceof RowConstant) {
-      RowConstant other = (RowConstant) obj;
-      return TUtil.checkEquals(values, other.values);
-    }
-
-    return false;
-  }
-
-  public String toString() {
-    StringBuilder sb = new StringBuilder("(");
-    for (int i = 0; i < values.toArray().length; i++) {
-      if (i != 0) {
-        sb.append(",");
-      }
-      sb.append(values.get(i).toString());
-    }
-    sb.append(")");
-    return sb.toString();
-  }
-
-  public Datum [] getValues() {
-    return values.toArray();
-  }
-
-  public void preOrder(EvalNodeVisitor visitor) {
-    visitor.visit(this);
-  }
-
-  public void postOrder(EvalNodeVisitor visitor) {
-    visitor.visit(this);
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e595384b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/RowConstantEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/RowConstantEval.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/RowConstantEval.java
new file mode 100644
index 0000000..ecda8ae
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/RowConstantEval.java
@@ -0,0 +1,89 @@
+/**
+ * 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.eval;
+
+import com.google.gson.annotations.Expose;
+import org.apache.tajo.catalog.CatalogUtil;
+import org.apache.tajo.common.TajoDataTypes;
+import org.apache.tajo.datum.ArrayDatum;
+import org.apache.tajo.datum.Datum;
+import org.apache.tajo.util.TUtil;
+
+public class RowConstantEval extends EvalNode {
+  @Expose ArrayDatum values;
+
+  public RowConstantEval(Datum[] values) {
+    super(EvalType.ROW_CONSTANT);
+    this.values = new ArrayDatum(values);
+  }
+
+  @Override
+  public EvalContext newContext() {
+    return null;
+  }
+
+  @Override
+  public TajoDataTypes.DataType[] getValueType() {
+    return new TajoDataTypes.DataType[] {CatalogUtil.newDataTypeWithoutLen(values.get(0).type())};
+  }
+
+  @Override
+  public String getName() {
+    return "ROW";
+  }
+
+  @Override
+  public Datum terminate(EvalContext ctx) {
+    return values;
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (obj instanceof RowConstantEval) {
+      RowConstantEval other = (RowConstantEval) obj;
+      return TUtil.checkEquals(values, other.values);
+    }
+
+    return false;
+  }
+
+  public String toString() {
+    StringBuilder sb = new StringBuilder("(");
+    for (int i = 0; i < values.toArray().length; i++) {
+      if (i != 0) {
+        sb.append(",");
+      }
+      sb.append(values.get(i).toString());
+    }
+    sb.append(")");
+    return sb.toString();
+  }
+
+  public Datum [] getValues() {
+    return values.toArray();
+  }
+
+  public void preOrder(EvalNodeVisitor visitor) {
+    visitor.visit(this);
+  }
+
+  public void postOrder(EvalNodeVisitor visitor) {
+    visitor.visit(this);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e595384b/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 e373d76..8429759 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
@@ -117,7 +117,9 @@ public class HiveConverter extends HiveParserBaseVisitor<Expr>{
 
             if(ctx.havingClause() != null) {
                 Expr havingCondition = visitHavingClause(ctx.havingClause());
-                aggregation.setHavingCondition(havingCondition);
+                Having having = new Having(havingCondition);
+                having.setChild(current);
+                current = having;
             }
         }
 
@@ -213,8 +215,10 @@ public class HiveConverter extends HiveParserBaseVisitor<Expr>{
                 current = aggregation;
 
                 if(ctx.havingClause() != null) {
-                    Expr havingCondition = visitHavingClause(ctx.havingClause());
-                    aggregation.setHavingCondition(havingCondition);
+                  Expr havingCondition = visitHavingClause(ctx.havingClause());
+                  Having having = new Having(havingCondition);
+                  having.setChild(current);
+                  current = having;
                 }
             }
 
@@ -325,8 +329,10 @@ public class HiveConverter extends HiveParserBaseVisitor<Expr>{
             current = aggregation;
 
             if(ctx.havingClause() != null) {
-                Expr havingCondition = visitHavingClause(ctx.havingClause());
-                aggregation.setHavingCondition(havingCondition);
+              Expr havingCondition = visitHavingClause(ctx.havingClause());
+              Having having = new Having(havingCondition);
+              having.setChild(current);
+              current = having;
             }
         }
 

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e595384b/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 60025f4..97c66b5 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
@@ -172,7 +172,9 @@ public class SQLAnalyzer extends SQLParserBaseVisitor<Expr> {
         if (ctx.table_expression().having_clause() != null) {
           Expr havingCondition = visitBoolean_value_expression(
               ctx.table_expression().having_clause().boolean_value_expression());
-          aggregation.setHavingCondition(havingCondition);
+          Having having = new Having(havingCondition);
+          having.setChild(current);
+          current = having;
         }
       }
 

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e595384b/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 78422b0..633609a 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
@@ -22,19 +22,20 @@ import org.apache.tajo.algebra.*;
 
 import java.util.Stack;
 
-public interface AlgebraVisitor<T1, T2> {
-  T2 visitProjection(T1 ctx, Stack<OpType> stack, Projection expr) throws PlanningException;
-  T2 visitLimit(T1 ctx, Stack<OpType> stack, Limit expr) throws PlanningException;
-  T2 visitSort(T1 ctx, Stack<OpType> stack, Sort expr) throws PlanningException;
-  T2 visitGroupBy(T1 ctx, Stack<OpType> stack, Aggregation expr) throws PlanningException;
-  T2 visitJoin(T1 ctx, Stack<OpType> stack, Join expr) throws PlanningException;
-  T2 visitFilter(T1 ctx, Stack<OpType> stack, Selection expr) throws PlanningException;
-  T2 visitUnion(T1 ctx, Stack<OpType> stack, SetOperation expr) throws PlanningException;
-  T2 visitExcept(T1 ctx, Stack<OpType> stack, SetOperation expr) throws PlanningException;
-  T2 visitIntersect(T1 ctx, Stack<OpType> stack, SetOperation expr) throws PlanningException;
-  T2 visitRelationList(T1 ctx, Stack<OpType> stack, RelationList expr) throws PlanningException;
-  T2 visitTableSubQuery(T1 ctx, Stack<OpType> stack, TableSubQuery expr) throws PlanningException;
-  T2 visitRelation(T1 ctx, Stack<OpType> stack, Relation expr) throws PlanningException;
-  T2 visitCreateTable(T1 ctx, Stack<OpType> stack, CreateTable expr) throws PlanningException;
-  T2 visitDropTable(T1 ctx, Stack<OpType> stack, DropTable expr) throws PlanningException;
+public interface AlgebraVisitor<CONTEXT, RESULT> {
+  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 visitRelationList(CONTEXT ctx, Stack<OpType> stack, RelationList expr) throws PlanningException;
+  RESULT visitTableSubQuery(CONTEXT ctx, Stack<OpType> stack, TableSubQuery expr) throws PlanningException;
+  RESULT visitRelation(CONTEXT ctx, Stack<OpType> stack, Relation expr) throws PlanningException;
+  RESULT visitCreateTable(CONTEXT ctx, Stack<OpType> stack, CreateTable expr) throws PlanningException;
+  RESULT visitDropTable(CONTEXT ctx, Stack<OpType> stack, DropTable expr) throws PlanningException;
 }

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e595384b/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 16df8f8..06ab38c 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
@@ -58,6 +58,9 @@ public abstract class BaseAlgebraVisitor<CONTEXT, RESULT> implements AlgebraVisi
       case Sort:
         current = visitSort(ctx, stack, (Sort) expr);
         break;
+      case Having:
+        current = visitHaving(ctx, stack, (Having) expr);
+        break;
       case Aggregation:
         current = visitGroupBy(ctx, stack, (Aggregation) expr);
         break;
@@ -135,6 +138,14 @@ public abstract class BaseAlgebraVisitor<CONTEXT, RESULT> implements AlgebraVisi
   }
 
   @Override
+  public RESULT visitHaving(CONTEXT ctx, Stack<OpType> stack, Having expr) throws PlanningException {
+    stack.push(expr.getType());
+    RESULT child = visitChild(ctx, stack, expr.getChild());
+    stack.pop();
+    return child;
+  }
+
+  @Override
   public RESULT visitGroupBy(CONTEXT ctx, Stack<OpType> stack, Aggregation expr) throws PlanningException {
     stack.push(expr.getType());
     RESULT child = visitChild(ctx, stack, expr.getChild());
@@ -215,7 +226,7 @@ public abstract class BaseAlgebraVisitor<CONTEXT, RESULT> implements AlgebraVisi
     stack.push(expr.getType());
     RESULT child = null;
     if (expr.hasSubQuery()) {
-       child = visitChild(ctx, stack, expr.getSubQuery());
+      child = visitChild(ctx, stack, expr.getSubQuery());
     }
     stack.pop();
     return child;

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e595384b/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 b58b05e..0a564d9 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
@@ -93,127 +93,127 @@ public class BasicLogicalPlanVisitor<T> implements LogicalPlanVisitor<T> {
   }
 
   @Override
-  public LogicalNode visitRoot(LogicalPlan plan, LogicalRootNode node, Stack<LogicalNode> stack, T data)
+  public LogicalNode visitRoot(LogicalPlan plan, LogicalRootNode node, Stack<LogicalNode> stack, T context)
       throws PlanningException {
     stack.push(node);
-    visitChild(plan, node.getChild(), stack, data);
+    visitChild(plan, node.getChild(), stack, context);
     stack.pop();
     return node;
   }
 
   @Override
-  public LogicalNode visitProjection(LogicalPlan plan, ProjectionNode node, Stack<LogicalNode> stack, T data)
+  public LogicalNode visitProjection(LogicalPlan plan, ProjectionNode node, Stack<LogicalNode> stack, T context)
       throws PlanningException {
     stack.push(node);
-    visitChild(plan, node.getChild(), stack, data);
+    visitChild(plan, node.getChild(), stack, context);
     stack.pop();
     return node;
   }
 
   @Override
-  public LogicalNode visitLimit(LogicalPlan plan, LimitNode node, Stack<LogicalNode> stack, T data)
+  public LogicalNode visitLimit(LogicalPlan plan, LimitNode node, Stack<LogicalNode> stack, T context)
       throws PlanningException {
     stack.push(node);
-    visitChild(plan, node.getChild(), stack, data);
+    visitChild(plan, node.getChild(), stack, context);
     stack.pop();
     return node;
   }
 
   @Override
-  public LogicalNode visitSort(LogicalPlan plan, SortNode node, Stack<LogicalNode> stack, T data)
+  public LogicalNode visitSort(LogicalPlan plan, SortNode node, Stack<LogicalNode> stack, T context)
       throws PlanningException {
     stack.push(node);
-    visitChild(plan, node.getChild(), stack, data);
+    visitChild(plan, node.getChild(), stack, context);
     stack.pop();
     return node;
   }
 
   @Override
-  public LogicalNode visitGroupBy(LogicalPlan plan, GroupbyNode node, Stack<LogicalNode> stack, T data)
+  public LogicalNode visitGroupBy(LogicalPlan plan, GroupbyNode node, Stack<LogicalNode> stack, T context)
       throws PlanningException {
     stack.push(node);
-    visitChild(plan, node.getChild(), stack, data);
+    visitChild(plan, node.getChild(), stack, context);
     stack.pop();
     return node;
   }
 
   @Override
-  public LogicalNode visitFilter(LogicalPlan plan, SelectionNode node, Stack<LogicalNode> stack, T data)
+  public LogicalNode visitFilter(LogicalPlan plan, SelectionNode node, Stack<LogicalNode> stack, T context)
       throws PlanningException {
     stack.push(node);
-    visitChild(plan, node.getChild(), stack, data);
+    visitChild(plan, node.getChild(), stack, context);
     stack.pop();
     return node;
   }
 
   @Override
-  public LogicalNode visitJoin(LogicalPlan plan, JoinNode node, Stack<LogicalNode> stack, T data)
+  public LogicalNode visitJoin(LogicalPlan plan, JoinNode node, Stack<LogicalNode> stack, T context)
       throws PlanningException {
     stack.push(node);
-    visitChild(plan, node.getLeftChild(), stack, data);
-    visitChild(plan, node.getRightChild(), stack, data);
+    visitChild(plan, node.getLeftChild(), stack, context);
+    visitChild(plan, node.getRightChild(), stack, context);
     stack.pop();
     return node;
   }
 
   @Override
-  public LogicalNode visitUnion(LogicalPlan plan, UnionNode node, Stack<LogicalNode> stack, T data)
+  public LogicalNode visitUnion(LogicalPlan plan, UnionNode node, Stack<LogicalNode> stack, T context)
       throws PlanningException {
     stack.push(node);
-    visitChild(plan, node.getLeftChild(), stack, data);
-    visitChild(plan, node.getRightChild(), stack, data);
+    visitChild(plan, node.getLeftChild(), stack, context);
+    visitChild(plan, node.getRightChild(), stack, context);
     stack.pop();
     return node;
   }
 
   @Override
-  public LogicalNode visitExcept(LogicalPlan plan, ExceptNode node, Stack<LogicalNode> stack, T data)
+  public LogicalNode visitExcept(LogicalPlan plan, ExceptNode node, Stack<LogicalNode> stack, T context)
       throws PlanningException {
     stack.push(node);
-    visitChild(plan, node.getLeftChild(), stack, data);
-    visitChild(plan, node.getRightChild(), stack, data);
+    visitChild(plan, node.getLeftChild(), stack, context);
+    visitChild(plan, node.getRightChild(), stack, context);
     stack.pop();
     return node;
   }
 
   @Override
-  public LogicalNode visitIntersect(LogicalPlan plan, IntersectNode node, Stack<LogicalNode> stack, T data)
+  public LogicalNode visitIntersect(LogicalPlan plan, IntersectNode node, Stack<LogicalNode> stack, T context)
       throws PlanningException {
     stack.push(node);
-    visitChild(plan, node.getLeftChild(), stack, data);
-    visitChild(plan, node.getRightChild(), stack, data);
+    visitChild(plan, node.getLeftChild(), stack, context);
+    visitChild(plan, node.getRightChild(), stack, context);
     stack.pop();
     return node;
   }
 
   @Override
-  public LogicalNode visitTableSubQuery(LogicalPlan plan, TableSubQueryNode node, Stack<LogicalNode> stack, T data)
+  public LogicalNode visitTableSubQuery(LogicalPlan plan, TableSubQueryNode node, Stack<LogicalNode> stack, T context)
       throws PlanningException {
     stack.push(node);
-    visitChild(plan, node.getSubQuery(), stack, data);
+    visitChild(plan, node.getSubQuery(), stack, context);
     stack.pop();
     return node;
   }
 
   @Override
-  public LogicalNode visitScan(LogicalPlan plan, ScanNode node, Stack<LogicalNode> stack, T data)
+  public LogicalNode visitScan(LogicalPlan plan, ScanNode node, Stack<LogicalNode> stack, T context)
       throws PlanningException {
     return node;
   }
 
   @Override
-  public LogicalNode visitStoreTable(LogicalPlan plan, StoreTableNode node, Stack<LogicalNode> stack, T data)
+  public LogicalNode visitStoreTable(LogicalPlan plan, StoreTableNode node, Stack<LogicalNode> stack, T context)
       throws PlanningException {
     stack.push(node);
-    visitChild(plan, node.getChild(), stack, data);
+    visitChild(plan, node.getChild(), stack, context);
     stack.pop();
     return node;
   }
 
   @Override
-  public LogicalNode visitInsert(LogicalPlan plan, InsertNode node, Stack<LogicalNode> stack, T data) throws PlanningException {
+  public LogicalNode visitInsert(LogicalPlan plan, InsertNode node, Stack<LogicalNode> stack, T context) throws PlanningException {
     stack.push(node);
-    visitChild(plan, node.getSubQuery(), stack, data);
+    visitChild(plan, node.getSubQuery(), stack, context);
     stack.pop();
     return node;
   }

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e595384b/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 d572494..ce07d77 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
@@ -72,11 +72,12 @@ public class ExplainLogicalPlanVisitor extends BasicLogicalPlanVisitor<ExplainLo
   }
 
   @Override
-  public LogicalNode visitRoot(LogicalPlan plan, LogicalRootNode node, Stack<LogicalNode> stack, Context data)
+  public LogicalNode visitRoot(LogicalPlan plan, LogicalRootNode node, Stack<LogicalNode> stack, Context context)
       throws PlanningException {
-    return visitChild(plan, node.getChild(), stack, data);
+    return visitChild(plan, node.getChild(), stack, context);
   }
 
+  @Override
   public LogicalNode visitProjection(LogicalPlan plan, ProjectionNode node, Stack<LogicalNode> stack,
                                      Context context) throws PlanningException {
     return visitUnaryNode(plan, node, stack, context);
@@ -88,11 +89,13 @@ public class ExplainLogicalPlanVisitor extends BasicLogicalPlanVisitor<ExplainLo
     return visitUnaryNode(plan, node, stack, context);
   }
 
+  @Override
   public LogicalNode visitSort(LogicalPlan plan, SortNode node, Stack<LogicalNode> stack,
                                Context context) throws PlanningException {
     return visitUnaryNode(plan, node, stack, context);
   }
 
+  @Override
   public LogicalNode visitGroupBy(LogicalPlan plan, GroupbyNode node, Stack<LogicalNode> stack,
                                   Context context) throws PlanningException {
     return visitUnaryNode(plan, node, stack, context);
@@ -120,6 +123,7 @@ public class ExplainLogicalPlanVisitor extends BasicLogicalPlanVisitor<ExplainLo
     return node;
   }
 
+  @Override
   public LogicalNode visitFilter(LogicalPlan plan, SelectionNode node, Stack<LogicalNode> stack,
                                  Context context) throws PlanningException {
     return visitUnaryNode(plan, node, stack, context);

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e595384b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlan.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlan.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlan.java
index d81165f..fb1f729 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlan.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlan.java
@@ -18,15 +18,11 @@
 
 package org.apache.tajo.engine.planner;
 
-import org.apache.tajo.algebra.ColumnReferenceExpr;
-import org.apache.tajo.algebra.OpType;
-import org.apache.tajo.algebra.Projection;
+import org.apache.tajo.algebra.*;
 import org.apache.tajo.annotation.NotThreadSafe;
 import org.apache.tajo.catalog.Column;
 import org.apache.tajo.catalog.Schema;
-import org.apache.tajo.engine.eval.EvalNode;
-import org.apache.tajo.engine.eval.EvalTreeUtil;
-import org.apache.tajo.engine.eval.EvalType;
+import org.apache.tajo.engine.eval.*;
 import org.apache.tajo.engine.planner.graph.SimpleDirectedGraph;
 import org.apache.tajo.engine.planner.logical.*;
 import org.apache.tajo.util.TUtil;
@@ -320,15 +316,15 @@ public class LogicalPlan {
     private LogicalNode rootNode;
     private NodeType rootType;
     private Map<String, RelationNode> relations = new HashMap<String, RelationNode>();
-    private Projection projection;
+    private Map<OpType, List<Expr>> algebraicExprs = TUtil.newHashMap();
 
     // changing states
     private LogicalNode latestNode;
     private boolean resolvedGrouping = true;
     private boolean hasGrouping;
     private Projectable projectionNode;
-    private SelectionNode selectionNode;
     private GroupbyNode groupingNode;
+    private SelectionNode selectionNode;
     private StoreTableNode storeTableNode;
     private InsertNode insertNode;
     private Schema schema;
@@ -404,12 +400,40 @@ public class LogicalPlan {
       return (T) this.latestNode;
     }
 
-    public void setProjection(Projection projection) {
-      this.projection = projection;
+    public void setAlgebraicExpr(Expr expr) {
+      TUtil.putToNestedList(algebraicExprs, expr.getType(), expr);
+    }
+
+    public boolean hasAlgebraicExpr(OpType opType) {
+      return algebraicExprs.containsKey(opType);
+    }
+
+    public <T extends Expr> List<T> getAlgebraicExpr(OpType opType) {
+      return (List<T>) algebraicExprs.get(opType);
+    }
+
+    public <T extends Expr> T getSingletonExpr(OpType opType) {
+      if (hasAlgebraicExpr(opType)) {
+        return (T) algebraicExprs.get(opType).get(0);
+      } else {
+        return null;
+      }
+    }
+
+    public boolean hasProjection() {
+      return hasAlgebraicExpr(OpType.Projection);
     }
 
     public Projection getProjection() {
-      return this.projection;
+      return getSingletonExpr(OpType.Projection);
+    }
+
+    public boolean hasHaving() {
+      return hasAlgebraicExpr(OpType.Having);
+    }
+
+    public Having getHaving() {
+      return getSingletonExpr(OpType.Having);
     }
 
     public void setProjectionNode(Projectable node) {
@@ -424,7 +448,7 @@ public class LogicalPlan {
       return this.resolvedGrouping;
     }
 
-    public void needToResolveGrouping() {
+    public void resolveGroupingRequired() {
       this.resolvedGrouping = true;
     }
 
@@ -434,18 +458,18 @@ public class LogicalPlan {
     }
 
     public boolean hasGrouping() {
-      return hasGrouping || hasGroupingNode();
+      return hasGrouping || hasGroupbyNode();
     }
 
-    public boolean hasGroupingNode() {
+    public boolean hasGroupbyNode() {
       return this.groupingNode != null;
     }
 
-    public void setGroupingNode(GroupbyNode groupingNode) {
+    public void setGroupbyNode(GroupbyNode groupingNode) {
       this.groupingNode = groupingNode;
     }
 
-    public GroupbyNode getGroupingNode() {
+    public GroupbyNode getGroupbyNode() {
       return this.groupingNode;
     }
 
@@ -502,7 +526,8 @@ public class LogicalPlan {
           break;
 
         case GROUP_BY:
-          needToResolveGrouping();
+          resolveGroupingRequired();
+          setGroupbyNode((GroupbyNode) node);
           break;
 
         case SELECTION:
@@ -574,7 +599,7 @@ public class LogicalPlan {
     }
 
     public void fillTarget(int idx) throws VerifyException {
-      targetListManager.update(idx, planner.createTarget(LogicalPlan.this, this, projection.getTargets()[idx]));
+      targetListManager.update(idx, planner.createTarget(LogicalPlan.this, this, getProjection().getTargets()[idx]));
     }
 
     public boolean checkIfTargetCanBeEvaluated(int targetId, LogicalNode node) {
@@ -607,7 +632,7 @@ public class LogicalPlan {
 
     public void checkAndResolveTargets(LogicalNode node) throws PlanningException {
       // If all columns are projected and do not include any expression
-      if (projection.isAllProjected() && node instanceof RelationNode) {
+      if (getProjection().isAllProjected() && node instanceof RelationNode) {
         initTargetList(PlannerUtil.schemaToTargets(node.getOutSchema()));
         resolveAllTargetList();
 
@@ -682,8 +707,31 @@ public class LogicalPlan {
           }
         } else if (node instanceof GroupbyNode) {
           // Set the current targets to the GroupByNode because the GroupByNode is the last projection operator.
-          ((Projectable)node).setTargets(getCurrentTargets());
+          GroupbyNode groupbyNode = (GroupbyNode) node;
+          groupbyNode.setTargets(getCurrentTargets());
           node.setOutSchema(updateSchema());
+
+          // if a having condition is given,
+          if (hasHaving()) {
+            EvalNode havingCondition = planner.createEvalTree(LogicalPlan.this, this, getHaving().getQual());
+            List<AggFuncCallEval> aggrFunctions = EvalTreeUtil.findDistinctAggFunction(havingCondition);
+
+            if (aggrFunctions.size() == 0) {
+              groupbyNode.setHavingCondition(havingCondition);
+            } else {
+              Target [] addedTargets = new Target[aggrFunctions.size()];
+              for (int i = 0; i < aggrFunctions.size(); i++) {
+                Target aggrFunctionTarget = new Target(aggrFunctions.get(i), newAnonymousColumnName());
+                addedTargets[i] = aggrFunctionTarget;
+                EvalTreeUtil.replace(havingCondition, aggrFunctions.get(i),
+                    new FieldEval(aggrFunctionTarget.getColumnSchema()));
+              }
+              Target [] updatedTargets = TUtil.concat(groupbyNode.getTargets(), addedTargets);
+              groupbyNode.setTargets(updatedTargets);
+              groupbyNode.setHavingCondition(havingCondition);
+              groupbyNode.setHavingSchema(PlannerUtil.targetToSchema(groupbyNode.getTargets()));
+            }
+          }
         }
       }
     }

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e595384b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlanVisitor.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlanVisitor.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlanVisitor.java
index ca5a8f0..d0a1cf6 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlanVisitor.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlanVisitor.java
@@ -22,33 +22,33 @@ import org.apache.tajo.engine.planner.logical.*;
 
 import java.util.Stack;
 
-public interface LogicalPlanVisitor <T> {
-  LogicalNode visitRoot(LogicalPlan plan, LogicalRootNode node, Stack<LogicalNode> stack, T data)
+public interface LogicalPlanVisitor <CONTEXT> {
+  LogicalNode visitRoot(LogicalPlan plan, LogicalRootNode node, Stack<LogicalNode> stack, CONTEXT context)
       throws PlanningException;
-  LogicalNode visitProjection(LogicalPlan plan, ProjectionNode node, Stack<LogicalNode> stack, T data)
+  LogicalNode visitProjection(LogicalPlan plan, ProjectionNode node, Stack<LogicalNode> stack, CONTEXT context)
       throws PlanningException;
-  LogicalNode visitLimit(LogicalPlan plan, LimitNode node, Stack<LogicalNode> stack, T data)
+  LogicalNode visitLimit(LogicalPlan plan, LimitNode node, Stack<LogicalNode> stack, CONTEXT context)
       throws PlanningException;
-  LogicalNode visitSort(LogicalPlan plan, SortNode node, Stack<LogicalNode> stack, T data)
+  LogicalNode visitSort(LogicalPlan plan, SortNode node, Stack<LogicalNode> stack, CONTEXT context)
       throws PlanningException;
-  LogicalNode visitGroupBy(LogicalPlan plan, GroupbyNode node, Stack<LogicalNode> stack, T data)
+  LogicalNode visitGroupBy(LogicalPlan plan, GroupbyNode node, Stack<LogicalNode> stack, CONTEXT context)
       throws PlanningException;
-  LogicalNode visitFilter(LogicalPlan plan, SelectionNode node, Stack<LogicalNode> stack, T data)
+  LogicalNode visitFilter(LogicalPlan plan, SelectionNode node, Stack<LogicalNode> stack, CONTEXT context)
       throws PlanningException;
-  LogicalNode visitJoin(LogicalPlan plan, JoinNode node, Stack<LogicalNode> stack, T data)
+  LogicalNode visitJoin(LogicalPlan plan, JoinNode node, Stack<LogicalNode> stack, CONTEXT context)
       throws PlanningException;
-  LogicalNode visitUnion(LogicalPlan plan, UnionNode node, Stack<LogicalNode> stack, T data)
+  LogicalNode visitUnion(LogicalPlan plan, UnionNode node, Stack<LogicalNode> stack, CONTEXT context)
       throws PlanningException;
-  LogicalNode visitExcept(LogicalPlan plan, ExceptNode node, Stack<LogicalNode> stack, T data)
+  LogicalNode visitExcept(LogicalPlan plan, ExceptNode node, Stack<LogicalNode> stack, CONTEXT context)
       throws PlanningException;
-  LogicalNode visitIntersect(LogicalPlan plan, IntersectNode node, Stack<LogicalNode> stack, T data)
+  LogicalNode visitIntersect(LogicalPlan plan, IntersectNode node, Stack<LogicalNode> stack, CONTEXT context)
       throws PlanningException;
-  LogicalNode visitTableSubQuery(LogicalPlan plan, TableSubQueryNode node, Stack<LogicalNode> stack, T data)
+  LogicalNode visitTableSubQuery(LogicalPlan plan, TableSubQueryNode node, Stack<LogicalNode> stack, CONTEXT context)
       throws PlanningException;
-  LogicalNode visitScan(LogicalPlan plan, ScanNode node, Stack<LogicalNode> stack, T data)
+  LogicalNode visitScan(LogicalPlan plan, ScanNode node, Stack<LogicalNode> stack, CONTEXT context)
       throws PlanningException;
-  LogicalNode visitStoreTable(LogicalPlan plan, StoreTableNode node, Stack<LogicalNode> stack, T data)
+  LogicalNode visitStoreTable(LogicalPlan plan, StoreTableNode node, Stack<LogicalNode> stack, CONTEXT context)
       throws PlanningException;
-  LogicalNode visitInsert(LogicalPlan plan, InsertNode node, Stack<LogicalNode> stack, T data)
+  LogicalNode visitInsert(LogicalPlan plan, InsertNode node, Stack<LogicalNode> stack, CONTEXT context)
       throws PlanningException;
 }

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e595384b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlanner.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlanner.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlanner.java
index ed5b54e..17f3634 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlanner.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlanner.java
@@ -87,7 +87,7 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
   public LogicalPlan createPlan(Expr expr) throws PlanningException {
 
     LogicalPlan plan = new LogicalPlan(this);
-    LogicalNode subroot = null;
+    LogicalNode subroot;
 
     Stack<OpType> stack = new Stack<OpType>();
 
@@ -106,6 +106,7 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
 
   public void preHook(PlanContext context, Stack<OpType> stack, Expr expr) {
     context.block = checkIfNewBlockOrGet(context.plan, context.block.getName());
+    context.block.setAlgebraicExpr(expr);
   }
 
   public LogicalNode postHook(PlanContext context, Stack<OpType> stack, Expr expr, LogicalNode current)
@@ -441,7 +442,7 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
 
       // 4. Set Child Plan and Update Input Schemes Phase
       groupingNode.setChild(child);
-      block.setGroupingNode(groupingNode);
+      block.setGroupbyNode(groupingNode);
       groupingNode.setInSchema(child.getOutSchema());
 
       // 5. Update Output Schema and Targets for Upper Plan
@@ -452,7 +453,7 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
       List<Column[]> cuboids  = generateCuboids(annotateGroupingColumn(plan, block.getName(),
           groupElements[0].getColumns(), null));
       UnionNode topUnion = createGroupByUnion(plan, block, child, cuboids, 0);
-      block.needToResolveGrouping();
+      block.resolveGroupingRequired();
       block.getTargetListManager().resolveAll();
 
       return topUnion;
@@ -573,7 +574,7 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
     // 2. Build Child Plans:
     stack.push(OpType.Sort);
     LogicalNode child = visitChild(context, stack, sort.getChild());
-    child = insertGroupingIfUnresolved(plan, block, child, stack);
+    child = insertGroupbyNodeIfUnresolved(block, child, stack);
     stack.pop();
 
     // 3. Build this plan:
@@ -630,7 +631,6 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
     LogicalPlan plan = context.plan;
     QueryBlock block = context.block;
 
-    block.setProjection(projection);
     if (!projection.isAllProjected()) {
       block.targetListManager = new TargetListManager(plan, projection);
     }
@@ -649,7 +649,7 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
     // 2: Build Child Plans
     stack.push(OpType.Projection);
     LogicalNode child = visitChild(context, stack, projection.getChild());
-    child = insertGroupingIfUnresolved(plan, block, child, stack);
+    child = insertGroupbyNodeIfUnresolved(block, child, stack);
     stack.pop();
 
     // All targets must be evaluable before the projection.
@@ -689,8 +689,8 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
    * Insert a group-by operator before a sort or a projection operator.
    * It is used only when a group-by clause is not given.
    */
-  private LogicalNode insertGroupingIfUnresolved(LogicalPlan plan, QueryBlock block,
-                                                 LogicalNode child, Stack<OpType> stack) throws PlanningException {
+  private LogicalNode insertGroupbyNodeIfUnresolved(QueryBlock block,
+                                                    LogicalNode child, Stack<OpType> stack) throws PlanningException {
 
     if (!block.isGroupingResolved()) {
       GroupbyNode groupbyNode = new GroupbyNode(new Column[] {});
@@ -921,6 +921,8 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
       case Literal:
         LiteralValue literal = (LiteralValue) expr;
         switch (literal.getValueType()) {
+          case Boolean:
+            return new ConstEval(DatumFactory.createBool(literal.getValue()));
           case String:
             return new ConstEval(DatumFactory.createText(literal.getValue()));
           case Unsigned_Integer:
@@ -941,7 +943,7 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
           constEvals[i] = (ConstEval) createEvalTree(plan, block, valueList.getValues()[i]);
           values[i] = constEvals[i].getValue();
         }
-        return new RowConstant(values);
+        return new RowConstantEval(values);
       }
 
         // unary expression
@@ -960,8 +962,8 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
         InPredicate inPredicate = (InPredicate) expr;
         FieldEval predicand =
             new FieldEval(plan.resolveColumn(block, null, (ColumnReferenceExpr) inPredicate.getPredicand()));
-        RowConstant rowConstant = (RowConstant) createEvalTree(plan, block, inPredicate.getInValue());
-        return new InEval(predicand, rowConstant, inPredicate.isNot());
+        RowConstantEval rowConstantEval = (RowConstantEval) createEvalTree(plan, block, inPredicate.getInValue());
+        return new InEval(predicand, rowConstantEval, inPredicate.isNot());
       }
 
       case Is:
@@ -1021,7 +1023,9 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
         }
 
         FunctionDesc funcDesc = catalog.getFunction(setFunction.getSignature(), paramTypes);
-        block.setHasGrouping();
+        if (!block.hasGroupbyNode()) {
+          block.setHasGrouping();
+        }
         try {
           return new AggFuncCallEval(funcDesc, (AggFunction) funcDesc.newInstance(), givenArgs);
         } catch (InternalException e) {
@@ -1055,7 +1059,9 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
             return new FuncCallEval(funcDesc,
                 (GeneralFunction) funcDesc.newInstance(), givenArgs);
           else {
-            block.setHasGrouping();
+            if (!block.hasGroupbyNode()) {
+              block.setHasGrouping();
+            }
             return new AggFuncCallEval(funcDesc,
                 (AggFunction) funcDesc.newInstance(), givenArgs);
           }

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e595384b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/PhysicalPlannerImpl.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/PhysicalPlannerImpl.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/PhysicalPlannerImpl.java
index e6a0e51..b118852 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/PhysicalPlannerImpl.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/PhysicalPlannerImpl.java
@@ -92,8 +92,8 @@ public class PhysicalPlannerImpl implements PhysicalPlanner {
   }
 
   private PhysicalExec createPlanRecursive(TaskAttemptContext ctx, LogicalNode logicalNode) throws IOException {
-    PhysicalExec outer;
-    PhysicalExec inner;
+    PhysicalExec leftExec;
+    PhysicalExec rightExec;
 
     switch (logicalNode.getType()) {
 
@@ -107,60 +107,60 @@ public class PhysicalPlannerImpl implements PhysicalPlanner {
 
       case STORE:
         StoreTableNode storeNode = (StoreTableNode) logicalNode;
-        outer = createPlanRecursive(ctx, storeNode.getChild());
-        return createStorePlan(ctx, storeNode, outer);
+        leftExec = createPlanRecursive(ctx, storeNode.getChild());
+        return createStorePlan(ctx, storeNode, leftExec);
 
       case SELECTION:
         SelectionNode selNode = (SelectionNode) logicalNode;
-        outer = createPlanRecursive(ctx, selNode.getChild());
-        return new SelectionExec(ctx, selNode, outer);
+        leftExec = createPlanRecursive(ctx, selNode.getChild());
+        return new SelectionExec(ctx, selNode, leftExec);
 
       case PROJECTION:
         ProjectionNode prjNode = (ProjectionNode) logicalNode;
-        outer = createPlanRecursive(ctx, prjNode.getChild());
-        return new ProjectionExec(ctx, prjNode, outer);
+        leftExec = createPlanRecursive(ctx, prjNode.getChild());
+        return new ProjectionExec(ctx, prjNode, leftExec);
 
       case TABLE_SUBQUERY: {
         TableSubQueryNode subQueryNode = (TableSubQueryNode) logicalNode;
-        outer = createPlanRecursive(ctx, subQueryNode.getSubQuery());
-        return outer;
+        leftExec = createPlanRecursive(ctx, subQueryNode.getSubQuery());
+        return leftExec;
 
       } case SCAN:
-        outer = createScanPlan(ctx, (ScanNode) logicalNode);
-        return outer;
+        leftExec = createScanPlan(ctx, (ScanNode) logicalNode);
+        return leftExec;
 
       case GROUP_BY:
         GroupbyNode grpNode = (GroupbyNode) logicalNode;
-        outer = createPlanRecursive(ctx, grpNode.getChild());
-        return createGroupByPlan(ctx, grpNode, outer);
+        leftExec = createPlanRecursive(ctx, grpNode.getChild());
+        return createGroupByPlan(ctx, grpNode, leftExec);
 
       case SORT:
         SortNode sortNode = (SortNode) logicalNode;
-        outer = createPlanRecursive(ctx, sortNode.getChild());
-        return createSortPlan(ctx, sortNode, outer);
+        leftExec = createPlanRecursive(ctx, sortNode.getChild());
+        return createSortPlan(ctx, sortNode, leftExec);
 
       case JOIN:
         JoinNode joinNode = (JoinNode) logicalNode;
-        outer = createPlanRecursive(ctx, joinNode.getLeftChild());
-        inner = createPlanRecursive(ctx, joinNode.getRightChild());
-        return createJoinPlan(ctx, joinNode, outer, inner);
+        leftExec = createPlanRecursive(ctx, joinNode.getLeftChild());
+        rightExec = createPlanRecursive(ctx, joinNode.getRightChild());
+        return createJoinPlan(ctx, joinNode, leftExec, rightExec);
 
       case UNION:
         UnionNode unionNode = (UnionNode) logicalNode;
-        outer = createPlanRecursive(ctx, unionNode.getLeftChild());
-        inner = createPlanRecursive(ctx, unionNode.getRightChild());
-        return new UnionExec(ctx, outer, inner);
+        leftExec = createPlanRecursive(ctx, unionNode.getLeftChild());
+        rightExec = createPlanRecursive(ctx, unionNode.getRightChild());
+        return new UnionExec(ctx, leftExec, rightExec);
 
       case LIMIT:
         LimitNode limitNode = (LimitNode) logicalNode;
-        outer = createPlanRecursive(ctx, limitNode.getChild());
+        leftExec = createPlanRecursive(ctx, limitNode.getChild());
         return new LimitExec(ctx, limitNode.getInSchema(),
-            limitNode.getOutSchema(), outer, limitNode);
+            limitNode.getOutSchema(), leftExec, limitNode);
 
       case BST_INDEX_SCAN:
         IndexScanNode indexScanNode = (IndexScanNode) logicalNode;
-        outer = createIndexScanExec(ctx, indexScanNode);
-        return outer;
+        leftExec = createIndexScanExec(ctx, indexScanNode);
+        return leftExec;
 
       default:
         return null;

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e595384b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/Target.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/Target.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/Target.java
index 670cbfb..7e2bc16 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/Target.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/Target.java
@@ -82,7 +82,7 @@ public class Target implements Cloneable, GsonObject {
   public String toString() {
     StringBuilder sb = new StringBuilder(expr.toString());
     if(hasAlias()) {
-      sb.append(", alias=").append(alias);
+      sb.append(" as ").append(alias);
     }
     return sb.toString();
   }

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e595384b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/GroupbyNode.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/GroupbyNode.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/GroupbyNode.java
index 34da374..5c4e28e 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/GroupbyNode.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/GroupbyNode.java
@@ -20,6 +20,7 @@ package org.apache.tajo.engine.planner.logical;
 
 import com.google.gson.annotations.Expose;
 import org.apache.tajo.catalog.Column;
+import org.apache.tajo.catalog.Schema;
 import org.apache.tajo.engine.eval.EvalNode;
 import org.apache.tajo.engine.planner.PlanString;
 import org.apache.tajo.engine.planner.Target;
@@ -27,6 +28,7 @@ import org.apache.tajo.util.TUtil;
 
 public class GroupbyNode extends UnaryNode implements Projectable, Cloneable {
 	@Expose private Column [] columns;
+  @Expose private Schema havingSchema;
 	@Expose private EvalNode havingCondition = null;
 	@Expose private Target [] targets;
 	
@@ -65,6 +67,14 @@ public class GroupbyNode extends UnaryNode implements Projectable, Cloneable {
 	  this.havingCondition = evalTree;
 	}
 
+  public final void setHavingSchema(Schema schema) {
+    this.havingSchema = schema;
+  }
+
+  public Schema getHavingSchema() {
+    return this.havingSchema;
+  }
+
   @Override
   public boolean hasTargets() {
     return this.targets != null;
@@ -153,16 +163,7 @@ public class GroupbyNode extends UnaryNode implements Projectable, Cloneable {
   public PlanString getPlanString() {
     PlanString planStr = new PlanString("Aggregation");
 
-    StringBuilder sb = new StringBuilder("Targets: ");
-    for (int i = 0; i < targets.length; i++) {
-      sb.append(targets[i]);
-      if( i < targets.length - 1) {
-        sb.append(",");
-      }
-    }
-    planStr.addExplan(sb.toString());
-
-    sb = new StringBuilder("Groups: ");
+    StringBuilder sb = new StringBuilder();
     sb.append("(");
     Column [] groupingColumns = columns;
     for (int j = 0; j < groupingColumns.length; j++) {
@@ -174,7 +175,20 @@ public class GroupbyNode extends UnaryNode implements Projectable, Cloneable {
 
     sb.append(")");
 
+    planStr.appendTitle(sb.toString());
+
+    sb = new StringBuilder("target list: ");
+    for (int i = 0; i < targets.length; i++) {
+      sb.append(targets[i]);
+      if( i < targets.length - 1) {
+        sb.append(",");
+      }
+    }
     planStr.addExplan(sb.toString());
+
+    planStr.addDetail("out schema:").appendDetail(getOutSchema().toString());
+    planStr.addDetail("in schema:").appendDetail(getInSchema().toString());
+
     return planStr;
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e595384b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/AggregationExec.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/AggregationExec.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/AggregationExec.java
index a00fa41..fb4a3b9 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/AggregationExec.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/AggregationExec.java
@@ -21,6 +21,7 @@ package org.apache.tajo.engine.planner.physical;
 import com.google.common.collect.Sets;
 import org.apache.tajo.TaskAttemptContext;
 import org.apache.tajo.catalog.Column;
+import org.apache.tajo.catalog.Schema;
 import org.apache.tajo.datum.DatumFactory;
 import org.apache.tajo.engine.eval.ConstEval;
 import org.apache.tajo.engine.eval.EvalContext;
@@ -33,21 +34,33 @@ import java.io.IOException;
 import java.util.Set;
 
 public abstract class AggregationExec extends UnaryPhysicalExec {
-  protected GroupbyNode annotation;
-
-  @SuppressWarnings("unused")
-  protected final EvalNode havingQual;
+  protected GroupbyNode plan;
 
   protected Set<Column> nonNullGroupingFields;
   protected int keylist [];
   protected int measureList[];
   protected final EvalNode evals [];
   protected EvalContext evalContexts [];
+  protected Schema evalSchema;
+
+  protected EvalNode havingQual;
+  protected EvalContext havingContext;
 
   public AggregationExec(final TaskAttemptContext context, GroupbyNode plan,
                          PhysicalExec child) throws IOException {
     super(context, plan.getInSchema(), plan.getOutSchema(), child);
-    this.havingQual = plan.getHavingCondition();
+    this.plan = plan;
+
+    if (plan.hasHavingCondition()) {
+      this.havingQual = plan.getHavingCondition();
+      this.havingContext = plan.getHavingCondition().newContext();
+    }
+
+    if (plan.getHavingSchema() != null) {
+      this.evalSchema = plan.getHavingSchema();
+    } else {
+      this.evalSchema = plan.getOutSchema();
+    }
 
     nonNullGroupingFields = Sets.newHashSet();
     // keylist will contain a list of IDs of grouping column

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e595384b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/HashAggregateExec.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/HashAggregateExec.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/HashAggregateExec.java
index 427e6f4..019db82 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/HashAggregateExec.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/HashAggregateExec.java
@@ -47,12 +47,13 @@ public class HashAggregateExec extends AggregationExec {
                            PhysicalExec subOp) throws IOException {
     super(ctx, annotation, subOp);
     tupleSlots = new HashMap<Tuple, EvalContext[]>(10000);
-    this.tuple = new VTuple(outSchema.getColumnNum());
+    this.tuple = new VTuple(evalSchema.getColumnNum());
   }
   
   private void compute() throws IOException {
     Tuple tuple;
     Tuple keyTuple;
+    int targetLength = plan.getTargets().length;
     while((tuple = child.next()) != null && !context.isStopped()) {
       keyTuple = new VTuple(keylist.length);
       // build one key tuple
@@ -66,8 +67,8 @@ public class HashAggregateExec extends AggregationExec {
           evals[measureList[i]].eval(tmpTuple[measureList[i]], inSchema, tuple);
         }
       } else { // if the key occurs firstly
-        EvalContext evalCtx [] = new EvalContext[outSchema.getColumnNum()];
-        for(int i = 0; i < outSchema.getColumnNum(); i++) {
+        EvalContext evalCtx [] = new EvalContext[targetLength];
+        for(int i = 0; i < targetLength; i++) {
           evalCtx[i] = evals[i].newContext();
           evals[i].eval(evalCtx[i], inSchema, tuple);
         }
@@ -83,14 +84,31 @@ public class HashAggregateExec extends AggregationExec {
       iterator = tupleSlots.entrySet().iterator();
       computed = true;
     }
-        
-    if(iterator.hasNext()) {
-      EvalContext [] ctx =  iterator.next().getValue();
+
+    EvalContext [] ctx;
+    if (havingQual == null) {
+      if (iterator.hasNext()) {
+      ctx =  iterator.next().getValue();
+
       for (int i = 0; i < ctx.length; i++) {
         tuple.put(i, evals[i].terminate(ctx[i]));
       }
+
       return tuple;
+      } else {
+        return null;
+      }
     } else {
+      while(iterator.hasNext()) {
+        ctx =  iterator.next().getValue();
+        for (int i = 0; i < ctx.length; i++) {
+          tuple.put(i, evals[i].terminate(ctx[i]));
+        }
+        havingQual.eval(havingContext, evalSchema, tuple);
+        if (havingQual.terminate(havingContext).asBool()) {
+          return tuple;
+        }
+      }
       return null;
     }
   }