tajo-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From hj...@apache.org
Subject [27/35] TAJO-1125: Separate logical plan and optimizer into a maven module.
Date Sun, 26 Oct 2014 19:27:33 GMT
http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-core/src/main/java/org/apache/tajo/engine/planner/ExprAnnotator.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/planner/ExprAnnotator.java b/tajo-core/src/main/java/org/apache/tajo/engine/planner/ExprAnnotator.java
deleted file mode 100644
index 3115104..0000000
--- a/tajo-core/src/main/java/org/apache/tajo/engine/planner/ExprAnnotator.java
+++ /dev/null
@@ -1,935 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.tajo.engine.planner;
-
-import com.google.common.collect.Sets;
-import org.apache.tajo.algebra.*;
-import org.apache.tajo.catalog.CatalogService;
-import org.apache.tajo.catalog.CatalogUtil;
-import org.apache.tajo.catalog.Column;
-import org.apache.tajo.catalog.FunctionDesc;
-import org.apache.tajo.catalog.exception.NoSuchFunctionException;
-import org.apache.tajo.common.TajoDataTypes;
-import org.apache.tajo.datum.*;
-import org.apache.tajo.engine.eval.*;
-import org.apache.tajo.engine.function.AggFunction;
-import org.apache.tajo.engine.function.GeneralFunction;
-import org.apache.tajo.engine.planner.logical.NodeType;
-import org.apache.tajo.engine.planner.nameresolver.NameResolvingMode;
-import org.apache.tajo.engine.planner.nameresolver.NameResolver;
-import org.apache.tajo.exception.InternalException;
-import org.apache.tajo.exception.InvalidOperationException;
-import org.apache.tajo.util.Pair;
-import org.apache.tajo.util.TUtil;
-import org.apache.tajo.util.datetime.DateTimeUtil;
-import org.apache.tajo.util.datetime.TimeMeta;
-
-import java.util.Set;
-import java.util.Stack;
-
-import static org.apache.tajo.algebra.WindowSpec.WindowFrameEndBoundType;
-import static org.apache.tajo.algebra.WindowSpec.WindowFrameStartBoundType;
-import static org.apache.tajo.catalog.proto.CatalogProtos.FunctionType;
-import static org.apache.tajo.common.TajoDataTypes.DataType;
-import static org.apache.tajo.common.TajoDataTypes.Type;
-import static org.apache.tajo.engine.planner.logical.WindowSpec.WindowEndBound;
-import static org.apache.tajo.engine.planner.logical.WindowSpec.WindowFrame;
-import static org.apache.tajo.engine.planner.logical.WindowSpec.WindowStartBound;
-
-/**
- * <code>ExprAnnotator</code> makes an annotated expression called <code>EvalNode</code> from an
- * {@link org.apache.tajo.algebra.Expr}. It visits descendants recursively from a given expression, and finally
- * it returns an EvalNode.
- */
-public class ExprAnnotator extends BaseAlgebraVisitor<ExprAnnotator.Context, EvalNode> {
-  private CatalogService catalog;
-
-  public ExprAnnotator(CatalogService catalog) {
-    this.catalog = catalog;
-  }
-
-  static class Context {
-    LogicalPlan plan;
-    LogicalPlan.QueryBlock currentBlock;
-    NameResolvingMode columnRsvLevel;
-
-    public Context(LogicalPlanner.PlanContext planContext, NameResolvingMode colRsvLevel) {
-      this.plan = planContext.plan;
-      this.currentBlock = planContext.queryBlock;
-      this.columnRsvLevel = colRsvLevel;
-    }
-  }
-
-  public EvalNode createEvalNode(LogicalPlanner.PlanContext planContext, Expr expr,
-                                 NameResolvingMode colRsvLevel)
-      throws PlanningException {
-    Context context = new Context(planContext, colRsvLevel);
-    return planContext.evalOptimizer.optimize(planContext, visit(context, new Stack<Expr>(), expr));
-  }
-
-  public static void assertEval(boolean condition, String message) throws PlanningException {
-    if (!condition) {
-      throw new PlanningException(message);
-    }
-  }
-
-  /**
-   * It checks both terms in binary expression. If one of both needs type conversion, it inserts a cast expression.
-   *
-   * @param lhs left hand side term
-   * @param rhs right hand side term
-   * @return a pair including left/right hand side terms
-   */
-  public static Pair<EvalNode, EvalNode> convertTypesIfNecessary(EvalNode lhs, EvalNode rhs) {
-    Type lhsType = lhs.getValueType().getType();
-    Type rhsType = rhs.getValueType().getType();
-
-    // If one of both is NULL, it just returns the original types without casting.
-    if (lhsType == Type.NULL_TYPE || rhsType == Type.NULL_TYPE) {
-      return new Pair<EvalNode, EvalNode>(lhs, rhs);
-    }
-
-    Type toBeCasted = TUtil.getFromNestedMap(CatalogUtil.OPERATION_CASTING_MAP, lhsType, rhsType);
-    if (toBeCasted != null) { // if not null, one of either should be converted to another type.
-      // Overwrite lhs, rhs, or both with cast expression.
-      if (lhsType != toBeCasted) {
-        lhs = convertType(lhs, CatalogUtil.newSimpleDataType(toBeCasted));
-      }
-      if (rhsType != toBeCasted) {
-        rhs = convertType(rhs, CatalogUtil.newSimpleDataType(toBeCasted));
-      }
-    }
-
-    return new Pair<EvalNode, EvalNode>(lhs, rhs);
-  }
-
-  /**
-   * Insert a type conversion expression to a given expression.
-   * If the type of expression and <code>toType</code> is already the same, it just returns the original expression.
-   *
-   * @param evalNode an expression
-   * @param toType target type
-   * @return type converted expression.
-   */
-  private static EvalNode convertType(EvalNode evalNode, DataType toType) {
-
-    // if original and toType is the same, we don't need type conversion.
-    if (evalNode.getValueType().equals(toType)) {
-      return evalNode;
-    }
-    // the conversion to null is not allowed.
-    if (evalNode.getValueType().getType() == Type.NULL_TYPE || toType.getType() == Type.NULL_TYPE) {
-      return evalNode;
-    }
-
-    if (evalNode.getType() == EvalType.BETWEEN) {
-      BetweenPredicateEval between = (BetweenPredicateEval) evalNode;
-
-      between.setPredicand(convertType(between.getPredicand(), toType));
-      between.setBegin(convertType(between.getBegin(), toType));
-      between.setEnd(convertType(between.getEnd(), toType));
-
-      return between;
-
-    } else if (evalNode.getType() == EvalType.CASE) {
-
-      CaseWhenEval caseWhenEval = (CaseWhenEval) evalNode;
-      for (CaseWhenEval.IfThenEval ifThen : caseWhenEval.getIfThenEvals()) {
-        ifThen.setResult(convertType(ifThen.getResult(), toType));
-      }
-
-      if (caseWhenEval.hasElse()) {
-        caseWhenEval.setElseResult(convertType(caseWhenEval.getElse(), toType));
-      }
-
-      return caseWhenEval;
-
-    } else if (evalNode.getType() == EvalType.ROW_CONSTANT) {
-      RowConstantEval original = (RowConstantEval) evalNode;
-
-      Datum[] datums = original.getValues();
-      Datum[] convertedDatum = new Datum[datums.length];
-
-      for (int i = 0; i < datums.length; i++) {
-        convertedDatum[i] = DatumFactory.cast(datums[i], toType);
-      }
-
-      RowConstantEval convertedRowConstant = new RowConstantEval(convertedDatum);
-
-      return convertedRowConstant;
-
-    } else if (evalNode.getType() == EvalType.CONST) {
-      ConstEval original = (ConstEval) evalNode;
-      ConstEval newConst = new ConstEval(DatumFactory.cast(original.getValue(), toType));
-      return newConst;
-
-    } else {
-      return new CastEval(evalNode, toType);
-    }
-  }
-
-  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-  // Logical Operator Section
-  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-  @Override
-  public EvalNode visitAnd(Context ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
-    stack.push(expr);
-    EvalNode left = visit(ctx, stack, expr.getLeft());
-    EvalNode right = visit(ctx, stack, expr.getRight());
-    stack.pop();
-
-    return new BinaryEval(EvalType.AND, left, right);
-  }
-
-  @Override
-  public EvalNode visitOr(Context ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
-    stack.push(expr);
-    EvalNode left = visit(ctx, stack, expr.getLeft());
-    EvalNode right = visit(ctx, stack, expr.getRight());
-    stack.pop();
-
-    return new BinaryEval(EvalType.OR, left, right);
-  }
-
-  @Override
-  public EvalNode visitNot(Context ctx, Stack<Expr> stack, NotExpr expr) throws PlanningException {
-    stack.push(expr);
-    EvalNode child = visit(ctx, stack, expr.getChild());
-    stack.pop();
-    return new NotEval(child);
-  }
-
-  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-  // Comparison Predicates Section
-  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-  @Override
-  public EvalNode visitEquals(Context ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
-    return visitCommonComparison(ctx, stack, expr);
-  }
-
-  @Override
-  public EvalNode visitNotEquals(Context ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
-    return visitCommonComparison(ctx, stack, expr);
-  }
-
-  @Override
-  public EvalNode visitLessThan(Context ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
-    return visitCommonComparison(ctx, stack, expr);
-  }
-
-  @Override
-  public EvalNode visitLessThanOrEquals(Context ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
-    return visitCommonComparison(ctx, stack, expr);
-  }
-
-  @Override
-  public EvalNode visitGreaterThan(Context ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
-    return visitCommonComparison(ctx, stack, expr);
-  }
-
-  @Override
-  public EvalNode visitGreaterThanOrEquals(Context ctx, Stack<Expr> stack, BinaryOperator expr)
-      throws PlanningException {
-    return visitCommonComparison(ctx, stack, expr);
-  }
-
-  public EvalNode visitCommonComparison(Context ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
-    stack.push(expr);
-    EvalNode left = visit(ctx, stack, expr.getLeft());
-    EvalNode right = visit(ctx, stack, expr.getRight());
-    stack.pop();
-
-    EvalType evalType;
-    switch (expr.getType()) {
-      case Equals:
-        evalType = EvalType.EQUAL;
-        break;
-      case NotEquals:
-        evalType = EvalType.NOT_EQUAL;
-        break;
-      case LessThan:
-        evalType = EvalType.LTH;
-        break;
-      case LessThanOrEquals:
-        evalType = EvalType.LEQ;
-        break;
-      case GreaterThan:
-        evalType = EvalType.GTH;
-        break;
-      case GreaterThanOrEquals:
-        evalType = EvalType.GEQ;
-        break;
-      default:
-      throw new IllegalStateException("Wrong Expr Type: " + expr.getType());
-    }
-
-    return createBinaryNode(evalType, left, right);
-  }
-
-  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-  // Other Predicates Section
-  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-  @Override
-  public EvalNode visitBetween(Context ctx, Stack<Expr> stack, BetweenPredicate between) throws PlanningException {
-    stack.push(between);
-    EvalNode predicand = visit(ctx, stack, between.predicand());
-    EvalNode begin = visit(ctx, stack, between.begin());
-    EvalNode end = visit(ctx, stack, between.end());
-    stack.pop();
-
-    // implicit type conversion
-    DataType widestType = null;
-
-    try {
-      widestType = CatalogUtil.getWidestType(predicand.getValueType(), begin.getValueType(), end.getValueType());
-    } catch (InvalidOperationException ioe) {
-      throw new PlanningException(ioe);
-    }
-
-    BetweenPredicateEval betweenEval = new BetweenPredicateEval(
-        between.isNot(),
-        between.isSymmetric(),
-        predicand, begin, end);
-
-    betweenEval = (BetweenPredicateEval) convertType(betweenEval, widestType);
-    return betweenEval;
-  }
-
-  @Override
-  public EvalNode visitCaseWhen(Context ctx, Stack<Expr> stack, CaseWhenPredicate caseWhen) throws PlanningException {
-    CaseWhenEval caseWhenEval = new CaseWhenEval();
-
-    EvalNode condition;
-    EvalNode result;
-
-    for (CaseWhenPredicate.WhenExpr when : caseWhen.getWhens()) {
-      condition = visit(ctx, stack, when.getCondition());
-      result = visit(ctx, stack, when.getResult());
-      caseWhenEval.addIfCond(condition, result);
-    }
-
-    if (caseWhen.hasElseResult()) {
-      caseWhenEval.setElseResult(visit(ctx, stack, caseWhen.getElseResult()));
-    }
-
-    // Getting the widest type from all if-then expressions and else expression.
-    DataType widestType = caseWhenEval.getIfThenEvals().get(0).getResult().getValueType();
-    for (int i = 1; i < caseWhenEval.getIfThenEvals().size(); i++) {
-      widestType = CatalogUtil.getWidestType(caseWhenEval.getIfThenEvals().get(i).getResult().getValueType(),
-          widestType);
-    }
-    if (caseWhen.hasElseResult()) {
-      widestType = CatalogUtil.getWidestType(widestType, caseWhenEval.getElse().getValueType());
-    }
-
-    assertEval(widestType != null, "Invalid Type Conversion for CaseWhen");
-
-    // implicit type conversion
-    caseWhenEval = (CaseWhenEval) convertType(caseWhenEval, widestType);
-
-    return caseWhenEval;
-  }
-
-  @Override
-  public EvalNode visitIsNullPredicate(Context ctx, Stack<Expr> stack, IsNullPredicate expr) throws PlanningException {
-    stack.push(expr);
-    EvalNode child = visit(ctx, stack, expr.getPredicand());
-    stack.pop();
-    return new IsNullEval(expr.isNot(), child);
-  }
-
-  @Override
-  public EvalNode visitInPredicate(Context ctx, Stack<Expr> stack, InPredicate expr) throws PlanningException {
-    stack.push(expr);
-    EvalNode lhs = visit(ctx, stack, expr.getLeft());
-    RowConstantEval rowConstantEval = (RowConstantEval) visit(ctx, stack, expr.getInValue());
-    stack.pop();
-
-    Pair<EvalNode, EvalNode> pair = convertTypesIfNecessary(lhs, rowConstantEval);
-
-    return new InEval(pair.getFirst(), (RowConstantEval) pair.getSecond(), expr.isNot());
-  }
-
-  @Override
-  public EvalNode visitValueListExpr(Context ctx, Stack<Expr> stack, ValueListExpr expr) throws PlanningException {
-    Datum[] values = new Datum[expr.getValues().length];
-    EvalNode [] evalNodes = new EvalNode[expr.getValues().length];
-    for (int i = 0; i < expr.getValues().length; i++) {
-      evalNodes[i] = visit(ctx, stack, expr.getValues()[i]);
-      if (!EvalTreeUtil.checkIfCanBeConstant(evalNodes[i])) {
-        throw new PlanningException("Non constant values cannot be included in IN PREDICATE.");
-      }
-      values[i] = EvalTreeUtil.evaluateImmediately(evalNodes[i]);
-    }
-    return new RowConstantEval(values);
-  }
-
-  @Override
-  public EvalNode visitExistsPredicate(Context ctx, Stack<Expr> stack, ExistsPredicate expr) throws PlanningException {
-    throw new PlanningException("Cannot support EXISTS clause yet");
-  }
-
-  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-  // String Operator or Pattern Matching Predicates Section
-  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-  @Override
-  public EvalNode visitLikePredicate(Context ctx, Stack<Expr> stack, PatternMatchPredicate expr)
-      throws PlanningException {
-    return visitPatternMatchPredicate(ctx, stack, expr);
-  }
-
-  @Override
-  public EvalNode visitSimilarToPredicate(Context ctx, Stack<Expr> stack, PatternMatchPredicate expr)
-      throws PlanningException {
-    return visitPatternMatchPredicate(ctx, stack, expr);
-  }
-
-  @Override
-  public EvalNode visitRegexpPredicate(Context ctx, Stack<Expr> stack, PatternMatchPredicate expr)
-      throws PlanningException {
-    return visitPatternMatchPredicate(ctx, stack, expr);
-  }
-
-  @Override
-  public EvalNode visitConcatenate(Context ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
-    stack.push(expr);
-    EvalNode lhs = visit(ctx, stack, expr.getLeft());
-    EvalNode rhs = visit(ctx, stack, expr.getRight());
-    stack.pop();
-
-    if (lhs.getValueType().getType() != Type.TEXT) {
-      lhs = convertType(lhs, CatalogUtil.newSimpleDataType(Type.TEXT));
-    }
-    if (rhs.getValueType().getType() != Type.TEXT) {
-      rhs = convertType(rhs, CatalogUtil.newSimpleDataType(Type.TEXT));
-    }
-
-    return new BinaryEval(EvalType.CONCATENATE, lhs, rhs);
-  }
-
-  private EvalNode visitPatternMatchPredicate(Context ctx, Stack<Expr> stack, PatternMatchPredicate expr)
-      throws PlanningException {
-    EvalNode field = visit(ctx, stack, expr.getPredicand());
-    ConstEval pattern = (ConstEval) visit(ctx, stack, expr.getPattern());
-
-    // A pattern is a const value in pattern matching predicates.
-    // In a binary expression, the result is always null if a const value in left or right side is null.
-    if (pattern.getValue() instanceof NullDatum) {
-      return new ConstEval(NullDatum.get());
-    } else {
-      if (expr.getType() == OpType.LikePredicate) {
-        return new LikePredicateEval(expr.isNot(), field, pattern, expr.isCaseInsensitive());
-      } else if (expr.getType() == OpType.SimilarToPredicate) {
-        return new SimilarToPredicateEval(expr.isNot(), field, pattern);
-      } else {
-        return new RegexPredicateEval(expr.isNot(), field, pattern, expr.isCaseInsensitive());
-      }
-    }
-  }
-
-  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-  // Arithmetic Operators
-  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-  private static BinaryEval createBinaryNode(EvalType type, EvalNode lhs, EvalNode rhs) {
-    Pair<EvalNode, EvalNode> pair = convertTypesIfNecessary(lhs, rhs); // implicit type conversion if necessary
-    return new BinaryEval(type, pair.getFirst(), pair.getSecond());
-  }
-
-  @Override
-  public EvalNode visitPlus(Context ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
-    stack.push(expr);
-    EvalNode left = visit(ctx, stack, expr.getLeft());
-    EvalNode right = visit(ctx, stack, expr.getRight());
-    stack.pop();
-
-    return createBinaryNode(EvalType.PLUS, left, right);
-  }
-
-  @Override
-  public EvalNode visitMinus(Context ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
-    stack.push(expr);
-    EvalNode left = visit(ctx, stack, expr.getLeft());
-    EvalNode right = visit(ctx, stack, expr.getRight());
-    stack.pop();
-
-    return createBinaryNode(EvalType.MINUS, left, right);
-  }
-
-  @Override
-  public EvalNode visitMultiply(Context ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
-    stack.push(expr);
-    EvalNode left = visit(ctx, stack, expr.getLeft());
-    EvalNode right = visit(ctx, stack, expr.getRight());
-    stack.pop();
-
-    return createBinaryNode(EvalType.MULTIPLY, left, right);
-  }
-
-  @Override
-  public EvalNode visitDivide(Context ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
-    stack.push(expr);
-    EvalNode left = visit(ctx, stack, expr.getLeft());
-    EvalNode right = visit(ctx, stack, expr.getRight());
-    stack.pop();
-
-    return createBinaryNode(EvalType.DIVIDE, left, right);
-  }
-
-  @Override
-  public EvalNode visitModular(Context ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
-    stack.push(expr);
-    EvalNode left = visit(ctx, stack, expr.getLeft());
-    EvalNode right = visit(ctx, stack, expr.getRight());
-    stack.pop();
-
-    return createBinaryNode(EvalType.MODULAR, left, right);
-  }
-
-  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-  // Other Expressions
-  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-  @Override
-  public EvalNode visitSign(Context ctx, Stack<Expr> stack, SignedExpr expr) throws PlanningException {
-    stack.push(expr);
-    EvalNode numericExpr = visit(ctx, stack, expr.getChild());
-    stack.pop();
-
-    if (expr.isNegative()) {
-      return new SignedEval(expr.isNegative(), numericExpr);
-    } else {
-      return numericExpr;
-    }
-  }
-
-  @Override
-  public EvalNode visitColumnReference(Context ctx, Stack<Expr> stack, ColumnReferenceExpr expr)
-      throws PlanningException {
-    Column column;
-
-    switch (ctx.columnRsvLevel) {
-    case LEGACY:
-      column = ctx.plan.resolveColumn(ctx.currentBlock, expr);
-      break;
-    case RELS_ONLY:
-    case RELS_AND_SUBEXPRS:
-    case SUBEXPRS_AND_RELS:
-      column = NameResolver.resolve(ctx.plan, ctx.currentBlock, expr, ctx.columnRsvLevel);
-      break;
-    default:
-      throw new PlanningException("Unsupported column resolving level: " + ctx.columnRsvLevel.name());
-    }
-    return new FieldEval(column);
-  }
-
-  @Override
-  public EvalNode visitTargetExpr(Context ctx, Stack<Expr> stack, NamedExpr expr) throws PlanningException {
-    throw new PlanningException("ExprAnnotator cannot take NamedExpr");
-  }
-
-  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-  // Functions and General Set Functions Section
-  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-  @Override
-  public EvalNode visitFunction(Context ctx, Stack<Expr> stack, FunctionExpr expr) throws PlanningException {
-    stack.push(expr); // <--- Push
-
-    // Given parameters
-    Expr[] params = expr.getParams();
-    if (params == null) {
-      params = new Expr[0];
-    }
-
-    EvalNode[] givenArgs = new EvalNode[params.length];
-    DataType[] paramTypes = new DataType[params.length];
-
-    for (int i = 0; i < params.length; i++) {
-      givenArgs[i] = visit(ctx, stack, params[i]);
-      paramTypes[i] = givenArgs[i].getValueType();
-    }
-
-    stack.pop(); // <--- Pop
-
-    if (!catalog.containFunction(expr.getSignature(), paramTypes)) {
-      throw new NoSuchFunctionException(expr.getSignature(), paramTypes);
-    }
-
-    FunctionDesc funcDesc = catalog.getFunction(expr.getSignature(), paramTypes);
-
-    // trying the implicit type conversion between actual parameter types and the definition types.
-    if (CatalogUtil.checkIfVariableLengthParamDefinition(TUtil.newList(funcDesc.getParamTypes()))) {
-      DataType lastDataType = funcDesc.getParamTypes()[0];
-      for (int i = 0; i < givenArgs.length; i++) {
-        if (i < (funcDesc.getParamTypes().length - 1)) { // variable length
-          lastDataType = funcDesc.getParamTypes()[i];
-        } else {
-          lastDataType = CatalogUtil.newSimpleDataType(CatalogUtil.getPrimitiveTypeOf(lastDataType.getType()));
-        }
-        givenArgs[i] = convertType(givenArgs[i], lastDataType);
-      }
-    } else {
-      assertEval(funcDesc.getParamTypes().length == givenArgs.length,
-          "The number of parameters is mismatched to the function definition: " + funcDesc.toString());
-      // According to our function matching method, each given argument can be casted to the definition parameter.
-      for (int i = 0; i < givenArgs.length; i++) {
-        givenArgs[i] = convertType(givenArgs[i], funcDesc.getParamTypes()[i]);
-      }
-    }
-
-
-    try {
-      FunctionType functionType = funcDesc.getFuncType();
-      if (functionType == FunctionType.GENERAL
-          || functionType == FunctionType.UDF) {
-        return new GeneralFunctionEval(funcDesc, (GeneralFunction) funcDesc.newInstance(), givenArgs);
-      } else if (functionType == FunctionType.AGGREGATION
-          || functionType == FunctionType.UDA) {
-        if (!ctx.currentBlock.hasNode(NodeType.GROUP_BY)) {
-          ctx.currentBlock.setAggregationRequire();
-        }
-        return new AggregationFunctionCallEval(funcDesc, (AggFunction) funcDesc.newInstance(), givenArgs);
-      } else if (functionType == FunctionType.DISTINCT_AGGREGATION
-          || functionType == FunctionType.DISTINCT_UDA) {
-        throw new PlanningException("Unsupported function: " + funcDesc.toString());
-      } else {
-        throw new PlanningException("Unsupported Function Type: " + functionType.name());
-      }
-    } catch (InternalException e) {
-      throw new PlanningException(e);
-    }
-  }
-
-  @Override
-  public EvalNode visitCountRowsFunction(Context ctx, Stack<Expr> stack, CountRowsFunctionExpr expr)
-      throws PlanningException {
-    FunctionDesc countRows = catalog.getFunction("count", FunctionType.AGGREGATION,
-        new DataType[] {});
-    if (countRows == null) {
-      throw new NoSuchFunctionException(expr.getSignature(), new DataType[]{});
-    }
-
-    try {
-      ctx.currentBlock.setAggregationRequire();
-
-      return new AggregationFunctionCallEval(countRows, (AggFunction) countRows.newInstance(),
-          new EvalNode[] {});
-    } catch (InternalException e) {
-      throw new NoSuchFunctionException(countRows.getFunctionName(), new DataType[]{});
-    }
-  }
-
-  @Override
-  public EvalNode visitGeneralSetFunction(Context ctx, Stack<Expr> stack, GeneralSetFunctionExpr setFunction)
-      throws PlanningException {
-
-    Expr[] params = setFunction.getParams();
-    EvalNode[] givenArgs = new EvalNode[params.length];
-    DataType[] paramTypes = new DataType[params.length];
-
-    FunctionType functionType = setFunction.isDistinct() ?
-        FunctionType.DISTINCT_AGGREGATION : FunctionType.AGGREGATION;
-    givenArgs[0] = visit(ctx, stack, params[0]);
-    if (setFunction.getSignature().equalsIgnoreCase("count")) {
-      paramTypes[0] = CatalogUtil.newSimpleDataType(Type.ANY);
-    } else {
-      paramTypes[0] = givenArgs[0].getValueType();
-    }
-
-    if (!catalog.containFunction(setFunction.getSignature(), functionType, paramTypes)) {
-      throw new NoSuchFunctionException(setFunction.getSignature(), paramTypes);
-    }
-
-    FunctionDesc funcDesc = catalog.getFunction(setFunction.getSignature(), functionType, paramTypes);
-    if (!ctx.currentBlock.hasNode(NodeType.GROUP_BY)) {
-      ctx.currentBlock.setAggregationRequire();
-    }
-
-    try {
-      return new AggregationFunctionCallEval(funcDesc, (AggFunction) funcDesc.newInstance(), givenArgs);
-    } catch (InternalException e) {
-      throw new PlanningException(e);
-    }
-  }
-
-  public static final Set<String> WINDOW_FUNCTIONS =
-      Sets.newHashSet("row_number", "rank", "dense_rank", "percent_rank", "cume_dist");
-
-  public EvalNode visitWindowFunction(Context ctx, Stack<Expr> stack, WindowFunctionExpr windowFunc)
-      throws PlanningException {
-
-    WindowSpec windowSpec = windowFunc.getWindowSpec();
-
-    Expr key;
-    if (windowSpec.hasPartitionBy()) {
-      for (int i = 0; i < windowSpec.getPartitionKeys().length; i++) {
-        key = windowSpec.getPartitionKeys()[i];
-        visit(ctx, stack, key);
-      }
-    }
-
-    EvalNode [] sortKeys = null;
-    if (windowSpec.hasOrderBy()) {
-      sortKeys = new EvalNode[windowSpec.getSortSpecs().length];
-      for (int i = 0; i < windowSpec.getSortSpecs().length; i++) {
-        key = windowSpec.getSortSpecs()[i].getKey();
-        sortKeys[i] = visit(ctx, stack, key);
-      }
-    }
-
-    String funcName = windowFunc.getSignature();
-    boolean distinct = windowFunc.isDistinct();
-    Expr[] params = windowFunc.getParams();
-    EvalNode[] givenArgs = new EvalNode[params.length];
-    TajoDataTypes.DataType[] paramTypes = new TajoDataTypes.DataType[params.length];
-    FunctionType functionType;
-
-    WindowFrame frame = null;
-
-    if (params.length > 0) {
-      givenArgs[0] = visit(ctx, stack, params[0]);
-      if (windowFunc.getSignature().equalsIgnoreCase("count")) {
-        paramTypes[0] = CatalogUtil.newSimpleDataType(TajoDataTypes.Type.ANY);
-      } else if (windowFunc.getSignature().equalsIgnoreCase("row_number")) {
-        paramTypes[0] = CatalogUtil.newSimpleDataType(Type.INT8);
-      } else {
-        paramTypes[0] = givenArgs[0].getValueType();
-      }
-    } else {
-      if (windowFunc.getSignature().equalsIgnoreCase("rank")) {
-        givenArgs = sortKeys != null ? sortKeys : new EvalNode[0];
-      }
-    }
-
-    if (frame == null) {
-      if (windowSpec.hasOrderBy()) {
-        frame = new WindowFrame(new WindowStartBound(WindowFrameStartBoundType.UNBOUNDED_PRECEDING),
-            new WindowEndBound(WindowFrameEndBoundType.CURRENT_ROW));
-      } else if (windowFunc.getSignature().equalsIgnoreCase("row_number")) {
-        frame = new WindowFrame(new WindowStartBound(WindowFrameStartBoundType.UNBOUNDED_PRECEDING),
-            new WindowEndBound(WindowFrameEndBoundType.UNBOUNDED_FOLLOWING));
-      } else {
-        frame = new WindowFrame();
-      }
-    }
-
-    // TODO - containFunction and getFunction should support the function type mask which provides ORing multiple types.
-    // the below checking against WINDOW_FUNCTIONS is a workaround code for the above problem.
-    if (WINDOW_FUNCTIONS.contains(funcName.toLowerCase())) {
-      if (distinct) {
-        throw new NoSuchFunctionException("row_number() does not support distinct keyword.");
-      }
-      functionType = FunctionType.WINDOW;
-    } else {
-      functionType = distinct ? FunctionType.DISTINCT_AGGREGATION : FunctionType.AGGREGATION;
-    }
-
-    if (!catalog.containFunction(windowFunc.getSignature(), functionType, paramTypes)) {
-      throw new NoSuchFunctionException(funcName, paramTypes);
-    }
-
-    FunctionDesc funcDesc = catalog.getFunction(funcName, functionType, paramTypes);
-
-    try {
-      return new WindowFunctionEval(funcDesc, (AggFunction) funcDesc.newInstance(), givenArgs, frame);
-    } catch (InternalException e) {
-      throw new PlanningException(e);
-    }
-  }
-
-  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-  // Literal Section
-  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-  @Override
-  public EvalNode visitDataType(Context ctx, Stack<Expr> stack, DataTypeExpr expr) throws PlanningException {
-    return super.visitDataType(ctx, stack, expr);
-  }
-
-  @Override
-  public EvalNode visitCastExpr(Context ctx, Stack<Expr> stack, CastExpr expr) throws PlanningException {
-    EvalNode child = super.visitCastExpr(ctx, stack, expr);
-
-    if (child.getType() == EvalType.CONST) { // if it is a casting operation for a constant value
-      ConstEval constEval = (ConstEval) child; // it will be pre-computed and casted to a constant value
-      return new ConstEval(DatumFactory.cast(constEval.getValue(), LogicalPlanner.convertDataType(expr.getTarget())));
-    } else {
-      return new CastEval(child, LogicalPlanner.convertDataType(expr.getTarget()));
-    }
-  }
-
-  @Override
-  public EvalNode visitLiteral(Context ctx, Stack<Expr> stack, LiteralValue expr) throws PlanningException {
-    switch (expr.getValueType()) {
-    case Boolean:
-      return new ConstEval(DatumFactory.createBool(((BooleanLiteral) expr).isTrue()));
-    case String:
-      return new ConstEval(DatumFactory.createText(expr.getValue()));
-    case Unsigned_Integer:
-      return new ConstEval(DatumFactory.createInt4(expr.getValue()));
-    case Unsigned_Large_Integer:
-      return new ConstEval(DatumFactory.createInt8(expr.getValue()));
-    case Unsigned_Float:
-      return new ConstEval(DatumFactory.createFloat8(expr.getValue()));
-    default:
-      throw new RuntimeException("Unsupported type: " + expr.getValueType());
-    }
-  }
-
-  @Override
-  public EvalNode visitNullLiteral(Context ctx, Stack<Expr> stack, NullLiteral expr) throws PlanningException {
-    return new ConstEval(NullDatum.get());
-  }
-
-  @Override
-  public EvalNode visitDateLiteral(Context context, Stack<Expr> stack, DateLiteral expr) throws PlanningException {
-    DateValue dateValue = expr.getDate();
-    int[] dates = dateToIntArray(dateValue.getYears(), dateValue.getMonths(), dateValue.getDays());
-
-    TimeMeta tm = new TimeMeta();
-    tm.years = dates[0];
-    tm.monthOfYear = dates[1];
-    tm.dayOfMonth = dates[2];
-
-    DateTimeUtil.j2date(DateTimeUtil.date2j(dates[0], dates[1], dates[2]), tm);
-
-    return new ConstEval(new DateDatum(DateTimeUtil.date2j(tm.years, tm.monthOfYear, tm.dayOfMonth)));
-  }
-
-  @Override
-  public EvalNode visitTimestampLiteral(Context ctx, Stack<Expr> stack, TimestampLiteral expr)
-      throws PlanningException {
-    DateValue dateValue = expr.getDate();
-    TimeValue timeValue = expr.getTime();
-
-    int [] dates = dateToIntArray(dateValue.getYears(),
-        dateValue.getMonths(),
-        dateValue.getDays());
-    int [] times = timeToIntArray(timeValue.getHours(),
-        timeValue.getMinutes(),
-        timeValue.getSeconds(),
-        timeValue.getSecondsFraction());
-
-    long timestamp;
-    if (timeValue.hasSecondsFraction()) {
-      timestamp = DateTimeUtil.toJulianTimestamp(dates[0], dates[1], dates[2], times[0], times[1], times[2],
-          times[3] * 1000);
-    } else {
-      timestamp = DateTimeUtil.toJulianTimestamp(dates[0], dates[1], dates[2], times[0], times[1], times[2], 0);
-    }
-
-    TimeMeta tm = new TimeMeta();
-    DateTimeUtil.toJulianTimeMeta(timestamp, tm);
-    DateTimeUtil.toUTCTimezone(tm);
-
-    return new ConstEval(new TimestampDatum(DateTimeUtil.toJulianTimestamp(tm)));
-  }
-
-  @Override
-  public EvalNode visitIntervalLiteral(Context ctx, Stack<Expr> stack, IntervalLiteral expr) throws PlanningException {
-    return new ConstEval(new IntervalDatum(expr.getExprStr()));
-  }
-
-  @Override
-  public EvalNode visitTimeLiteral(Context ctx, Stack<Expr> stack, TimeLiteral expr) throws PlanningException {
-    TimeValue timeValue = expr.getTime();
-    int [] times = timeToIntArray(timeValue.getHours(),
-        timeValue.getMinutes(),
-        timeValue.getSeconds(),
-        timeValue.getSecondsFraction());
-
-    long time;
-    if (timeValue.hasSecondsFraction()) {
-      time = DateTimeUtil.toTime(times[0], times[1], times[2], times[3] * 1000);
-    } else {
-      time = DateTimeUtil.toTime(times[0], times[1], times[2], 0);
-    }
-    TimeDatum timeDatum = new TimeDatum(time);
-    TimeMeta tm = timeDatum.toTimeMeta();
-    DateTimeUtil.toUTCTimezone(tm);
-
-    return new ConstEval(new TimeDatum(DateTimeUtil.toTime(tm)));
-  }
-
-  public static int [] dateToIntArray(String years, String months, String days)
-      throws PlanningException {
-    int year = Integer.valueOf(years);
-    int month = Integer.valueOf(months);
-    int day = Integer.valueOf(days);
-
-    if (!(1 <= year && year <= 9999)) {
-      throw new PlanningException(String.format("Years (%d) must be between 1 and 9999 integer value", year));
-    }
-
-    if (!(1 <= month && month <= 12)) {
-      throw new PlanningException(String.format("Months (%d) must be between 1 and 12 integer value", month));
-    }
-
-    if (!(1<= day && day <= 31)) {
-      throw new PlanningException(String.format("Days (%d) must be between 1 and 31 integer value", day));
-    }
-
-    int [] results = new int[3];
-    results[0] = year;
-    results[1] = month;
-    results[2] = day;
-
-    return results;
-  }
-
-  public static int [] timeToIntArray(String hours, String minutes, String seconds, String fractionOfSecond)
-      throws PlanningException {
-    int hour = Integer.valueOf(hours);
-    int minute = Integer.valueOf(minutes);
-    int second = Integer.valueOf(seconds);
-    int fraction = 0;
-    if (fractionOfSecond != null) {
-      fraction = Integer.valueOf(fractionOfSecond);
-    }
-
-    if (!(0 <= hour && hour <= 23)) {
-      throw new PlanningException(String.format("Hours (%d) must be between 0 and 24 integer value", hour));
-    }
-
-    if (!(0 <= minute && minute <= 59)) {
-      throw new PlanningException(String.format("Minutes (%d) must be between 0 and 59 integer value", minute));
-    }
-
-    if (!(0 <= second && second <= 59)) {
-      throw new PlanningException(String.format("Seconds (%d) must be between 0 and 59 integer value", second));
-    }
-
-    if (fraction != 0) {
-      if (!(0 <= fraction && fraction <= 999)) {
-        throw new PlanningException(String.format("Seconds (%d) must be between 0 and 999 integer value", fraction));
-      }
-    }
-
-    int [] results = new int[4];
-    results[0] = hour;
-    results[1] = minute;
-    results[2] = second;
-    results[3] = fraction;
-
-    return results;
-  }
-}

http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-core/src/main/java/org/apache/tajo/engine/planner/ExprFinder.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/planner/ExprFinder.java b/tajo-core/src/main/java/org/apache/tajo/engine/planner/ExprFinder.java
deleted file mode 100644
index dbc844d..0000000
--- a/tajo-core/src/main/java/org/apache/tajo/engine/planner/ExprFinder.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.tajo.engine.planner;
-
-import org.apache.tajo.algebra.BinaryOperator;
-import org.apache.tajo.algebra.Expr;
-import org.apache.tajo.algebra.OpType;
-import org.apache.tajo.algebra.UnaryOperator;
-
-import java.util.HashSet;
-import java.util.Set;
-import java.util.Stack;
-
-public class ExprFinder extends SimpleAlgebraVisitor<ExprFinder.Context, Object> {
-
-  static class Context {
-    Set<Expr> set = new HashSet<Expr>();
-    OpType targetType;
-
-    Context(OpType type) {
-      this.targetType = type;
-    }
-  }
-
-  public static <T extends Expr> Set<T> finds(Expr expr, OpType type) {
-    Context context = new Context(type);
-    ExprFinder finder = new ExprFinder();
-    Stack<Expr> stack = new Stack<Expr>();
-    stack.push(expr);
-    try {
-      finder.visit(context, new Stack<Expr>(), expr);
-    } catch (PlanningException e) {
-      throw new RuntimeException(e);
-    }
-    stack.pop();
-    return (Set<T>) context.set;
-  }
-
-  public Object visit(Context ctx, Stack<Expr> stack, Expr expr) throws PlanningException {
-    if (expr instanceof UnaryOperator) {
-      preHook(ctx, stack, expr);
-      visitUnaryOperator(ctx, stack, (UnaryOperator) expr);
-      postHook(ctx, stack, expr, null);
-    } else if (expr instanceof BinaryOperator) {
-      preHook(ctx, stack, expr);
-      visitBinaryOperator(ctx, stack, (BinaryOperator) expr);
-      postHook(ctx, stack, expr, null);
-    } else {
-      super.visit(ctx, stack, expr);
-    }
-
-    if (ctx.targetType == expr.getType()) {
-      ctx.set.add(expr);
-    }
-
-    return null;
-  }
-}

http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-core/src/main/java/org/apache/tajo/engine/planner/ExprNormalizer.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/planner/ExprNormalizer.java b/tajo-core/src/main/java/org/apache/tajo/engine/planner/ExprNormalizer.java
deleted file mode 100644
index 3718056..0000000
--- a/tajo-core/src/main/java/org/apache/tajo/engine/planner/ExprNormalizer.java
+++ /dev/null
@@ -1,388 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.tajo.engine.planner;
-
-import com.google.common.collect.Sets;
-import org.apache.tajo.algebra.*;
-import org.apache.tajo.catalog.CatalogUtil;
-import org.apache.tajo.engine.exception.NoSuchColumnException;
-import org.apache.tajo.engine.planner.nameresolver.NameResolvingMode;
-import org.apache.tajo.engine.planner.nameresolver.NameResolver;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Set;
-import java.util.Stack;
-
-/**
- * ExprNormalizer performs two kinds of works:
- *
- * <h3>1. Duplication Removal.</h3>
- *
- * For example, assume a simple query as follows:
- * <pre>
- *   select price * rate as total_price, ..., order by price * rate
- * </pre>
- *
- * The expression <code>price * rate</code> is duplicated in both select list and order by clause.
- * Against those cases, ExprNormalizer removes duplicated expressions and replaces one with one reference.
- * In the case, ExprNormalizer replaces price * rate with total_price reference.
- *
- * <h3>2. Dissection of Expression</h3>
- *
- * A expression can be a complex expressions, including a mixed of scalar and aggregation expressions.
- * For example, assume an aggregation query as follows:
- * <pre>
- *   select sum(price * rate) * (1 - avg(discount_rate))), ...
- * </pre>
- *
- * In this case, ExprNormalizer dissects the expression 'sum(price * rate) * (1 - avg(discount_rate)))'
- * into the following expressions:
- * <ul>
- *   <li>$1 = price * rage</li>
- *   <li>$2 = sum($1)</li>
- *   <li>$3 = avg(discount_rate)</li>
- *   <li>$4 = $2 * (1 - $3)</li>
- * </ul>
- *
- * It mainly two advantages. Firstly, it makes complex expression evaluations easier across multiple physical executors.
- * Second, it gives move opportunities to remove duplicated expressions.
- *
- * <h3>3. Name Normalization</h3>
- *
- * Users can use qualified column names, unqualified column names or aliased column references.
- *
- * Consider the following example:
- *
- * <pre>
- *   select rate_a as total_rate, rate_a * 100, table1.rate_a, ... WHERE total_rate * 100
- * </pre>
- *
- * <code>total_rate</code>, <code>rate_a</code>, and <code>table1.rate_a</code> are all the same references. But,
- * they have different forms. Due to their different forms, duplication removal can be hard.
- *
- * In order to solve this problem, ExprNormalizer normalizes all column references as qualified names while it keeps
- * its points..
- */
-class ExprNormalizer extends SimpleAlgebraVisitor<ExprNormalizer.ExprNormalizedResult, Object> {
-
-  public static class ExprNormalizedResult {
-    private final LogicalPlan plan;
-    private final LogicalPlan.QueryBlock block;
-    private final boolean tryBinaryCommonTermsElimination;
-
-    Expr baseExpr; // outmost expressions, which can includes one or more references of the results of aggregation
-                   // function.
-    List<NamedExpr> aggExprs = new ArrayList<NamedExpr>(); // aggregation functions
-    List<NamedExpr> scalarExprs = new ArrayList<NamedExpr>(); // scalar expressions which can be referred
-    List<NamedExpr> windowAggExprs = new ArrayList<NamedExpr>(); // window expressions which can be referred
-    Set<WindowSpecReferences> windowSpecs = Sets.newLinkedHashSet();
-
-    public ExprNormalizedResult(LogicalPlanner.PlanContext context, boolean tryBinaryCommonTermsElimination) {
-      this.plan = context.plan;
-      this.block = context.queryBlock;
-      this.tryBinaryCommonTermsElimination = tryBinaryCommonTermsElimination;
-    }
-
-    public boolean isBinaryCommonTermsElimination() {
-      return tryBinaryCommonTermsElimination;
-    }
-
-    @Override
-    public String toString() {
-      return baseExpr.toString() + ", agg=" + aggExprs.size() + ", scalar=" + scalarExprs.size();
-    }
-  }
-
-  public ExprNormalizedResult normalize(LogicalPlanner.PlanContext context, Expr expr) throws PlanningException {
-    return normalize(context, expr, false);
-  }
-  public ExprNormalizedResult normalize(LogicalPlanner.PlanContext context, Expr expr, boolean subexprElimination)
-      throws PlanningException {
-    ExprNormalizedResult exprNormalizedResult = new ExprNormalizedResult(context, subexprElimination);
-    Stack<Expr> stack = new Stack<Expr>();
-    stack.push(expr);
-    visit(exprNormalizedResult, new Stack<Expr>(), expr);
-    exprNormalizedResult.baseExpr = stack.pop();
-    return exprNormalizedResult;
-  }
-
-  @Override
-  public Object visitCaseWhen(ExprNormalizedResult ctx, Stack<Expr> stack, CaseWhenPredicate expr)
-      throws PlanningException {
-    stack.push(expr);
-    for (CaseWhenPredicate.WhenExpr when : expr.getWhens()) {
-      visit(ctx, stack, when.getCondition());
-      visit(ctx, stack, when.getResult());
-
-      if (OpType.isAggregationFunction(when.getCondition().getType())) {
-        String referenceName = ctx.block.namedExprsMgr.addExpr(when.getCondition());
-        ctx.aggExprs.add(new NamedExpr(when.getCondition(), referenceName));
-        when.setCondition(new ColumnReferenceExpr(referenceName));
-      }
-
-      if (OpType.isAggregationFunction(when.getResult().getType())) {
-        String referenceName = ctx.block.namedExprsMgr.addExpr(when.getResult());
-        ctx.aggExprs.add(new NamedExpr(when.getResult(), referenceName));
-        when.setResult(new ColumnReferenceExpr(referenceName));
-      }
-    }
-
-    if (expr.hasElseResult()) {
-      visit(ctx, stack, expr.getElseResult());
-      if (OpType.isAggregationFunction(expr.getElseResult().getType())) {
-        String referenceName = ctx.block.namedExprsMgr.addExpr(expr.getElseResult());
-        ctx.aggExprs.add(new NamedExpr(expr.getElseResult(), referenceName));
-        expr.setElseResult(new ColumnReferenceExpr(referenceName));
-      }
-    }
-    stack.pop();
-    return expr;
-  }
-
-  @Override
-  public Expr visitUnaryOperator(ExprNormalizedResult ctx, Stack<Expr> stack, UnaryOperator expr) throws PlanningException {
-    super.visitUnaryOperator(ctx, stack, expr);
-    if (OpType.isAggregationFunction(expr.getChild().getType())) {
-      // Get an anonymous column name and replace the aggregation function by the column name
-      String refName = ctx.block.namedExprsMgr.addExpr(expr.getChild());
-      ctx.aggExprs.add(new NamedExpr(expr.getChild(), refName));
-      expr.setChild(new ColumnReferenceExpr(refName));
-    }
-
-    return expr;
-  }
-
-  private boolean isBinaryCommonTermsElimination(ExprNormalizedResult ctx, Expr expr) {
-    return ctx.isBinaryCommonTermsElimination() && expr.getType() != OpType.Column
-        && ctx.block.namedExprsMgr.contains(expr);
-  }
-
-  @Override
-  public Expr visitBinaryOperator(ExprNormalizedResult ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
-    stack.push(expr);
-
-    visit(ctx, new Stack<Expr>(), expr.getLeft());
-    if (isBinaryCommonTermsElimination(ctx, expr.getLeft())) {
-      String refName = ctx.block.namedExprsMgr.addExpr(expr.getLeft());
-      expr.setLeft(new ColumnReferenceExpr(refName));
-    }
-
-    visit(ctx, new Stack<Expr>(), expr.getRight());
-    if (isBinaryCommonTermsElimination(ctx, expr.getRight())) {
-      String refName = ctx.block.namedExprsMgr.addExpr(expr.getRight());
-      expr.setRight(new ColumnReferenceExpr(refName));
-    }
-    stack.pop();
-
-    ////////////////////////
-    // For Left Term
-    ////////////////////////
-
-    if (OpType.isAggregationFunction(expr.getLeft().getType())) {
-      String leftRefName = ctx.block.namedExprsMgr.addExpr(expr.getLeft());
-      ctx.aggExprs.add(new NamedExpr(expr.getLeft(), leftRefName));
-      expr.setLeft(new ColumnReferenceExpr(leftRefName));
-    }
-
-
-    ////////////////////////
-    // For Right Term
-    ////////////////////////
-    if (OpType.isAggregationFunction(expr.getRight().getType())) {
-      String rightRefName = ctx.block.namedExprsMgr.addExpr(expr.getRight());
-      ctx.aggExprs.add(new NamedExpr(expr.getRight(), rightRefName));
-      expr.setRight(new ColumnReferenceExpr(rightRefName));
-    }
-
-    return expr;
-  }
-
-  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-  // Function Section
-  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-  @Override
-  public Expr visitFunction(ExprNormalizedResult ctx, Stack<Expr> stack, FunctionExpr expr) throws PlanningException {
-    stack.push(expr);
-
-    Expr param;
-    Expr[] paramExprs = expr.getParams();
-    if (paramExprs != null) {
-      for (int i = 0; i < paramExprs.length; i++) {
-        param = paramExprs[i];
-        visit(ctx, stack, param);
-
-        if (OpType.isAggregationFunction(param.getType())) {
-          String referenceName = ctx.plan.generateUniqueColumnName(param);
-          ctx.aggExprs.add(new NamedExpr(param, referenceName));
-          expr.getParams()[i] = new ColumnReferenceExpr(referenceName);
-        }
-      }
-    }
-    stack.pop();
-
-    return expr;
-  }
-
-  @Override
-  public Expr visitGeneralSetFunction(ExprNormalizedResult ctx, Stack<Expr> stack, GeneralSetFunctionExpr expr)
-      throws PlanningException {
-    stack.push(expr);
-
-    Expr param;
-    for (int i = 0; i < expr.getParams().length; i++) {
-      param = expr.getParams()[i];
-      visit(ctx, stack, param);
-
-
-      // If parameters are all constants, we don't need to dissect an aggregation expression into two parts:
-      // function and parameter parts.
-      if (!OpType.isLiteralType(param.getType()) && param.getType() != OpType.Column) {
-        String referenceName = ctx.block.namedExprsMgr.addExpr(param);
-        ctx.scalarExprs.add(new NamedExpr(param, referenceName));
-        expr.getParams()[i] = new ColumnReferenceExpr(referenceName);
-      }
-    }
-    stack.pop();
-    return expr;
-  }
-
-  public Expr visitWindowFunction(ExprNormalizedResult ctx, Stack<Expr> stack, WindowFunctionExpr expr)
-      throws PlanningException {
-    stack.push(expr);
-
-    WindowSpec windowSpec = expr.getWindowSpec();
-    Expr key;
-
-    WindowSpecReferences windowSpecReferences;
-    if (windowSpec.hasWindowName()) {
-      windowSpecReferences = new WindowSpecReferences(windowSpec.getWindowName());
-    } else {
-      String [] partitionKeyReferenceNames = null;
-      if (windowSpec.hasPartitionBy()) {
-        partitionKeyReferenceNames = new String [windowSpec.getPartitionKeys().length];
-        for (int i = 0; i < windowSpec.getPartitionKeys().length; i++) {
-          key = windowSpec.getPartitionKeys()[i];
-          visit(ctx, stack, key);
-          partitionKeyReferenceNames[i] = ctx.block.namedExprsMgr.addExpr(key);
-        }
-      }
-
-      String [] orderKeyReferenceNames = null;
-      if (windowSpec.hasOrderBy()) {
-        orderKeyReferenceNames = new String[windowSpec.getSortSpecs().length];
-        for (int i = 0; i < windowSpec.getSortSpecs().length; i++) {
-          key = windowSpec.getSortSpecs()[i].getKey();
-          visit(ctx, stack, key);
-          String referenceName = ctx.block.namedExprsMgr.addExpr(key);
-          if (OpType.isAggregationFunction(key.getType())) {
-            ctx.aggExprs.add(new NamedExpr(key, referenceName));
-            windowSpec.getSortSpecs()[i].setKey(new ColumnReferenceExpr(referenceName));
-          }
-          orderKeyReferenceNames[i] = referenceName;
-        }
-      }
-      windowSpecReferences =
-          new WindowSpecReferences(partitionKeyReferenceNames,orderKeyReferenceNames);
-    }
-    ctx.windowSpecs.add(windowSpecReferences);
-
-    String funcExprRef = ctx.block.namedExprsMgr.addExpr(expr);
-    ctx.windowAggExprs.add(new NamedExpr(expr, funcExprRef));
-    stack.pop();
-
-    ctx.block.setHasWindowFunction();
-    return expr;
-  }
-
-  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-  // Literal Section
-  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-  @Override
-  public Expr visitCastExpr(ExprNormalizedResult ctx, Stack<Expr> stack, CastExpr expr) throws PlanningException {
-    super.visitCastExpr(ctx, stack, expr);
-    if (OpType.isAggregationFunction(expr.getType())) {
-      String referenceName = ctx.block.namedExprsMgr.addExpr(expr.getChild());
-      ctx.aggExprs.add(new NamedExpr(expr.getChild(), referenceName));
-      expr.setChild(new ColumnReferenceExpr(referenceName));
-    }
-    return expr;
-  }
-
-  @Override
-  public Expr visitColumnReference(ExprNormalizedResult ctx, Stack<Expr> stack, ColumnReferenceExpr expr)
-      throws PlanningException {
-
-    if (ctx.block.isAliasedName(expr.getCanonicalName())) {
-      String originalName = ctx.block.getOriginalName(expr.getCanonicalName());
-      expr.setName(originalName);
-      return expr;
-    }
-    // if a column reference is not qualified, it finds and sets the qualified column name.
-    if (!(expr.hasQualifier() && CatalogUtil.isFQTableName(expr.getQualifier()))) {
-      if (!ctx.block.namedExprsMgr.contains(expr.getCanonicalName()) && expr.getType() == OpType.Column) {
-        try {
-          String normalized =
-              NameResolver.resolve(ctx.plan, ctx.block, expr, NameResolvingMode.LEGACY).getQualifiedName();
-          expr.setName(normalized);
-        } catch (NoSuchColumnException nsc) {
-        }
-      }
-    }
-    return expr;
-  }
-
-  public static class WindowSpecReferences {
-    String windowName;
-
-    String [] partitionKeys;
-    String [] orderKeys;
-
-    public WindowSpecReferences(String windowName) {
-      this.windowName = windowName;
-    }
-
-    public WindowSpecReferences(String [] partitionKeys, String [] orderKeys) {
-      this.partitionKeys = partitionKeys;
-      this.orderKeys = orderKeys;
-    }
-
-    public String getWindowName() {
-      return windowName;
-    }
-
-    public boolean hasPartitionKeys() {
-      return partitionKeys != null;
-    }
-
-    public String [] getPartitionKeys() {
-      return partitionKeys;
-    }
-
-    public boolean hasOrderBy() {
-      return orderKeys != null;
-    }
-
-    public String [] getOrderKeys() {
-      return orderKeys;
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-core/src/main/java/org/apache/tajo/engine/planner/ExprsVerifier.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/planner/ExprsVerifier.java b/tajo-core/src/main/java/org/apache/tajo/engine/planner/ExprsVerifier.java
deleted file mode 100644
index 5cb1fd9..0000000
--- a/tajo-core/src/main/java/org/apache/tajo/engine/planner/ExprsVerifier.java
+++ /dev/null
@@ -1,251 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.tajo.engine.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;
-
-  static {
-    instance = new ExprsVerifier();
-  }
-
-  public static VerificationState verify(VerificationState state, LogicalNode currentNode, EvalNode expression)
-      throws PlanningException {
-    instance.visitChild(state, expression, new Stack<EvalNode>());
-    Set<Column> referredColumns = EvalTreeUtil.findUniqueColumns(expression);
-    for (Column referredColumn : referredColumns) {
-      if (!currentNode.getInSchema().contains(referredColumn)) {
-        throw new PlanningException("Invalid State: " + referredColumn + " cannot be accessible 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;
-    }
-
-    if (checkTextData(dataType1) && checkTextData(dataType2)) {
-      return true;
-    }
-
-    if (checkDateTime(dataType1) && checkDateTime(dataType2)) {
-      return true;
-    }
-
-    if (checkNetworkType(dataType1) && checkNetworkType(dataType2)) {
-      return true;
-    }
-
-    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();
-    if (!isCompatibleType(leftType, rightType)) {
-      state.addVerification("No operator matches the given name and argument type(s): " + expr.toString());
-    }
-  }
-
-  public EvalNode visitEqual(VerificationState context, BinaryEval expr, Stack<EvalNode> stack) {
-    super.visitEqual(context, expr, stack);
-    verifyComparisonOperator(context, expr);
-    return 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 context, BinaryEval expr, Stack<EvalNode> stack) {
-    super.visitLessThan(context, expr, stack);
-    verifyComparisonOperator(context, expr);
-    return expr;
-  }
-
-  @Override
-  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 context, BinaryEval expr, Stack<EvalNode> stack) {
-    super.visitGreaterThan(context, expr, stack);
-    verifyComparisonOperator(context, expr);
-    return expr;
-  }
-
-  @Override
-  public EvalNode visitGreaterThanOrEqual(VerificationState context, BinaryEval expr, Stack<EvalNode> stack) {
-    super.visitGreaterThanOrEqual(context, expr, stack);
-    verifyComparisonOperator(context, expr);
-    return expr;
-  }
-
-  private static void checkDivisionByZero(VerificationState state, BinaryEval evalNode) {
-    if (evalNode.getRightExpr().getType() == EvalType.CONST) {
-      ConstEval constEval = evalNode.getRightExpr();
-      if (constEval.getValue().asFloat8() == 0) {
-        state.addVerification("division by zero");
-      }
-    }
-  }
-
-  private static void checkArithmeticOperand(VerificationState state, BinaryEval evalNode) {
-    EvalNode leftExpr = evalNode.getLeftExpr();
-    EvalNode rightExpr = evalNode.getRightExpr();
-
-    DataType leftDataType = leftExpr.getValueType();
-    DataType rightDataType = rightExpr.getValueType();
-
-    Type leftType = leftDataType.getType();
-    Type rightType = rightDataType.getType();
-
-    if (leftType == Type.DATE &&
-          (checkIntType(rightDataType) ||
-              rightType == Type.DATE || rightType == Type.INTERVAL || rightType == Type.TIME)) {
-      return;
-    }
-
-    if (leftType == Type.INTERVAL &&
-        (checkNumericType(rightDataType) ||
-            rightType == Type.DATE || rightType == Type.INTERVAL || rightType == Type.TIME ||
-            rightType == Type.TIMESTAMP)) {
-      return;
-    }
-
-    if (leftType == Type.TIME &&
-        (rightType == Type.DATE || rightType == Type.INTERVAL || rightType == Type.TIME)) {
-      return;
-    }
-
-    if (leftType == Type.TIMESTAMP &&
-        (rightType == Type.TIMESTAMP || rightType == Type.INTERVAL || rightType == Type.TIME)) {
-      return;
-    }
-
-    if (!(checkNumericType(leftDataType) && checkNumericType(rightDataType))) {
-      state.addVerification("No operator matches the given name and argument type(s): " + evalNode.toString());
-    }
-  }
-
-  private static boolean checkNetworkType(DataType dataType) {
-    return dataType.getType() == Type.INET4 || dataType.getType() == Type.INET6;
-  }
-
-  private static boolean checkIntType(DataType dataType) {
-    int typeNumber = dataType.getType().getNumber();
-    return Type.INT1.getNumber() < typeNumber && typeNumber <= Type.INT8.getNumber();
-  }
-
-  private static boolean checkNumericType(DataType dataType) {
-    int typeNumber = dataType.getType().getNumber();
-    return Type.INT1.getNumber() <= typeNumber && typeNumber <= Type.NUMERIC.getNumber();
-  }
-
-  private static boolean checkTextData(DataType dataType) {
-    int typeNumber = dataType.getType().getNumber();
-    return Type.CHAR.getNumber() <= typeNumber && typeNumber <= Type.TEXT.getNumber();
-  }
-
-  private static boolean checkDateTime(DataType dataType) {
-    int typeNumber = dataType.getType().getNumber();
-    return (Type.DATE.getNumber() <= typeNumber && typeNumber <= Type.INTERVAL.getNumber()) ||
-        (Type.TIMEZ.getNumber() <= typeNumber && typeNumber <= Type.TIMESTAMPZ.getNumber());
-  }
-
-  @Override
-  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 context, BinaryEval evalNode, Stack<EvalNode> stack) {
-    super.visitMinus(context, evalNode, stack);
-    checkArithmeticOperand(context, evalNode);
-    return evalNode;
-  }
-
-  @Override
-  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 context, BinaryEval evalNode, Stack<EvalNode> stack) {
-    super.visitDivide(context, evalNode, stack);
-    checkArithmeticOperand(context, evalNode);
-    checkDivisionByZero(context, evalNode);
-    return evalNode;
-  }
-
-  @Override
-  public EvalNode visitModular(VerificationState context, BinaryEval evalNode, Stack<EvalNode> stack) {
-    super.visitDivide(context, evalNode, stack);
-    checkArithmeticOperand(context, evalNode);
-    checkDivisionByZero(context, evalNode);
-    return evalNode;
-  }
-
-  @Override
-  public EvalNode visitFuncCall(VerificationState context, GeneralFunctionEval evalNode, Stack<EvalNode> stack) {
-    super.visitFuncCall(context, evalNode, stack);
-    if (evalNode.getArgs() != null) {
-      for (EvalNode param : evalNode.getArgs()) {
-        visitChild(context, param, stack);
-      }
-    }
-    return evalNode;
-  }
-}

http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-core/src/main/java/org/apache/tajo/engine/planner/GroupElement.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/planner/GroupElement.java b/tajo-core/src/main/java/org/apache/tajo/engine/planner/GroupElement.java
deleted file mode 100644
index 3fb05c2..0000000
--- a/tajo-core/src/main/java/org/apache/tajo/engine/planner/GroupElement.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.tajo.engine.planner;
-
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-import com.google.gson.annotations.Expose;
-import org.apache.tajo.algebra.Aggregation;
-import org.apache.tajo.engine.eval.EvalNode;
-
-public class GroupElement implements Cloneable {
-  @Expose private Aggregation.GroupType type;
-  @Expose private EvalNode [] groupingSets;
-
-  @SuppressWarnings("unused")
-  public GroupElement() {
-    // for gson
-  }
-
-  public GroupElement(Aggregation.GroupType type, EvalNode [] groupingSets) {
-    this.type = type;
-    this.groupingSets = groupingSets;
-  }
-
-  public Aggregation.GroupType getType() {
-    return this.type;
-  }
-
-  public EvalNode [] getGroupingSets() {
-    return this.groupingSets;
-  }
-
-  public String toString() {
-    Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation()
-        .setPrettyPrinting().create();
-    return gson.toJson(this);
-  }
-
-  public Object clone() throws CloneNotSupportedException {
-    GroupElement groups = (GroupElement) super.clone();
-    groups.type = type;
-    groups.groupingSets = new EvalNode [groupingSets.length];
-    for (int i = 0; i < groupingSets.length; i++) {
-      groups.groupingSets[i++] = (EvalNode) groupingSets[i].clone();
-    }
-    return groups;
-  }
-}

http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-core/src/main/java/org/apache/tajo/engine/planner/LogicalOptimizer.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/planner/LogicalOptimizer.java b/tajo-core/src/main/java/org/apache/tajo/engine/planner/LogicalOptimizer.java
deleted file mode 100644
index a43cc1a..0000000
--- a/tajo-core/src/main/java/org/apache/tajo/engine/planner/LogicalOptimizer.java
+++ /dev/null
@@ -1,311 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.tajo.engine.planner;
-
-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.classification.InterfaceStability;
-import org.apache.tajo.SessionVars;
-import org.apache.tajo.algebra.JoinType;
-import org.apache.tajo.conf.TajoConf;
-import org.apache.tajo.conf.TajoConf.ConfVars;
-import org.apache.tajo.engine.eval.AlgebraicUtil;
-import org.apache.tajo.engine.eval.EvalNode;
-import org.apache.tajo.engine.planner.graph.DirectedGraphCursor;
-import org.apache.tajo.engine.planner.logical.*;
-import org.apache.tajo.engine.planner.logical.join.FoundJoinOrder;
-import org.apache.tajo.engine.planner.logical.join.GreedyHeuristicJoinOrderAlgorithm;
-import org.apache.tajo.engine.planner.logical.join.JoinGraph;
-import org.apache.tajo.engine.planner.logical.join.JoinOrderAlgorithm;
-import org.apache.tajo.engine.planner.rewrite.*;
-import org.apache.tajo.engine.query.QueryContext;
-
-import java.util.LinkedHashSet;
-import java.util.Set;
-import java.util.Stack;
-
-import static org.apache.tajo.engine.planner.LogicalPlan.BlockEdge;
-import static org.apache.tajo.engine.planner.logical.join.GreedyHeuristicJoinOrderAlgorithm.getCost;
-
-/**
- * This class optimizes a logical plan.
- */
-@InterfaceStability.Evolving
-public class LogicalOptimizer {
-  private static final Log LOG = LogFactory.getLog(LogicalOptimizer.class.getName());
-
-  private BasicQueryRewriteEngine rulesBeforeJoinOpt;
-  private BasicQueryRewriteEngine rulesAfterToJoinOpt;
-  private JoinOrderAlgorithm joinOrderAlgorithm = new GreedyHeuristicJoinOrderAlgorithm();
-
-  public LogicalOptimizer(TajoConf systemConf) {
-    rulesBeforeJoinOpt = new BasicQueryRewriteEngine();
-    if (systemConf.getBoolVar(ConfVars.$TEST_FILTER_PUSHDOWN_ENABLED)) {
-      rulesBeforeJoinOpt.addRewriteRule(new FilterPushDownRule());
-    }
-
-    rulesAfterToJoinOpt = new BasicQueryRewriteEngine();
-    rulesAfterToJoinOpt.addRewriteRule(new ProjectionPushDownRule());
-    rulesAfterToJoinOpt.addRewriteRule(new PartitionedTableRewriter(systemConf));
-
-    // Currently, it is only used for some test cases to inject exception manually.
-    String userDefinedRewriterClass = systemConf.get("tajo.plan.rewriter.classes");
-    if (userDefinedRewriterClass != null && !userDefinedRewriterClass.isEmpty()) {
-      for (String eachRewriterClass : userDefinedRewriterClass.split(",")) {
-        try {
-          RewriteRule rule = (RewriteRule) Class.forName(eachRewriterClass).newInstance();
-          rulesAfterToJoinOpt.addRewriteRule(rule);
-        } catch (Exception e) {
-          LOG.error("Can't initiate a Rewriter object: " + eachRewriterClass, e);
-          continue;
-        }
-      }
-    }
-  }
-
-  public LogicalNode optimize(LogicalPlan plan) throws PlanningException {
-    return optimize(null, plan);
-  }
-
-  public LogicalNode optimize(QueryContext context, LogicalPlan plan) throws PlanningException {
-    rulesBeforeJoinOpt.rewrite(plan);
-
-    DirectedGraphCursor<String, BlockEdge> blockCursor =
-        new DirectedGraphCursor<String, BlockEdge>(plan.getQueryBlockGraph(), plan.getRootBlock().getName());
-
-    if (context == null || context.getBool(SessionVars.TEST_JOIN_OPT_ENABLED)) {
-      // default is true
-      while (blockCursor.hasNext()) {
-        optimizeJoinOrder(plan, blockCursor.nextBlock());
-      }
-    } else {
-      LOG.info("Skip Join Optimized.");
-    }
-    rulesAfterToJoinOpt.rewrite(plan);
-    return plan.getRootBlock().getRoot();
-  }
-
-  private void optimizeJoinOrder(LogicalPlan plan, String blockName) throws PlanningException {
-    LogicalPlan.QueryBlock block = plan.getBlock(blockName);
-
-    if (block.hasNode(NodeType.JOIN)) {
-      String originalOrder = JoinOrderStringBuilder.buildJoinOrderString(plan, block);
-      double nonOptimizedJoinCost = JoinCostComputer.computeCost(plan, block);
-
-      // finding relations and filter expressions
-      JoinGraphContext joinGraphContext = JoinGraphBuilder.buildJoinGraph(plan, block);
-
-      // finding join order and restore remain filter order
-      FoundJoinOrder order = joinOrderAlgorithm.findBestOrder(plan, block,
-          joinGraphContext.joinGraph, joinGraphContext.relationsForProduct);
-
-      // replace join node with FoundJoinOrder.
-      JoinNode newJoinNode = order.getOrderedJoin();
-      JoinNode old = PlannerUtil.findTopNode(block.getRoot(), NodeType.JOIN);
-
-      JoinTargetCollector collector = new JoinTargetCollector();
-      Set<Target> targets = new LinkedHashSet<Target>();
-      collector.visitJoin(targets, plan, block, old, new Stack<LogicalNode>());
-
-      if (targets.size() == 0) {
-        newJoinNode.setTargets(PlannerUtil.schemaToTargets(old.getOutSchema()));
-      } else {
-        newJoinNode.setTargets(targets.toArray(new Target[targets.size()]));
-      }
-      PlannerUtil.replaceNode(plan, block.getRoot(), old, newJoinNode);
-      // End of replacement logic
-
-      String optimizedOrder = JoinOrderStringBuilder.buildJoinOrderString(plan, block);
-      block.addPlanHistory("Non-optimized join order: " + originalOrder + " (cost: " + nonOptimizedJoinCost + ")");
-      block.addPlanHistory("Optimized join order    : " + optimizedOrder + " (cost: " + order.getCost() + ")");
-    }
-  }
-
-  private static class JoinTargetCollector extends BasicLogicalPlanVisitor<Set<Target>, LogicalNode> {
-    @Override
-    public LogicalNode visitJoin(Set<Target> ctx, LogicalPlan plan, LogicalPlan.QueryBlock block, JoinNode node,
-                                 Stack<LogicalNode> stack)
-        throws PlanningException {
-      super.visitJoin(ctx, plan, block, node, stack);
-
-      if (node.hasTargets()) {
-        for (Target target : node.getTargets()) {
-          ctx.add(target);
-        }
-      }
-      return node;
-    }
-  }
-
-  private static class JoinGraphContext {
-    JoinGraph joinGraph = new JoinGraph();
-    Set<EvalNode> quals = Sets.newHashSet();
-    Set<String> relationsForProduct = Sets.newHashSet();
-  }
-
-  private static class JoinGraphBuilder extends BasicLogicalPlanVisitor<JoinGraphContext, LogicalNode> {
-    private final static JoinGraphBuilder instance;
-
-    static {
-      instance = new JoinGraphBuilder();
-    }
-
-    /**
-     * This is based on the assumtion that all join and filter conditions are placed on the right join and
-     * scan operators. In other words, filter push down must be performed before this method.
-     * Otherwise, this method may build incorrectly a join graph.
-     */
-    public static JoinGraphContext buildJoinGraph(LogicalPlan plan, LogicalPlan.QueryBlock block)
-        throws PlanningException {
-      JoinGraphContext joinGraphContext = new JoinGraphContext();
-      instance.visit(joinGraphContext, plan, block);
-      return joinGraphContext;
-    }
-
-    public LogicalNode visitFilter(JoinGraphContext context, LogicalPlan plan, LogicalPlan.QueryBlock block,
-                                   SelectionNode node, Stack<LogicalNode> stack) throws PlanningException {
-      super.visitFilter(context, plan, block, node, stack);
-      context.quals.addAll(Lists.newArrayList(AlgebraicUtil.toConjunctiveNormalFormArray(node.getQual())));
-      return node;
-    }
-
-    @Override
-    public LogicalNode visitJoin(JoinGraphContext joinGraphContext, LogicalPlan plan, LogicalPlan.QueryBlock block,
-                                 JoinNode joinNode, Stack<LogicalNode> stack)
-        throws PlanningException {
-      super.visitJoin(joinGraphContext, plan, block, joinNode, stack);
-      if (joinNode.hasJoinQual()) {
-        joinGraphContext.joinGraph.addJoin(plan, block, joinNode);
-      } else {
-        LogicalNode leftChild = joinNode.getLeftChild();
-        LogicalNode rightChild = joinNode.getRightChild();
-        if (leftChild instanceof RelationNode) {
-          RelationNode rel = (RelationNode) leftChild;
-          joinGraphContext.relationsForProduct.add(rel.getCanonicalName());
-        }
-        if (rightChild instanceof RelationNode) {
-          RelationNode rel = (RelationNode) rightChild;
-          joinGraphContext.relationsForProduct.add(rel.getCanonicalName());
-        }
-      }
-      return joinNode;
-    }
-  }
-
-  public static class JoinOrderStringBuilder extends BasicLogicalPlanVisitor<StringBuilder, LogicalNode> {
-    private static final JoinOrderStringBuilder instance;
-    static {
-      instance = new JoinOrderStringBuilder();
-    }
-
-    public static JoinOrderStringBuilder getInstance() {
-      return instance;
-    }
-
-    public static String buildJoinOrderString(LogicalPlan plan, LogicalPlan.QueryBlock block) throws PlanningException {
-      StringBuilder originalOrder = new StringBuilder();
-      instance.visit(originalOrder, plan, block);
-      return originalOrder.toString();
-    }
-
-    @Override
-    public LogicalNode visitJoin(StringBuilder sb, LogicalPlan plan, LogicalPlan.QueryBlock block, JoinNode joinNode,
-                                 Stack<LogicalNode> stack)
-        throws PlanningException {
-      stack.push(joinNode);
-      sb.append("(");
-      visit(sb, plan, block, joinNode.getLeftChild(), stack);
-      sb.append(" ").append(getJoinNotation(joinNode.getJoinType())).append(" ");
-      visit(sb, plan, block, joinNode.getRightChild(), stack);
-      sb.append(")");
-      stack.pop();
-      return joinNode;
-    }
-
-    private static String getJoinNotation(JoinType joinType) {
-      switch (joinType) {
-      case CROSS: return "⋈";
-      case INNER: return "⋈θ";
-      case LEFT_OUTER: return "⟕";
-      case RIGHT_OUTER: return "⟖";
-      case FULL_OUTER: return "⟗";
-      case LEFT_SEMI: return "⋉";
-      case RIGHT_SEMI: return "⋊";
-      case LEFT_ANTI: return "▷";
-      }
-      return ",";
-    }
-
-    @Override
-    public LogicalNode visitTableSubQuery(StringBuilder sb, LogicalPlan plan, LogicalPlan.QueryBlock block,
-                                          TableSubQueryNode node, Stack<LogicalNode> stack) {
-      sb.append(node.getTableName());
-      return node;
-    }
-
-    public LogicalNode visitScan(StringBuilder sb, LogicalPlan plan, LogicalPlan.QueryBlock block, ScanNode node,
-                                 Stack<LogicalNode> stack) {
-      sb.append(node.getTableName());
-      return node;
-    }
-  }
-
-  private static class CostContext {
-    double accumulatedCost = 0;
-  }
-
-  public static class JoinCostComputer extends BasicLogicalPlanVisitor<CostContext, LogicalNode> {
-    private static final JoinCostComputer instance;
-
-    static {
-      instance = new JoinCostComputer();
-    }
-
-    public static double computeCost(LogicalPlan plan, LogicalPlan.QueryBlock block) throws PlanningException {
-      CostContext costContext = new CostContext();
-      instance.visit(costContext, plan, block);
-      return costContext.accumulatedCost;
-    }
-
-    @Override
-    public LogicalNode visitJoin(CostContext joinGraphContext, LogicalPlan plan, LogicalPlan.QueryBlock block,
-                                 JoinNode joinNode, Stack<LogicalNode> stack)
-        throws PlanningException {
-      super.visitJoin(joinGraphContext, plan, block, joinNode, stack);
-
-      double filterFactor = 1;
-      if (joinNode.hasJoinQual()) {
-        EvalNode [] quals = AlgebraicUtil.toConjunctiveNormalFormArray(joinNode.getJoinQual());
-        filterFactor = Math.pow(GreedyHeuristicJoinOrderAlgorithm.DEFAULT_SELECTION_FACTOR, quals.length);
-      }
-
-      if (joinNode.getLeftChild() instanceof RelationNode) {
-        joinGraphContext.accumulatedCost = getCost(joinNode.getLeftChild()) * getCost(joinNode.getRightChild())
-            * filterFactor;
-      } else {
-        joinGraphContext.accumulatedCost = joinGraphContext.accumulatedCost +
-            (joinGraphContext.accumulatedCost * getCost(joinNode.getRightChild()) * filterFactor);
-      }
-
-      return joinNode;
-    }
-  }
-}
\ No newline at end of file


Mime
View raw message