tajo-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From hyun...@apache.org
Subject [2/2] git commit: TAJO-595: The same expressions without different alias are not allowed. (hyunsik)
Date Mon, 17 Feb 2014 10:03:10 GMT
TAJO-595: The same expressions without different alias are not allowed. (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/fbc358c2
Tree: http://git-wip-us.apache.org/repos/asf/incubator-tajo/tree/fbc358c2
Diff: http://git-wip-us.apache.org/repos/asf/incubator-tajo/diff/fbc358c2

Branch: refs/heads/master
Commit: fbc358c2030e78f6616b286cf0736afaa8a583f8
Parents: ae541ff
Author: Hyunsik Choi <hyunsik@apache.org>
Authored: Mon Feb 17 19:01:52 2014 +0900
Committer: Hyunsik Choi <hyunsik@apache.org>
Committed: Mon Feb 17 19:02:10 2014 +0900

----------------------------------------------------------------------
 CHANGES.txt                                     |   5 +-
 .../org/apache/tajo/algebra/LiteralValue.java   |   6 +
 .../java/org/apache/tajo/catalog/Schema.java    |   2 +-
 .../org/apache/tajo/engine/eval/EvalNode.java   |   4 +
 .../tajo/engine/planner/ExprNormalizer.java     |   2 +-
 .../tajo/engine/planner/ExprsVerifier.java      |  96 +++--
 .../apache/tajo/engine/planner/InsertNode.java  |   2 +-
 .../apache/tajo/engine/planner/LogicalPlan.java |  46 ++-
 .../engine/planner/LogicalPlanPreprocessor.java |   4 +-
 .../engine/planner/LogicalPlanVerifier.java     |  70 +++-
 .../tajo/engine/planner/LogicalPlanner.java     | 134 +++----
 .../tajo/engine/planner/NamedExprsManager.java  | 299 +++++++++------
 .../apache/tajo/engine/planner/PlanString.java  |   6 +
 .../apache/tajo/engine/planner/PlannerUtil.java |  13 +-
 .../engine/planner/PreLogicalPlanVerifier.java  |  18 +-
 .../engine/planner/global/GlobalPlanner.java    |   5 +-
 .../engine/planner/logical/CreateTableNode.java |   2 +-
 .../engine/planner/logical/DropTableNode.java   |   2 +-
 .../tajo/engine/planner/logical/ExceptNode.java |   2 +-
 .../engine/planner/logical/GroupbyNode.java     |   2 +-
 .../tajo/engine/planner/logical/HavingNode.java |   2 +-
 .../engine/planner/logical/IntersectNode.java   |   2 +-
 .../tajo/engine/planner/logical/JoinNode.java   |   3 +-
 .../tajo/engine/planner/logical/LimitNode.java  |   2 +-
 .../engine/planner/logical/LogicalRootNode.java |   2 +-
 .../logical/PartitionedTableScanNode.java       |   2 +-
 .../planner/logical/PersistentStoreNode.java    |   2 +-
 .../engine/planner/logical/Projectable.java     |  39 ++
 .../engine/planner/logical/ProjectionNode.java  |   4 +-
 .../tajo/engine/planner/logical/ScanNode.java   |   2 +-
 .../engine/planner/logical/SelectionNode.java   |   2 +-
 .../tajo/engine/planner/logical/SortNode.java   |   2 +-
 .../engine/planner/logical/StoreTableNode.java  |   2 +-
 .../planner/logical/TableSubQueryNode.java      |   2 +-
 .../tajo/engine/planner/logical/UnionNode.java  |   2 +-
 .../planner/rewrite/ProjectionPushDownRule.java | 361 +++++++++++++------
 .../org/apache/tajo/master/GlobalEngine.java    |   9 +-
 .../tajo/master/querymaster/Repartitioner.java  |   7 +-
 .../tajo/engine/query/TestGroupByQuery.java     |  17 +-
 .../apache/tajo/engine/query/TestJoinQuery.java |  17 +-
 .../tajo/engine/query/TestSelectQuery.java      |  24 ++
 .../testGroupByWithSameExprs1.sql               |   6 +
 .../testGroupByWithSameExprs2.sql               |   6 +
 .../TestJoinQuery/testJoinCoReferredEvals1.sql  |  11 +
 .../testJoinCoReferredEvalsWithSameExprs1.sql   |  14 +
 .../testJoinCoReferredEvalsWithSameExprs2.sql   |  22 ++
 .../queries/TestJoinQuery/testJoinRefEval.sql   |  11 -
 .../TestSelectQuery/testSelectAsterisk5.sql     |   1 +
 ...tSelectSameConstantsWithDifferentAliases.sql |   1 +
 .../testSelectSameExprsWithDifferentAliases.sql |   1 +
 .../testGroupByWithSameExprs1.result            |   6 +
 .../testGroupByWithSameExprs2.result            |   6 +
 .../testPartialFilterPushDown.result            |   2 +-
 .../testJoinCoReferredEvals1.result             |  27 ++
 ...testJoinCoReferredEvalsWithSameExprs1.result |  22 ++
 ...testJoinCoReferredEvalsWithSameExprs2.result |  22 ++
 .../TestJoinQuery/testJoinRefEval.result        |  27 --
 .../TestSelectQuery/testSelectAsterisk5.result  |   3 +
 ...lectSameConstantsWithDifferentAliases.result |   7 +
 ...stSelectSameExprsWithDifferentAliases.result |   7 +
 60 files changed, 993 insertions(+), 434 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/fbc358c2/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index 879d816..4bcaa2b 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -256,7 +256,10 @@ Release 0.8.0 - unreleased
 
   BUG FIXES
 
-    TAJO-554: LogicalPlanner should allow additional expressions with asterisk 
+    TAJO-595: The same expressions without different alias are not allowed.
+    (hyunsik)
+
+    TAJO-554: LogicalPlanner should allow additional expressions with asterisk
     in select list. (jihoon)
 
     TAJO-593: outer groupby and groupby in derived table causes only one

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/fbc358c2/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 f7d7720..2978c06 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
@@ -57,4 +57,10 @@ public class LiteralValue extends Expr {
 
     return a && b;
   }
+
+  public String toString() {
+    StringBuilder sb = new StringBuilder(valueType == LiteralType.String ? "'" + value + "'" : value);
+    sb.append("(").append(valueType).append(")");
+    return sb.toString();
+  }
 }

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/fbc358c2/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/Schema.java
----------------------------------------------------------------------
diff --git a/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/Schema.java b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/Schema.java
index 2f57ff2..f253151 100644
--- a/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/Schema.java
+++ b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/Schema.java
@@ -311,7 +311,7 @@ public class Schema implements ProtoObject<SchemaProto>, Cloneable, GsonObject {
 	  for(Column col : fields) {
 	    sb.append(col);
 	    if (i < fields.size() - 1) {
-	      sb.append(",");
+	      sb.append(", ");
 	    }
 	    i++;
 	  }

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/fbc358c2/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalNode.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalNode.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalNode.java
index 5578043..1180bde 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalNode.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalNode.java
@@ -26,6 +26,10 @@ import org.apache.tajo.engine.json.CoreGsonHelper;
 import org.apache.tajo.json.GsonObject;
 import org.apache.tajo.storage.Tuple;
 
+/**
+ * An annotated expression which includes actual data domains.
+ * It is also used for evaluation.
+ */
 public abstract class EvalNode implements Cloneable, GsonObject {
 	@Expose protected EvalType type;
 	@Expose protected EvalNode leftExpr;

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/fbc358c2/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/ExprNormalizer.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/ExprNormalizer.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/ExprNormalizer.java
index 6363bf6..e7de03f 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/ExprNormalizer.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/ExprNormalizer.java
@@ -196,7 +196,7 @@ class ExprNormalizer extends SimpleAlgebraVisitor<ExprNormalizer.ExprNormalizedR
       visit(ctx, stack, param);
 
       if (isAggregationFunction(param)) {
-        String referenceName = ctx.plan.newGeneratedFieldName(param);
+        String referenceName = ctx.plan.generateUniqueColumnName(param);
         ctx.aggExprs.add(new NamedExpr(param, referenceName));
         expr.getParams()[i] = new ColumnReferenceExpr(referenceName);
       }

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/fbc358c2/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/ExprsVerifier.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/ExprsVerifier.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/ExprsVerifier.java
index c473ac1..b14c448 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/ExprsVerifier.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/ExprsVerifier.java
@@ -18,13 +18,23 @@
 
 package org.apache.tajo.engine.planner;
 
+import org.apache.tajo.catalog.Column;
 import org.apache.tajo.engine.eval.*;
+import org.apache.tajo.engine.planner.logical.LogicalNode;
 
+import java.util.Set;
 import java.util.Stack;
 
 import static org.apache.tajo.common.TajoDataTypes.DataType;
 import static org.apache.tajo.common.TajoDataTypes.Type;
 
+/**
+ * It verifies one predicate or expression with the semantic and data type checks as follows:
+ * <ul>
+ *   <ul>Both expressions in a binary expression are compatible to each other</ul>
+ *   <ul>All column references of one expression are avilable at this node</ul>
+ * </ul>
+ */
 public class ExprsVerifier extends BasicEvalNodeVisitor<VerificationState, EvalNode> {
   private static final ExprsVerifier instance;
 
@@ -32,11 +42,22 @@ public class ExprsVerifier extends BasicEvalNodeVisitor<VerificationState, EvalN
     instance = new ExprsVerifier();
   }
 
-  public static VerificationState verify(VerificationState state, EvalNode expression) {
+  public static VerificationState verify(VerificationState state, LogicalNode currentNode, EvalNode expression)
+      throws PlanningException {
     instance.visitChild(state, expression, new Stack<EvalNode>());
+    Set<Column> referredColumns = EvalTreeUtil.findDistinctRefColumns(expression);
+    for (Column referredColumn : referredColumns) {
+      if (!currentNode.getInSchema().contains(referredColumn)) {
+        throw new PlanningException("Invalid State: " + referredColumn + " cannot be referred at Node ("
+            + currentNode.getPID() + ")");
+      }
+    }
     return state;
   }
 
+  /**
+   * It checks the compatibility of two data types.
+   */
   private static boolean isCompatibleType(DataType dataType1, DataType dataType2) {
     if (checkNumericType(dataType1) && checkNumericType(dataType2)) {
       return true;
@@ -53,6 +74,9 @@ public class ExprsVerifier extends BasicEvalNodeVisitor<VerificationState, EvalN
     return false;
   }
 
+  /**
+   * It checks both expressions in a comparison operator are compatible to each other.
+   */
   private static void verifyComparisonOperator(VerificationState state, BinaryEval expr) {
     DataType leftType = expr.getLeftExpr().getValueType();
     DataType rightType = expr.getRightExpr().getValueType();
@@ -61,43 +85,43 @@ public class ExprsVerifier extends BasicEvalNodeVisitor<VerificationState, EvalN
     }
   }
 
-  public EvalNode visitEqual(VerificationState state, BinaryEval expr, Stack<EvalNode> stack) {
-    super.visitEqual(state, expr, stack);
-    verifyComparisonOperator(state, expr);
+  public EvalNode visitEqual(VerificationState context, BinaryEval expr, Stack<EvalNode> stack) {
+    super.visitEqual(context, expr, stack);
+    verifyComparisonOperator(context, expr);
     return expr;
   }
 
-  public EvalNode visitNotEqual(VerificationState state, BinaryEval expr, Stack<EvalNode> stack) {
-    super.visitNotEqual(state, expr, stack);
-    verifyComparisonOperator(state, expr);
+  public EvalNode visitNotEqual(VerificationState context, BinaryEval expr, Stack<EvalNode> stack) {
+    super.visitNotEqual(context, expr, stack);
+    verifyComparisonOperator(context, expr);
     return expr;
   }
 
   @Override
-  public EvalNode visitLessThan(VerificationState state, BinaryEval expr, Stack<EvalNode> stack) {
-    super.visitLessThan(state, expr, stack);
-    verifyComparisonOperator(state, expr);
+  public EvalNode visitLessThan(VerificationState context, BinaryEval expr, Stack<EvalNode> stack) {
+    super.visitLessThan(context, expr, stack);
+    verifyComparisonOperator(context, expr);
     return expr;
   }
 
   @Override
-  public EvalNode visitLessThanOrEqual(VerificationState state, BinaryEval expr, Stack<EvalNode> stack) {
-    super.visitLessThanOrEqual(state, expr, stack);
-    verifyComparisonOperator(state, expr);
+  public EvalNode visitLessThanOrEqual(VerificationState context, BinaryEval expr, Stack<EvalNode> stack) {
+    super.visitLessThanOrEqual(context, expr, stack);
+    verifyComparisonOperator(context, expr);
     return expr;
   }
 
   @Override
-  public EvalNode visitGreaterThan(VerificationState state, BinaryEval expr, Stack<EvalNode> stack) {
-    super.visitGreaterThan(state, expr, stack);
-    verifyComparisonOperator(state, expr);
+  public EvalNode visitGreaterThan(VerificationState context, BinaryEval expr, Stack<EvalNode> stack) {
+    super.visitGreaterThan(context, expr, stack);
+    verifyComparisonOperator(context, expr);
     return expr;
   }
 
   @Override
-  public EvalNode visitGreaterThanOrEqual(VerificationState state, BinaryEval expr, Stack<EvalNode> stack) {
-    super.visitGreaterThanOrEqual(state, expr, stack);
-    verifyComparisonOperator(state, expr);
+  public EvalNode visitGreaterThanOrEqual(VerificationState context, BinaryEval expr, Stack<EvalNode> stack) {
+    super.visitGreaterThanOrEqual(context, expr, stack);
+    verifyComparisonOperator(context, expr);
     return expr;
   }
 
@@ -135,39 +159,39 @@ public class ExprsVerifier extends BasicEvalNodeVisitor<VerificationState, EvalN
   }
 
   @Override
-  public EvalNode visitPlus(VerificationState state, BinaryEval evalNode, Stack<EvalNode> stack) {
-    super.visitDivide(state, evalNode, stack);
-    checkArithmeticOperand(state, evalNode);
+  public EvalNode visitPlus(VerificationState context, BinaryEval evalNode, Stack<EvalNode> stack) {
+    super.visitPlus(context, evalNode, stack);
+    checkArithmeticOperand(context, evalNode);
     return evalNode;
   }
 
   @Override
-  public EvalNode visitMinus(VerificationState state, BinaryEval evalNode, Stack<EvalNode> stack) {
-    super.visitDivide(state, evalNode, stack);
-    checkArithmeticOperand(state, evalNode);
+  public EvalNode visitMinus(VerificationState context, BinaryEval evalNode, Stack<EvalNode> stack) {
+    super.visitMinus(context, evalNode, stack);
+    checkArithmeticOperand(context, evalNode);
     return evalNode;
   }
 
   @Override
-  public EvalNode visitMultiply(VerificationState state, BinaryEval evalNode, Stack<EvalNode> stack) {
-    super.visitDivide(state, evalNode, stack);
-    checkArithmeticOperand(state, evalNode);
+  public EvalNode visitMultiply(VerificationState context, BinaryEval evalNode, Stack<EvalNode> stack) {
+    super.visitMultiply(context, evalNode, stack);
+    checkArithmeticOperand(context, evalNode);
     return evalNode;
   }
 
   @Override
-  public EvalNode visitDivide(VerificationState state, BinaryEval evalNode, Stack<EvalNode> stack) {
-    super.visitDivide(state, evalNode, stack);
-    checkArithmeticOperand(state, evalNode);
-    checkDivisionByZero(state, evalNode);
+  public EvalNode visitDivide(VerificationState context, BinaryEval evalNode, Stack<EvalNode> stack) {
+    super.visitDivide(context, evalNode, stack);
+    checkArithmeticOperand(context, evalNode);
+    checkDivisionByZero(context, evalNode);
     return evalNode;
   }
 
   @Override
-  public EvalNode visitModular(VerificationState state, BinaryEval evalNode, Stack<EvalNode> stack) {
-    super.visitDivide(state, evalNode, stack);
-    checkArithmeticOperand(state, evalNode);
-    checkDivisionByZero(state, evalNode);
+  public EvalNode visitModular(VerificationState context, BinaryEval evalNode, Stack<EvalNode> stack) {
+    super.visitDivide(context, evalNode, stack);
+    checkArithmeticOperand(context, evalNode);
+    checkDivisionByZero(context, evalNode);
     return evalNode;
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/fbc358c2/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/InsertNode.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/InsertNode.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/InsertNode.java
index d9645a4..bdc7837 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/InsertNode.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/InsertNode.java
@@ -184,7 +184,7 @@ public class InsertNode extends StoreTableNode implements Cloneable {
 
   @Override
   public PlanString getPlanString() {
-    PlanString planString = new PlanString("INSERT");
+    PlanString planString = new PlanString(this);
     planString.appendTitle(" INTO ");
     if (hasTargetTable()) {
       planString.appendTitle(getTableName());

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/fbc358c2/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 9890943..47bd166 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
@@ -87,20 +87,50 @@ public class LogicalPlan {
     return newAndGetBlock(NONAME_BLOCK_PREFIX + (noNameBlockId++));
   }
 
-  private String generateFieldName(String prefix) {
-    int sequence = noNameColumnId++;
-    return NONAMED_COLUMN_PREFIX + prefix.toLowerCase() + (sequence > 0 ? "_" + sequence : "");
+  /**
+   * It generates an unique column name from EvalNode. It is usually used for an expression or predicate without
+   * a specified name (i.e., alias).
+   */
+  public String generateUniqueColumnName(EvalNode evalNode) {
+    String prefix = evalNode.getName();
+    return attachSeqIdToGeneratedColumnName(prefix).toLowerCase();
   }
 
-  public String newGeneratedFieldName(EvalNode evalNode) {
-    String prefix = evalNode.getName();
-    return generateFieldName(prefix);
+  /**
+   * It generates an unique column name from Expr. It is usually used for an expression or predicate without
+   * a specified name (i.e., alias).
+   */
+  public String generateUniqueColumnName(Expr expr) {
+    String generatedName;
+    if (expr.getType() == OpType.Column) {
+      generatedName = ((ColumnReferenceExpr) expr).getCanonicalName();
+    } else { // if a generated column name
+      generatedName = attachSeqIdToGeneratedColumnName(getGeneratedPrefixFromExpr(expr));
+    }
+    return generatedName.toLowerCase();
   }
 
-  public String newGeneratedFieldName(Expr expr) {
+  /**
+   * It attaches a generated column name with a sequence id. It always keeps generated names unique.
+   */
+  private String attachSeqIdToGeneratedColumnName(String prefix) {
+    int sequence = noNameColumnId++;
+    return NONAMED_COLUMN_PREFIX + prefix.toLowerCase() + (sequence > 0 ? "_" + sequence : "");
+  }
+
+  /**
+   * It generates a column reference prefix name. It is usually used for an expression or predicate without
+   * a specified name (i.e., alias). For example, a predicate in WHERE does not have any alias name.
+   * It just returns a prefix name. In other words, it always returns the same prefix for the same type of expressions.
+   * So, you must add some suffix to the returned name in order to distinguish reference names.
+   */
+  private static String getGeneratedPrefixFromExpr(Expr expr) {
     String prefix;
 
     switch (expr.getType()) {
+    case Column:
+      prefix = ((ColumnReferenceExpr) expr).getCanonicalName();
+      break;
     case CountRowsFunction:
       prefix = "count";
       break;
@@ -115,7 +145,7 @@ public class LogicalPlan {
     default:
       prefix = expr.getType().name();
     }
-    return generateFieldName(prefix);
+    return prefix;
   }
 
   public QueryBlock getRootBlock() {

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/fbc358c2/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlanPreprocessor.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlanPreprocessor.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlanPreprocessor.java
index df9b952..a6bedcf 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlanPreprocessor.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlanPreprocessor.java
@@ -203,7 +203,9 @@ class LogicalPlanPreprocessor extends BaseAlgebraVisitor<LogicalPlanPreprocessor
       } else if (evalNode.getType() == EvalType.FIELD) {
         targets[i] = new Target((FieldEval) evalNode);
       } else {
-        targets[i] = new Target(evalNode, "?name_" + i);
+        String generatedName = ctx.plan.generateUniqueColumnName(namedExpr.getExpr());
+        targets[i] = new Target(evalNode, generatedName);
+        namedExpr.setAlias(generatedName);
       }
     }
     stack.pop(); // <--- Pop

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/fbc358c2/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlanVerifier.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlanVerifier.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlanVerifier.java
index 9c58b7d..6800519 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlanVerifier.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlanVerifier.java
@@ -36,23 +36,50 @@ public class LogicalPlanVerifier extends BasicLogicalPlanVisitor<VerificationSta
     this.catalog = catalog;
   }
 
+  /**
+   * It checks if an output schema of a projectable node and target's output data types are equivalent to each other.
+   */
+  private static void verifyProjectableOutputSchema(Projectable node) throws PlanningException {
+
+    Schema outputSchema = node.getOutSchema();
+    Schema targetSchema = PlannerUtil.targetToSchema(node.getTargets());
+
+    if (outputSchema.getColumnNum() != node.getTargets().length) {
+      throw new PlanningException(String.format("Output schema and Target's schema are mismatched at Node (%d)",
+          + node.getPID()));
+    }
+
+    for (int i = 0; i < outputSchema.getColumnNum(); i++) {
+      if (!outputSchema.getColumn(i).getDataType().equals(targetSchema.getColumn(i).getDataType())) {
+        Column targetColumn = targetSchema.getColumn(i);
+        Column insertColumn = outputSchema.getColumn(i);
+        throw new PlanningException("ERROR: " +
+            insertColumn.getColumnName() + " is of type " + insertColumn.getDataType().getType().name() +
+            ", but target column '" + targetColumn.getColumnName() + "' is of type " +
+            targetColumn.getDataType().getType().name());
+      }
+    }
+  }
+
   @Override
   public LogicalNode visitProjection(VerificationState state, LogicalPlan plan, LogicalPlan.QueryBlock block,
                                      ProjectionNode node, Stack<LogicalNode> stack) throws PlanningException {
-    visit(state, plan, block, node.getChild(), stack);
+    super.visitProjection(state, plan, block, node, stack);
 
     for (Target target : node.getTargets()) {
-      ExprsVerifier.verify(state, target.getEvalTree());
+      ExprsVerifier.verify(state, node, target.getEvalTree());
     }
 
+    verifyProjectableOutputSchema(node);
+
     return node;
   }
 
   @Override
   public LogicalNode visitLimit(VerificationState state, LogicalPlan plan, LogicalPlan.QueryBlock block,
                                 LimitNode node, Stack<LogicalNode> stack) throws PlanningException {
+    super.visitLimit(state, plan, block, node, stack);
 
-    visit(state, plan, block, node.getChild(), stack);
     if (node.getFetchFirstNum() < 0) {
       state.addVerification("LIMIT must not be negative");
     }
@@ -63,7 +90,9 @@ public class LogicalPlanVerifier extends BasicLogicalPlanVisitor<VerificationSta
   @Override
   public LogicalNode visitGroupBy(VerificationState state, LogicalPlan plan, LogicalPlan.QueryBlock block,
                                   GroupbyNode node, Stack<LogicalNode> stack) throws PlanningException {
-    visit(state, plan, block, node.getChild(), stack);
+    super.visitGroupBy(state, plan, block, node, stack);
+
+    verifyProjectableOutputSchema(node);
     return node;
   }
 
@@ -71,7 +100,7 @@ public class LogicalPlanVerifier extends BasicLogicalPlanVisitor<VerificationSta
   public LogicalNode visitFilter(VerificationState state, LogicalPlan plan, LogicalPlan.QueryBlock block,
                                  SelectionNode node, Stack<LogicalNode> stack) throws PlanningException {
     visit(state, plan, block, node.getChild(), stack);
-    ExprsVerifier.verify(state, node.getQual());
+    ExprsVerifier.verify(state, node, node.getQual());
     return node;
   }
 
@@ -82,9 +111,11 @@ public class LogicalPlanVerifier extends BasicLogicalPlanVisitor<VerificationSta
     visit(state, plan, block, node.getRightChild(), stack);
 
     if (node.hasJoinQual()) {
-      ExprsVerifier.verify(state, node.getJoinQual());
+      ExprsVerifier.verify(state, node, node.getJoinQual());
     }
 
+    verifyProjectableOutputSchema(node);
+
     return node;
   }
 
@@ -114,8 +145,7 @@ public class LogicalPlanVerifier extends BasicLogicalPlanVisitor<VerificationSta
   @Override
   public LogicalNode visitUnion(VerificationState state, LogicalPlan plan, LogicalPlan.QueryBlock block,
                                 UnionNode node, Stack<LogicalNode> stack) throws PlanningException {
-    visit(state, plan, block, node.getLeftChild(), stack);
-    visit(state, plan, block, node.getRightChild(), stack);
+    super.visitUnion(state, plan, block, node, stack);
     verifySetStatement(state, node);
     return node;
   }
@@ -123,7 +153,7 @@ public class LogicalPlanVerifier extends BasicLogicalPlanVisitor<VerificationSta
   @Override
   public LogicalNode visitExcept(VerificationState state, LogicalPlan plan, LogicalPlan.QueryBlock block,
                                  ExceptNode node, Stack<LogicalNode> stack) throws PlanningException {
-    visit(state, plan, block, node, stack);
+    super.visitExcept(state, plan, block, node, stack);
     verifySetStatement(state, node);
     return node;
   }
@@ -131,8 +161,7 @@ public class LogicalPlanVerifier extends BasicLogicalPlanVisitor<VerificationSta
   @Override
   public LogicalNode visitIntersect(VerificationState state, LogicalPlan plan, LogicalPlan.QueryBlock block,
                                     IntersectNode node, Stack<LogicalNode> stack) throws PlanningException {
-    visit(state, plan, block, node.getLeftChild(), stack);
-    visit(state, plan, block, node.getRightChild(), stack);
+    super.visitIntersect(state, plan, block, node, stack);
     verifySetStatement(state, node);
     return node;
   }
@@ -142,30 +171,31 @@ public class LogicalPlanVerifier extends BasicLogicalPlanVisitor<VerificationSta
                                Stack<LogicalNode> stack) throws PlanningException {
     if (node.hasTargets()) {
       for (Target target : node.getTargets()) {
-        ExprsVerifier.verify(state, target.getEvalTree());
+        ExprsVerifier.verify(state, node, target.getEvalTree());
       }
     }
 
     if (node.hasQual()) {
-      ExprsVerifier.verify(state, node.getQual());
+      ExprsVerifier.verify(state, node, node.getQual());
     }
+
+    verifyProjectableOutputSchema(node);
+
     return node;
   }
 
   @Override
   public LogicalNode visitStoreTable(VerificationState state, LogicalPlan plan, LogicalPlan.QueryBlock block,
                                      StoreTableNode node, Stack<LogicalNode> stack) throws PlanningException {
-    visit(state, plan, block, node.getChild(), stack);
-
+    super.visitStoreTable(state, plan, block, node, stack);
     return node;
   }
 
   @Override
   public LogicalNode visitInsert(VerificationState state, LogicalPlan plan, LogicalPlan.QueryBlock block,
                                  InsertNode node, Stack<LogicalNode> stack) throws PlanningException {
-    LogicalNode child = visit(state, plan, block, node.getChild(), stack);
-
-    return child;
+    super.visitInsert(state, plan, block, node, stack);
+    return node;
   }
 
   /**
@@ -187,7 +217,9 @@ public class LogicalPlanVerifier extends BasicLogicalPlanVisitor<VerificationSta
 
   @Override
   public LogicalNode visitCreateTable(VerificationState state, LogicalPlan plan, LogicalPlan.QueryBlock block,
-                                      CreateTableNode node, Stack<LogicalNode> stack) {
+                                      CreateTableNode node, Stack<LogicalNode> stack) throws PlanningException {
+    super.visitCreateTable(state, plan, block, node, stack);
+
     if (catalog.existsTable(node.getTableName())) {
       state.addVerification("relation \"" + node.getTableName() + "\" already exists");
     }

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/fbc358c2/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 9a8fd51..f7c0bfa 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
@@ -21,6 +21,7 @@ package org.apache.tajo.engine.planner;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Joiner;
 import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.hadoop.conf.Configuration;
@@ -320,7 +321,7 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
       if (namedExpr.hasAlias()) {
         targets[i] = new Target(evalNode, namedExpr.getAlias());
       } else {
-        targets[i] = new Target(evalNode, context.plan.newGeneratedFieldName(namedExpr.getExpr()));
+        targets[i] = new Target(evalNode, context.plan.generateUniqueColumnName(namedExpr.getExpr()));
       }
     }
     EvalExprNode evalExprNode = context.queryBlock.getNodeFromExpr(projection);
@@ -336,12 +337,12 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
     Target [] targets = new Target[referenceNames.length];
 
     for (int i = 0; i < referenceNames.length; i++) {
-      if (block.namedExprsMgr.isResolved(referenceNames[i])) {
+      if (block.namedExprsMgr.isEvaluated(referenceNames[i])) {
         targets[i] = block.namedExprsMgr.getTarget(referenceNames[i]);
       } else {
         NamedExpr namedExpr = block.namedExprsMgr.getNamedExpr(referenceNames[i]);
         EvalNode evalNode = exprAnnotator.createEvalNode(plan, block, namedExpr.getExpr());
-        block.namedExprsMgr.resolveExpr(referenceNames[i], evalNode);
+        block.namedExprsMgr.markAsEvaluated(referenceNames[i], evalNode);
         targets[i] = new Target(evalNode, referenceNames[i]);
       }
     }
@@ -355,7 +356,8 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
         for (Column c : columns) {
           if (!projectable.getInSchema().contains(c)) {
             throw new PlanningException(c.getQualifiedName()
-                + " must appear in the GROUP BY clause or be used in an aggregate function");
+                + " must appear in the GROUP BY clause or be used in an aggregate function at node ("
+                + projectable.getPID() + ")" );
           }
         }
       }
@@ -363,14 +365,18 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
       GroupbyNode groupbyNode = (GroupbyNode) projectable;
       for (Column c : groupbyNode.getGroupingColumns()) {
         if (!projectable.getInSchema().contains(c)) {
-          throw new PlanningException("Cannot get such a field: " + c);
+          throw new PlanningException(String.format("Cannot get the field \"%s\" at node (%d)",
+              c, projectable.getPID()));
         }
       }
-      for (AggregationFunctionCallEval f : groupbyNode.getAggFunctions()) {
-        Set<Column> columns = EvalTreeUtil.findDistinctRefColumns(f);
-        for (Column c : columns) {
-          if (!projectable.getInSchema().contains(c)) {
-            throw new PlanningException("Cannot get such a field: " + c);
+      if (groupbyNode.hasAggFunctions()) {
+        for (AggregationFunctionCallEval f : groupbyNode.getAggFunctions()) {
+          Set<Column> columns = EvalTreeUtil.findDistinctRefColumns(f);
+          for (Column c : columns) {
+            if (!projectable.getInSchema().contains(c)) {
+              throw new PlanningException(String.format("Cannot get the field \"%s\" at node (%d)",
+                  c, projectable.getPID()));
+            }
           }
         }
       }
@@ -380,7 +386,8 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
         Set<Column> columns = EvalTreeUtil.findDistinctRefColumns(target.getEvalTree());
         for (Column c : columns) {
           if (!relationNode.getTableSchema().contains(c)) {
-            throw new PlanningException("Cannot get such a field: " + c);
+            throw new PlanningException(String.format("Cannot get the field \"%s\" at node (%d)",
+                c, projectable.getPID()));
           }
         }
       }
@@ -389,7 +396,8 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
         Set<Column> columns = EvalTreeUtil.findDistinctRefColumns(target.getEvalTree());
         for (Column c : columns) {
           if (!projectable.getInSchema().contains(c)) {
-            throw new PlanningException("Cannot get such a field: " + c);
+            throw new PlanningException(String.format("Cannot get the field \"%s\" at node (%d)",
+                c, projectable.getPID()));
           }
         }
       }
@@ -414,7 +422,7 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
     Set<String> aggEvalNames = new LinkedHashSet<String>();
     Set<AggregationFunctionCallEval> aggEvals = new LinkedHashSet<AggregationFunctionCallEval>();
     boolean includeDistinctFunction = false;
-    for (Iterator<NamedExpr> it = block.namedExprsMgr.getUnresolvedExprs(); it.hasNext();) {
+    for (Iterator<NamedExpr> it = block.namedExprsMgr.getIteratorForUnevaluatedExprs(); it.hasNext();) {
       NamedExpr rawTarget = it.next();
       try {
         includeDistinctFunction = PlannerUtil.existsDistinctAggregationFunction(rawTarget.getExpr());
@@ -422,7 +430,7 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
         if (evalNode.getType() == EvalType.AGG_FUNCTION) {
           aggEvalNames.add(rawTarget.getAlias());
           aggEvals.add((AggregationFunctionCallEval) evalNode);
-          block.namedExprsMgr.resolveExpr(rawTarget.getAlias(), evalNode);
+          block.namedExprsMgr.markAsEvaluated(rawTarget.getAlias(), evalNode);
         }
       } catch (VerifyException ve) {
       }
@@ -430,7 +438,8 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
 
     groupbyNode.setDistinct(includeDistinctFunction);
     groupbyNode.setAggFunctions(aggEvals.toArray(new AggregationFunctionCallEval[aggEvals.size()]));
-    Target [] targets = ProjectionPushDownRule.buildGroupByTarget(groupbyNode, aggEvalNames.toArray(new String[aggEvalNames.size()]));
+    Target [] targets = ProjectionPushDownRule.buildGroupByTarget(groupbyNode, null,
+        aggEvalNames.toArray(new String[aggEvalNames.size()]));
     groupbyNode.setTargets(targets);
 
     // this inserted group-by node doesn't pass through preprocessor. So manually added.
@@ -472,12 +481,12 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
       stack.pop();
       ////////////////////////////////////////////////////////
 
-      if (block.namedExprsMgr.isResolved(referName)) {
+      if (block.namedExprsMgr.isEvaluated(referName)) {
         firstFetNum = block.namedExprsMgr.getTarget(referName).getEvalTree();
       } else {
         NamedExpr namedExpr = block.namedExprsMgr.getNamedExpr(referName);
         firstFetNum = exprAnnotator.createEvalNode(context.plan, block, namedExpr.getExpr());
-        block.namedExprsMgr.resolveExpr(referName, firstFetNum);
+        block.namedExprsMgr.markAsEvaluated(referName, firstFetNum);
       }
     }
     LimitNode limitNode = block.getNodeFromExpr(limit);
@@ -529,7 +538,7 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
     Column column;
     SortSpec [] annotatedSortSpecs = new SortSpec[sortKeyNum];
     for (int i = 0; i < sortKeyNum; i++) {
-      if (block.namedExprsMgr.isResolved(referNames[i])) {
+      if (block.namedExprsMgr.isEvaluated(referNames[i])) {
         column = block.namedExprsMgr.getTarget(referNames[i]).getNamedColumn();
       } else {
         throw new IllegalStateException("Unexpected State: " + TUtil.arrayToString(sortSpecs));
@@ -568,12 +577,12 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
     having.setOutSchema(child.getOutSchema());
 
     EvalNode havingCondition;
-    if (block.namedExprsMgr.isResolved(referName)) {
+    if (block.namedExprsMgr.isEvaluated(referName)) {
       havingCondition = block.namedExprsMgr.getTarget(referName).getEvalTree();
     } else {
       NamedExpr namedExpr = block.namedExprsMgr.getNamedExpr(referName);
       havingCondition = exprAnnotator.createEvalNode(context.plan, block, namedExpr.getExpr());
-      block.namedExprsMgr.resolveExpr(referName, havingCondition);
+      block.namedExprsMgr.markAsEvaluated(referName, havingCondition);
     }
 
     // set having condition
@@ -618,7 +627,7 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
     // Set grouping sets
     Column [] groupingColumns = new Column[aggregation.getGroupSet()[0].getGroupingSets().length];
     for (int i = 0; i < groupingColumns.length; i++) {
-      if (block.namedExprsMgr.isResolved(groupingKeyRefNames[i])) {
+      if (block.namedExprsMgr.isEvaluated(groupingKeyRefNames[i])) {
         groupingColumns[i] = block.namedExprsMgr.getTarget(groupingKeyRefNames[i]).getNamedColumn();
       } else {
         throw new PlanningException("Each grouping column expression must be a scalar expression.");
@@ -634,13 +643,13 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
     List<String> aggEvalNames = TUtil.newList();
     List<AggregationFunctionCallEval> aggEvalNodes = TUtil.newList();
     boolean includeDistinctFunction = false;
-    for (Iterator<NamedExpr> iterator = block.namedExprsMgr.getUnresolvedExprs(); iterator.hasNext();) {
+    for (Iterator<NamedExpr> iterator = block.namedExprsMgr.getIteratorForUnevaluatedExprs(); iterator.hasNext();) {
       NamedExpr namedExpr = iterator.next();
       try {
         includeDistinctFunction |= PlannerUtil.existsDistinctAggregationFunction(namedExpr.getExpr());
         EvalNode evalNode = exprAnnotator.createEvalNode(context.plan, context.queryBlock, namedExpr.getExpr());
         if (evalNode.getType() == EvalType.AGG_FUNCTION) {
-          block.namedExprsMgr.resolveExpr(namedExpr.getAlias(), evalNode);
+          block.namedExprsMgr.markAsEvaluated(namedExpr.getAlias(), evalNode);
           aggEvalNames.add(namedExpr.getAlias());
           aggEvalNodes.add((AggregationFunctionCallEval) evalNode);
         }
@@ -705,7 +714,7 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
     QueryBlock block = context.queryBlock;
 
     ExprNormalizedResult normalizedResult = normalizer.normalize(context, selection.getQual());
-    block.namedExprsMgr.addReferences(normalizedResult.baseExpr);
+    block.namedExprsMgr.addExpr(normalizedResult.baseExpr);
     if (normalizedResult.aggExprs.size() > 0 || normalizedResult.scalarExprs.size() > 0) {
       throw new VerifyException("Filter condition cannot include aggregation function");
     }
@@ -745,7 +754,7 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
 
     if (join.hasQual()) {
       ExprNormalizedResult normalizedResult = normalizer.normalize(context, join.getQual());
-      block.namedExprsMgr.addReferences(normalizedResult.baseExpr);
+      block.namedExprsMgr.addExpr(normalizedResult.baseExpr);
       if (normalizedResult.aggExprs.size() > 0 || normalizedResult.scalarExprs.size() > 0) {
         throw new VerifyException("Filter condition cannot include aggregation function");
       }
@@ -781,10 +790,10 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
       joinCondition = AlgebraicUtil.eliminateConstantExprs(evalNode);
     }
 
-    List<Expr> newlyEvaluatedExprs = getNewlyEvaluatedExprsForJoin(plan, block, joinNode, stack);
+    List<String> newlyEvaluatedExprs = getNewlyEvaluatedExprsForJoin(plan, block, joinNode, stack);
     List<Target> targets = TUtil.newList(PlannerUtil.schemaToTargets(merged));
 
-    for (Expr newAddedExpr : newlyEvaluatedExprs) {
+    for (String newAddedExpr : newlyEvaluatedExprs) {
       targets.add(block.namedExprsMgr.getTarget(newAddedExpr, true));
     }
     joinNode.setTargets(targets.toArray(new Target[targets.size()]));
@@ -800,17 +809,17 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
     return joinNode;
   }
 
-  private List<Expr> getNewlyEvaluatedExprsForJoin(LogicalPlan plan, QueryBlock block, JoinNode joinNode,
+  private List<String> getNewlyEvaluatedExprsForJoin(LogicalPlan plan, QueryBlock block, JoinNode joinNode,
                                                    Stack<Expr> stack) {
     EvalNode evalNode;
-    List<Expr> newlyEvaluatedExprs = TUtil.newList();
-    for (Iterator<NamedExpr> it = block.namedExprsMgr.getUnresolvedExprs(); it.hasNext();) {
+    List<String> newlyEvaluatedExprs = TUtil.newList();
+    for (Iterator<NamedExpr> it = block.namedExprsMgr.getIteratorForUnevaluatedExprs(); it.hasNext();) {
       NamedExpr namedExpr = it.next();
       try {
         evalNode = exprAnnotator.createEvalNode(plan, block, namedExpr.getExpr());
         if (LogicalPlanner.checkIfBeEvaluatedAtJoin(block, evalNode, joinNode, stack.peek().getType() != OpType.Join)) {
-          block.namedExprsMgr.resolveExpr(namedExpr.getAlias(), evalNode);
-          newlyEvaluatedExprs.add(namedExpr.getExpr());
+          block.namedExprsMgr.markAsEvaluated(namedExpr.getAlias(), evalNode);
+          newlyEvaluatedExprs.add(namedExpr.getAlias());
         }
       } catch (VerifyException ve) {} catch (PlanningException e) {
         e.printStackTrace();
@@ -872,20 +881,20 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
     join.setInSchema(merged);
 
     EvalNode evalNode;
-    List<Expr> newlyEvaluatedExprs = TUtil.newList();
-    for (Iterator<NamedExpr> it = block.namedExprsMgr.getUnresolvedExprs(); it.hasNext();) {
+    List<String> newlyEvaluatedExprs = TUtil.newList();
+    for (Iterator<NamedExpr> it = block.namedExprsMgr.getIteratorForUnevaluatedExprs(); it.hasNext();) {
       NamedExpr namedExpr = it.next();
       try {
         evalNode = exprAnnotator.createEvalNode(plan, block, namedExpr.getExpr());
         if (EvalTreeUtil.findDistinctAggFunction(evalNode).size() == 0) {
-          block.namedExprsMgr.resolveExpr(namedExpr.getAlias(), evalNode);
-          newlyEvaluatedExprs.add(namedExpr.getExpr());
+          block.namedExprsMgr.markAsEvaluated(namedExpr.getAlias(), evalNode);
+          newlyEvaluatedExprs.add(namedExpr.getAlias());
         }
       } catch (VerifyException ve) {}
     }
 
     List<Target> targets = TUtil.newList(PlannerUtil.schemaToTargets(merged));
-    for (Expr newAddedExpr : newlyEvaluatedExprs) {
+    for (String newAddedExpr : newlyEvaluatedExprs) {
       targets.add(block.namedExprsMgr.getTarget(newAddedExpr, true));
     }
     join.setTargets(targets.toArray(new Target[targets.size()]));
@@ -930,7 +939,7 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
       try {
         EvalNode evalNode = exprAnnotator.createEvalNode(context.plan, context.queryBlock, rawTarget.getExpr());
         if (checkIfBeEvaluatedAtRelation(block, evalNode, scanNode)) {
-          block.namedExprsMgr.resolveExpr(rawTarget.getAlias(), evalNode);
+          block.namedExprsMgr.markAsEvaluated(rawTarget.getAlias(), evalNode);
           newlyEvaluatedExprsReferences.add(rawTarget.getAlias()); // newly added exr
         }
       } catch (VerifyException ve) {
@@ -938,19 +947,9 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
     }
 
     // Assume that each unique expr is evaluated once.
-    List<Target> targets = new ArrayList<Target>();
-    for (Column column : scanNode.getTableSchema().getColumns()) {
-      ColumnReferenceExpr columnRef = new ColumnReferenceExpr(column.getQualifier(), column.getColumnName());
-      if (block.namedExprsMgr.contains(columnRef)) {
-        String referenceName = block.namedExprsMgr.getName(columnRef);
-        targets.add(new Target(new FieldEval(column), referenceName));
-        newlyEvaluatedExprsReferences.remove(column.getQualifiedName());
-      } else {
-        targets.add(new Target(new FieldEval(column)));
-      }
-    }
+    LinkedHashSet<Target> targets = createFieldTargetsFromRelation(block, scanNode, newlyEvaluatedExprsReferences);
 
-    // The fact the some expr is included in newlyEvaluatedExprsReferences means that it is already resolved.
+    // The fact the some expr is included in newlyEvaluatedExprsReferences means that it is already evaluated.
     // So, we get a raw expression and then creates a target.
     for (String reference : newlyEvaluatedExprsReferences) {
       NamedExpr refrrer = block.namedExprsMgr.getNamedExpr(reference);
@@ -964,6 +963,21 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
     return scanNode;
   }
 
+  private static LinkedHashSet<Target> createFieldTargetsFromRelation(QueryBlock block, RelationNode relationNode,
+                                                      Set<String> newlyEvaluatedRefNames) {
+    LinkedHashSet<Target> targets = Sets.newLinkedHashSet();
+    for (Column column : relationNode.getTableSchema().getColumns()) {
+      String aliasName = block.namedExprsMgr.checkAndGetIfAliasedColumn(column.getQualifiedName());
+      if (aliasName != null) {
+        targets.add(new Target(new FieldEval(column), aliasName));
+        newlyEvaluatedRefNames.remove(aliasName);
+      } else {
+        targets.add(new Target(new FieldEval(column)));
+      }
+    }
+    return targets;
+  }
+
   private void updatePhysicalInfo(TableDesc desc) {
     if (desc.getPath() != null) {
       try {
@@ -994,32 +1008,22 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
     subQueryNode.setSubQuery(child);
 
     // Add additional expressions required in upper nodes.
-    Set<Expr> newlyEvaluatedExprs = new LinkedHashSet<Expr>();
+    Set<String> newlyEvaluatedExprs = TUtil.newHashSet();
     for (NamedExpr rawTarget : block.namedExprsMgr.getAllNamedExprs()) {
       try {
         EvalNode evalNode = exprAnnotator.createEvalNode(context.plan, context.queryBlock, rawTarget.getExpr());
         if (checkIfBeEvaluatedAtRelation(block, evalNode, subQueryNode)) {
-          block.namedExprsMgr.resolveExpr(rawTarget.getAlias(), evalNode);
-          newlyEvaluatedExprs.add(rawTarget.getExpr()); // newly added exr
+          block.namedExprsMgr.markAsEvaluated(rawTarget.getAlias(), evalNode);
+          newlyEvaluatedExprs.add(rawTarget.getAlias()); // newly added exr
         }
       } catch (VerifyException ve) {
       }
     }
 
     // Assume that each unique expr is evaluated once.
-    List<Target> targets = new ArrayList<Target>();
-    for (Column column : subQueryNode.getInSchema().getColumns()) {
-      ColumnReferenceExpr columnRef = new ColumnReferenceExpr(column.getQualifier(), column.getColumnName());
-      if (block.namedExprsMgr.contains(columnRef)) {
-        String referenceName = block.namedExprsMgr.getName(columnRef);
-        targets.add(new Target(new FieldEval(column), referenceName));
-        newlyEvaluatedExprs.remove(columnRef);
-      } else {
-        targets.add(new Target(new FieldEval(column)));
-      }
-    }
+    LinkedHashSet<Target> targets = createFieldTargetsFromRelation(block, subQueryNode, newlyEvaluatedExprs);
 
-    for (Expr newAddedExpr : newlyEvaluatedExprs) {
+    for (String newAddedExpr : newlyEvaluatedExprs) {
       targets.add(block.namedExprsMgr.getTarget(newAddedExpr, true));
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/fbc358c2/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/NamedExprsManager.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/NamedExprsManager.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/NamedExprsManager.java
index 6ce7bdf..33f6fc6 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/NamedExprsManager.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/NamedExprsManager.java
@@ -20,6 +20,8 @@ package org.apache.tajo.engine.planner;
 
 import com.google.common.collect.BiMap;
 import com.google.common.collect.HashBiMap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
 import org.apache.tajo.algebra.ColumnReferenceExpr;
 import org.apache.tajo.algebra.Expr;
 import org.apache.tajo.algebra.NamedExpr;
@@ -32,25 +34,48 @@ import org.apache.tajo.util.TUtil;
 
 import java.util.*;
 
-import static java.util.Map.Entry;
-
 /**
- * NamedExprsManager manages an expressions to be evaluated in a query block.
- * NamedExprsManager uses a reference name to identify one expression or one
- * EvalNode (annotated expression).
+ * NamedExprsManager manages an expressions used in a query block. All expressions used in a query block must be
+ * added to NamedExprsManager. When an expression is added to NamedExprsManager, NamedExprsManager gives a reference
+ * to the expression. If the expression already has an alias name, it gives the alias name as the reference
+ * to the expression. If the expression does not have any alias, it gives a generated name as the reference to the
+ * expression. Usually, predicates in WHERE clause, expressions in GROUP-BY, ORDER-BY, LIMIT clauses are not given
+ * any alias name. Those reference names are used to identify an individual expression.
+ *
+ * NamedExprsManager only keeps unique expressions. Since expressions in a query block can be duplicated,
+ * one or more reference names can point one expressions. Due to this process, it naturally removes duplicated
+ * expression.
+ *
+ * As we mentioned above, one or more reference names can indicate one expression. Primary names are used for
+ * representing expressions. A primary name of an expression indicates the reference obtained when
+ * the expression is added firstly. All output schemas uses only primary names of expressions.
+ *
+ * Each expression that NamedExprsManager keeps has an boolean state to indicate whether the expression is evaluated
+ * or not. The <code>evaluated</code> state means that upper logical operators can access this expression like a column
+ * reference. For it, the reference name is used to access this expression like a column reference,
+ * The evaluated state is set with an EvalNode which is an annotated expression.
+ * {@link #getTarget(String)} returns EvalNodes by a reference name.
  */
 public class NamedExprsManager {
-  /** Map; Reference name -> EvalNode */
-  private Map<String, EvalNode> nameToEvalMap = new LinkedHashMap<String, EvalNode>();
-  /** Map: EvalNode -> String */
-  private Map<EvalNode, String> evalToNameMap = new LinkedHashMap<EvalNode, String>();
-  /** Map; Reference name -> Expr */
-  private LinkedHashMap<String, Expr> nameToExprMap = new LinkedHashMap<String, Expr>();
-  /** Map; Expr -> Reference Name */
-  private LinkedHashMap<Expr, String> exprToNameMap = new LinkedHashMap<Expr, String>();
-  /** Map; Reference Name -> Boolean (if it is resolved or not) */
-  private LinkedHashMap<String, Boolean> resolvedFlags = new LinkedHashMap<String, Boolean>();
+  /** a sequence id */
+  private int sequenceId = 0;
+
+  /** Map: Name -> ID. Two or more different names can indicates the same id. */
+  private LinkedHashMap<String, Integer> nameToIdMap = Maps.newLinkedHashMap();
+
+  /** Map; ID <-> EvalNode */
+  private BiMap<Integer, EvalNode> idToEvalMap = HashBiMap.create();
+
+  /** Map: ID -> Names */
+  private LinkedHashMap<Integer, List<String>> idToNamesMap = Maps.newLinkedHashMap();
+
+  /** Map: ID -> Expr */
+  private BiMap<Integer, Expr> idToExprBiMap = HashBiMap.create();
 
+  /** Map; Name -> Boolean (if it is resolved or not) */
+  private LinkedHashMap<Integer, Boolean> evaluationStateMap = Maps.newLinkedHashMap();
+
+  /** Map: Alias Name <-> Original Name */
   private BiMap<String, String> aliasedColumnMap = HashBiMap.create();
 
   private LogicalPlan plan;
@@ -59,32 +84,45 @@ public class NamedExprsManager {
     this.plan = plan;
   }
 
+  private int getNextId() {
+    return sequenceId++;
+  }
+
+  private static String normalizeName(String name) {
+    return name.toLowerCase();
+  }
+
   /**
-   * Check whether the expression corresponding to a given name was resolved.
+   * Check whether the expression corresponding to a given name was evaluated.
    *
    * @param name The name of a certain expression to be checked
    * @return true if resolved. Otherwise, false.
    */
-  public boolean isResolved(String name) {
-    String normalized = name.toLowerCase();
-    return resolvedFlags.containsKey(normalized) && resolvedFlags.get(normalized);
+  public boolean isEvaluated(String name) {
+    String normalized = normalizeName(name);
+    if (nameToIdMap.containsKey(normalized)) {
+      int refId = nameToIdMap.get(normalized);
+      return evaluationStateMap.containsKey(refId) && evaluationStateMap.get(refId);
+    } else {
+      return false;
+    }
   }
 
   public boolean contains(String name) {
-    return nameToExprMap.containsKey(name);
+    return nameToIdMap.containsKey(name);
   }
 
   public boolean contains(Expr expr) {
-    return exprToNameMap.containsKey(expr);
+    return idToExprBiMap.inverse().containsKey(expr);
   }
 
-  public String getName(Expr expr) {
-    return exprToNameMap.get(expr);
+  private Expr getExpr(String name) {
+    return idToExprBiMap.get(nameToIdMap.get(name));
   }
 
   public NamedExpr getNamedExpr(String name) {
     String normalized = name.toLowerCase();
-    return new NamedExpr(nameToExprMap.get(normalized), normalized);
+    return new NamedExpr(getExpr(name), normalized);
   }
 
   public boolean isAliased(String name) {
@@ -103,45 +141,52 @@ public class NamedExprsManager {
     return aliasedColumnMap.inverse().get(aliasName);
   }
 
-  public String addExpr(Expr expr, String alias) {
-    if (exprToNameMap.containsKey(expr)) {
-      return exprToNameMap.get(expr);
-    } else {
-      String normalized = alias.toLowerCase();
-      nameToExprMap.put(normalized, expr);
-      exprToNameMap.put(expr, normalized);
-      resolvedFlags.put(normalized, false);
-      return normalized;
+  /**
+   * Adds an expression and returns a reference name.
+   */
+  public String addExpr(Expr expr) throws PlanningException {
+    if (idToExprBiMap.inverse().containsKey(expr)) {
+      int refId = idToExprBiMap.inverse().get(expr);
+      return idToNamesMap.get(refId).get(0);
     }
-  }
 
-  public String [] addReferences(Expr expr) throws PlanningException {
-    Set<ColumnReferenceExpr> foundSet = ExprFinder.finds(expr, OpType.Column);
-    String [] names = new String[foundSet.size()];
-    int i = 0;
-    for (ColumnReferenceExpr column : foundSet) {
-      addExpr(column);
-      names[i++] = column.getCanonicalName();
-    }
-    return names;
+    String generatedName = plan.generateUniqueColumnName(expr);
+    return addExpr(expr, generatedName);
   }
 
-  public String addExpr(Expr expr) {
-    String name;
+  /**
+   * Adds an expression with an alias name and returns a reference name.
+   * It specifies the alias as an reference name.
+   */
+  public String addExpr(Expr expr, String alias) throws PlanningException {
+    String normalized = normalizeName(alias);
+
+    // if this name already exists, just returns the name.
+    if (nameToIdMap.containsKey(normalized)) {
+      return normalized;
+    }
 
-    // all columns are projected automatically. BTW, should we add column reference to this list?
-    if (expr.getType() == OpType.Column) {
-      name = ((ColumnReferenceExpr)expr).getCanonicalName();
-      if (nameToExprMap.containsKey(name)) { // if it is column and another one already exists, skip.
-        return name;
-      }
+    // if the name is first
+    int refId;
+    if (idToExprBiMap.inverse().containsKey(expr)) {
+      refId = idToExprBiMap.inverse().get(expr);
     } else {
-      name = plan.newGeneratedFieldName(expr);
+      refId = getNextId();
+      idToExprBiMap.put(refId, expr);
     }
-    return addExpr(expr, name);
+
+    nameToIdMap.put(normalized, refId);
+    TUtil.putToNestedList(idToNamesMap, refId, normalized);
+    evaluationStateMap.put(refId, false);
+
+    return normalized;
   }
 
-  public String addNamedExpr(NamedExpr namedExpr) {
+  /**
+   * Adds an expression and returns a reference name.
+   * If an alias is given, it specifies the alias as an reference name.
+   */
+  public String addNamedExpr(NamedExpr namedExpr) throws PlanningException {
     if (namedExpr.hasAlias()) {
       return addExpr(namedExpr.getExpr(), namedExpr.getAlias());
     } else {
@@ -149,11 +194,15 @@ public class NamedExprsManager {
     }
   }
 
-  public String [] addNamedExprArray(@Nullable Collection<NamedExpr> targets) {
-    if (targets != null || targets.size() > 0) {
-      String [] names = new String[targets.size()];
+  /**
+   * Adds a list of expressions and returns a list of reference names.
+   * If some NamedExpr has an alias, NamedExprsManager specifies the alias for the NamedExpr.
+   */
+  public String [] addNamedExprArray(@Nullable Collection<NamedExpr> namedExprs) throws PlanningException {
+    if (namedExprs != null && namedExprs.size() > 0) {
+      String [] names = new String[namedExprs.size()];
       int i = 0;
-      for (NamedExpr target : targets) {
+      for (NamedExpr target : namedExprs) {
         names[i++] = addNamedExpr(target);
       }
       return names;
@@ -163,23 +212,26 @@ public class NamedExprsManager {
   }
 
   public Collection<NamedExpr> getAllNamedExprs() {
-    List<NamedExpr> namedExprList = new ArrayList<NamedExpr>();
-    for (Entry<String, Expr> entry: nameToExprMap.entrySet()) {
-      namedExprList.add(new NamedExpr(entry.getValue(), entry.getKey()));
+    List<NamedExpr> namedExprList = Lists.newArrayList();
+    for (Map.Entry<Integer, Expr> entry: idToExprBiMap.entrySet()) {
+      namedExprList.add(new NamedExpr(entry.getValue(), idToNamesMap.get(entry.getKey()).get(0)));
     }
     return namedExprList;
   }
 
-  public void resolveExpr(String name, EvalNode evalNode) throws PlanningException {
-    String normalized = name.toLowerCase();
-
-    if (evalNode.getType() == EvalType.CONST) {
-      resolvedFlags.put(normalized, true);
-    }
+  /**
+   * It marks the expression identified by the reference name as <code>evaluated</code>.
+   * In addition, it adds an EvanNode for the expression identified by the reference.
+   *
+   * @param referenceName The reference name to be marked as 'evaluated'.
+   * @param evalNode EvalNode to be added.
+   */
+  public void markAsEvaluated(String referenceName, EvalNode evalNode) throws PlanningException {
+    String normalized = referenceName.toLowerCase();
 
-    nameToEvalMap.put(normalized, evalNode);
-    evalToNameMap.put(evalNode, normalized);
-    resolvedFlags.put(normalized, true);
+    int refId = nameToIdMap.get(normalized);
+    evaluationStateMap.put(refId, true);
+    idToEvalMap.put(refId, evalNode);
 
     String originalName = checkAndGetIfAliasedColumn(normalized);
     if (originalName != null) {
@@ -191,9 +243,9 @@ public class NamedExprsManager {
    * It returns an original column name if it is aliased column reference.
    * Otherwise, it will return NULL.
    */
-  private String checkAndGetIfAliasedColumn(String name) {
-    Expr expr = nameToExprMap.get(name);
-    if (expr.getType() == OpType.Column) {
+  public String checkAndGetIfAliasedColumn(String name) {
+    Expr expr = getExpr(name);
+    if (expr != null && expr.getType() == OpType.Column) {
       ColumnReferenceExpr column = (ColumnReferenceExpr) expr;
       if (!column.getCanonicalName().equals(name)) {
         return column.getCanonicalName();
@@ -202,29 +254,71 @@ public class NamedExprsManager {
     return null;
   }
 
-  public Target getTarget(Expr expr, boolean unresolved) {
-    String name = exprToNameMap.get(expr);
-    return getTarget(name, unresolved);
-  }
-
   public Target getTarget(String name) {
     return getTarget(name, false);
   }
 
-  public Target getTarget(String name, boolean unresolved) {
-    String normalized = name;
-    if (!unresolved && resolvedFlags.containsKey(normalized) && resolvedFlags.get(normalized)) {
-      EvalNode evalNode = nameToEvalMap.get(normalized);
+  /**
+   * It checks if a given name is the primary name.
+   *
+   * @See {@link NamedExprsManager}
+   * @see {@link NamedExprsManager#getPrimaryName}
+   *
+   * @param id The expression id
+   * @param name The name to be checked if it is primary name.
+   * @return The primary name
+   */
+  private boolean isPrimaryName(int id, String name) {
+    return idToNamesMap.get(id).get(0).equals(name);
+  }
+
+  /**
+   * One or more reference names can indicate one expression. Primary names are used for
+   * representing expressions. A primary name of an expression indicates the reference obtained when
+   * the expression is added firstly. All output schemas uses only primary names of expressions.
+   *
+   * @param id The expression id
+   * @return The primary name
+   */
+  private String getPrimaryName(int id) {
+    return idToNamesMap.get(id).get(0);
+  }
+
+  /**
+   * get a Target instance. A target consists of a reference name and an EvalNode corresponding to the reference name.
+   * According to evaluation state, it returns different EvalNodes.
+   * If the expression corresponding to the reference name is evaluated, it just returns {@link FieldEval}
+   * (i.e., a column reference). Otherwise, it returns the original EvalNode of the expression.
+   *
+   * @param referenceName The reference name to get EvalNode
+   * @param unevaluatedForm If TRUE, it always return the annotated EvalNode of the expression.
+   * @return
+   */
+  public Target getTarget(String referenceName, boolean unevaluatedForm) {
+    String normalized = referenceName;
+    int refId = nameToIdMap.get(normalized);
+
+    if (!unevaluatedForm && evaluationStateMap.containsKey(refId) && evaluationStateMap.get(refId)) {
+      EvalNode evalNode = idToEvalMap.get(refId);
+
+      // If the expression is already evaluated, it should use the FieldEval to access a field value.
+      // But, if this reference name is not primary name, it cannot use the reference name.
+      // It changes the given reference name to the primary name.
+      if (isEvaluated(normalized) && !isPrimaryName(refId, referenceName)) {
+        return new Target(new FieldEval(getPrimaryName(refId),evalNode.getValueType()), referenceName);
+      }
+
       EvalNode referredEval;
       if (evalNode.getType() == EvalType.CONST) {
         referredEval = evalNode;
       } else {
-        referredEval = new FieldEval(normalized, evalNode.getValueType());
+        referredEval = new FieldEval(idToNamesMap.get(refId).get(0), evalNode.getValueType());
       }
-      return new Target(referredEval, name);
+      return new Target(referredEval, referenceName);
+
     } else {
-      if (nameToEvalMap.containsKey(normalized)) {
-        return new Target(nameToEvalMap.get(normalized), name);
+      if (idToEvalMap.containsKey(refId)) {
+        return new Target(idToEvalMap.get(refId), referenceName);
       } else {
         return null;
       }
@@ -232,35 +326,36 @@ public class NamedExprsManager {
   }
 
   public String toString() {
-    return "unresolved=" + nameToExprMap.size() + ", resolved=" + nameToEvalMap.size()
+    return "unevaluated=" + nameToIdMap.size() + ", evaluated=" + idToEvalMap.size()
         + ", renamed=" + aliasedColumnMap.size();
   }
 
   /**
-   * It returns an iterator for unresolved NamedExprs.
+   * It returns an iterator for unevaluated NamedExprs.
    */
-  public Iterator<NamedExpr> getUnresolvedExprs() {
-    return new UnresolvedIterator();
+  public Iterator<NamedExpr> getIteratorForUnevaluatedExprs() {
+    return new UnevaluatedIterator();
   }
 
-  public class UnresolvedIterator implements Iterator<NamedExpr> {
+  public class UnevaluatedIterator implements Iterator<NamedExpr> {
     private final Iterator<NamedExpr> iterator;
 
-    public UnresolvedIterator() {
-      List<NamedExpr> unresolvedList = TUtil.newList();
-      for (Entry<String,Expr> entry : nameToExprMap.entrySet()) {
-        if (!isResolved(entry.getKey())) {
-          unresolvedList.add(new NamedExpr(entry.getValue(), entry.getKey()));
+    public UnevaluatedIterator() {
+      List<NamedExpr> unEvaluatedList = TUtil.newList();
+      for (Integer refId: idToNamesMap.keySet()) {
+        String name = idToNamesMap.get(refId).get(0);
+        if (!isEvaluated(name)) {
+          Expr expr = idToExprBiMap.get(refId);
+          unEvaluatedList.add(new NamedExpr(expr, name));
         }
       }
-      if (unresolvedList.size() == 0) {
+      if (unEvaluatedList.size() == 0) {
         iterator = null;
       } else {
-        iterator = unresolvedList.iterator();
+        iterator = unEvaluatedList.iterator();
       }
     }
 
-
     @Override
     public boolean hasNext() {
       return iterator != null && iterator.hasNext();
@@ -275,10 +370,4 @@ public class NamedExprsManager {
     public void remove() {
     }
   }
-
-  public void reset() {
-    for (String name : resolvedFlags.keySet()) {
-      resolvedFlags.put(name, false);
-    }
-  }
 }

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/fbc358c2/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/PlanString.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/PlanString.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/PlanString.java
index 4ecad60..98f921b 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/PlanString.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/PlanString.java
@@ -18,6 +18,8 @@
 
 package org.apache.tajo.engine.planner;
 
+import org.apache.tajo.engine.planner.logical.LogicalNode;
+
 import java.util.ArrayList;
 import java.util.List;
 
@@ -31,6 +33,10 @@ public class PlanString {
   StringBuilder currentExplanation;
   StringBuilder currentDetail;
 
+  public PlanString(LogicalNode node) {
+    this.title = new StringBuilder(node.getType().name() + "(" + node.getPID() + ")");
+  }
+
   public PlanString(String title) {
     this.title = new StringBuilder(title);
   }

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/fbc358c2/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/PlannerUtil.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/PlannerUtil.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/PlannerUtil.java
index e9293de..624518b 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/PlannerUtil.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/PlannerUtil.java
@@ -21,10 +21,7 @@ package org.apache.tajo.engine.planner;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
-import org.apache.tajo.algebra.CountRowsFunctionExpr;
-import org.apache.tajo.algebra.Expr;
-import org.apache.tajo.algebra.GeneralSetFunctionExpr;
-import org.apache.tajo.algebra.JoinType;
+import org.apache.tajo.algebra.*;
 import org.apache.tajo.annotation.Nullable;
 import org.apache.tajo.catalog.Column;
 import org.apache.tajo.catalog.Schema;
@@ -502,13 +499,9 @@ public class PlannerUtil {
     List<Target> targets = TUtil.newList();
 
     FieldEval eval;
-    Column column;
     for (int i = 0; i < schema.getColumnNum(); i++) {
-      column = schema.getColumn(i);
-      if (column.getColumnName().charAt(0) != LogicalPlan.NONAMED_COLUMN_PREFIX) {
-        eval = new FieldEval(schema.getColumn(i));
-        targets.add(new Target(eval));
-      }
+      eval = new FieldEval(schema.getColumn(i));
+      targets.add(new Target(eval));
     }
     return targets.toArray(new Target[targets.size()]);
   }

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/fbc358c2/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/PreLogicalPlanVerifier.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/PreLogicalPlanVerifier.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/PreLogicalPlanVerifier.java
index fe93f46..6dac031 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/PreLogicalPlanVerifier.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/PreLogicalPlanVerifier.java
@@ -20,7 +20,9 @@ package org.apache.tajo.engine.planner;
 
 import org.apache.tajo.algebra.*;
 import org.apache.tajo.catalog.CatalogService;
+import org.apache.tajo.util.TUtil;
 
+import java.util.Set;
 import java.util.Stack;
 
 public class PreLogicalPlanVerifier extends BaseAlgebraVisitor <VerificationState, Expr> {
@@ -30,9 +32,23 @@ public class PreLogicalPlanVerifier extends BaseAlgebraVisitor <VerificationStat
     this.catalog = catalog;
   }
 
+  public Expr visitProjection(VerificationState state, Stack<Expr> stack, Projection expr) throws PlanningException {
+    Set<String> names = TUtil.newHashSet();
+    for (NamedExpr namedExpr : expr.getNamedExprs()) {
+      if (namedExpr.hasAlias()) {
+        if (names.contains(namedExpr.getAlias())) {
+          state.addVerification(String.format("column name \"%s\" specified more than once", namedExpr.getAlias()));
+        } else {
+          names.add(namedExpr.getAlias());
+        }
+      }
+    }
+    return expr;
+  }
+
   @Override
   public Expr visitGroupBy(VerificationState ctx, Stack<Expr> stack, Aggregation expr) throws PlanningException {
-    Expr child = super.visitGroupBy(ctx, stack, expr);
+    super.visitGroupBy(ctx, stack, expr);
 
     // Enforcer only ordinary grouping set.
     for (Aggregation.GroupElement groupingElement : expr.getGroupSet()) {

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/fbc358c2/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/global/GlobalPlanner.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/global/GlobalPlanner.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/global/GlobalPlanner.java
index d040d7e..f390b52 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/global/GlobalPlanner.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/global/GlobalPlanner.java
@@ -432,14 +432,15 @@ public class GlobalPlanner {
         }
 
         firstPhaseEvals[i].setFirstPhase();
-        firstPhaseEvalNames[i] = plan.newGeneratedFieldName(firstPhaseEvals[i]);
+        firstPhaseEvalNames[i] = plan.generateUniqueColumnName(firstPhaseEvals[i]);
         FieldEval param = new FieldEval(firstPhaseEvalNames[i], firstPhaseEvals[i].getValueType());
         secondPhaseEvals[i].setArgs(new EvalNode[] {param});
       }
 
       secondPhaseGroupBy.setAggFunctions(secondPhaseEvals);
       firstPhaseGroupBy.setAggFunctions(firstPhaseEvals);
-      Target [] firstPhaseTargets = ProjectionPushDownRule.buildGroupByTarget(firstPhaseGroupBy, firstPhaseEvalNames);
+      Target [] firstPhaseTargets = ProjectionPushDownRule.buildGroupByTarget(firstPhaseGroupBy, null,
+          firstPhaseEvalNames);
       firstPhaseGroupBy.setTargets(firstPhaseTargets);
       secondPhaseGroupBy.setInSchema(PlannerUtil.targetToSchema(firstPhaseTargets));
     }

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/fbc358c2/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/CreateTableNode.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/CreateTableNode.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/CreateTableNode.java
index c266bbc..6dcca2d 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/CreateTableNode.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/CreateTableNode.java
@@ -78,7 +78,7 @@ public class CreateTableNode extends StoreTableNode implements Cloneable {
 
   @Override
   public PlanString getPlanString() {
-    return new PlanString("CreateTable");
+    return new PlanString(this);
   }
   
   @Override

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/fbc358c2/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/DropTableNode.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/DropTableNode.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/DropTableNode.java
index 4dda7af..06d8185 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/DropTableNode.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/DropTableNode.java
@@ -43,7 +43,7 @@ public class DropTableNode extends LogicalNode {
 
   @Override
   public PlanString getPlanString() {
-    return new PlanString("DropTable " + (purge ? " (PURGE)" : ""));
+    return new PlanString(this).appendTitle(purge ? " (PURGE)" : "");
   }
 
   public boolean equals(Object obj) {

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/fbc358c2/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/ExceptNode.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/ExceptNode.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/ExceptNode.java
index 0520214..0ed39df 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/ExceptNode.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/ExceptNode.java
@@ -33,7 +33,7 @@ public class ExceptNode extends BinaryNode {
 
   @Override
   public PlanString getPlanString() {
-    PlanString planStr = new PlanString("Except");
+    PlanString planStr = new PlanString(this);
     planStr.appendTitle(" (L - " + ((TableSubQueryNode)getLeftChild()).getTableName());
     planStr.appendTitle(", R - " + ((TableSubQueryNode)getRightChild()).getTableName());
     planStr.appendTitle(")");

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/fbc358c2/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 58fa6e2..a7f36ec 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
@@ -165,7 +165,7 @@ public class GroupbyNode extends UnaryNode implements Projectable, Cloneable {
 
   @Override
   public PlanString getPlanString() {
-    PlanString planStr = new PlanString("Aggregation");
+    PlanString planStr = new PlanString(this);
 
     StringBuilder sb = new StringBuilder();
     sb.append("(");

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/fbc358c2/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/HavingNode.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/HavingNode.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/HavingNode.java
index f4eafd0..816c34e 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/HavingNode.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/HavingNode.java
@@ -58,7 +58,7 @@ public class HavingNode extends UnaryNode implements Cloneable {
 
   @Override
   public PlanString getPlanString() {
-    return new PlanString("Having: ").appendTitle(qual.toString());
+    return new PlanString(this).appendTitle(" (").appendTitle(qual.toString()).appendTitle(")");
   }
 
   public String toString() {

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/fbc358c2/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/IntersectNode.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/IntersectNode.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/IntersectNode.java
index 493698d..74aa9eb 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/IntersectNode.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/IntersectNode.java
@@ -32,7 +32,7 @@ public class IntersectNode extends BinaryNode {
 
   @Override
   public PlanString getPlanString() {
-    PlanString planStr = new PlanString("Intersect");
+    PlanString planStr = new PlanString(this);
     planStr.appendTitle(" (L - " + ((TableSubQueryNode)getLeftChild()).getTableName());
     planStr.appendTitle(", R - " + ((TableSubQueryNode)getRightChild()).getTableName());
     planStr.appendTitle(")");

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/fbc358c2/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/JoinNode.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/JoinNode.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/JoinNode.java
index 2628c3b..8902932 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/JoinNode.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/JoinNode.java
@@ -93,8 +93,7 @@ public class JoinNode extends BinaryNode implements Projectable, Cloneable {
 
   @Override
   public PlanString getPlanString() {
-    PlanString planStr = new PlanString("Join (type : ")
-        .appendTitle(joinType +")");
+    PlanString planStr = new PlanString(this).appendTitle("(").appendTitle(joinType.name()).appendTitle(")");
     if (hasJoinQual()) {
       planStr.addExplan("Join Cond: " + joinQual.toString());
     }

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/fbc358c2/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/LimitNode.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/LimitNode.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/LimitNode.java
index 197a5bc..a3d1f4b 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/LimitNode.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/LimitNode.java
@@ -38,7 +38,7 @@ public final class LimitNode extends UnaryNode implements Cloneable {
 
   @Override
   public PlanString getPlanString() {
-    return new PlanString("Limit " + fetchFirstNum);
+    return new PlanString(this).appendTitle(" " + fetchFirstNum);
   }
   
   @Override 

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/fbc358c2/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/LogicalRootNode.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/LogicalRootNode.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/LogicalRootNode.java
index 72f5ee8..bacf14f 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/LogicalRootNode.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/LogicalRootNode.java
@@ -36,6 +36,6 @@ public class LogicalRootNode extends UnaryNode implements Cloneable {
 
   @Override
   public PlanString getPlanString() {
-    return new PlanString("Root");
+    return new PlanString(this);
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/fbc358c2/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/PartitionedTableScanNode.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/PartitionedTableScanNode.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/PartitionedTableScanNode.java
index 824e858..868c493 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/PartitionedTableScanNode.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/PartitionedTableScanNode.java
@@ -142,7 +142,7 @@ public class PartitionedTableScanNode extends ScanNode {
 
   @Override
   public PlanString getPlanString() {
-    PlanString planStr = new PlanString("Scan on ").appendTitle(getTableName());
+    PlanString planStr = new PlanString(this).appendTitle(" on " + getTableName());
     if (hasAlias()) {
       planStr.appendTitle(" as ").appendTitle(alias);
     }

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/fbc358c2/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/PersistentStoreNode.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/PersistentStoreNode.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/PersistentStoreNode.java
index 2a357c4..65fd4f5 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/PersistentStoreNode.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/PersistentStoreNode.java
@@ -61,7 +61,7 @@ public abstract class PersistentStoreNode extends UnaryNode implements Cloneable
 
   @Override
   public PlanString getPlanString() {
-    PlanString planStr = new PlanString("Store");
+    PlanString planStr = new PlanString(this);
     planStr.addExplan("Store type: " + storageType);
 
     return planStr;

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/fbc358c2/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/Projectable.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/Projectable.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/Projectable.java
index d72b31e..1e4bdc5 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/Projectable.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/Projectable.java
@@ -21,14 +21,53 @@ package org.apache.tajo.engine.planner.logical;
 import org.apache.tajo.catalog.Schema;
 import org.apache.tajo.engine.planner.Target;
 
+/**
+ * Projectable is an interface for a LogicalNode which has a list of targets.
+ * What a logical node has a list of targets means that the node evaluated a list of expressions.
+ * For example, {@link org.apache.tajo.engine.planner.logical.ScanNode},
+ * {@link org.apache.tajo.engine.planner.logical.JoinNode},
+ * {@link org.apache.tajo.engine.planner.logical.GroupbyNode}, and
+ * {@link org.apache.tajo.engine.planner.logical.ProjectionNode} are all <i>Projectable</i> nodes.
+ * The expression evaluation occurs only at those projectable nodes.
+ */
 public interface Projectable {
+
+  /**
+   * Get a PlanNode Id
+   * @return PlanNodeId
+   */
+  int getPID();
+
+  /**
+   * check if this node has a target list
+   * @return TRUE if this node has a target list. Otherwise, FALSE.
+   */
   boolean hasTargets();
 
+  /**
+   * Set a target list
+   *
+   * @param targets The array of targets
+   */
   void setTargets(Target[] targets);
 
+  /**
+   * Get a list of targets
+   *
+   * @return The array of targets
+   */
   Target [] getTargets();
 
+  /**
+   * Get an input schema
+   * @return The input schema
+   */
   public Schema getInSchema();
 
+  /**
+   * Get an output schema
+   *
+   * @return The output schema
+   */
   public Schema getOutSchema();
 }


Mime
View raw message