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/08/07 02:52:09 UTC

git commit: TAJO-102: Add AlgebraVisitor and Refactor LogicalPlanner to use the visitor. (hyunsik)

Updated Branches:
  refs/heads/master 36dd87a32 -> 87420eb3a


TAJO-102: Add AlgebraVisitor and Refactor LogicalPlanner to use the visitor. (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/87420eb3
Tree: http://git-wip-us.apache.org/repos/asf/incubator-tajo/tree/87420eb3
Diff: http://git-wip-us.apache.org/repos/asf/incubator-tajo/diff/87420eb3

Branch: refs/heads/master
Commit: 87420eb3a2a6e91ada5d05520c347f747ce20683
Parents: 36dd87a
Author: Hyunsik Choi <hy...@apache.org>
Authored: Wed Aug 7 09:48:29 2013 +0900
Committer: Hyunsik Choi <hy...@apache.org>
Committed: Wed Aug 7 09:49:43 2013 +0900

----------------------------------------------------------------------
 CHANGES.txt                                     |   2 +
 .../tajo/engine/planner/AlgebraVisitor.java     |  39 +++
 .../tajo/engine/planner/BaseAlgebraVisitor.java | 207 ++++++++++++
 .../tajo/engine/planner/LogicalOptimizer.java   |  26 +-
 .../apache/tajo/engine/planner/LogicalPlan.java |  18 +-
 .../tajo/engine/planner/LogicalPlanner.java     | 323 +++++++++----------
 .../tajo/engine/planner/TargetListManager.java  |  20 +-
 .../org/apache/tajo/master/GlobalEngine.java    |   2 +-
 .../org/apache/tajo/BackendTestingUtil.java     |   2 +-
 .../plan/global/TestGlobalQueryPlanner.java     |  17 +-
 .../engine/planner/TestLogicalOptimizer.java    |  10 +-
 .../global/TestGlobalQueryOptimizer.java        |   3 +-
 .../planner/physical/TestPhysicalPlanner.java   |  33 +-
 .../engine/planner/physical/TestSortExec.java   |   2 +-
 14 files changed, 472 insertions(+), 232 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/87420eb3/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index 6f71a00..97eaa6b 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -15,6 +15,8 @@ Release 0.2.0 - unreleased
 
   IMPROVEMENTS
 
+    TAJO-102: Add AlgebraVisitor and Refactor LogicalPlanner to use the visitor.    (hyunsik)
+
     TAJO-87: Integration of tajo algebra module and SQL parser. (hyunsik)
 
     TAJO-70: Refactor GlobalEngine to handle DDL statements. (hyunsik)

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/87420eb3/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
new file mode 100644
index 0000000..9dba5e1
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/AlgebraVisitor.java
@@ -0,0 +1,39 @@
+/**
+ * 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 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 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;
+}

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/87420eb3/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
new file mode 100644
index 0000000..03eca32
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/BaseAlgebraVisitor.java
@@ -0,0 +1,207 @@
+/**
+ * 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 java.util.Stack;
+
+public abstract class BaseAlgebraVisitor<T1, T2> implements AlgebraVisitor<T1, T2> {
+
+  /**
+   * The prehook is called before each expression is visited.
+   */
+  public void preHook(T1 ctx, Stack<OpType> stack, Expr expr) throws PlanningException {
+  }
+
+
+  /**
+   * The posthook is called before each expression is visited.
+   */
+  public T2 postHook(T1 ctx, Stack<OpType> stack, Expr expr, T2 current) throws PlanningException {
+    return current;
+  }
+
+  /**
+   * visitChild visits each relational operator expression recursively.
+   *
+   * @param stack The stack contains the upper operators' type.
+   * @param expr The visiting relational operator
+   */
+  public T2 visitChild(T1 ctx, Stack<OpType> stack, Expr expr) throws PlanningException {
+    preHook(ctx, stack, expr);
+
+    T2 current;
+    switch (expr.getType()) {
+      case Projection:
+        current = visitProjection(ctx, stack, (Projection) expr);
+        break;
+      case Limit:
+        current = visitLimit(ctx, stack, (Limit) expr);
+        break;
+      case Sort:
+        current = visitSort(ctx, stack, (Sort) expr);
+        break;
+      case Aggregation:
+        current = visitGroupBy(ctx, stack, (Aggregation) expr);
+        break;
+      case Join:
+        current = visitJoin(ctx, stack, (Join) expr);
+        break;
+      case Filter:
+        current = visitFilter(ctx, stack, (Selection) expr);
+        break;
+      case Union:
+        current = visitUnion(ctx, stack, (SetOperation) expr);
+        break;
+      case Except:
+        current = visitExcept(ctx, stack, (SetOperation) expr);
+        break;
+      case Intersect:
+        current = visitIntersect(ctx, stack, (SetOperation) expr);
+        break;
+      case RelationList:
+        current = visitRelationList(ctx, stack, (RelationList) expr);
+        break;
+      case Relation:
+        current = visitRelation(ctx, stack, (Relation) expr);
+        break;
+      case CreateTable:
+        current = visitCreateTable(ctx, stack, (CreateTable) expr);
+        break;
+      case DropTable:
+        current = visitDropTable(ctx, stack, (DropTable) expr);
+        break;
+      default:
+        throw new PlanningException("Cannot support this type algebra \"" + expr.getType() + "\"");
+    }
+
+    postHook(ctx, stack, expr, current);
+
+    return current;
+  }
+
+  @Override
+  public T2 visitProjection(T1 ctx, Stack<OpType> stack, Projection expr) throws PlanningException {
+    stack.push(expr.getType());
+    T2 child = visitChild(ctx, stack, expr.getChild());
+    stack.pop();
+    return child;
+  }
+
+  @Override
+  public T2 visitLimit(T1 ctx, Stack<OpType> stack, Limit expr) throws PlanningException {
+    stack.push(expr.getType());
+    T2 child = visitChild(ctx, stack, expr.getChild());
+    stack.pop();
+    return child;
+  }
+
+  @Override
+  public T2 visitSort(T1 ctx, Stack<OpType> stack, Sort expr) throws PlanningException {
+    stack.push(expr.getType());
+    T2 child = visitChild(ctx, stack, expr.getChild());
+    stack.pop();
+    return child;
+  }
+
+  @Override
+  public T2 visitGroupBy(T1 ctx, Stack<OpType> stack, Aggregation expr) throws PlanningException {
+    stack.push(expr.getType());
+    T2 child = visitChild(ctx, stack, expr.getChild());
+    stack.pop();
+    return child;
+  }
+
+  @Override
+  public T2 visitJoin(T1 ctx, Stack<OpType> stack, Join expr) throws PlanningException {
+    stack.push(expr.getType());
+    T2 child = visitChild(ctx, stack, expr.getLeft());
+    visitChild(ctx, stack, expr.getRight());
+    stack.pop();
+    return child;
+  }
+
+  @Override
+  public T2 visitFilter(T1 ctx, Stack<OpType> stack, Selection expr) throws PlanningException {
+    stack.push(expr.getType());
+    T2 child = visitChild(ctx, stack, expr.getChild());
+    stack.pop();
+    return child;
+  }
+
+  @Override
+  public T2 visitUnion(T1 ctx, Stack<OpType> stack, SetOperation expr) throws PlanningException {
+    stack.push(expr.getType());
+    T2 child = visitChild(ctx, stack, expr.getLeft());
+    visitChild(ctx, stack, expr.getRight());
+    stack.pop();
+    return child;
+  }
+
+  @Override
+  public T2 visitExcept(T1 ctx, Stack<OpType> stack, SetOperation expr) throws PlanningException {
+    stack.push(expr.getType());
+    T2 child = visitChild(ctx, stack, expr.getLeft());
+    visitChild(ctx, stack, expr.getRight());
+    stack.pop();
+    return child;
+  }
+
+  @Override
+  public T2 visitIntersect(T1 ctx, Stack<OpType> stack, SetOperation expr) throws PlanningException {
+    stack.push(expr.getType());
+    T2 child = visitChild(ctx, stack, expr.getLeft());
+    visitChild(ctx, stack, expr.getRight());
+    stack.pop();
+    return child;
+  }
+
+  @Override
+  public T2 visitRelationList(T1 ctx, Stack<OpType> stack, RelationList expr) throws PlanningException {
+    stack.push(expr.getType());
+    T2 child = null;
+    for (Expr e : expr.getRelations()) {
+      child = visitChild(ctx, stack, e);
+    }
+    stack.pop();
+    return child;
+  }
+
+  @Override
+  public T2 visitRelation(T1 ctx, Stack<OpType> stack, Relation expr) throws PlanningException {
+    return null;
+  }
+
+  @Override
+  public T2 visitCreateTable(T1 ctx, Stack<OpType> stack, CreateTable expr) throws PlanningException {
+    stack.push(expr.getType());
+    T2 child = null;
+    if (expr.hasSubQuery()) {
+       child = visitChild(ctx, stack, expr.getSubQuery());
+    }
+    stack.pop();
+    return child;
+  }
+
+  @Override
+  public T2 visitDropTable(T1 ctx, Stack<OpType> stack, DropTable expr) throws PlanningException {
+    return null;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/87420eb3/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalOptimizer.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalOptimizer.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalOptimizer.java
index 3cb83ad..ad245c0 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalOptimizer.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalOptimizer.java
@@ -60,7 +60,7 @@ public class LogicalOptimizer {
     }
   }
 
-  public static LogicalNode optimize(LogicalPlan plan) throws CloneNotSupportedException {
+  public static LogicalNode optimize(LogicalPlan plan) throws PlanningException {
     LogicalNode toBeOptimized;
 
     toBeOptimized = plan.getRootBlock().getRoot();
@@ -224,7 +224,7 @@ public class LogicalOptimizer {
    * @param plan
    */
   private static void pushProjection(LogicalPlan plan)
-      throws CloneNotSupportedException {
+      throws PlanningException {
     Stack<LogicalNode> stack = new Stack<LogicalNode>();
 
     OptimizationContext optCtx;
@@ -260,7 +260,7 @@ public class LogicalOptimizer {
   private static LogicalNode pushProjectionRecursive(
       final LogicalPlan plan, final OptimizationContext optContext,
       final LogicalNode node, final Stack<LogicalNode> stack,
-      final Set<Column> upperRequired) throws CloneNotSupportedException {
+      final Set<Column> upperRequired) throws PlanningException {
 
     LogicalNode currentNode = null;
 
@@ -307,7 +307,7 @@ public class LogicalOptimizer {
   }
 
   private static LogicalNode pushDownCommonPost(LogicalPlan plan, OptimizationContext context, UnaryNode node,
-                                                Set<Column> upperRequired, Stack<LogicalNode> stack) throws CloneNotSupportedException {
+                                                Set<Column> upperRequired, Stack<LogicalNode> stack) throws PlanningException {
     stack.push(node);
     LogicalNode child = pushProjectionRecursive(plan, context,
         node.getSubNode(), stack, upperRequired);
@@ -323,7 +323,7 @@ public class LogicalOptimizer {
 
   private static LogicalNode pushDownProjection(LogicalPlan plan, OptimizationContext context,
                                                    ProjectionNode projNode, Set<Column> upperRequired,
-                                                   Stack<LogicalNode> path) throws CloneNotSupportedException {
+                                                   Stack<LogicalNode> path) throws PlanningException {
 
     for (Target target : projNode.getTargets()) {
       upperRequired.add(target.getColumnSchema());
@@ -352,7 +352,7 @@ public class LogicalOptimizer {
 
   private static LogicalNode pushDownSelection(LogicalPlan plan, OptimizationContext context,
                                                  SelectionNode selectionNode, Set<Column> upperRequired,
-                                                 Stack<LogicalNode> path) throws CloneNotSupportedException {
+                                                 Stack<LogicalNode> path) throws PlanningException {
     if (selectionNode.getQual() != null) {
       upperRequired.addAll(EvalTreeUtil.findDistinctRefColumns(selectionNode.getQual()));
     }
@@ -362,7 +362,7 @@ public class LogicalOptimizer {
 
   private static GroupbyNode pushDownGroupBy(LogicalPlan plan, OptimizationContext context, GroupbyNode groupbyNode,
                                              Set<Column> upperRequired, Stack<LogicalNode> stack)
-      throws CloneNotSupportedException {
+      throws PlanningException {
 
     Set<Column> currentRequired = new HashSet<Column>(upperRequired);
 
@@ -379,8 +379,7 @@ public class LogicalOptimizer {
   }
 
   private static SortNode pushDownSort(LogicalPlan plan, OptimizationContext context, SortNode sortNode,
-                                       Set<Column> upperRequired, Stack<LogicalNode> stack)
-      throws CloneNotSupportedException {
+                                       Set<Column> upperRequired, Stack<LogicalNode> stack) throws PlanningException {
 
     for (SortSpec spec : sortNode.getSortKeys()) {
       upperRequired.add(spec.getSortKey());
@@ -393,7 +392,7 @@ public class LogicalOptimizer {
 
   private static JoinNode pushDownJoin(LogicalPlan plan, OptimizationContext context, JoinNode joinNode,
                                        Set<Column> upperRequired, Stack<LogicalNode> path)
-      throws CloneNotSupportedException {
+      throws PlanningException {
     Set<Column> currentRequired = Sets.newHashSet(upperRequired);
 
     if (joinNode.hasTargets()) {
@@ -425,8 +424,7 @@ public class LogicalOptimizer {
   }
 
   private static BinaryNode pushDownSetNode(LogicalPlan plan, OptimizationContext context, UnionNode node,
-                                            Set<Column> upperRequired, Stack<LogicalNode> stack)
-      throws CloneNotSupportedException {
+                                            Set<Column> upperRequired, Stack<LogicalNode> stack) throws PlanningException {
     BinaryNode setNode = node;
 
     LogicalPlan.QueryBlock leftBlock = plan.getBlock(setNode.getOuterNode());
@@ -452,7 +450,7 @@ public class LogicalOptimizer {
 
   private static ScanNode pushdownScanNode(OptimizationContext optContext, ScanNode scanNode,
                                            Set<Column> upperRequired, Stack<LogicalNode> stack)
-      throws CloneNotSupportedException {
+      throws PlanningException {
     return (ScanNode) pushDownProjectablePost(optContext, scanNode, upperRequired, isTopmostProjectable(stack));
   }
 
@@ -468,7 +466,7 @@ public class LogicalOptimizer {
 
   private static LogicalNode pushDownProjectablePost(OptimizationContext context, LogicalNode node,
                                                      Set<Column> upperRequired, boolean last)
-      throws CloneNotSupportedException {
+      throws PlanningException {
     TargetListManager targetListManager = context.getTargetListManager();
     EvalNode expr;
 

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/87420eb3/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 5a9f101..8c39d00 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
@@ -19,6 +19,7 @@
 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.annotation.NotThreadSafe;
 import org.apache.tajo.catalog.Column;
@@ -101,7 +102,7 @@ public class LogicalPlan {
     return queryBlocks.values();
   }
 
-  public boolean postVisit(String blockName, LogicalNode node, Stack<ExprType> path) {
+  public boolean postVisit(String blockName, LogicalNode node, Stack<OpType> path) {
     if (visited.contains(node)) {
       return false;
     }
@@ -179,7 +180,7 @@ public class LogicalPlan {
    */
   public Column findColumnFromChildNode(ColumnReferenceExpr columnRef, String blockName,
                                         LogicalNode node)
-      throws VerifyException{
+      throws VerifyException {
     List<Column> candidates = new ArrayList<Column>();
 
     Column candidate;
@@ -445,7 +446,7 @@ public class LogicalPlan {
      * It requires node's default output schemas.
      * @param node
      */
-    public void checkAndSetEvaluatedTargets(LogicalNode node) {
+    public void checkAndSetEvaluatedTargets(LogicalNode node) throws PlanningException {
       if (!(node instanceof Projectable)) {
         return;
       }
@@ -518,7 +519,7 @@ public class LogicalPlan {
 
           if (newEvaluatedTargetIds.size() > 0) {
             // fill addedTargets with output columns and new expression columns (e.g., aliased column or expressions)
-            Target [] addedTargets = new Target[baseSchema.getColumnNum() + newEvaluatedTargetIds.size()];
+            Target[] addedTargets = new Target[baseSchema.getColumnNum() + newEvaluatedTargetIds.size()];
             PlannerUtil.schemaToTargets(baseSchema, addedTargets);
             int baseIdx = baseSchema.getColumnNum();
             for (int i = 0; i < newEvaluatedTargetIds.size(); i++) {
@@ -542,11 +543,8 @@ public class LogicalPlan {
       }
 
       // replace the evaluated targets for upper operators
-      try {
-        targetListManager.getUpdatedTarget();
-      } catch (CloneNotSupportedException e) {
-        throw new InternalError(e.getMessage());
-      }
+      targetListManager.getUpdatedTarget();
+
 
       if (targetListManager.isAllEvaluated()) {
         schema = targetListManager.getUpdatedSchema();
@@ -557,7 +555,7 @@ public class LogicalPlan {
       return targetListManager;
     }
 
-    public Target [] getCurrentTargets() {
+    public Target[] getCurrentTargets() {
       return targetListManager.getTargets();
     }
   }

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/87420eb3/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 d8bb157..dab58b9 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
@@ -36,7 +36,6 @@ import org.apache.tajo.engine.eval.EvalNode.Type;
 import org.apache.tajo.engine.planner.LogicalPlan.QueryBlock;
 import org.apache.tajo.engine.planner.logical.*;
 import org.apache.tajo.engine.query.exception.InvalidQueryException;
-import org.apache.tajo.engine.query.exception.NotSupportQueryException;
 import org.apache.tajo.engine.query.exception.UndefinedFunctionException;
 import org.apache.tajo.engine.utils.SchemaUtil;
 import org.apache.tajo.exception.InternalException;
@@ -50,9 +49,16 @@ import static org.apache.tajo.algebra.Aggregation.GroupType;
  * This class creates a logical plan from a parse tree ({@link org.apache.tajo.engine.parser.SQLAnalyzer})
  * generated by {@link org.apache.tajo.engine.parser.SQLAnalyzer}.
  *
- * @see org.apache.tajo.engine.parser
+ * Relational operators can be divided into two categories as follows:
+ * <oi>
+ *  <li>General operator: this type operators do not affect the tuple schema.
+ *  Selection, Sort, and Limit belong to this type.</li>
+ *  <li>Projectable operator: this type operators affects the tuple schema.
+ *  Scan, Groupby, and Join belong to this type.
+ *  </li>
+ * </oi>
  */
-public class LogicalPlanner {
+public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContext, LogicalNode> {
   private static Log LOG = LogFactory.getLog(LogicalPlanner.class);
   private final CatalogService catalog;
 
@@ -60,6 +66,16 @@ public class LogicalPlanner {
     this.catalog = catalog;
   }
 
+  public static class PlanContext {
+    LogicalPlan plan;
+    QueryBlock block;
+
+    public PlanContext(LogicalPlan plan, QueryBlock block) {
+      this.plan = plan;
+      this.block = block;
+    }
+  }
+
   /**
    * This generates a logical plan.
    *
@@ -71,15 +87,13 @@ public class LogicalPlanner {
     LogicalPlan plan = new LogicalPlan(this);
     LogicalNode subroot = null;
 
-    Stack<ExprType> stack =
-        new Stack<ExprType>();
+    Stack<OpType> stack =new Stack<OpType>();
 
     QueryBlock rootBlock = plan.newAndGetBlock(LogicalPlan.ROOT_BLOCK);
+    PlanContext context = new PlanContext(plan, rootBlock);
     try {
-      subroot = createPlanInternal(plan, rootBlock, expr, stack);
-    } catch (CloneNotSupportedException e) {
-      throw new InvalidQueryException(e);
-    } catch (VerifyException e) {
+      subroot = visitChild(context, stack, expr);
+    } catch (PlanningException e) {
       e.printStackTrace();
     }
 
@@ -92,90 +106,23 @@ public class LogicalPlanner {
     return plan;
   }
 
-  /**
-   * Relational operators can be divided into two categories as follows:
-   * <oi>
-   *  <li>General operator: this type operators do not affect tuple schema and do not evaluate
-   *  expressions. Selection, Sort, and Limit belong to this operator.</li>
-   *  <li>Projectable operator: this type operators affects tuple schema and evaluate expressions.
-   *  Scan, Groupby, and Join belong to this operators.
-   *  </li>
-   * </oi>
-   */
-  private LogicalNode createPlanInternal(LogicalPlan plan, QueryBlock block, Expr expr, Stack<ExprType> stack)
-      throws CloneNotSupportedException, VerifyException {
-    LogicalNode currentNode;
-    QueryBlock currentBlock = checkNewBlockAndGet(plan, block.getName());
-
-    switch(expr.getType()) {
-      case Projection:
-        Projection projection = (Projection) expr;
-        currentNode = buildProjectionNode(plan, currentBlock, projection, stack);
-        break;
-
-      case Filter:
-        Selection selection = (Selection) expr;
-        currentNode = buildSelectionNode(plan, currentBlock, selection, stack);
-        break;
-
-      case Aggregation:
-        Aggregation aggregation = (Aggregation) expr;
-        currentNode = buildGroupingPlan(plan, currentBlock, aggregation, stack);
-        break;
-
-      case Join:
-        Join join = (Join) expr;
-        currentNode = buildExplicitJoinPlan(plan, currentBlock, join, stack);
-        break;
-
-      case Sort:
-        Sort sort = (Sort) expr;
-        currentNode = buildSortPlan(plan, currentBlock, sort, stack);
-        break;
-
-      case Limit:
-        Limit limit = (Limit) expr;
-        currentNode = buildLimitPlan(plan, currentBlock, limit, stack);
-        break;
-
-      case Union:
-      case Except:
-      case Intersect:
-        SetOperation setOp = (SetOperation) expr;
-        currentNode = buildSetPlan(plan, currentBlock, setOp, stack);
-        break;
-
-
-      case RelationList:
-        currentNode = buildRelationListPlan(plan, currentBlock, (RelationList) expr, stack);
-        if (((RelationList) expr).size() == 1) { // skip visitPost because it is already visited
-          return currentNode;
-        }
-        break;
-
-      case Relation:
-        currentNode = buildScanPlan(currentBlock, expr);
-        break;
-
-      case CreateTable:
-        CreateTable createTable = (CreateTable) expr;
-        currentNode = buildCreateTable(plan, currentBlock, createTable, stack);
-        break;
-
-      case DropTable:
-        DropTable dropTable = (DropTable) expr;
-        currentNode = buildDropTable(dropTable);
-        break;
+  public void preHook(PlanContext context, Stack<OpType> stack, Expr expr) {
+    context.block = checkNewBlockAndGet(context.plan, context.block.getName());
+  }
 
-      default:
-        throw new NotSupportQueryException(expr.getType().name());
+  public LogicalNode postHook(PlanContext context, Stack<OpType> stack, Expr expr, LogicalNode current)
+      throws PlanningException {
+    // == Post work ==
+    if (expr.getType() == OpType.RelationList && ((RelationList) expr).size() == 1) {
+      return current;
     }
 
     // mark the node as the visited node and do post work for each operator
-    plan.postVisit(block.getName(), currentNode, stack);
+    context.plan.postVisit(context.block.getName(), current, stack);
     // check and set evaluated targets and update in/out schemas
-    currentBlock.checkAndSetEvaluatedTargets(currentNode);
-    return currentNode;
+    context.block.checkAndSetEvaluatedTargets(current);
+
+    return current;
   }
 
   /**
@@ -191,7 +138,8 @@ public class LogicalPlanner {
     }
   }
 
-  private ScanNode buildScanPlan(QueryBlock block, Expr expr)
+  @Override
+  public ScanNode visitRelation(PlanContext context, Stack<OpType> stack, Relation expr)
       throws VerifyException {
     // 1. init phase
 
@@ -213,11 +161,11 @@ public class LogicalPlanner {
   /*===============================================================================================
     JOIN SECTION
    ===============================================================================================*/
-  private LogicalNode buildRelationListPlan(LogicalPlan plan, QueryBlock block,
-                                            RelationList relations, Stack<ExprType> stack)
-      throws VerifyException, CloneNotSupportedException {
+  @Override
+  public LogicalNode visitRelationList(PlanContext context, Stack<OpType> stack, RelationList relations)
+      throws PlanningException {
 
-    LogicalNode current = createPlanInternal(plan, block, relations.getRelations()[0], stack);
+    LogicalNode current = visitChild(context, stack, relations.getRelations()[0]);
 
     LogicalNode left;
     LogicalNode right;
@@ -225,7 +173,7 @@ public class LogicalPlanner {
 
       for (int i = 1; i < relations.size(); i++) {
         left = current;
-        right = createPlanInternal(plan, block, relations.getRelations()[i], stack);
+        right = visitChild(context, stack, relations.getRelations()[i]);
         current = createCatasianProduct(left, right);
       }
     }
@@ -233,13 +181,17 @@ public class LogicalPlanner {
     return current;
   }
 
-  private LogicalNode buildExplicitJoinPlan(LogicalPlan plan, QueryBlock block, Join join, Stack<ExprType> stack)
-      throws VerifyException, CloneNotSupportedException {
+  @Override
+  public LogicalNode visitJoin(PlanContext context, Stack<OpType> stack, Join join)
+      throws PlanningException {
     // Phase 1: Init
+    LogicalPlan plan = context.plan;
+    QueryBlock block = context.block;
+
     // Phase 2: build child plans
-    stack.push(ExprType.JOIN);
-    LogicalNode left = createPlanInternal(plan, block, join.getLeft(), stack);
-    LogicalNode right = createPlanInternal(plan, block, join.getRight(), stack);
+    stack.push(OpType.Join);
+    LogicalNode left = visitChild(context, stack, join.getLeft());
+    LogicalNode right = visitChild(context, stack, join.getRight());
     stack.pop();
 
     // Phase 3: build this plan
@@ -328,19 +280,42 @@ public class LogicalPlanner {
   /*===============================================================================================
     SET OPERATION SECTION
    ===============================================================================================*/
-  private LogicalNode buildSetPlan(LogicalPlan plan, QueryBlock block, SetOperation setOperation,
-                                   Stack<ExprType> stack) throws VerifyException, CloneNotSupportedException {
-    LogicalNode left;
-    LogicalNode right;
 
-    QueryBlock leftBlock = plan.newAnonymousBlock();
-    Stack<ExprType> leftStack = new Stack<ExprType>();
-    left = createPlanInternal(plan, leftBlock, setOperation.getLeft(), leftStack);
-    Stack<ExprType> rightStack = new Stack<ExprType>();
-    QueryBlock rightBlock = plan.newAnonymousBlock();
-    right = createPlanInternal(plan, rightBlock, setOperation.getRight(), rightStack);
+  @Override
+  public LogicalNode visitUnion(PlanContext context, Stack<OpType> stack, SetOperation setOperation)
+      throws PlanningException {
+    return buildSetPlan(context, stack, setOperation);
+  }
+
+  @Override
+  public LogicalNode visitExcept(PlanContext context, Stack<OpType> stack, SetOperation setOperation)
+      throws PlanningException {
+    return buildSetPlan(context, stack, setOperation);
+  }
+
+  @Override
+  public LogicalNode visitIntersect(PlanContext context, Stack<OpType> stack, SetOperation setOperation)
+      throws PlanningException {
+    return buildSetPlan(context, stack, setOperation);
+  }
+
+  private LogicalNode buildSetPlan(PlanContext context, Stack<OpType> stack, SetOperation setOperation)
+      throws PlanningException {
+
+    // 1. Init Phase
+    LogicalPlan plan = context.plan;
+    QueryBlock block = context.block;
+
+    // 2. Build Child Plans
+    PlanContext leftContext = new PlanContext(plan, plan.newAnonymousBlock());
+    Stack<OpType> leftStack = new Stack<OpType>();
+    LogicalNode left = visitChild(leftContext, leftStack, setOperation.getLeft());
+
+    PlanContext rightContext = new PlanContext(plan, plan.newAnonymousBlock());
+    Stack<OpType> rightStack = new Stack<OpType>();
+    LogicalNode right = visitChild(rightContext, rightStack, setOperation.getRight());
 
-    verifySetStatement(setOperation.getType(), leftBlock, rightBlock);
+    verifySetStatement(setOperation.getType(), leftContext.block, rightContext.block);
 
     BinaryNode setOp;
     if (setOperation.getType() == OpType.Union) {
@@ -355,7 +330,7 @@ public class LogicalPlanner {
 
     // Strip the table names from the targets of the both blocks
     // in order to check the equivalence the schemas of both blocks.
-    Target [] leftStrippedTargets = PlannerUtil.stripTarget(leftBlock.getCurrentTargets());
+    Target[] leftStrippedTargets = PlannerUtil.stripTarget(leftContext.block.getCurrentTargets());
 
     Schema outSchema = PlannerUtil.targetToSchema(leftStrippedTargets);
     setOp.setInSchema(left.getOutSchema());
@@ -364,10 +339,6 @@ public class LogicalPlanner {
     setOp.setInner(right);
 
     if (isNoUpperProjection(stack)) {
-//      ProjectionNode projectionNode = new ProjectionNode(leftStrippedTargets);
-//      projectionNode.setSubNode(setOp);
-
-//      localBlock.setProjectionNode(projectionNode);
       block.targetListManager = new TargetListManager(plan, leftStrippedTargets);
       block.targetListManager.setEvaluatedAll();
       block.targetListManager.getUpdatedTarget();
@@ -384,8 +355,8 @@ public class LogicalPlanner {
       throw new VerifyException("ERROR: each " + type.name() + " query must have the same number of columns");
     }
 
-    Target [] targets1 = left.getCurrentTargets();
-    Target [] targets2 = right.getCurrentTargets();
+    Target[] targets1 = left.getCurrentTargets();
+    Target[] targets2 = right.getCurrentTargets();
 
     for (int i = 0; i < targets1.length; i++) {
       if (!targets1[i].getDataType().equals(targets2[i].getDataType())) {
@@ -397,14 +368,16 @@ public class LogicalPlanner {
     return true;
   }
 
-  private SelectionNode buildSelectionNode(LogicalPlan plan, QueryBlock block, Selection selection,
-                                           Stack<ExprType> stack)
-      throws VerifyException, CloneNotSupportedException {
+  @Override
+  public SelectionNode visitFilter(PlanContext context, Stack<OpType> stack, Selection selection)
+      throws PlanningException {
     // 1. init phase:
+    LogicalPlan plan = context.plan;
+    QueryBlock block = context.block;
 
     // 2. build child plans:
-    stack.push(ExprType.SELECTION);
-    LogicalNode child = createPlanInternal(plan, block, selection.getChild(), stack);
+    stack.push(OpType.Filter);
+    LogicalNode child = visitChild(context, stack, selection.getChild());
     stack.pop();
 
     // 3. build this plan:
@@ -426,15 +399,17 @@ public class LogicalPlanner {
     GROUP BY SECTION
    ===============================================================================================*/
 
-  private LogicalNode buildGroupingPlan(LogicalPlan plan, QueryBlock block, Aggregation aggregation,
-                                        Stack<ExprType> stack)
-      throws VerifyException, CloneNotSupportedException {
+  @Override
+  public LogicalNode visitGroupBy(PlanContext context, Stack<OpType> stack, Aggregation aggregation)
+      throws PlanningException {
 
     // 1. Initialization Phase:
+    LogicalPlan plan = context.plan;
+    QueryBlock block = context.block;
 
     // 2. Build Child Plan Phase:
-    stack.push(ExprType.GROUP_BY);
-    LogicalNode child = createPlanInternal(plan, block, aggregation.getChild(), stack);
+    stack.push(OpType.Aggregation);
+    LogicalNode child = visitChild(context, stack, aggregation.getChild());
     stack.pop();
 
     // 3. Build This Plan:
@@ -463,7 +438,7 @@ public class LogicalPlanner {
       return groupingNode;
 
     } else if (groupElements[0].getType() == GroupType.Cube) { // for cube by
-      List<Column []> cuboids  = generateCuboids(annotateGroupingColumn(plan, block.getName(),
+      List<Column[]> cuboids  = generateCuboids(annotateGroupingColumn(plan, block.getName(),
           groupElements[0].getColumns(), child));
       UnionNode topUnion = createGroupByUnion(plan, block, child, cuboids, 0);
       block.resolveGrouping();
@@ -478,13 +453,13 @@ public class LogicalPlanner {
   private UnionNode createGroupByUnion(final LogicalPlan plan,
                                        final QueryBlock block,
                                        final LogicalNode subNode,
-                                       final List<Column []> cuboids,
+                                       final List<Column[]> cuboids,
                                        final int idx) {
     UnionNode union;
     try {
       if ((cuboids.size() - idx) > 2) {
         GroupbyNode g1 = new GroupbyNode(cuboids.get(idx));
-        Target [] clone = cloneTargets(block.getCurrentTargets());
+        Target[] clone = cloneTargets(block.getCurrentTargets());
 
         g1.setTargets(clone);
         g1.setSubNode((LogicalNode) subNode.clone());
@@ -500,7 +475,7 @@ public class LogicalPlanner {
         return union;
       } else {
         GroupbyNode g1 = new GroupbyNode(cuboids.get(idx));
-        Target [] clone = cloneTargets(block.getCurrentTargets());
+        Target[] clone = cloneTargets(block.getCurrentTargets());
         g1.setTargets(clone);
         g1.setSubNode((LogicalNode) subNode.clone());
         g1.setInSchema(g1.getSubNode().getOutSchema());
@@ -529,10 +504,10 @@ public class LogicalPlanner {
   /**
    * It transforms a list of column references into a list of annotated columns with considering aliased expressions.
    */
-  private Column [] annotateGroupingColumn(LogicalPlan plan, String blockName,
+  private Column[] annotateGroupingColumn(LogicalPlan plan, String blockName,
                                            ColumnReferenceExpr[] columnRefs, LogicalNode child)
       throws VerifyException {
-    Column [] columns = new Column[columnRefs.length];
+    Column[] columns = new Column[columnRefs.length];
     for (int i = 0; i < columnRefs.length; i++) {
       columns[i] = plan.findColumnFromChildNode(columnRefs[i], blockName, child);
     }
@@ -540,9 +515,9 @@ public class LogicalPlanner {
     return columns;
   }
 
-  private static Target [] cloneTargets(Target [] sourceTargets)
+  private static Target[] cloneTargets(Target[] sourceTargets)
       throws CloneNotSupportedException {
-    Target [] clone = new Target[sourceTargets.length];
+    Target[] clone = new Target[sourceTargets.length];
     for (int i = 0; i < sourceTargets.length; i++) {
       clone[i] = (Target) sourceTargets[i].clone();
     }
@@ -550,13 +525,13 @@ public class LogicalPlanner {
     return clone;
   }
 
-  public static final Column [] ALL= Lists.newArrayList().toArray(new Column[0]);
+  public static final Column[] ALL= Lists.newArrayList().toArray(new Column[0]);
 
-  public static List<Column []> generateCuboids(Column [] columns) {
+  public static List<Column[]> generateCuboids(Column[] columns) {
     int numCuboids = (int) Math.pow(2, columns.length);
     int maxBits = columns.length;
 
-    List<Column []> cube = Lists.newArrayList();
+    List<Column[]> cube = Lists.newArrayList();
     List<Column> cuboidCols;
 
     cube.add(ALL);
@@ -577,18 +552,21 @@ public class LogicalPlanner {
     SORT SECTION
    ===============================================================================================*/
 
-  private SortNode buildSortPlan(LogicalPlan plan, QueryBlock block, Sort sort, Stack<ExprType> stack)
-      throws VerifyException, CloneNotSupportedException {
+  @Override
+  public SortNode visitSort(PlanContext context, Stack<OpType> stack, Sort sort) throws PlanningException {
 
     // 1. Initialization Phase:
+    LogicalPlan plan = context.plan;
+    QueryBlock block = context.block;
+
     // 2. Build Child Plans:
-    stack.push(ExprType.SORT);
-    LogicalNode child = createPlanInternal(plan, block, sort.getChild(), stack);
+    stack.push(OpType.Sort);
+    LogicalNode child = visitChild(context, stack, sort.getChild());
     child = insertGroupingIfUnresolved(plan, block.getName(), child, stack);
     stack.pop();
 
     // 3. Build this plan:
-    SortSpec [] annotatedSortSpecs = new SortSpec[sort.getSortSpecs().length];
+    SortSpec[] annotatedSortSpecs = new SortSpec[sort.getSortSpecs().length];
     Column column;
     Sort.SortSpec[] sortSpecs = sort.getSortSpecs();
     for (int i = 0; i < sort.getSortSpecs().length; i++) {
@@ -606,11 +584,15 @@ public class LogicalPlanner {
     return sortNode;
   }
 
-  private LimitNode buildLimitPlan(LogicalPlan plan, QueryBlock block, Limit limit, Stack<ExprType> stack)
-      throws VerifyException, CloneNotSupportedException {
+  @Override
+  public LimitNode visitLimit(PlanContext context, Stack<OpType> stack, Limit limit) throws PlanningException {
+    // 1. Init Phase:
+    LogicalPlan plan = context.plan;
+    QueryBlock block = context.block;
+
     // build child plans
-    stack.push(ExprType.LIMIT);
-    LogicalNode child = createPlanInternal(plan, block, limit.getChild(), stack);
+    stack.push(OpType.Limit);
+    LogicalNode child = visitChild(context, stack, limit.getChild());
     stack.pop();
 
     // build limit plan
@@ -629,11 +611,14 @@ public class LogicalPlanner {
     PROJECTION SECTION
    ===============================================================================================*/
 
-  private LogicalNode buildProjectionNode(LogicalPlan plan, QueryBlock block,
-                                          Projection projection, Stack<ExprType> stack)
-      throws VerifyException, CloneNotSupportedException {
+  @Override
+  public LogicalNode visitProjection(PlanContext context, Stack<OpType> stack, Projection projection)
+      throws PlanningException {
 
     //1: init Phase
+    LogicalPlan plan = context.plan;
+    QueryBlock block = context.block;
+
     block.setProjection(projection);
     if (!projection.isAllProjected()) {
       block.targetListManager = new TargetListManager(plan, projection.size());
@@ -651,8 +636,8 @@ public class LogicalPlanner {
     }
 
     // 2: Build Child Plans
-    stack.push(ExprType.PROJECTION);
-    LogicalNode child = createPlanInternal(plan, block, projection.getChild(), stack);
+    stack.push(OpType.Projection);
+    LogicalNode child = visitChild(context, stack, projection.getChild());
     child = insertGroupingIfUnresolved(plan, block.getName(), child, stack);
     stack.pop();
 
@@ -694,7 +679,7 @@ public class LogicalPlanner {
    * It is used only when a group-by clause is not given.
    */
   private LogicalNode insertGroupingIfUnresolved(LogicalPlan plan, String blockName,
-                                                 LogicalNode child, Stack<ExprType> stack) {
+                                                 LogicalNode child, Stack<OpType> stack) throws PlanningException {
     QueryBlock block = plan.getBlock(blockName);
     if (!block.isGroupingResolved()) {
       GroupbyNode groupbyNode = new GroupbyNode(new Column[] {});
@@ -710,9 +695,9 @@ public class LogicalPlanner {
     }
   }
 
-  private boolean isNoUpperProjection(Stack<ExprType> stack) {
-    for (ExprType node : stack) {
-      if (!( (node == ExprType.PROJECTION) || (node == ExprType.GROUP_BY) || (node == ExprType.JOIN) )) {
+  private boolean isNoUpperProjection(Stack<OpType> stack) {
+    for (OpType node : stack) {
+      if (!( (node == OpType.Projection) || (node == OpType.Aggregation) || (node == OpType.Join) )) {
         return false;
       }
     }
@@ -724,14 +709,15 @@ public class LogicalPlanner {
     Data Definition Language (DDL) SECTION
    ===============================================================================================*/
 
-  private LogicalNode buildCreateTable(LogicalPlan plan, QueryBlock block, CreateTable expr, Stack<ExprType> stack)
-      throws VerifyException, CloneNotSupportedException {
+  @Override
+  public LogicalNode visitCreateTable(PlanContext context, Stack<OpType> stack, CreateTable expr)
+      throws PlanningException {
 
      String tableName = expr.getTableName();
 
     if (expr.hasSubQuery()) {
-      stack.add(ExprType.CREATE_TABLE);
-      LogicalNode subQuery = createPlanInternal(plan, block, expr.getSubQuery(), stack);
+      stack.add(OpType.CreateTable);
+      LogicalNode subQuery = visitChild(context, stack, expr.getSubQuery());
       stack.pop();
       StoreTableNode storeNode = new StoreTableNode(tableName);
       storeNode.setSubNode(subQuery);
@@ -788,6 +774,8 @@ public class LogicalPlanner {
     }
   }
 
+
+
   /**
    * It transforms table definition elements to schema.
    *
@@ -807,7 +795,8 @@ public class LogicalPlanner {
     return schema;
   }
 
-  private LogicalNode buildDropTable(DropTable dropTable) {
+  @Override
+  public LogicalNode visitDropTable(PlanContext context, Stack<OpType> stack, DropTable dropTable) {
     DropTableNode dropTableNode = new DropTableNode(dropTable.getTableName());
     return dropTableNode;
   }
@@ -880,18 +869,18 @@ public class LogicalPlanner {
           plan.getBlock(blockName).setHasGrouping();
 
           return new AggFuncCallEval(countRows, (AggFunction) countRows.newInstance(),
-              new EvalNode [] {});
+              new EvalNode[] {});
         } catch (InternalException e) {
           throw new UndefinedFunctionException(CatalogUtil.
-              getCanonicalName(countRows.getSignature(), new DataType[] {}));
+              getCanonicalName(countRows.getSignature(), new DataType[]{}));
         }
 
       case CountValueFunction:
       case Function:
         FunctionExpr function = (FunctionExpr) expr;
         // Given parameters
-        Expr [] params = function.getParams();
-        EvalNode [] givenArgs = new EvalNode[params.length];
+        Expr[] params = function.getParams();
+        EvalNode[] givenArgs = new EvalNode[params.length];
         DataType[] paramTypes = new DataType[params.length];
 
         if (expr.getType() == OpType.CountValueFunction) {
@@ -990,7 +979,7 @@ public class LogicalPlanner {
     return caseEval;
   }
 
-  Target [] annotateTargets(LogicalPlan plan, String blockName,
+  Target[] annotateTargets(LogicalPlan plan, String blockName,
                                        org.apache.tajo.algebra.Target [] targets)
       throws VerifyException {
     Target annotatedTargets [] = new Target[targets.length];
@@ -1014,7 +1003,7 @@ public class LogicalPlanner {
   /**
    * It transforms a list of targets to schema. If it contains anonymous targets, it names them.
    */
-  static Schema getProjectedSchema(LogicalPlan plan, Target [] targets) {
+  static Schema getProjectedSchema(LogicalPlan plan, Target[] targets) {
     Schema projected = new Schema();
     for(Target t : targets) {
       DataType type = t.getEvalTree().getValueType()[0];

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/87420eb3/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/TargetListManager.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/TargetListManager.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/TargetListManager.java
index 739a23d..d30c047 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/TargetListManager.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/TargetListManager.java
@@ -31,8 +31,8 @@ import java.util.Collection;
 public class TargetListManager {
   private LogicalPlan plan;
   private boolean [] evaluatedFlags;
-  private Target [] targets;
-  private Target [] unevaluatedTargets;
+  private Target[] targets;
+  private Target[] unevaluatedTargets;
 
   public TargetListManager(LogicalPlan plan, int targetNum) {
     this.plan = plan;
@@ -45,7 +45,7 @@ public class TargetListManager {
     this.unevaluatedTargets = new Target[targetNum];
   }
 
-  public TargetListManager(LogicalPlan plan, Target [] original) {
+  public TargetListManager(LogicalPlan plan, Target[] original) {
     this.plan = plan;
 
     targets = new Target[original.length];
@@ -69,11 +69,11 @@ public class TargetListManager {
     return targets[id];
   }
 
-  public Target [] getTargets() {
+  public Target[] getTargets() {
     return this.targets;
   }
 
-  public Target [] getUnEvaluatedTargets() {
+  public Target[] getUnEvaluatedTargets() {
     return this.unevaluatedTargets;
   }
 
@@ -100,8 +100,8 @@ public class TargetListManager {
     return evaluatedFlags[id];
   }
 
-  public Target [] getUpdatedTarget() throws CloneNotSupportedException {
-    Target [] updated = new Target[targets.length];
+  public Target[] getUpdatedTarget() throws PlanningException {
+    Target[] updated = new Target[targets.length];
     for (int i = 0; i < targets.length; i++) {
       if (targets[i] == null) { // if it is not created
         continue;
@@ -111,7 +111,11 @@ public class TargetListManager {
         Column col = getEvaluatedColumn(i);
         updated[i] = new Target(new FieldEval(col));
       } else {
-        updated[i] = (Target) targets[i].clone();
+        try {
+          updated[i] = (Target) targets[i].clone();
+        } catch (CloneNotSupportedException e) {
+          throw new PlanningException(e);
+        }
       }
     }
     targets = updated;

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/87420eb3/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/master/GlobalEngine.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/master/GlobalEngine.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/master/GlobalEngine.java
index 3710f02..a0bd27f 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/master/GlobalEngine.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/master/GlobalEngine.java
@@ -229,7 +229,7 @@ public class GlobalEngine extends AbstractService {
     LogicalNode optimizedPlan = null;
     try {
       optimizedPlan = LogicalOptimizer.optimize(plan);
-    } catch (CloneNotSupportedException e) {
+    } catch (PlanningException e) {
       e.printStackTrace();
     }
     LOG.info("LogicalPlan:\n" + plan.getRootBlock().getRoot());

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/87420eb3/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/BackendTestingUtil.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/BackendTestingUtil.java b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/BackendTestingUtil.java
index 361a560..77f665f 100644
--- a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/BackendTestingUtil.java
+++ b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/BackendTestingUtil.java
@@ -106,7 +106,7 @@ public class BackendTestingUtil {
   }
 
   public ResultSet run(String [] tableNames, File [] tables, Schema [] schemas, String query)
-      throws IOException, CloneNotSupportedException {
+      throws IOException, PlanningException {
     Path workDir = createTmpTestDir();
     StorageManager sm = StorageManager.get(new TajoConf(), workDir);
     List<Fragment> frags = Lists.newArrayList();

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/87420eb3/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/plan/global/TestGlobalQueryPlanner.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/plan/global/TestGlobalQueryPlanner.java b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/plan/global/TestGlobalQueryPlanner.java
index c3c9e04..def2506 100644
--- a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/plan/global/TestGlobalQueryPlanner.java
+++ b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/plan/global/TestGlobalQueryPlanner.java
@@ -34,7 +34,10 @@ import org.apache.tajo.datum.Datum;
 import org.apache.tajo.datum.DatumFactory;
 import org.apache.tajo.engine.eval.TestEvalTree.TestSum;
 import org.apache.tajo.engine.parser.SQLAnalyzer;
-import org.apache.tajo.engine.planner.*;
+import org.apache.tajo.engine.planner.LogicalOptimizer;
+import org.apache.tajo.engine.planner.LogicalPlan;
+import org.apache.tajo.engine.planner.LogicalPlanner;
+import org.apache.tajo.engine.planner.PlanningException;
 import org.apache.tajo.engine.planner.global.MasterPlan;
 import org.apache.tajo.engine.planner.logical.*;
 import org.apache.tajo.master.ExecutionBlock;
@@ -142,7 +145,7 @@ public class TestGlobalQueryPlanner {
   }
   
   @Test
-  public void testScan() throws IOException, CloneNotSupportedException {
+  public void testScan() throws IOException, PlanningException {
     Expr context = analyzer.parse(
         "select age, sumtest(salary) from table0");
 
@@ -164,7 +167,7 @@ public class TestGlobalQueryPlanner {
 
   @Test
   public void testGroupby() throws IOException, KeeperException,
-      InterruptedException, CloneNotSupportedException {
+      InterruptedException, PlanningException {
     Expr context = analyzer.parse(
         "create table store1 as select age, sumtest(salary) from table0 group by age");
     LogicalPlan plan = logicalPlanner.createPlan(context);
@@ -202,7 +205,7 @@ public class TestGlobalQueryPlanner {
   }
   
   @Test
-  public void testSort() throws IOException, CloneNotSupportedException {
+  public void testSort() throws IOException, PlanningException {
     Expr context = analyzer.parse(
         "create table store1 as select age from table0 order by age");
     LogicalPlan plan = logicalPlanner.createPlan(context);
@@ -244,7 +247,7 @@ public class TestGlobalQueryPlanner {
   }
   
   @Test
-  public void testJoin() throws IOException, CloneNotSupportedException {
+  public void testJoin() throws IOException, PlanningException {
     Expr expr = analyzer.parse(
         "select table0.age,table0.salary,table1.salary from table0,table1 " +
             "where table0.salary = table1.salary order by table0.age");
@@ -312,7 +315,7 @@ public class TestGlobalQueryPlanner {
   }
   
   @Test
-  public void testSelectAfterJoin() throws IOException, CloneNotSupportedException {
+  public void testSelectAfterJoin() throws IOException, PlanningException {
     String query = "select table0.name, table1.salary from table0,table1 where table0.name = table1.name and table1.salary > 10";
     Expr context = analyzer.parse(query);
     LogicalPlan plan = logicalPlanner.createPlan(context);
@@ -335,7 +338,7 @@ public class TestGlobalQueryPlanner {
   }
   
   //@Test
-  public void testCubeby() throws IOException, CloneNotSupportedException {
+  public void testCubeby() throws IOException, PlanningException {
     Expr expr = analyzer.parse(
         "select age, sum(salary) from table0 group by cube (age, id)");
     LogicalPlan plan = logicalPlanner.createPlan(expr);

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/87420eb3/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/TestLogicalOptimizer.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/TestLogicalOptimizer.java b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/TestLogicalOptimizer.java
index fe2b114..d55b9e4 100644
--- a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/TestLogicalOptimizer.java
+++ b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/TestLogicalOptimizer.java
@@ -104,7 +104,7 @@ public class TestLogicalOptimizer {
   };
   
   @Test
-  public final void testProjectionPushWithNaturalJoin() throws CloneNotSupportedException {
+  public final void testProjectionPushWithNaturalJoin() throws PlanningException, CloneNotSupportedException {
     // two relations
     Expr expr = sqlAnalyzer.parse(QUERIES[4]);
     LogicalPlan newPlan = planner.createPlan(expr);
@@ -131,7 +131,7 @@ public class TestLogicalOptimizer {
   }
   
   @Test
-  public final void testProjectionPushWithInnerJoin() throws CloneNotSupportedException {
+  public final void testProjectionPushWithInnerJoin() throws PlanningException {
     // two relations
     Expr expr = sqlAnalyzer.parse(QUERIES[5]);
     LogicalPlan newPlan = planner.createPlan(expr);
@@ -139,7 +139,7 @@ public class TestLogicalOptimizer {
   }
   
   @Test
-  public final void testProjectionPush() throws CloneNotSupportedException {
+  public final void testProjectionPush() throws CloneNotSupportedException, PlanningException {
     // two relations
     Expr expr = sqlAnalyzer.parse(QUERIES[2]);
     LogicalPlan newPlan = planner.createPlan(expr);
@@ -162,7 +162,7 @@ public class TestLogicalOptimizer {
   }
   
   @Test
-  public final void testOptimizeWithGroupBy() throws CloneNotSupportedException {
+  public final void testOptimizeWithGroupBy() throws CloneNotSupportedException, PlanningException {
     Expr expr = sqlAnalyzer.parse(QUERIES[3]);
     LogicalPlan newPlan = planner.createPlan(expr);
     LogicalNode plan = newPlan.getRootBlock().getRoot();
@@ -188,7 +188,7 @@ public class TestLogicalOptimizer {
   }
 
   @Test
-  public final void testPushable() throws CloneNotSupportedException {
+  public final void testPushable() throws CloneNotSupportedException, PlanningException {
     // two relations
     Expr expr = sqlAnalyzer.parse(QUERIES[0]);
     LogicalPlan newPlan = planner.createPlan(expr);

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/87420eb3/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/global/TestGlobalQueryOptimizer.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/global/TestGlobalQueryOptimizer.java b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/global/TestGlobalQueryOptimizer.java
index 0c6b1e7..1d2b0c1 100644
--- a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/global/TestGlobalQueryOptimizer.java
+++ b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/global/TestGlobalQueryOptimizer.java
@@ -40,6 +40,7 @@ import org.apache.tajo.engine.parser.SQLAnalyzer;
 import org.apache.tajo.engine.planner.LogicalOptimizer;
 import org.apache.tajo.engine.planner.LogicalPlan;
 import org.apache.tajo.engine.planner.LogicalPlanner;
+import org.apache.tajo.engine.planner.PlanningException;
 import org.apache.tajo.engine.planner.logical.*;
 import org.apache.tajo.master.ExecutionBlock;
 import org.apache.tajo.master.GlobalPlanner;
@@ -136,7 +137,7 @@ public class TestGlobalQueryOptimizer {
   }
 
   @Test
-  public void testReduceLogicalQueryUnitSteps() throws IOException, CloneNotSupportedException {
+  public void testReduceLogicalQueryUnitSteps() throws IOException, PlanningException {
     Expr expr = analyzer.parse(
         "select table0.age,table0.salary,table1.salary from table0,table1 where table0.salary = table1.salary order by table0.age");
     LogicalPlan plan = logicalPlanner.createPlan(expr);

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/87420eb3/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/physical/TestPhysicalPlanner.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/physical/TestPhysicalPlanner.java b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/physical/TestPhysicalPlanner.java
index 77b43f1..e329fad 100644
--- a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/physical/TestPhysicalPlanner.java
+++ b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/physical/TestPhysicalPlanner.java
@@ -177,7 +177,7 @@ public class TestPhysicalPlanner {
   };
 
   @Test
-  public final void testCreateScanPlan() throws IOException, CloneNotSupportedException {
+  public final void testCreateScanPlan() throws IOException, PlanningException {
     Fragment[] frags = StorageManager.splitNG(conf, "employee", employee.getMeta(),
         employee.getPath(), Integer.MAX_VALUE);
     Path workDir = CommonTestingUtil.getTestDir("target/test-data/testCreateScanPlan");
@@ -207,7 +207,7 @@ public class TestPhysicalPlanner {
   }
 
   @Test
-  public final void testGroupByPlan() throws IOException, CloneNotSupportedException {
+  public final void testGroupByPlan() throws IOException, PlanningException {
     Fragment[] frags = StorageManager.splitNG(conf, "score", score.getMeta(), score.getPath(),
         Integer.MAX_VALUE);
     Path workDir = CommonTestingUtil.getTestDir("target/test-data/testGroupByPlan");
@@ -238,8 +238,7 @@ public class TestPhysicalPlanner {
   }
 
   @Test
-  public final void testHashGroupByPlanWithALLField() throws IOException,
-      CloneNotSupportedException {
+  public final void testHashGroupByPlanWithALLField() throws IOException, PlanningException {
     // TODO - currently, this query does not use hash-based group operator.
     Fragment[] frags = StorageManager.splitNG(conf, "score", score.getMeta(), score.getPath(),
         Integer.MAX_VALUE);
@@ -269,7 +268,7 @@ public class TestPhysicalPlanner {
   }
 
   @Test
-  public final void testSortGroupByPlan() throws IOException, CloneNotSupportedException {
+  public final void testSortGroupByPlan() throws IOException, PlanningException {
     Fragment[] frags = StorageManager.splitNG(conf, "score", score.getMeta(), score.getPath(),
         Integer.MAX_VALUE);
     Path workDir = CommonTestingUtil.getTestDir("target/test-data/testSortGroupByPlan");
@@ -326,7 +325,7 @@ public class TestPhysicalPlanner {
   };
 
   @Test
-  public final void testStorePlan() throws IOException, CloneNotSupportedException {
+  public final void testStorePlan() throws IOException, PlanningException {
     Fragment[] frags = StorageManager.splitNG(conf, "score", score.getMeta(), score.getPath(),
         Integer.MAX_VALUE);
     Path workDir = CommonTestingUtil.getTestDir("target/test-data/testStorePlan");
@@ -367,7 +366,7 @@ public class TestPhysicalPlanner {
   }
 
   @Test
-  public final void testStorePlanWithRCFile() throws IOException, CloneNotSupportedException {
+  public final void testStorePlanWithRCFile() throws IOException, PlanningException {
     Fragment[] frags = StorageManager.splitNG(conf, "score", score.getMeta(), score.getPath(),
         Integer.MAX_VALUE);
     Path workDir = CommonTestingUtil.getTestDir("target/test-data/testStorePlanWithRCFile");
@@ -407,7 +406,7 @@ public class TestPhysicalPlanner {
   }
 
   @Test
-  public final void testPartitionedStorePlan() throws IOException, CloneNotSupportedException {
+  public final void testPartitionedStorePlan() throws IOException, PlanningException {
     Fragment[] frags = StorageManager.splitNG(conf, "score", score.getMeta(), score.getPath(),
         Integer.MAX_VALUE);
     QueryUnitAttemptId id = TUtil.newQueryUnitAttemptId();
@@ -466,7 +465,7 @@ public class TestPhysicalPlanner {
 
   @Test
   public final void testPartitionedStorePlanWithEmptyGroupingSet()
-      throws IOException, CloneNotSupportedException {
+      throws IOException, PlanningException {
     Fragment[] frags = StorageManager.splitNG(conf, "score", score.getMeta(), score.getPath(),
         Integer.MAX_VALUE);
     QueryUnitAttemptId id = TUtil.newQueryUnitAttemptId();
@@ -522,7 +521,7 @@ public class TestPhysicalPlanner {
   }
 
   @Test
-  public final void testAggregationFunction() throws IOException, CloneNotSupportedException {
+  public final void testAggregationFunction() throws IOException, PlanningException {
     Fragment[] frags = StorageManager.splitNG(conf, "score", score.getMeta(), score.getPath(),
         Integer.MAX_VALUE);
     Path workDir = CommonTestingUtil.getTestDir("target/test-data/testAggregationFunction");
@@ -555,7 +554,7 @@ public class TestPhysicalPlanner {
   }
 
   @Test
-  public final void testCountFunction() throws IOException, CloneNotSupportedException {
+  public final void testCountFunction() throws IOException, PlanningException {
     Fragment[] frags = StorageManager.splitNG(conf, "score", score.getMeta(), score.getPath(),
         Integer.MAX_VALUE);
     Path workDir = CommonTestingUtil.getTestDir("target/test-data/testCountFunction");
@@ -586,7 +585,7 @@ public class TestPhysicalPlanner {
   }
 
   @Test
-  public final void testGroupByWithNullValue() throws IOException, CloneNotSupportedException {
+  public final void testGroupByWithNullValue() throws IOException, PlanningException {
     Fragment[] frags = StorageManager.splitNG(conf, "score", score.getMeta(), score.getPath(),
         Integer.MAX_VALUE);
     Path workDir = CommonTestingUtil.getTestDir("target/test-data/testGroupByWithNullValue");
@@ -609,7 +608,7 @@ public class TestPhysicalPlanner {
   }
 
   @Test
-  public final void testUnionPlan() throws IOException, CloneNotSupportedException {
+  public final void testUnionPlan() throws IOException, PlanningException {
     Fragment[] frags = StorageManager.splitNG(conf, "employee", employee.getMeta(), employee.getPath(),
         Integer.MAX_VALUE);
     Path workDir = CommonTestingUtil.getTestDir("target/test-data/testUnionPlan");
@@ -635,7 +634,7 @@ public class TestPhysicalPlanner {
   }
 
   @Test
-  public final void testEvalExpr() throws IOException, CloneNotSupportedException {
+  public final void testEvalExpr() throws IOException, PlanningException {
     Path workDir = CommonTestingUtil.getTestDir("target/test-data/testEvalExpr");
     TaskAttemptContext ctx = new TaskAttemptContext(conf, TUtil.newQueryUnitAttemptId(),
         new Fragment[] { }, workDir);
@@ -669,7 +668,7 @@ public class TestPhysicalPlanner {
   };
 
   //@Test
-  public final void testCreateIndex() throws IOException, CloneNotSupportedException {
+  public final void testCreateIndex() throws IOException, PlanningException {
     Fragment[] frags = StorageManager.splitNG(conf, "employee", employee.getMeta(), employee.getPath(),
         Integer.MAX_VALUE);
     Path workDir = CommonTestingUtil.getTestDir("target/test-data/testCreateIndex");
@@ -695,7 +694,7 @@ public class TestPhysicalPlanner {
   };
 
   @Test
-  public final void testDuplicateEliminate() throws IOException, CloneNotSupportedException {
+  public final void testDuplicateEliminate() throws IOException, PlanningException {
     Fragment[] frags = StorageManager.splitNG(conf, "score", score.getMeta(), score.getPath(),
         Integer.MAX_VALUE);
 
@@ -727,7 +726,7 @@ public class TestPhysicalPlanner {
   };
 
   @Test
-  public final void testIndexedStoreExec() throws IOException, CloneNotSupportedException {
+  public final void testIndexedStoreExec() throws IOException, PlanningException {
     Fragment[] frags = StorageManager.splitNG(conf, "employee", employee.getMeta(),
         employee.getPath(), Integer.MAX_VALUE);
 

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/87420eb3/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/physical/TestSortExec.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/physical/TestSortExec.java b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/physical/TestSortExec.java
index 472a371..be389a3 100644
--- a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/physical/TestSortExec.java
+++ b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/physical/TestSortExec.java
@@ -104,7 +104,7 @@ public class TestSortExec {
       "select managerId, empId, deptName from employee order by managerId, empId desc" };
 
   @Test
-  public final void testNext() throws IOException, CloneNotSupportedException {
+  public final void testNext() throws IOException, PlanningException {
     Fragment [] frags = sm.splitNG(conf, "employee", employeeMeta, tablePath, Integer.MAX_VALUE);
     Path workDir = CommonTestingUtil.getTestDir("target/test-data/TestSortExec");
     TaskAttemptContext ctx = new TaskAttemptContext(conf, TUtil