tajo-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jihoon...@apache.org
Subject [09/33] TAJO-1125: Separate logical plan and optimizer into a maven module.
Date Sun, 26 Oct 2014 05:46:08 GMT
http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-plan/src/main/java/org/apache/tajo/plan/NamedExprsManager.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/NamedExprsManager.java b/tajo-plan/src/main/java/org/apache/tajo/plan/NamedExprsManager.java
new file mode 100644
index 0000000..991860f
--- /dev/null
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/NamedExprsManager.java
@@ -0,0 +1,380 @@
+/**
+ * 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.plan;
+
+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;
+import org.apache.tajo.algebra.OpType;
+import org.apache.tajo.annotation.Nullable;
+import org.apache.tajo.plan.expr.EvalNode;
+import org.apache.tajo.plan.expr.EvalType;
+import org.apache.tajo.plan.expr.FieldEval;
+import org.apache.tajo.util.TUtil;
+
+import java.util.*;
+
+/**
+ * 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 {
+  /** 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 final LogicalPlan plan;
+
+  private final LogicalPlan.QueryBlock block;
+
+  public NamedExprsManager(LogicalPlan plan, LogicalPlan.QueryBlock block) {
+    this.plan = plan;
+    this.block = block;
+  }
+
+  private int getNextId() {
+    return sequenceId++;
+  }
+
+  /**
+   * 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 isEvaluated(String name) {
+    if (nameToIdMap.containsKey(name)) {
+      int refId = nameToIdMap.get(name);
+      return evaluationStateMap.containsKey(refId) && evaluationStateMap.get(refId);
+    } else {
+      return false;
+    }
+  }
+
+  public boolean contains(String name) {
+    return nameToIdMap.containsKey(name);
+  }
+
+  public boolean contains(Expr expr) {
+    return idToExprBiMap.inverse().containsKey(expr);
+  }
+
+  private Expr getExpr(String name) {
+    return idToExprBiMap.get(nameToIdMap.get(name));
+  }
+
+  public NamedExpr getNamedExpr(String name) {
+    String normalized = name;
+    return new NamedExpr(getExpr(name), normalized);
+  }
+
+  public boolean isAliased(String name) {
+    return aliasedColumnMap.containsKey(name);
+  }
+
+  public String getAlias(String originalName) {
+    return aliasedColumnMap.get(originalName);
+  }
+
+  public boolean isAliasedName(String aliasName) {
+    return aliasedColumnMap.inverse().containsKey(aliasName);
+  }
+
+  public String getOriginalName(String aliasName) {
+    return aliasedColumnMap.inverse().get(aliasName);
+  }
+
+  /**
+   * 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);
+    }
+
+    if (block.isRegisteredConst(expr)) {
+      return block.getConstReference(expr);
+    }
+
+    String generatedName = plan.generateUniqueColumnName(expr);
+    return addExpr(expr, generatedName);
+  }
+
+  /**
+   * 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 {
+
+    if (OpType.isLiteralType(expr.getType())) {
+      return alias;
+    }
+
+    // if this name already exists, just returns the name.
+    if (nameToIdMap.containsKey(alias)) {
+      return alias;
+    }
+
+    // if the name is first
+    int refId;
+    if (idToExprBiMap.inverse().containsKey(expr)) {
+      refId = idToExprBiMap.inverse().get(expr);
+    } else {
+      refId = getNextId();
+      idToExprBiMap.put(refId, expr);
+    }
+
+    nameToIdMap.put(alias, refId);
+    evaluationStateMap.put(refId, false);
+
+    // add the entry to idToNames map
+    TUtil.putToNestedList(idToNamesMap, refId, alias);
+
+    return alias;
+  }
+
+  /**
+   * 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 {
+      return addExpr(namedExpr.getExpr());
+    }
+  }
+
+  /**
+   * 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 : namedExprs) {
+        names[i++] = addNamedExpr(target);
+      }
+      return names;
+    } else {
+      return null;
+    }
+  }
+
+  public Collection<NamedExpr> getAllNamedExprs() {
+    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;
+  }
+
+  /**
+   * 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;
+
+    int refId = nameToIdMap.get(normalized);
+    evaluationStateMap.put(refId, true);
+    idToEvalMap.put(refId, evalNode);
+
+    String originalName = checkAndGetIfAliasedColumn(normalized);
+    if (originalName != null) {
+      aliasedColumnMap.put(originalName, normalized);
+    }
+  }
+
+  /**
+   * It returns an original column name if it is aliased column reference.
+   * Otherwise, it will return NULL.
+   */
+  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();
+      }
+    }
+    return null;
+  }
+
+  public Target getTarget(String name) {
+    return getTarget(name, false);
+  }
+
+  /**
+   * 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 (evalNode.getType() != EvalType.CONST && 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(idToNamesMap.get(refId).get(0), evalNode.getValueType());
+      }
+      return new Target(referredEval, referenceName);
+
+    } else {
+      if (idToEvalMap.containsKey(refId)) {
+        return new Target(idToEvalMap.get(refId), referenceName);
+      } else {
+        return null;
+      }
+    }
+  }
+
+  public String toString() {
+    return "unevaluated=" + nameToIdMap.size() + ", evaluated=" + idToEvalMap.size()
+        + ", renamed=" + aliasedColumnMap.size();
+  }
+
+  /**
+   * It returns an iterator for unevaluated NamedExprs.
+   */
+  public Iterator<NamedExpr> getIteratorForUnevaluatedExprs() {
+    return new UnevaluatedIterator();
+  }
+
+  public class UnevaluatedIterator implements Iterator<NamedExpr> {
+    private final Iterator<NamedExpr> iterator;
+
+    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 (unEvaluatedList.size() == 0) {
+        iterator = null;
+      } else {
+        iterator = unEvaluatedList.iterator();
+      }
+    }
+
+    @Override
+    public boolean hasNext() {
+      return iterator != null && iterator.hasNext();
+    }
+
+    @Override
+    public NamedExpr next() {
+      return iterator.next();
+    }
+
+    @Override
+    public void remove() {
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-plan/src/main/java/org/apache/tajo/plan/PlanString.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/PlanString.java b/tajo-plan/src/main/java/org/apache/tajo/plan/PlanString.java
new file mode 100644
index 0000000..b06c68f
--- /dev/null
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/PlanString.java
@@ -0,0 +1,119 @@
+/**
+ * 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.plan;
+
+import org.apache.tajo.plan.logical.LogicalNode;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class PlanString {
+  final StringBuilder title;
+
+  final List<String> explanations = new ArrayList<String>();
+  final List<String> details = new ArrayList<String>();
+
+  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);
+  }
+
+  public PlanString appendTitle(String str) {
+    title.append(str);
+    return this;
+  }
+
+  public PlanString addExplan(String explain) {
+    flushCurrentExplanation();
+    currentExplanation = new StringBuilder(explain);
+    return this;
+  }
+
+  public PlanString appendExplain(String explain) {
+    if (currentExplanation == null) {
+      currentExplanation = new StringBuilder();
+    }
+    currentExplanation.append(explain);
+    return this;
+  }
+
+  public PlanString addDetail(String detail) {
+    flushCurrentDetail();
+    currentDetail = new StringBuilder(detail);
+    return this;
+  }
+
+  public PlanString appendDetail(String detail) {
+    if (currentDetail == null) {
+      currentDetail = new StringBuilder();
+    }
+    currentDetail.append(detail);
+    return this;
+
+  }
+
+  public String getTitle() {
+    return title.toString();
+  }
+
+  public List<String> getExplanations() {
+    flushCurrentExplanation();
+    return explanations;
+  }
+
+  public List<String> getDetails() {
+    flushCurrentDetail();
+    return details;
+  }
+
+  private void flushCurrentExplanation() {
+    if (currentExplanation != null) {
+      explanations.add(currentExplanation.toString());
+      currentExplanation = null;
+    }
+  }
+
+  private void flushCurrentDetail() {
+    if (currentDetail != null) {
+      details.add(currentDetail.toString());
+      currentDetail = null;
+    }
+  }
+
+  public String toString() {
+    StringBuilder output = new StringBuilder();
+    output.append(getTitle()).append("\n");
+
+    for (String str : getExplanations()) {
+      output.append("  => ").append(str).append("\n");
+    }
+
+    for (String str : getDetails()) {
+      output.append("  => ").append(str).append("\n");
+    }
+    return output.toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-plan/src/main/java/org/apache/tajo/plan/PlanningException.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/PlanningException.java b/tajo-plan/src/main/java/org/apache/tajo/plan/PlanningException.java
new file mode 100644
index 0000000..2a52401
--- /dev/null
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/PlanningException.java
@@ -0,0 +1,29 @@
+/**
+ * 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.plan;
+
+public class PlanningException extends Exception {
+  public PlanningException(String message) {
+    super(message);
+  }
+
+  public PlanningException(Exception e) {
+    super(e);
+  }
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-plan/src/main/java/org/apache/tajo/plan/Target.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/Target.java b/tajo-plan/src/main/java/org/apache/tajo/plan/Target.java
new file mode 100644
index 0000000..f49a93d
--- /dev/null
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/Target.java
@@ -0,0 +1,130 @@
+/**
+ * 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.plan;
+
+import com.google.gson.annotations.Expose;
+import org.apache.tajo.catalog.Column;
+import org.apache.tajo.common.TajoDataTypes.DataType;
+import org.apache.tajo.json.GsonObject;
+import org.apache.tajo.plan.expr.EvalNode;
+import org.apache.tajo.plan.expr.FieldEval;
+import org.apache.tajo.plan.serder.PlanGsonHelper;
+import org.apache.tajo.util.TUtil;
+
+/**
+ * A Target contains how to evaluate an expression and its alias name.
+ */
+public class Target implements Cloneable, GsonObject {
+  @Expose private EvalNode expr;
+  @Expose private Column column;
+  @Expose private String alias = null;
+
+  public Target(FieldEval fieldEval) {
+    this.expr = fieldEval;
+    this.column = fieldEval.getColumnRef();
+  }
+
+  public Target(final EvalNode eval, final String alias) {
+    this.expr = eval;
+    // force lower case
+    String normalized = alias;
+
+    // If an expr is a column reference and its alias is equivalent to column name, ignore a given alias.
+    if (eval instanceof FieldEval
+        && eval.getName().equals(normalized)) {
+      column = ((FieldEval) eval).getColumnRef();
+    } else {
+      column = new Column(normalized, eval.getValueType());
+      setAlias(alias);
+    }
+  }
+
+  public String getCanonicalName() {
+    return !hasAlias() ? column.getQualifiedName() : alias;
+  }
+
+  public final void setExpr(EvalNode expr) {
+    this.expr = expr;
+  }
+
+  public final void setAlias(String alias) {
+    this.alias = alias;
+    this.column = new Column(alias, expr.getValueType());
+  }
+
+  public final String getAlias() {
+    return alias;
+  }
+
+  public final boolean hasAlias() {
+    return alias != null;
+  }
+
+  public DataType getDataType() {
+    return column.getDataType();
+  }
+
+  public <T extends EvalNode> T getEvalTree() {
+    return (T) this.expr;
+  }
+
+  public Column getNamedColumn() {
+    return this.column;
+  }
+
+  public String toString() {
+    StringBuilder sb = new StringBuilder(expr.toString());
+    if(hasAlias()) {
+      sb.append(" as ").append(alias);
+    }
+    return sb.toString();
+  }
+
+  public boolean equals(Object obj) {
+    if(obj instanceof Target) {
+      Target other = (Target) obj;
+
+      boolean b1 = expr.equals(other.expr);
+      boolean b2 = column.equals(other.column);
+      boolean b3 = TUtil.checkEquals(alias, other.alias);
+
+      return b1 && b2 && b3;
+    } else {
+      return false;
+    }
+  }
+
+  public int hashCode() {
+    return this.expr.getName().hashCode();
+  }
+
+  @Override
+  public Object clone() throws CloneNotSupportedException {
+    Target target = (Target) super.clone();
+    target.expr = (EvalNode) expr.clone();
+    target.column = column;
+    target.alias = alias != null ? alias : null;
+
+    return target;
+  }
+
+  public String toJson() {
+    return PlanGsonHelper.toJson(this, Target.class);
+  }
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-plan/src/main/java/org/apache/tajo/plan/TypeDeterminant.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/TypeDeterminant.java b/tajo-plan/src/main/java/org/apache/tajo/plan/TypeDeterminant.java
new file mode 100644
index 0000000..8605b3d
--- /dev/null
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/TypeDeterminant.java
@@ -0,0 +1,322 @@
+/**
+ * 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.plan;
+
+import com.google.common.base.Preconditions;
+import org.apache.tajo.DataTypeUtil;
+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.catalog.proto.CatalogProtos;
+import org.apache.tajo.common.TajoDataTypes;
+import org.apache.tajo.plan.visitor.SimpleAlgebraVisitor;
+
+import java.util.Stack;
+
+import static org.apache.tajo.common.TajoDataTypes.DataType;
+import static org.apache.tajo.common.TajoDataTypes.Type.BOOLEAN;
+import static org.apache.tajo.common.TajoDataTypes.Type.NULL_TYPE;
+
+public class TypeDeterminant extends SimpleAlgebraVisitor<LogicalPlanner.PlanContext, DataType> {
+  private DataType BOOL_TYPE = CatalogUtil.newSimpleDataType(BOOLEAN);
+  private CatalogService catalog;
+
+  public TypeDeterminant(CatalogService catalog) {
+    this.catalog = catalog;
+  }
+
+  public DataType determineDataType(LogicalPlanner.PlanContext ctx, Expr expr) throws PlanningException {
+    return visit(ctx, new Stack<Expr>(), expr);
+  }
+
+  @Override
+  public DataType visitUnaryOperator(LogicalPlanner.PlanContext ctx, Stack<Expr> stack, UnaryOperator expr)
+      throws PlanningException {
+    stack.push(expr);
+    DataType dataType = null;
+    switch (expr.getType()) {
+    case IsNullPredicate:
+    case ExistsPredicate:
+      dataType = BOOL_TYPE;
+      break;
+    case Cast:
+      dataType = LogicalPlanner.convertDataType(((CastExpr)expr).getTarget());
+      break;
+    default:
+      dataType = visit(ctx, stack, expr.getChild());
+    }
+
+    return dataType;
+  }
+
+  @Override
+  public DataType visitBinaryOperator(LogicalPlanner.PlanContext ctx, Stack<Expr> stack, BinaryOperator expr)
+      throws PlanningException {
+    stack.push(expr);
+    DataType lhsType = visit(ctx, stack, expr.getLeft());
+    DataType rhsType = visit(ctx, stack, expr.getRight());
+    stack.pop();
+    return computeBinaryType(expr.getType(), lhsType, rhsType);
+  }
+
+  public DataType computeBinaryType(OpType type, DataType lhsDataType, DataType rhsDataType) throws PlanningException {
+    Preconditions.checkNotNull(type);
+    Preconditions.checkNotNull(lhsDataType);
+    Preconditions.checkNotNull(rhsDataType);
+
+    if(OpType.isLogicalType(type) || OpType.isComparisonType(type)) {
+      return BOOL_TYPE;
+    } else if (OpType.isArithmeticType(type)) {
+      return DataTypeUtil.determineType(lhsDataType, rhsDataType);
+    } else if (type == OpType.Concatenate) {
+      return CatalogUtil.newSimpleDataType(TajoDataTypes.Type.TEXT);
+    } else if (type == OpType.InPredicate) {
+      return BOOL_TYPE;
+    } else if (type == OpType.LikePredicate || type == OpType.SimilarToPredicate || type == OpType.Regexp) {
+      return BOOL_TYPE;
+    } else {
+      throw new PlanningException(type.name() + "is not binary type");
+    }
+  }
+
+  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+  // Other Predicates Section
+  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+  @Override
+  public DataType visitBetween(LogicalPlanner.PlanContext ctx, Stack<Expr> stack, BetweenPredicate expr)
+      throws PlanningException {
+    return CatalogUtil.newSimpleDataType(BOOLEAN);
+  }
+
+  @Override
+  public DataType visitCaseWhen(LogicalPlanner.PlanContext ctx, Stack<Expr> stack, CaseWhenPredicate caseWhen)
+      throws PlanningException {
+    DataType lastDataType = null;
+
+    for (CaseWhenPredicate.WhenExpr when : caseWhen.getWhens()) {
+      DataType resultType = visit(ctx, stack, when.getResult());
+      if (lastDataType != null) {
+        lastDataType = CatalogUtil.getWidestType(lastDataType, resultType);
+      } else {
+        lastDataType = resultType;
+      }
+    }
+
+    if (caseWhen.hasElseResult()) {
+      DataType elseResultType = visit(ctx, stack, caseWhen.getElseResult());
+      lastDataType = CatalogUtil.getWidestType(lastDataType, elseResultType);
+    }
+
+    return lastDataType;
+  }
+
+  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+  // Other Expressions
+  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+  @Override
+  public DataType visitColumnReference(LogicalPlanner.PlanContext ctx, Stack<Expr> stack, ColumnReferenceExpr expr)
+      throws PlanningException {
+    stack.push(expr);
+    Column column = ctx.plan.resolveColumn(ctx.queryBlock, expr);
+    stack.pop();
+    return column.getDataType();
+  }
+
+  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+  // General Set Section
+  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+  @Override
+  public DataType visitFunction(LogicalPlanner.PlanContext 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];
+    }
+
+    DataType[] givenArgs = new DataType[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];
+    }
+
+    stack.pop(); // <--- Pop
+
+    if (!catalog.containFunction(expr.getSignature(), paramTypes)) {
+      throw new NoSuchFunctionException(expr.getSignature(), paramTypes);
+    }
+
+    FunctionDesc funcDesc = catalog.getFunction(expr.getSignature(), paramTypes);
+    return funcDesc.getReturnType();
+  }
+
+  @Override
+  public DataType visitCountRowsFunction(LogicalPlanner.PlanContext ctx, Stack<Expr> stack, CountRowsFunctionExpr expr)
+      throws PlanningException {
+    FunctionDesc countRows = catalog.getFunction("count", CatalogProtos.FunctionType.AGGREGATION,
+        new DataType[] {});
+    return countRows.getReturnType();
+  }
+
+  @Override
+  public DataType visitGeneralSetFunction(LogicalPlanner.PlanContext ctx, Stack<Expr> stack,
+                                          GeneralSetFunctionExpr setFunction) throws PlanningException {
+    stack.push(setFunction);
+
+    Expr[] params = setFunction.getParams();
+    DataType[] givenArgs = new DataType[params.length];
+    DataType[] paramTypes = new DataType[params.length];
+
+    CatalogProtos.FunctionType functionType = setFunction.isDistinct() ?
+        CatalogProtos.FunctionType.DISTINCT_AGGREGATION : CatalogProtos.FunctionType.AGGREGATION;
+    givenArgs[0] = visit(ctx, stack, params[0]);
+    if (setFunction.getSignature().equalsIgnoreCase("count")) {
+      paramTypes[0] = CatalogUtil.newSimpleDataType(TajoDataTypes.Type.ANY);
+    } else {
+      paramTypes[0] = givenArgs[0];
+    }
+
+    stack.pop(); // <-- pop
+
+    if (!catalog.containFunction(setFunction.getSignature(), functionType, paramTypes)) {
+      throw new NoSuchFunctionException(setFunction.getSignature(), paramTypes);
+    }
+
+    FunctionDesc funcDesc = catalog.getFunction(setFunction.getSignature(), functionType, paramTypes);
+    return funcDesc.getReturnType();
+  }
+
+  @Override
+  public DataType visitWindowFunction(LogicalPlanner.PlanContext ctx, Stack<Expr> stack, WindowFunctionExpr windowFunc)
+      throws PlanningException {
+    stack.push(windowFunc); // <--- Push
+
+    String funcName = windowFunc.getSignature();
+    boolean distinct = windowFunc.isDistinct();
+    Expr[] params = windowFunc.getParams();
+    DataType[] givenArgs = new DataType[params.length];
+    TajoDataTypes.DataType[] paramTypes = new TajoDataTypes.DataType[params.length];
+    CatalogProtos.FunctionType functionType;
+
+    // Rewrite parameters if necessary
+    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(TajoDataTypes.Type.INT8);
+      } else {
+        paramTypes[0] = givenArgs[0];
+      }
+    }
+    stack.pop(); // <--- Pop
+
+    // 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 (ExprAnnotator.WINDOW_FUNCTIONS.contains(funcName.toLowerCase())) {
+      if (distinct) {
+        throw new NoSuchFunctionException("row_number() does not support distinct keyword.");
+      }
+      functionType = CatalogProtos.FunctionType.WINDOW;
+    } else {
+      functionType = distinct ?
+          CatalogProtos.FunctionType.DISTINCT_AGGREGATION : CatalogProtos.FunctionType.AGGREGATION;
+    }
+
+    if (!catalog.containFunction(windowFunc.getSignature(), functionType, paramTypes)) {
+      throw new NoSuchFunctionException(funcName, paramTypes);
+    }
+
+    FunctionDesc funcDesc = catalog.getFunction(funcName, functionType, paramTypes);
+
+    return funcDesc.getReturnType();
+  }
+
+  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+  // Literal Section
+  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+  @Override
+  public DataType visitDataType(LogicalPlanner.PlanContext ctx, Stack<Expr> stack, DataTypeExpr expr)
+      throws PlanningException {
+    return LogicalPlanner.convertDataType(expr);
+  }
+
+  @Override
+  public DataType visitLiteral(LogicalPlanner.PlanContext ctx, Stack<Expr> stack, LiteralValue expr)
+      throws PlanningException {
+    // It must be the same to ExprAnnotator::visitLiteral.
+
+    switch (expr.getValueType()) {
+    case Boolean:
+      return CatalogUtil.newSimpleDataType(BOOLEAN);
+    case String:
+      return CatalogUtil.newSimpleDataType(TajoDataTypes.Type.TEXT);
+    case Unsigned_Integer:
+      return CatalogUtil.newSimpleDataType(TajoDataTypes.Type.INT4);
+    case Unsigned_Large_Integer:
+      return CatalogUtil.newSimpleDataType(TajoDataTypes.Type.INT8);
+    case Unsigned_Float:
+      return CatalogUtil.newSimpleDataType(TajoDataTypes.Type.FLOAT8);
+    default:
+      throw new RuntimeException("Unsupported type: " + expr.getValueType());
+    }
+  }
+
+  @Override
+  public DataType visitNullLiteral(LogicalPlanner.PlanContext ctx, Stack<Expr> stack, NullLiteral expr)
+      throws PlanningException {
+    return CatalogUtil.newSimpleDataType(NULL_TYPE);
+  }
+
+  @Override
+  public DataType visitTimestampLiteral(LogicalPlanner.PlanContext ctx, Stack<Expr> stack, TimestampLiteral expr)
+      throws PlanningException {
+    return CatalogUtil.newSimpleDataType(TajoDataTypes.Type.TIMESTAMP);
+  }
+
+  @Override
+  public DataType visitTimeLiteral(LogicalPlanner.PlanContext ctx, Stack<Expr> stack, TimeLiteral expr)
+      throws PlanningException {
+    return CatalogUtil.newSimpleDataType(TajoDataTypes.Type.TIME);
+  }
+
+  @Override
+  public DataType visitDateLiteral(LogicalPlanner.PlanContext ctx, Stack<Expr> stack, DateLiteral expr)
+      throws PlanningException {
+    return CatalogUtil.newSimpleDataType(TajoDataTypes.Type.DATE);
+  }
+
+  @Override
+  public DataType visitIntervalLiteral(LogicalPlanner.PlanContext ctx, Stack<Expr> stack, IntervalLiteral expr)
+      throws PlanningException {
+    return CatalogUtil.newSimpleDataType(TajoDataTypes.Type.INTERVAL);
+  }
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-plan/src/main/java/org/apache/tajo/plan/algebra/AlgebraVisitor.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/algebra/AlgebraVisitor.java b/tajo-plan/src/main/java/org/apache/tajo/plan/algebra/AlgebraVisitor.java
new file mode 100644
index 0000000..df1e341
--- /dev/null
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/algebra/AlgebraVisitor.java
@@ -0,0 +1,114 @@
+/**
+ * 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.plan.algebra;
+
+import org.apache.tajo.algebra.*;
+import org.apache.tajo.plan.PlanningException;
+
+import java.util.Stack;
+
+public interface AlgebraVisitor<CONTEXT, RESULT> {
+  // Relational Operators
+  RESULT visitProjection(CONTEXT ctx, Stack<Expr> stack, Projection expr) throws PlanningException;
+  RESULT visitLimit(CONTEXT ctx, Stack<Expr> stack, Limit expr) throws PlanningException;
+  RESULT visitSort(CONTEXT ctx, Stack<Expr> stack, Sort expr) throws PlanningException;
+  RESULT visitHaving(CONTEXT ctx, Stack<Expr> stack, Having expr) throws PlanningException;
+  RESULT visitGroupBy(CONTEXT ctx, Stack<Expr> stack, Aggregation expr) throws PlanningException;
+  RESULT visitJoin(CONTEXT ctx, Stack<Expr> stack, Join expr) throws PlanningException;
+  RESULT visitFilter(CONTEXT ctx, Stack<Expr> stack, Selection expr) throws PlanningException;
+  RESULT visitUnion(CONTEXT ctx, Stack<Expr> stack, SetOperation expr) throws PlanningException;
+  RESULT visitExcept(CONTEXT ctx, Stack<Expr> stack, SetOperation expr) throws PlanningException;
+  RESULT visitIntersect(CONTEXT ctx, Stack<Expr> stack, SetOperation expr) throws PlanningException;
+  RESULT visitSimpleTableSubQuery(CONTEXT ctx, Stack<Expr> stack, SimpleTableSubQuery expr) throws PlanningException;
+  RESULT visitTableSubQuery(CONTEXT ctx, Stack<Expr> stack, TablePrimarySubQuery expr) throws PlanningException;
+  RESULT visitRelationList(CONTEXT ctx, Stack<Expr> stack, RelationList expr) throws PlanningException;
+  RESULT visitRelation(CONTEXT ctx, Stack<Expr> stack, Relation expr) throws PlanningException;
+  RESULT visitScalarSubQuery(CONTEXT ctx, Stack<Expr> stack, ScalarSubQuery expr) throws PlanningException;
+  RESULT visitExplain(CONTEXT ctx, Stack<Expr> stack, Explain expr) throws PlanningException;
+
+  // Data definition language
+  RESULT visitCreateDatabase(CONTEXT ctx, Stack<Expr> stack, CreateDatabase expr) throws PlanningException;
+  RESULT visitDropDatabase(CONTEXT ctx, Stack<Expr> stack, DropDatabase expr) throws PlanningException;
+  RESULT visitCreateTable(CONTEXT ctx, Stack<Expr> stack, CreateTable expr) throws PlanningException;
+  RESULT visitDropTable(CONTEXT ctx, Stack<Expr> stack, DropTable expr) throws PlanningException;
+  RESULT visitAlterTablespace(CONTEXT ctx, Stack<Expr> stack, AlterTablespace expr) throws PlanningException;
+  RESULT visitAlterTable(CONTEXT ctx, Stack<Expr> stack, AlterTable expr) throws PlanningException;
+  RESULT visitTruncateTable(CONTEXT ctx, Stack<Expr> stack, TruncateTable expr) throws PlanningException;
+
+    // Insert or Update
+  RESULT visitInsert(CONTEXT ctx, Stack<Expr> stack, Insert expr) throws PlanningException;
+
+  // Logical operators
+  RESULT visitAnd(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException;
+  RESULT visitOr(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException;
+  RESULT visitNot(CONTEXT ctx, Stack<Expr> stack, NotExpr expr) throws PlanningException;
+
+  // comparison predicates
+  RESULT visitEquals(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException;
+  RESULT visitNotEquals(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException;
+  RESULT visitLessThan(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException;
+  RESULT visitLessThanOrEquals(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException;
+  RESULT visitGreaterThan(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException;
+  RESULT visitGreaterThanOrEquals(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException;
+
+  // Other Predicates
+  RESULT visitBetween(CONTEXT ctx, Stack<Expr> stack, BetweenPredicate expr) throws PlanningException;
+  RESULT visitCaseWhen(CONTEXT ctx, Stack<Expr> stack, CaseWhenPredicate expr) throws PlanningException;
+  RESULT visitIsNullPredicate(CONTEXT ctx, Stack<Expr> stack, IsNullPredicate expr) throws PlanningException;
+  RESULT visitInPredicate(CONTEXT ctx, Stack<Expr> stack, InPredicate expr) throws PlanningException;
+  RESULT visitValueListExpr(CONTEXT ctx, Stack<Expr> stack, ValueListExpr expr) throws PlanningException;
+  RESULT visitExistsPredicate(CONTEXT ctx, Stack<Expr> stack, ExistsPredicate expr) throws PlanningException;
+
+  // String Operator or Pattern Matching Predicates
+  RESULT visitLikePredicate(CONTEXT ctx, Stack<Expr> stack, PatternMatchPredicate expr) throws PlanningException;
+  RESULT visitSimilarToPredicate(CONTEXT ctx, Stack<Expr> stack, PatternMatchPredicate expr) throws PlanningException;
+  RESULT visitRegexpPredicate(CONTEXT ctx, Stack<Expr> stack, PatternMatchPredicate expr) throws PlanningException;
+  RESULT visitConcatenate(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException;
+
+  // arithmetic operators
+  RESULT visitPlus(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException;
+  RESULT visitMinus(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException;
+  RESULT visitMultiply(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException;
+  RESULT visitDivide(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException;
+  RESULT visitModular(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException;
+
+  // other expressions
+  RESULT visitSign(CONTEXT ctx, Stack<Expr> stack, SignedExpr expr) throws PlanningException;
+  RESULT visitColumnReference(CONTEXT ctx, Stack<Expr> stack, ColumnReferenceExpr expr) throws PlanningException;
+  RESULT visitTargetExpr(CONTEXT ctx, Stack<Expr> stack, NamedExpr expr) throws PlanningException;
+  RESULT visitQualifiedAsterisk(CONTEXT ctx, Stack<Expr> stack, QualifiedAsteriskExpr expr) throws PlanningException;
+
+  // functions
+  RESULT visitFunction(CONTEXT ctx, Stack<Expr> stack, FunctionExpr expr) throws PlanningException;
+  RESULT visitGeneralSetFunction(CONTEXT ctx, Stack<Expr> stack, GeneralSetFunctionExpr expr)
+      throws PlanningException;
+  RESULT visitCountRowsFunction(CONTEXT ctx, Stack<Expr> stack, CountRowsFunctionExpr expr) throws PlanningException;
+  RESULT visitWindowFunction(CONTEXT ctx, Stack<Expr> stack, WindowFunctionExpr expr) throws PlanningException;
+
+  // Literal
+  RESULT visitCastExpr(CONTEXT ctx, Stack<Expr> stack, CastExpr expr) throws PlanningException;
+
+  RESULT visitDataType(CONTEXT ctx, Stack<Expr> stack, DataTypeExpr expr) throws PlanningException;
+  RESULT visitLiteral(CONTEXT ctx, Stack<Expr> stack, LiteralValue expr) throws PlanningException;
+  RESULT visitNullLiteral(CONTEXT ctx, Stack<Expr> stack, NullLiteral expr) throws PlanningException;
+  RESULT visitTimestampLiteral(CONTEXT ctx, Stack<Expr> stack, TimestampLiteral expr) throws PlanningException;
+  RESULT visitIntervalLiteral(CONTEXT ctx, Stack<Expr> stack, IntervalLiteral expr) throws PlanningException;
+  RESULT visitTimeLiteral(CONTEXT ctx, Stack<Expr> stack, TimeLiteral expr) throws PlanningException;
+  RESULT visitDateLiteral(CONTEXT ctx, Stack<Expr> stack, DateLiteral expr) throws PlanningException;
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-plan/src/main/java/org/apache/tajo/plan/algebra/AmbiguousFieldException.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/algebra/AmbiguousFieldException.java b/tajo-plan/src/main/java/org/apache/tajo/plan/algebra/AmbiguousFieldException.java
new file mode 100644
index 0000000..ea3081c
--- /dev/null
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/algebra/AmbiguousFieldException.java
@@ -0,0 +1,32 @@
+/**
+ * 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.plan.algebra;
+
+import org.apache.tajo.plan.InvalidQueryException;
+
+public class AmbiguousFieldException extends InvalidQueryException {
+	private static final long serialVersionUID = 3102675985226352347L;
+
+	/**
+	 * @param fieldName
+	 */
+	public AmbiguousFieldException(String fieldName) {
+		super("ERROR: column name "+ fieldName + " is ambiguous");	
+	}
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-plan/src/main/java/org/apache/tajo/plan/algebra/BaseAlgebraVisitor.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/algebra/BaseAlgebraVisitor.java b/tajo-plan/src/main/java/org/apache/tajo/plan/algebra/BaseAlgebraVisitor.java
new file mode 100644
index 0000000..57ddfbd
--- /dev/null
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/algebra/BaseAlgebraVisitor.java
@@ -0,0 +1,790 @@
+/**
+ * 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.plan.algebra;
+
+import org.apache.tajo.algebra.*;
+import org.apache.tajo.plan.PlanningException;
+
+import java.util.Stack;
+
+public class BaseAlgebraVisitor<CONTEXT, RESULT> implements AlgebraVisitor<CONTEXT, RESULT> {
+
+  /**
+   * The prehook is called before each expression is visited.
+   */
+  public void preHook(CONTEXT ctx, Stack<Expr> stack, Expr expr) throws PlanningException {
+  }
+
+
+  /**
+   * The posthook is called before each expression is visited.
+   */
+  public RESULT postHook(CONTEXT ctx, Stack<Expr> stack, Expr expr, RESULT current) throws PlanningException {
+    return current;
+  }
+
+  /**
+   * visit visits each relational operator expression recursively.
+   *
+   * @param stack The stack contains the upper operators' type.
+   * @param expr The visiting relational operator
+   */
+  public RESULT visit(CONTEXT ctx, Stack<Expr> stack, Expr expr) throws PlanningException {
+    preHook(ctx, stack, expr);
+
+    RESULT current;
+
+    switch (expr.getType()) {
+
+    case Projection:
+      current = visitProjection(ctx, stack, (Projection) expr);
+      break;
+    case Limit:
+      current = visitLimit(ctx, stack, (Limit) expr);
+      break;
+    case Sort:
+      current = visitSort(ctx, stack, (Sort) expr);
+      break;
+    case Having:
+      current = visitHaving(ctx, stack, (Having) expr);
+      break;
+    case Aggregation:
+      current = visitGroupBy(ctx, stack, (Aggregation) expr);
+      break;
+    case Join:
+      current = visitJoin(ctx, stack, (Join) expr);
+      break;
+    case Filter:
+      current = visitFilter(ctx, stack, (Selection) expr);
+      break;
+    case Union:
+      current = visitUnion(ctx, stack, (SetOperation) expr);
+      break;
+    case Except:
+      current = visitExcept(ctx, stack, (SetOperation) expr);
+      break;
+    case Intersect:
+      current = visitIntersect(ctx, stack, (SetOperation) expr);
+      break;
+    case SimpleTableSubQuery:
+      current = visitSimpleTableSubQuery(ctx, stack, (SimpleTableSubQuery) expr);
+      break;
+    case TablePrimaryTableSubQuery:
+      current = visitTableSubQuery(ctx, stack, (TablePrimarySubQuery) expr);
+      break;
+    case RelationList:
+      current = visitRelationList(ctx, stack, (RelationList) expr);
+      break;
+    case Relation:
+      current = visitRelation(ctx, stack, (Relation) expr);
+      break;
+    case ScalarSubQuery:
+      current = visitScalarSubQuery(ctx, stack, (ScalarSubQuery) expr);
+      break;
+    case Explain:
+      current = visitExplain(ctx, stack, (Explain) expr);
+      break;
+
+    case CreateDatabase:
+      current = visitCreateDatabase(ctx, stack, (CreateDatabase) expr);
+      break;
+    case DropDatabase:
+      current = visitDropDatabase(ctx, stack, (DropDatabase) expr);
+      break;
+    case CreateTable:
+      current = visitCreateTable(ctx, stack, (CreateTable) expr);
+      break;
+    case DropTable:
+      current = visitDropTable(ctx, stack, (DropTable) expr);
+      break;
+    case AlterTablespace:
+      current = visitAlterTablespace(ctx, stack, (AlterTablespace) expr);
+      break;
+    case AlterTable:
+      current = visitAlterTable(ctx, stack, (AlterTable) expr);
+      break;
+    case TruncateTable:
+      current = visitTruncateTable(ctx, stack, (TruncateTable)expr);
+      break;
+
+    case Insert:
+      current = visitInsert(ctx, stack, (Insert) expr);
+      break;
+
+    case And:
+      current = visitAnd(ctx, stack, (BinaryOperator) expr);
+      break;
+    case Or:
+      current = visitOr(ctx, stack, (BinaryOperator) expr);
+      break;
+    case Not:
+      current = visitNot(ctx, stack, (NotExpr) expr);
+      break;
+
+    case Equals:
+      current = visitEquals(ctx, stack, (BinaryOperator) expr);
+      break;
+    case NotEquals:
+      current = visitNotEquals(ctx, stack, (BinaryOperator) expr);
+      break;
+    case LessThan:
+      current = visitLessThan(ctx, stack, (BinaryOperator) expr);
+      break;
+    case LessThanOrEquals:
+      current = visitLessThanOrEquals(ctx, stack, (BinaryOperator) expr);
+      break;
+    case GreaterThan:
+      current = visitGreaterThan(ctx, stack, (BinaryOperator) expr);
+      break;
+    case GreaterThanOrEquals:
+      current = visitGreaterThanOrEquals(ctx, stack, (BinaryOperator) expr);
+      break;
+
+    // Other Predicates
+    case Between:
+      current = visitBetween(ctx, stack, (BetweenPredicate) expr);
+      break;
+    case CaseWhen:
+      current = visitCaseWhen(ctx, stack, (CaseWhenPredicate) expr);
+      break;
+    case IsNullPredicate:
+      current = visitIsNullPredicate(ctx, stack, (IsNullPredicate) expr);
+      break;
+    case InPredicate:
+      current = visitInPredicate(ctx, stack, (InPredicate) expr);
+      break;
+    case ValueList:
+      current = visitValueListExpr(ctx, stack, (ValueListExpr) expr);
+      break;
+    case ExistsPredicate:
+      current = visitExistsPredicate(ctx, stack, (ExistsPredicate) expr);
+      break;
+
+    // String Operator or Pattern Matching Predicates
+    case LikePredicate:
+      current = visitLikePredicate(ctx, stack, (PatternMatchPredicate) expr);
+      break;
+    case SimilarToPredicate:
+      current = visitSimilarToPredicate(ctx, stack, (PatternMatchPredicate) expr);
+      break;
+    case Regexp:
+      current = visitRegexpPredicate(ctx, stack, (PatternMatchPredicate) expr);
+      break;
+    case Concatenate:
+      current = visitConcatenate(ctx, stack, (BinaryOperator) expr);
+      break;
+
+    // Arithmetic Operators
+    case Plus:
+      current = visitPlus(ctx, stack, (BinaryOperator) expr);
+      break;
+    case Minus:
+      current = visitMinus(ctx, stack, (BinaryOperator) expr);
+      break;
+    case Multiply:
+      current = visitMultiply(ctx, stack, (BinaryOperator) expr);
+      break;
+    case Divide:
+      current = visitDivide(ctx, stack, (BinaryOperator) expr);
+      break;
+    case Modular:
+      current = visitModular(ctx, stack, (BinaryOperator) expr);
+      break;
+
+    // Other Expressions
+    case Sign:
+      current = visitSign(ctx, stack, (SignedExpr) expr);
+      break;
+    case Column:
+      current = visitColumnReference(ctx, stack, (ColumnReferenceExpr) expr);
+      break;
+    case Target:
+      current = visitTargetExpr(ctx, stack, (NamedExpr) expr);
+      break;
+    case Function:
+      current = visitFunction(ctx, stack, (FunctionExpr) expr);
+      break;
+    case Asterisk:
+      current = visitQualifiedAsterisk(ctx, stack, (QualifiedAsteriskExpr) expr);
+      break;
+
+
+    case CountRowsFunction:
+      current = visitCountRowsFunction(ctx, stack, (CountRowsFunctionExpr) expr);
+      break;
+    case GeneralSetFunction:
+      current = visitGeneralSetFunction(ctx, stack, (GeneralSetFunctionExpr) expr);
+      break;
+    case WindowFunction:
+      current = visitWindowFunction(ctx, stack, (WindowFunctionExpr) expr);
+      break;
+
+
+    case DataType:
+      current = visitDataType(ctx, stack, (DataTypeExpr) expr);
+      break;
+    case Cast:
+      current = visitCastExpr(ctx, stack, (CastExpr) expr);
+      break;
+    case Literal:
+      current = visitLiteral(ctx, stack, (LiteralValue) expr);
+      break;
+    case NullLiteral:
+      current = visitNullLiteral(ctx, stack, (NullLiteral) expr);
+      break;
+    case DateLiteral:
+      current = visitDateLiteral(ctx, stack, (DateLiteral) expr);
+      break;
+    case TimeLiteral:
+      current = visitTimeLiteral(ctx, stack, (TimeLiteral) expr);
+      break;
+    case TimestampLiteral:
+      current = visitTimestampLiteral(ctx, stack, (TimestampLiteral) expr);
+      break;
+    case IntervalLiteral:
+      current = visitIntervalLiteral(ctx, stack, (IntervalLiteral) expr);
+      break;
+
+
+    default:
+      throw new PlanningException("Cannot support this type algebra \"" + expr.getType() + "\"");
+    }
+
+    // skip postHook against only one relation
+    if (expr.getType() == OpType.RelationList) {
+      RelationList relationList = (RelationList)expr;
+      if (relationList.size() == 1 && relationList.getRelations()[0].getType() == OpType.Relation) {
+        return current;
+      }
+    }
+
+    postHook(ctx, stack, expr, current);
+    return current;
+  }
+
+  private RESULT visitDefaultUnaryExpr(CONTEXT ctx, Stack<Expr> stack, UnaryOperator expr) throws PlanningException {
+    stack.push(expr);
+    RESULT child = visit(ctx, stack, expr.getChild());
+    stack.pop();
+    return child;
+  }
+
+  private RESULT visitDefaultBinaryExpr(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr)
+      throws PlanningException {
+    stack.push(expr);
+    RESULT child = visit(ctx, stack, expr.getLeft());
+    visit(ctx, stack, expr.getRight());
+    stack.pop();
+    return child;
+  }
+
+  @Override
+  public RESULT visitProjection(CONTEXT ctx, Stack<Expr> stack, Projection expr) throws PlanningException {
+    stack.push(expr);
+    try {
+      for (NamedExpr target : expr.getNamedExprs()) {
+        visit(ctx, stack, target);
+      }
+      if (expr.hasChild()) {
+        return visit(ctx, stack, expr.getChild());
+      }
+    } finally {
+      stack.pop();
+    }
+    return null;
+  }
+
+  @Override
+  public RESULT visitLimit(CONTEXT ctx, Stack<Expr> stack, Limit expr) throws PlanningException {
+    stack.push(expr);
+    visit(ctx, stack, expr.getFetchFirstNum());
+    RESULT result = visit(ctx, stack, expr.getChild());
+    stack.pop();
+    return result;
+  }
+
+  @Override
+  public RESULT visitSort(CONTEXT ctx, Stack<Expr> stack, Sort expr) throws PlanningException {
+    stack.push(expr);
+    for (Sort.SortSpec sortSpec : expr.getSortSpecs()) {
+      visit(ctx, stack, sortSpec.getKey());
+    }
+    RESULT result = visit(ctx, stack, expr.getChild());
+    return result;
+  }
+
+  @Override
+  public RESULT visitHaving(CONTEXT ctx, Stack<Expr> stack, Having expr) throws PlanningException {
+    stack.push(expr);
+    visit(ctx, stack, expr.getQual());
+    RESULT result = visit(ctx, stack, expr.getChild());
+    stack.pop();
+    return result;
+  }
+
+  @Override
+  public RESULT visitGroupBy(CONTEXT ctx, Stack<Expr> stack, Aggregation expr) throws PlanningException {
+    stack.push(expr);
+
+    for (org.apache.tajo.algebra.Aggregation.GroupElement groupElement : expr.getGroupSet()) {
+      for (Expr groupingSet : groupElement.getGroupingSets()) {
+        visit(ctx, stack, groupingSet);
+      }
+    }
+
+    RESULT result = visit(ctx, stack, expr.getChild());
+    stack.pop();
+    return result;
+  }
+
+  @Override
+  public RESULT visitJoin(CONTEXT ctx, Stack<Expr> stack, Join expr) throws PlanningException {
+    stack.push(expr);
+    visit(ctx, stack, expr.getQual());
+    visit(ctx, stack, expr.getLeft());
+    RESULT result = visit(ctx, stack, expr.getRight());
+    stack.pop();
+    return result;
+  }
+
+  @Override
+  public RESULT visitFilter(CONTEXT ctx, Stack<Expr> stack, Selection expr) throws PlanningException {
+    stack.push(expr);
+    visit(ctx, stack, expr.getQual());
+    RESULT result = visit(ctx, stack, expr.getChild());
+    stack.pop();
+    return result;
+  }
+
+  @Override
+  public RESULT visitUnion(CONTEXT ctx, Stack<Expr> stack, SetOperation expr) throws PlanningException {
+    return visitDefaultBinaryExpr(ctx, stack, expr);
+  }
+
+  @Override
+  public RESULT visitExcept(CONTEXT ctx, Stack<Expr> stack, SetOperation expr) throws PlanningException {
+    return visitDefaultBinaryExpr(ctx, stack, expr);
+  }
+
+  @Override
+  public RESULT visitIntersect(CONTEXT ctx, Stack<Expr> stack, SetOperation expr) throws PlanningException {
+    return visitDefaultBinaryExpr(ctx, stack, expr);
+  }
+
+  @Override
+  public RESULT visitSimpleTableSubQuery(CONTEXT ctx, Stack<Expr> stack, SimpleTableSubQuery expr)
+      throws PlanningException {
+    return visitDefaultUnaryExpr(ctx, stack, expr);
+  }
+
+  @Override
+  public RESULT visitTableSubQuery(CONTEXT ctx, Stack<Expr> stack, TablePrimarySubQuery expr)
+      throws PlanningException {
+    stack.push(expr);
+    RESULT child = visit(ctx, stack, expr.getSubQuery());
+    stack.pop();
+    return child;
+  }
+
+  @Override
+  public RESULT visitRelationList(CONTEXT ctx, Stack<Expr> stack, RelationList expr) throws PlanningException {
+    stack.push(expr);
+    RESULT child = null;
+    for (Expr e : expr.getRelations()) {
+      child = visit(ctx, stack, e);
+    }
+    stack.pop();
+    return child;
+  }
+
+  @Override
+  public RESULT visitRelation(CONTEXT ctx, Stack<Expr> stack, Relation expr) throws PlanningException {
+    return null;
+  }
+
+  @Override
+  public RESULT visitScalarSubQuery(CONTEXT ctx, Stack<Expr> stack, ScalarSubQuery expr) throws PlanningException {
+    return visitDefaultUnaryExpr(ctx, stack, expr);
+  }
+
+  @Override
+  public RESULT visitExplain(CONTEXT ctx, Stack<Expr> stack, Explain expr) throws PlanningException {
+    stack.push(expr);
+    RESULT child = visit(ctx, stack, expr.getChild());
+    stack.pop();
+    return child;
+  }
+
+  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+  // Data Definition Language Section
+  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+  @Override
+  public RESULT visitCreateDatabase(CONTEXT ctx, Stack<Expr> stack, CreateDatabase expr) throws PlanningException {
+    return null;
+  }
+
+  @Override
+  public RESULT visitDropDatabase(CONTEXT ctx, Stack<Expr> stack, DropDatabase expr) throws PlanningException {
+    return null;
+  }
+
+  @Override
+  public RESULT visitCreateTable(CONTEXT ctx, Stack<Expr> stack, CreateTable expr) throws PlanningException {
+    stack.push(expr);
+    RESULT child = null;
+    if (expr.hasSubQuery()) {
+      child = visit(ctx, stack, expr.getSubQuery());
+    }
+    stack.pop();
+    return child;
+  }
+
+  @Override
+  public RESULT visitDropTable(CONTEXT ctx, Stack<Expr> stack, DropTable expr) throws PlanningException {
+    return null;
+  }
+
+  @Override
+  public RESULT visitAlterTablespace(CONTEXT ctx, Stack<Expr> stack, AlterTablespace expr) throws PlanningException {
+    return null;
+  }
+
+  @Override
+  public RESULT visitAlterTable(CONTEXT ctx, Stack<Expr> stack, AlterTable expr) throws PlanningException {
+    return null;
+  }
+
+  public RESULT visitTruncateTable(CONTEXT ctx, Stack<Expr> stack, TruncateTable expr) throws PlanningException {
+    return null;
+  }
+  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+  // Insert or Update Section
+  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public RESULT visitInsert(CONTEXT ctx, Stack<Expr> stack, Insert expr) throws PlanningException {
+    stack.push(expr);
+    RESULT child = visit(ctx, stack, expr.getSubQuery());
+    stack.pop();
+    return child;
+  }
+
+  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+  // Logical Operator Section
+  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+  @Override
+  public RESULT visitAnd(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
+    return visitDefaultBinaryExpr(ctx, stack, expr);
+  }
+
+  @Override
+  public RESULT visitOr(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
+    return visitDefaultBinaryExpr(ctx, stack, expr);
+  }
+
+  @Override
+  public RESULT visitNot(CONTEXT ctx, Stack<Expr> stack, NotExpr expr) throws PlanningException {
+    return visitDefaultUnaryExpr(ctx, stack, expr);
+  }
+
+  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+  // Comparison Predicates Section
+  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+  @Override
+  public RESULT visitEquals(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
+    return visitDefaultBinaryExpr(ctx, stack, expr);
+  }
+
+  @Override
+  public RESULT visitNotEquals(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
+    return visitDefaultBinaryExpr(ctx, stack, expr);
+  }
+
+  @Override
+  public RESULT visitLessThan(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
+    return visitDefaultBinaryExpr(ctx, stack, expr);
+  }
+
+  @Override
+  public RESULT visitLessThanOrEquals(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
+    return visitDefaultBinaryExpr(ctx, stack, expr);
+  }
+
+  @Override
+  public RESULT visitGreaterThan(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
+    return visitDefaultBinaryExpr(ctx, stack, expr);
+  }
+
+  @Override
+  public RESULT visitGreaterThanOrEquals(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr)
+      throws PlanningException {
+    return visitDefaultBinaryExpr(ctx, stack, expr);
+  }
+
+  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+  // Other Predicates Section
+  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+  @Override
+  public RESULT visitBetween(CONTEXT ctx, Stack<Expr> stack, BetweenPredicate expr) throws PlanningException {
+    stack.push(expr);
+    RESULT result = visit(ctx, stack, expr.predicand());
+    visit(ctx, stack, expr.begin());
+    visit(ctx, stack, expr.end());
+    stack.pop();
+    return result;
+  }
+
+  @Override
+  public RESULT visitCaseWhen(CONTEXT ctx, Stack<Expr> stack, CaseWhenPredicate expr) throws PlanningException {
+    stack.push(expr);
+    RESULT result = null;
+    for (CaseWhenPredicate.WhenExpr when : expr.getWhens()) {
+      result = visit(ctx, stack, when.getCondition());
+      visit(ctx, stack, when.getResult());
+    }
+    if (expr.hasElseResult()) {
+      visit(ctx, stack, expr.getElseResult());
+    }
+    stack.pop();
+    return result;
+  }
+
+  @Override
+  public RESULT visitIsNullPredicate(CONTEXT ctx, Stack<Expr> stack, IsNullPredicate expr) throws PlanningException {
+    return visitDefaultUnaryExpr(ctx, stack, expr);
+  }
+
+  @Override
+  public RESULT visitInPredicate(CONTEXT ctx, Stack<Expr> stack, InPredicate expr) throws PlanningException {
+    return visitDefaultBinaryExpr(ctx, stack, expr);
+  }
+
+  @Override
+  public RESULT visitValueListExpr(CONTEXT ctx, Stack<Expr> stack, ValueListExpr expr) throws PlanningException {
+    stack.push(expr);
+    RESULT result = null;
+    for (Expr value : expr.getValues()) {
+      result = visit(ctx, stack, value);
+    }
+    stack.pop();
+    return result;
+  }
+
+  @Override
+  public RESULT visitExistsPredicate(CONTEXT ctx, Stack<Expr> stack, ExistsPredicate expr) throws PlanningException {
+    return visitDefaultUnaryExpr(ctx, stack, expr);
+  }
+
+  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+  // String Operator or Pattern Matching Predicates Section
+  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+  @Override
+  public RESULT visitLikePredicate(CONTEXT ctx, Stack<Expr> stack, PatternMatchPredicate expr)
+      throws PlanningException {
+    return visitDefaultBinaryExpr(ctx, stack, expr);
+  }
+
+  @Override
+  public RESULT visitSimilarToPredicate(CONTEXT ctx, Stack<Expr> stack, PatternMatchPredicate expr)
+      throws PlanningException {
+    return visitDefaultBinaryExpr(ctx, stack, expr);
+  }
+
+  @Override
+  public RESULT visitRegexpPredicate(CONTEXT ctx, Stack<Expr> stack, PatternMatchPredicate expr)
+      throws PlanningException {
+    return visitDefaultBinaryExpr(ctx, stack, expr);
+  }
+
+  @Override
+  public RESULT visitConcatenate(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
+    return visitDefaultBinaryExpr(ctx, stack, expr);
+  }
+
+  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+  // Arithmetic Operators
+  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+  @Override
+  public RESULT visitPlus(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
+    return visitDefaultBinaryExpr(ctx, stack, expr);
+  }
+
+  @Override
+  public RESULT visitMinus(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
+    return visitDefaultBinaryExpr(ctx, stack, expr);
+  }
+
+  @Override
+  public RESULT visitMultiply(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
+    return visitDefaultBinaryExpr(ctx, stack, expr);
+  }
+
+  @Override
+  public RESULT visitDivide(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
+    return visitDefaultBinaryExpr(ctx, stack, expr);
+  }
+
+  @Override
+  public RESULT visitModular(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
+    return visitDefaultBinaryExpr(ctx, stack, expr);
+  }
+
+  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+  // Other Expressions
+  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+  @Override
+  public RESULT visitSign(CONTEXT ctx, Stack<Expr> stack, SignedExpr expr) throws PlanningException {
+    return visitDefaultUnaryExpr(ctx, stack, expr);
+  }
+
+  @Override
+  public RESULT visitColumnReference(CONTEXT ctx, Stack<Expr> stack, ColumnReferenceExpr expr)
+      throws PlanningException {
+    return null;
+  }
+
+  @Override
+  public RESULT visitTargetExpr(CONTEXT ctx, Stack<Expr> stack, NamedExpr expr) throws PlanningException {
+    return visitDefaultUnaryExpr(ctx, stack, expr);
+  }
+
+  @Override
+  public RESULT visitFunction(CONTEXT ctx, Stack<Expr> stack, FunctionExpr expr) throws PlanningException {
+    stack.push(expr);
+    RESULT result = null;
+    if (expr.hasParams()) {
+      for (Expr param : expr.getParams()) {
+        result = visit(ctx, stack, param);
+      }
+    }
+    stack.pop();
+    return result;
+  }
+
+  @Override
+  public RESULT visitQualifiedAsterisk(CONTEXT ctx, Stack<Expr> stack, QualifiedAsteriskExpr expr) throws PlanningException {
+    return null;
+  }
+
+  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+  // General Set Section
+  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+  @Override
+  public RESULT visitCountRowsFunction(CONTEXT ctx, Stack<Expr> stack, CountRowsFunctionExpr expr)
+      throws PlanningException {
+    return null;
+  }
+
+  @Override
+  public RESULT visitGeneralSetFunction(CONTEXT ctx, Stack<Expr> stack, GeneralSetFunctionExpr expr)
+      throws PlanningException {
+    stack.push(expr);
+    RESULT result = null;
+    for (Expr param : expr.getParams()) {
+      result = visit(ctx, stack, param);
+    }
+    stack.pop();
+    return result;
+  }
+
+  @Override
+  public RESULT visitWindowFunction(CONTEXT ctx, Stack<Expr> stack, WindowFunctionExpr expr) throws PlanningException {
+    stack.push(expr);
+    RESULT result = null;
+    for (Expr param : expr.getParams()) {
+      result = visit(ctx, stack, param);
+    }
+
+    WindowSpec windowSpec = expr.getWindowSpec();
+
+    if (windowSpec.hasPartitionBy()) {
+      for (Expr partitionKey : windowSpec.getPartitionKeys()) {
+        visit(ctx, stack, partitionKey);
+      }
+    }
+    if (windowSpec.hasOrderBy()) {
+      for (Sort.SortSpec sortKey : windowSpec.getSortSpecs()) {
+        visit(ctx, stack, sortKey.getKey());
+      }
+    }
+    if (windowSpec.hasWindowFrame()) {
+      if (windowSpec.getWindowFrame().getStartBound().hasNumber()) {
+        visit(ctx, stack, windowSpec.getWindowFrame().getStartBound().getNumber());
+      }
+      if (windowSpec.getWindowFrame().getEndBound().hasNumber()) {
+        visit(ctx, stack, windowSpec.getWindowFrame().getEndBound().getNumber());
+      }
+    }
+
+    stack.pop();
+    return result;
+  }
+
+  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+  // Literal Section
+  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+  @Override
+  public RESULT visitDataType(CONTEXT ctx, Stack<Expr> stack, DataTypeExpr expr) throws PlanningException {
+    return null;
+  }
+
+  @Override
+  public RESULT visitCastExpr(CONTEXT ctx, Stack<Expr> stack, CastExpr expr) throws PlanningException {
+    stack.push(expr);
+    RESULT result = visit(ctx, stack, expr.getOperand());
+    stack.pop();
+    return result;
+  }
+
+  @Override
+  public RESULT visitLiteral(CONTEXT ctx, Stack<Expr> stack, LiteralValue expr) throws PlanningException {
+    return null;
+  }
+
+  @Override
+  public RESULT visitNullLiteral(CONTEXT ctx, Stack<Expr> stack, NullLiteral expr) throws PlanningException {
+    return null;
+  }
+
+  @Override
+  public RESULT visitTimestampLiteral(CONTEXT ctx, Stack<Expr> stack, TimestampLiteral expr) throws PlanningException {
+    return null;
+  }
+
+  @Override
+  public RESULT visitIntervalLiteral(CONTEXT ctx, Stack<Expr> stack, IntervalLiteral expr) throws PlanningException {
+    return null;
+  }
+
+  @Override
+  public RESULT visitTimeLiteral(CONTEXT ctx, Stack<Expr> stack, TimeLiteral expr) throws PlanningException {
+    return null;
+  }
+
+  @Override
+  public RESULT visitDateLiteral(CONTEXT ctx, Stack<Expr> stack, DateLiteral expr) throws PlanningException {
+    return null;
+  }
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-plan/src/main/java/org/apache/tajo/plan/annotator/Prioritized.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/annotator/Prioritized.java b/tajo-plan/src/main/java/org/apache/tajo/plan/annotator/Prioritized.java
new file mode 100644
index 0000000..8b202fc
--- /dev/null
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/annotator/Prioritized.java
@@ -0,0 +1,30 @@
+/*
+ * 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.plan.annotator;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface Prioritized {
+  int priority() default 99;
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-plan/src/main/java/org/apache/tajo/plan/expr/AggregationFunctionCallEval.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/expr/AggregationFunctionCallEval.java b/tajo-plan/src/main/java/org/apache/tajo/plan/expr/AggregationFunctionCallEval.java
new file mode 100644
index 0000000..542eae8
--- /dev/null
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/expr/AggregationFunctionCallEval.java
@@ -0,0 +1,123 @@
+/**
+ * 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.plan.expr;
+
+import com.google.gson.annotations.Expose;
+import org.apache.tajo.catalog.FunctionDesc;
+import org.apache.tajo.catalog.Schema;
+import org.apache.tajo.common.TajoDataTypes.DataType;
+import org.apache.tajo.datum.Datum;
+import org.apache.tajo.plan.function.AggFunction;
+import org.apache.tajo.plan.function.FunctionContext;
+import org.apache.tajo.storage.Tuple;
+import org.apache.tajo.storage.VTuple;
+
+public class AggregationFunctionCallEval extends FunctionEval implements Cloneable {
+  @Expose protected AggFunction instance;
+  @Expose boolean intermediatePhase = false;
+  @Expose boolean finalPhase = true;
+  @Expose String alias;
+
+  private Tuple params;
+
+  protected AggregationFunctionCallEval(EvalType type, FunctionDesc desc, AggFunction instance, EvalNode[] givenArgs) {
+    super(type, desc, givenArgs);
+    this.instance = instance;
+  }
+
+  public AggregationFunctionCallEval(FunctionDesc desc, AggFunction instance, EvalNode[] givenArgs) {
+    super(EvalType.AGG_FUNCTION, desc, givenArgs);
+    this.instance = instance;
+  }
+
+  public FunctionContext newContext() {
+    return instance.newContext();
+  }
+
+  public void merge(FunctionContext context, Schema schema, Tuple tuple) {
+    if (params == null) {
+      this.params = new VTuple(argEvals.length);
+    }
+
+    if (argEvals != null) {
+      for (int i = 0; i < argEvals.length; i++) {
+        params.put(i, argEvals[i].eval(schema, tuple));
+      }
+    }
+
+    if (!intermediatePhase && !finalPhase) {
+      // firstPhase
+      instance.eval(context, params);
+    } else {
+      instance.merge(context, params);
+    }
+  }
+
+  @Override
+  public Datum eval(Schema schema, Tuple tuple) {
+    throw new UnsupportedOperationException("Cannot execute eval() of aggregation function");
+  }
+
+  public Datum terminate(FunctionContext context) {
+    if (!finalPhase) {
+      return instance.getPartialResult(context);
+    } else {
+      return instance.terminate(context);
+    }
+  }
+
+  @Override
+  public DataType getValueType() {
+    if (!finalPhase) {
+      return instance.getPartialResultType();
+    } else {
+      return funcDesc.getReturnType();
+    }
+  }
+
+  public void setAlias(String alias) { this.alias = alias; }
+
+  public String getAlias() { return  this.alias; }
+
+  public Object clone() throws CloneNotSupportedException {
+    AggregationFunctionCallEval clone = (AggregationFunctionCallEval)super.clone();
+
+    clone.finalPhase = finalPhase;
+    clone.intermediatePhase = intermediatePhase;
+    clone.alias = alias;
+    clone.instance = (AggFunction)instance.clone();
+
+    return clone;
+  }
+
+  public void setFirstPhase() {
+    this.finalPhase = false;
+    this.intermediatePhase = false;
+  }
+
+  public void setFinalPhase() {
+    this.finalPhase = true;
+    this.intermediatePhase = false;
+  }
+
+  public void setIntermediatePhase() {
+    this.finalPhase = false;
+    this.intermediatePhase = true;
+  }
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-plan/src/main/java/org/apache/tajo/plan/expr/AlgebraicException.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/expr/AlgebraicException.java b/tajo-plan/src/main/java/org/apache/tajo/plan/expr/AlgebraicException.java
new file mode 100644
index 0000000..8cd9a8b
--- /dev/null
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/expr/AlgebraicException.java
@@ -0,0 +1,41 @@
+/**
+ * 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.plan.expr;
+
+public class AlgebraicException extends RuntimeException {
+  private static final long serialVersionUID = -1813125460274622006L;
+  
+  public AlgebraicException() {
+  }
+
+  public AlgebraicException(String message) {
+    super(message);
+  }
+
+  public AlgebraicException(Throwable cause) {
+    super(cause);
+  }
+
+  public AlgebraicException(String message, Throwable cause) {
+    super(message, cause);
+  }
+}


Mime
View raw message