You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tajo.apache.org by ji...@apache.org on 2014/10/26 06:46:08 UTC
[09/33] TAJO-1125: Separate logical plan and optimizer into a maven
module.
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);
+ }
+}