http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-core/src/main/java/org/apache/tajo/engine/planner/NamedExprsManager.java ---------------------------------------------------------------------- diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/planner/NamedExprsManager.java b/tajo-core/src/main/java/org/apache/tajo/engine/planner/NamedExprsManager.java deleted file mode 100644 index 8666a5c..0000000 --- a/tajo-core/src/main/java/org/apache/tajo/engine/planner/NamedExprsManager.java +++ /dev/null @@ -1,380 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tajo.engine.planner; - -import com.google.common.collect.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.engine.eval.EvalNode; -import org.apache.tajo.engine.eval.EvalType; -import org.apache.tajo.engine.eval.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-core/src/main/java/org/apache/tajo/engine/planner/PhysicalPlanner.java ---------------------------------------------------------------------- diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/planner/PhysicalPlanner.java b/tajo-core/src/main/java/org/apache/tajo/engine/planner/PhysicalPlanner.java index ebe47b4..d4c57db 100644 --- a/tajo-core/src/main/java/org/apache/tajo/engine/planner/PhysicalPlanner.java +++ b/tajo-core/src/main/java/org/apache/tajo/engine/planner/PhysicalPlanner.java @@ -22,7 +22,7 @@ package org.apache.tajo.engine.planner; import org.apache.tajo.worker.TaskAttemptContext; -import org.apache.tajo.engine.planner.logical.LogicalNode; +import org.apache.tajo.plan.logical.LogicalNode; import org.apache.tajo.engine.planner.physical.PhysicalExec; import org.apache.tajo.exception.InternalException; http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-core/src/main/java/org/apache/tajo/engine/planner/PhysicalPlannerImpl.java ---------------------------------------------------------------------- diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/planner/PhysicalPlannerImpl.java b/tajo-core/src/main/java/org/apache/tajo/engine/planner/PhysicalPlannerImpl.java index 485677a..f7f071f 100644 --- a/tajo-core/src/main/java/org/apache/tajo/engine/planner/PhysicalPlannerImpl.java +++ b/tajo-core/src/main/java/org/apache/tajo/engine/planner/PhysicalPlannerImpl.java @@ -36,7 +36,6 @@ import org.apache.tajo.catalog.proto.CatalogProtos.SortSpecProto; import org.apache.tajo.conf.TajoConf; import org.apache.tajo.engine.planner.enforce.Enforcer; import org.apache.tajo.engine.planner.global.DataChannel; -import org.apache.tajo.engine.planner.logical.*; import org.apache.tajo.engine.planner.physical.*; import org.apache.tajo.engine.query.QueryContext; import org.apache.tajo.exception.InternalException; @@ -45,6 +44,9 @@ import org.apache.tajo.ipc.TajoWorkerProtocol.DistinctGroupbyEnforcer; import org.apache.tajo.ipc.TajoWorkerProtocol.DistinctGroupbyEnforcer.DistinctAggregationAlgorithm; import org.apache.tajo.ipc.TajoWorkerProtocol.DistinctGroupbyEnforcer.MultipleAggregationStage; import org.apache.tajo.ipc.TajoWorkerProtocol.DistinctGroupbyEnforcer.SortSpecArray; +import org.apache.tajo.plan.LogicalPlan; +import org.apache.tajo.plan.util.PlannerUtil; +import org.apache.tajo.plan.logical.*; import org.apache.tajo.storage.StorageConstants; import org.apache.tajo.storage.StorageManager; import org.apache.tajo.storage.TupleComparator; @@ -56,7 +58,6 @@ import org.apache.tajo.util.TUtil; import org.apache.tajo.worker.TaskAttemptContext; import java.io.IOException; -import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.List; import java.util.Stack; http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-core/src/main/java/org/apache/tajo/engine/planner/PlanString.java ---------------------------------------------------------------------- diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/planner/PlanString.java b/tajo-core/src/main/java/org/apache/tajo/engine/planner/PlanString.java deleted file mode 100644 index 98f921b..0000000 --- a/tajo-core/src/main/java/org/apache/tajo/engine/planner/PlanString.java +++ /dev/null @@ -1,119 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tajo.engine.planner; - -import org.apache.tajo.engine.planner.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-core/src/main/java/org/apache/tajo/engine/planner/PlannerUtil.java ---------------------------------------------------------------------- diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/planner/PlannerUtil.java b/tajo-core/src/main/java/org/apache/tajo/engine/planner/PlannerUtil.java deleted file mode 100644 index 827be83..0000000 --- a/tajo-core/src/main/java/org/apache/tajo/engine/planner/PlannerUtil.java +++ /dev/null @@ -1,888 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tajo.engine.planner; - -import com.google.common.base.Preconditions; -import com.google.common.collect.Lists; -import com.google.common.collect.Sets; -import org.apache.hadoop.fs.FileStatus; -import org.apache.hadoop.fs.FileSystem; -import org.apache.hadoop.fs.Path; -import org.apache.tajo.algebra.*; -import org.apache.tajo.annotation.Nullable; -import org.apache.tajo.catalog.Column; -import org.apache.tajo.catalog.Schema; -import org.apache.tajo.catalog.SortSpec; -import org.apache.tajo.catalog.TableDesc; -import org.apache.tajo.catalog.proto.CatalogProtos; -import org.apache.tajo.catalog.proto.CatalogProtos.FragmentProto; -import org.apache.tajo.common.TajoDataTypes.DataType; -import org.apache.tajo.conf.TajoConf; -import org.apache.tajo.engine.eval.*; -import org.apache.tajo.engine.exception.InvalidQueryException; -import org.apache.tajo.engine.planner.logical.*; -import org.apache.tajo.engine.utils.SchemaUtil; -import org.apache.tajo.storage.StorageManager; -import org.apache.tajo.storage.TupleComparator; -import org.apache.tajo.storage.fragment.FileFragment; -import org.apache.tajo.storage.fragment.FragmentConvertor; -import org.apache.tajo.util.TUtil; - -import java.io.IOException; -import java.util.*; -import java.util.concurrent.atomic.AtomicInteger; - -public class PlannerUtil { - - public static boolean checkIfDDLPlan(LogicalNode node) { - LogicalNode baseNode = node; - if (node instanceof LogicalRootNode) { - baseNode = ((LogicalRootNode) node).getChild(); - } - - NodeType type = baseNode.getType(); - - return - type == NodeType.CREATE_DATABASE || - type == NodeType.DROP_DATABASE || - (type == NodeType.CREATE_TABLE && !((CreateTableNode) baseNode).hasSubQuery()) || - baseNode.getType() == NodeType.DROP_TABLE || - baseNode.getType() == NodeType.ALTER_TABLESPACE || - baseNode.getType() == NodeType.ALTER_TABLE || - baseNode.getType() == NodeType.TRUNCATE_TABLE; - } - - /** - * Checks whether the query is simple or not. - * The simple query can be defined as 'select * from tb_name [LIMIT X]'. - * - * @param plan The logical plan - * @return True if the query is a simple query. - */ - public static boolean checkIfSimpleQuery(LogicalPlan plan) { - LogicalRootNode rootNode = plan.getRootBlock().getRoot(); - - // one block, without where clause, no group-by, no-sort, no-join - boolean isOneQueryBlock = plan.getQueryBlocks().size() == 1; - boolean simpleOperator = rootNode.getChild().getType() == NodeType.LIMIT - || rootNode.getChild().getType() == NodeType.SCAN || rootNode.getChild().getType() == NodeType.PARTITIONS_SCAN; - boolean noOrderBy = !plan.getRootBlock().hasNode(NodeType.SORT); - boolean noGroupBy = !plan.getRootBlock().hasNode(NodeType.GROUP_BY); - boolean noWhere = !plan.getRootBlock().hasNode(NodeType.SELECTION); - boolean noJoin = !plan.getRootBlock().hasNode(NodeType.JOIN); - boolean singleRelation = - (plan.getRootBlock().hasNode(NodeType.SCAN) || plan.getRootBlock().hasNode(NodeType.PARTITIONS_SCAN)) && - PlannerUtil.getRelationLineage(plan.getRootBlock().getRoot()).length == 1; - - boolean noComplexComputation = false; - if (singleRelation) { - ScanNode scanNode = plan.getRootBlock().getNode(NodeType.SCAN); - if (scanNode == null) { - scanNode = plan.getRootBlock().getNode(NodeType.PARTITIONS_SCAN); - } - if (scanNode.hasTargets()) { - // If the number of columns in the select clause is s different from table schema, - // This query is not a simple query. - if (scanNode.getTableDesc().hasPartition()) { - // In the case of partitioned table, the actual number of columns is ScanNode.InSchema + partitioned columns - int numPartitionColumns = scanNode.getTableDesc().getPartitionMethod().getExpressionSchema().size(); - if (scanNode.getTargets().length != scanNode.getInSchema().size() + numPartitionColumns) { - return false; - } - } else { - if (scanNode.getTargets().length != scanNode.getInSchema().size()) { - return false; - } - } - noComplexComputation = true; - for (int i = 0; i < scanNode.getTargets().length; i++) { - noComplexComputation = - noComplexComputation && scanNode.getTargets()[i].getEvalTree().getType() == EvalType.FIELD; - if (noComplexComputation) { - noComplexComputation = noComplexComputation && - scanNode.getTargets()[i].getNamedColumn().equals( - scanNode.getTableDesc().getLogicalSchema().getColumn(i)); - } - if (!noComplexComputation) { - return noComplexComputation; - } - } - } - } - - return !checkIfDDLPlan(rootNode) && - (simpleOperator && noComplexComputation && isOneQueryBlock && - noOrderBy && noGroupBy && noWhere && noJoin && singleRelation); - } - - /** - * Checks whether the query has 'from clause' or not. - * - * @param plan The logical plan - * @return True if a query does not have 'from clause'. - */ - public static boolean checkIfNonFromQuery(LogicalPlan plan) { - LogicalNode node = plan.getRootBlock().getRoot(); - - // one block, without where clause, no group-by, no-sort, no-join - boolean isOneQueryBlock = plan.getQueryBlocks().size() == 1; - boolean noRelation = !plan.getRootBlock().hasAlgebraicExpr(OpType.Relation); - - return !checkIfDDLPlan(node) && noRelation && isOneQueryBlock; - } - - /** - * Get all RelationNodes which are descendant of a given LogicalNode. - * - * @param from The LogicalNode to start visiting LogicalNodes. - * @return an array of all descendant RelationNode of LogicalNode. - */ - public static String[] getRelationLineage(LogicalNode from) { - LogicalNode[] scans = findAllNodes(from, NodeType.SCAN, NodeType.PARTITIONS_SCAN); - String[] tableNames = new String[scans.length]; - ScanNode scan; - for (int i = 0; i < scans.length; i++) { - scan = (ScanNode) scans[i]; - tableNames[i] = scan.getCanonicalName(); - } - return tableNames; - } - - /** - * Get all RelationNodes which are descendant of a given LogicalNode. - * The finding is restricted within a query block. - * - * @param from The LogicalNode to start visiting LogicalNodes. - * @return an array of all descendant RelationNode of LogicalNode. - */ - public static Collection<String> getRelationLineageWithinQueryBlock(LogicalPlan plan, LogicalNode from) - throws PlanningException { - RelationFinderVisitor visitor = new RelationFinderVisitor(); - visitor.visit(null, plan, null, from, new Stack<LogicalNode>()); - return visitor.getFoundRelations(); - } - - public static class RelationFinderVisitor extends BasicLogicalPlanVisitor<Object, LogicalNode> { - private Set<String> foundRelNameSet = Sets.newHashSet(); - - public Set<String> getFoundRelations() { - return foundRelNameSet; - } - - @Override - public LogicalNode visit(Object context, LogicalPlan plan, @Nullable LogicalPlan.QueryBlock block, LogicalNode node, - Stack<LogicalNode> stack) throws PlanningException { - if (node.getType() != NodeType.TABLE_SUBQUERY) { - super.visit(context, plan, block, node, stack); - } - - if (node instanceof RelationNode) { - foundRelNameSet.add(((RelationNode) node).getCanonicalName()); - } - - return node; - } - } - - /** - * Delete the logical node from a plan. - * - * @param parent this node must be a parent node of one node to be removed. - * @param tobeRemoved this node must be a child node of the parent. - */ - public static LogicalNode deleteNode(LogicalNode parent, LogicalNode tobeRemoved) { - Preconditions.checkArgument(tobeRemoved instanceof UnaryNode, - "ERROR: the logical node to be removed must be unary node."); - - UnaryNode child = (UnaryNode) tobeRemoved; - LogicalNode grandChild = child.getChild(); - if (parent instanceof UnaryNode) { - UnaryNode unaryParent = (UnaryNode) parent; - - Preconditions.checkArgument(unaryParent.getChild() == child, - "ERROR: both logical node must be parent and child nodes"); - unaryParent.setChild(grandChild); - - } else if (parent instanceof BinaryNode) { - BinaryNode binaryParent = (BinaryNode) parent; - if (binaryParent.getLeftChild().deepEquals(child)) { - binaryParent.setLeftChild(grandChild); - } else if (binaryParent.getRightChild().deepEquals(child)) { - binaryParent.setRightChild(grandChild); - } else { - throw new IllegalStateException("ERROR: both logical node must be parent and child nodes"); - } - } else { - throw new InvalidQueryException("Unexpected logical plan: " + parent); - } - return child; - } - - public static void replaceNode(LogicalPlan plan, LogicalNode startNode, LogicalNode oldNode, LogicalNode newNode) { - LogicalNodeReplaceVisitor replacer = new LogicalNodeReplaceVisitor(oldNode, newNode); - try { - replacer.visit(new ReplacerContext(), plan, null, startNode, new Stack<LogicalNode>()); - } catch (PlanningException e) { - e.printStackTrace(); - } - } - - static class ReplacerContext { - boolean updateSchemaFlag = false; - } - - public static class LogicalNodeReplaceVisitor extends BasicLogicalPlanVisitor<ReplacerContext, LogicalNode> { - private LogicalNode target; - private LogicalNode tobeReplaced; - - public LogicalNodeReplaceVisitor(LogicalNode target, LogicalNode tobeReplaced) { - this.target = target; - this.tobeReplaced = tobeReplaced; - } - - /** - * If this node can have child, it returns TRUE. Otherwise, it returns FALSE. - */ - private static boolean checkIfVisitable(LogicalNode node) { - return node instanceof UnaryNode || node instanceof BinaryNode; - } - - @Override - public LogicalNode visit(ReplacerContext context, LogicalPlan plan, @Nullable LogicalPlan.QueryBlock block, - LogicalNode node, Stack<LogicalNode> stack) throws PlanningException { - LogicalNode left = null; - LogicalNode right = null; - - if (node instanceof UnaryNode) { - UnaryNode unaryNode = (UnaryNode) node; - if (unaryNode.getChild().deepEquals(target)) { - unaryNode.setChild(tobeReplaced); - left = tobeReplaced; - context.updateSchemaFlag = true; - } else if (checkIfVisitable(unaryNode.getChild())) { - left = visit(context, plan, null, unaryNode.getChild(), stack); - } - } else if (node instanceof BinaryNode) { - BinaryNode binaryNode = (BinaryNode) node; - if (binaryNode.getLeftChild().deepEquals(target)) { - binaryNode.setLeftChild(tobeReplaced); - left = tobeReplaced; - context.updateSchemaFlag = true; - } else if (checkIfVisitable(binaryNode.getLeftChild())) { - left = visit(context, plan, null, binaryNode.getLeftChild(), stack); - } else { - left = binaryNode.getLeftChild(); - } - - if (binaryNode.getRightChild().deepEquals(target)) { - binaryNode.setRightChild(tobeReplaced); - right = tobeReplaced; - context.updateSchemaFlag = true; - } else if (checkIfVisitable(binaryNode.getRightChild())) { - right = visit(context, plan, null, binaryNode.getRightChild(), stack); - } else { - right = binaryNode.getRightChild(); - } - } - - // update schemas of nodes except for leaf node (i.e., RelationNode) - if (context.updateSchemaFlag) { - if (node instanceof Projectable) { - if (node instanceof BinaryNode) { - node.setInSchema(SchemaUtil.merge(left.getOutSchema(), right.getOutSchema())); - } else { - node.setInSchema(left.getOutSchema()); - } - context.updateSchemaFlag = false; - } else { - node.setInSchema(left.getOutSchema()); - node.setOutSchema(left.getOutSchema()); - } - } - return node; - } - - @Override - public LogicalNode visitScan(ReplacerContext context, LogicalPlan plan, LogicalPlan.QueryBlock block, ScanNode node, - Stack<LogicalNode> stack) throws PlanningException { - return node; - } - - @Override - public LogicalNode visitPartitionedTableScan(ReplacerContext context, LogicalPlan plan, LogicalPlan. - QueryBlock block, PartitionedTableScanNode node, Stack<LogicalNode> stack) - - throws PlanningException { - return node; - } - } - - public static void replaceNode(LogicalNode plan, LogicalNode newNode, NodeType type) { - LogicalNode parent = findTopParentNode(plan, type); - Preconditions.checkArgument(parent instanceof UnaryNode); - Preconditions.checkArgument(!(newNode instanceof BinaryNode)); - UnaryNode parentNode = (UnaryNode) parent; - LogicalNode child = parentNode.getChild(); - if (child instanceof UnaryNode) { - ((UnaryNode) newNode).setChild(((UnaryNode) child).getChild()); - } - parentNode.setChild(newNode); - } - - /** - * Find the top logical node matched to type from the given node - * - * @param node start node - * @param type to find - * @return a found logical node - */ - public static <T extends LogicalNode> T findTopNode(LogicalNode node, NodeType type) { - Preconditions.checkNotNull(node); - Preconditions.checkNotNull(type); - - LogicalNodeFinder finder = new LogicalNodeFinder(type); - node.preOrder(finder); - - if (finder.getFoundNodes().size() == 0) { - return null; - } - return (T) finder.getFoundNodes().get(0); - } - - /** - * Find the most bottom logical node matched to type from the given node - * - * @param node start node - * @param type to find - * @return a found logical node - */ - public static <T extends LogicalNode> T findMostBottomNode(LogicalNode node, NodeType type) { - Preconditions.checkNotNull(node); - Preconditions.checkNotNull(type); - - LogicalNodeFinder finder = new LogicalNodeFinder(type); - node.preOrder(finder); - - if (finder.getFoundNodes().size() == 0) { - return null; - } - return (T) finder.getFoundNodes().get(finder.getFoundNodes().size() - 1); - } - - /** - * Find the all logical node matched to type from the given node - * - * @param node start node - * @param type to find - * @return a found logical node - */ - public static LogicalNode[] findAllNodes(LogicalNode node, NodeType... type) { - Preconditions.checkNotNull(node); - Preconditions.checkNotNull(type); - - LogicalNodeFinder finder = new LogicalNodeFinder(type); - node.postOrder(finder); - - if (finder.getFoundNodes().size() == 0) { - return new LogicalNode[]{}; - } - List<LogicalNode> founds = finder.getFoundNodes(); - return founds.toArray(new LogicalNode[founds.size()]); - } - - /** - * Find a parent node of a given-typed operator. - * - * @param node start node - * @param type to find - * @return the parent node of a found logical node - */ - public static <T extends LogicalNode> T findTopParentNode(LogicalNode node, NodeType type) { - Preconditions.checkNotNull(node); - Preconditions.checkNotNull(type); - - ParentNodeFinder finder = new ParentNodeFinder(type); - node.postOrder(finder); - - if (finder.getFoundNodes().size() == 0) { - return null; - } - return (T) finder.getFoundNodes().get(0); - } - - private static class LogicalNodeFinder implements LogicalNodeVisitor { - private List<LogicalNode> list = new ArrayList<LogicalNode>(); - private final NodeType[] tofind; - private boolean topmost = false; - private boolean finished = false; - - public LogicalNodeFinder(NodeType... type) { - this.tofind = type; - } - - public LogicalNodeFinder(NodeType[] type, boolean topmost) { - this(type); - this.topmost = topmost; - } - - @Override - public void visit(LogicalNode node) { - if (!finished) { - for (NodeType type : tofind) { - if (node.getType() == type) { - list.add(node); - } - if (topmost && list.size() > 0) { - finished = true; - } - } - } - } - - public List<LogicalNode> getFoundNodes() { - return list; - } - - public LogicalNode[] getFoundNodeArray() { - return list.toArray(new LogicalNode[list.size()]); - } - } - - private static class ParentNodeFinder implements LogicalNodeVisitor { - private List<LogicalNode> list = new ArrayList<LogicalNode>(); - private NodeType tofind; - - public ParentNodeFinder(NodeType type) { - this.tofind = type; - } - - @Override - public void visit(LogicalNode node) { - if (node instanceof UnaryNode) { - UnaryNode unary = (UnaryNode) node; - if (unary.getChild().getType() == tofind) { - list.add(node); - } - } else if (node instanceof BinaryNode) { - BinaryNode bin = (BinaryNode) node; - if (bin.getLeftChild().getType() == tofind || - bin.getRightChild().getType() == tofind) { - list.add(node); - } - } - } - - public List<LogicalNode> getFoundNodes() { - return list; - } - } - - /** - * fill targets with FieldEvals from a given schema - * - * @param schema to be transformed to targets - * @param targets to be filled - */ - public static void schemaToTargets(Schema schema, Target[] targets) { - FieldEval eval; - for (int i = 0; i < schema.size(); i++) { - eval = new FieldEval(schema.getColumn(i)); - targets[i] = new Target(eval); - } - } - - public static Target[] schemaToTargets(Schema schema) { - Target[] targets = new Target[schema.size()]; - - FieldEval eval; - for (int i = 0; i < schema.size(); i++) { - eval = new FieldEval(schema.getColumn(i)); - targets[i] = new Target(eval); - } - return targets; - } - - public static Target[] schemaToTargetsWithGeneratedFields(Schema schema) { - List<Target> targets = TUtil.newList(); - - FieldEval eval; - for (int i = 0; i < schema.size(); i++) { - eval = new FieldEval(schema.getColumn(i)); - targets.add(new Target(eval)); - } - return targets.toArray(new Target[targets.size()]); - } - - public static SortSpec[] schemaToSortSpecs(Schema schema) { - return columnsToSortSpecs(schema.toArray()); - } - - public static SortSpec[] columnsToSortSpecs(Column[] columns) { - SortSpec[] specs = new SortSpec[columns.length]; - - for (int i = 0; i < columns.length; i++) { - specs[i] = new SortSpec(columns[i], true, false); - } - - return specs; - } - - public static SortSpec[] columnsToSortSpecs(Collection<Column> columns) { - return columnsToSortSpecs(columns.toArray(new Column[columns.size()])); - } - - public static Schema sortSpecsToSchema(SortSpec[] sortSpecs) { - Schema schema = new Schema(); - for (SortSpec spec : sortSpecs) { - schema.addColumn(spec.getSortKey()); - } - - return schema; - } - - public static SortSpec[][] getSortKeysFromJoinQual(EvalNode joinQual, Schema outer, Schema inner) { - // It is used for the merge join executor. The merge join only considers the equi-join. - // So, theta-join flag must be false. - List<Column[]> joinKeyPairs = getJoinKeyPairs(joinQual, outer, inner, false); - SortSpec[] outerSortSpec = new SortSpec[joinKeyPairs.size()]; - SortSpec[] innerSortSpec = new SortSpec[joinKeyPairs.size()]; - - for (int i = 0; i < joinKeyPairs.size(); i++) { - outerSortSpec[i] = new SortSpec(joinKeyPairs.get(i)[0]); - innerSortSpec[i] = new SortSpec(joinKeyPairs.get(i)[1]); - } - - return new SortSpec[][]{outerSortSpec, innerSortSpec}; - } - - public static TupleComparator[] getComparatorsFromJoinQual(EvalNode joinQual, Schema leftSchema, Schema rightSchema) { - SortSpec[][] sortSpecs = getSortKeysFromJoinQual(joinQual, leftSchema, rightSchema); - TupleComparator[] comparators = new TupleComparator[2]; - comparators[0] = new TupleComparator(leftSchema, sortSpecs[0]); - comparators[1] = new TupleComparator(rightSchema, sortSpecs[1]); - return comparators; - } - - /** - * @return the first array contains left table's columns, and the second array contains right table's columns. - */ - public static Column[][] joinJoinKeyForEachTable(EvalNode joinQual, Schema leftSchema, - Schema rightSchema, boolean includeThetaJoin) { - List<Column[]> joinKeys = getJoinKeyPairs(joinQual, leftSchema, rightSchema, includeThetaJoin); - Column[] leftColumns = new Column[joinKeys.size()]; - Column[] rightColumns = new Column[joinKeys.size()]; - for (int i = 0; i < joinKeys.size(); i++) { - leftColumns[i] = joinKeys.get(i)[0]; - rightColumns[i] = joinKeys.get(i)[1]; - } - - return new Column[][]{leftColumns, rightColumns}; - } - - public static List<Column[]> getJoinKeyPairs(EvalNode joinQual, Schema leftSchema, Schema rightSchema, - boolean includeThetaJoin) { - JoinKeyPairFinder finder = new JoinKeyPairFinder(includeThetaJoin, leftSchema, rightSchema); - joinQual.preOrder(finder); - return finder.getPairs(); - } - - public static class JoinKeyPairFinder implements EvalNodeVisitor { - private boolean includeThetaJoin; - private final List<Column[]> pairs = Lists.newArrayList(); - private Schema[] schemas = new Schema[2]; - - public JoinKeyPairFinder(boolean includeThetaJoin, Schema outer, Schema inner) { - this.includeThetaJoin = includeThetaJoin; - schemas[0] = outer; - schemas[1] = inner; - } - - @Override - public void visit(EvalNode node) { - if (EvalTreeUtil.isJoinQual(node, includeThetaJoin)) { - BinaryEval binaryEval = (BinaryEval) node; - Column[] pair = new Column[2]; - - for (int i = 0; i <= 1; i++) { // access left, right sub expression - Column column = EvalTreeUtil.findAllColumnRefs(binaryEval.getChild(i)).get(0); - for (int j = 0; j < schemas.length; j++) { - // check whether the column is for either outer or inner - // 0 is outer, and 1 is inner - if (schemas[j].contains(column.getQualifiedName())) { - pair[j] = column; - } - } - } - - if (pair[0] == null || pair[1] == null) { - throw new IllegalStateException("Wrong join key: " + node); - } - pairs.add(pair); - } - } - - public List<Column[]> getPairs() { - return this.pairs; - } - } - - public static Schema targetToSchema(Collection<Target> targets) { - return targetToSchema(targets.toArray(new Target[targets.size()])); - } - - public static Schema targetToSchema(Target[] targets) { - Schema schema = new Schema(); - for (Target t : targets) { - DataType type = t.getEvalTree().getValueType(); - String name; - if (t.hasAlias()) { - name = t.getAlias(); - } else { - name = t.getEvalTree().getName(); - } - if (!schema.containsByQualifiedName(name)) { - schema.addColumn(name, type); - } - } - - return schema; - } - - /** - * It removes all table names from FieldEvals in targets - * - * @param sourceTargets The targets to be stripped - * @return The stripped targets - */ - public static Target[] stripTarget(Target[] sourceTargets) { - Target[] copy = new Target[sourceTargets.length]; - for (int i = 0; i < sourceTargets.length; i++) { - try { - copy[i] = (Target) sourceTargets[i].clone(); - } catch (CloneNotSupportedException e) { - throw new InternalError(e.getMessage()); - } - if (copy[i].getEvalTree().getType() == EvalType.FIELD) { - FieldEval fieldEval = copy[i].getEvalTree(); - if (fieldEval.getColumnRef().hasQualifier()) { - fieldEval.replaceColumnRef(fieldEval.getColumnName()); - } - } - } - - return copy; - } - - public static <T extends LogicalNode> T clone(LogicalPlan plan, LogicalNode node) { - try { - T copy = (T) node.clone(); - if (plan == null) { - copy.setPID(-1); - } else { - copy.setPID(plan.newPID()); - if (node instanceof DistinctGroupbyNode) { - DistinctGroupbyNode dNode = (DistinctGroupbyNode)copy; - for (GroupbyNode eachNode: dNode.getGroupByNodes()) { - eachNode.setPID(plan.newPID()); - } - } - } - return copy; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } - - public static boolean isCommutativeJoin(JoinType joinType) { - return joinType == JoinType.INNER; - } - - public static boolean existsAggregationFunction(Expr expr) throws PlanningException { - AggregationFunctionFinder finder = new AggregationFunctionFinder(); - AggFunctionFoundResult result = new AggFunctionFoundResult(); - finder.visit(result, new Stack<Expr>(), expr); - return result.generalSetFunction; - } - - public static boolean existsDistinctAggregationFunction(Expr expr) throws PlanningException { - AggregationFunctionFinder finder = new AggregationFunctionFinder(); - AggFunctionFoundResult result = new AggFunctionFoundResult(); - finder.visit(result, new Stack<Expr>(), expr); - return result.distinctSetFunction; - } - - static class AggFunctionFoundResult { - boolean generalSetFunction; - boolean distinctSetFunction; - } - - static class AggregationFunctionFinder extends SimpleAlgebraVisitor<AggFunctionFoundResult, Object> { - @Override - public Object visitCountRowsFunction(AggFunctionFoundResult ctx, Stack<Expr> stack, CountRowsFunctionExpr expr) - throws PlanningException { - ctx.generalSetFunction = true; - return super.visitCountRowsFunction(ctx, stack, expr); - } - - @Override - public Object visitGeneralSetFunction(AggFunctionFoundResult ctx, Stack<Expr> stack, GeneralSetFunctionExpr expr) - throws PlanningException { - ctx.generalSetFunction = true; - ctx.distinctSetFunction = expr.isDistinct(); - return super.visitGeneralSetFunction(ctx, stack, expr); - } - } - - public static Collection<String> toQualifiedFieldNames(Collection<String> fieldNames, String qualifier) { - List<String> names = TUtil.newList(); - for (String n : fieldNames) { - String[] parts = n.split("\\."); - if (parts.length == 1) { - names.add(qualifier + "." + parts[0]); - } else { - names.add(qualifier + "." + parts[1]); - } - } - return names; - } - - public static SortSpec[] convertSortSpecs(Collection<CatalogProtos.SortSpecProto> sortSpecProtos) { - SortSpec[] sortSpecs = new SortSpec[sortSpecProtos.size()]; - int i = 0; - for (CatalogProtos.SortSpecProto proto : sortSpecProtos) { - sortSpecs[i++] = new SortSpec(proto); - } - return sortSpecs; - } - - /** - * Generate an explain string of a LogicalNode and its descendant nodes. - * - * @param node The LogicalNode instance to be started - * @return A pretty print explain string - */ - public static String buildExplainString(LogicalNode node) { - ExplainLogicalPlanVisitor explain = new ExplainLogicalPlanVisitor(); - - StringBuilder explains = new StringBuilder(); - try { - ExplainLogicalPlanVisitor.Context explainContext = explain.getBlockPlanStrings(null, node); - while (!explainContext.explains.empty()) { - explains.append( - ExplainLogicalPlanVisitor.printDepthString(explainContext.getMaxDepth(), explainContext.explains.pop())); - } - } catch (PlanningException e) { - throw new RuntimeException(e); - } - - return explains.toString(); - } - - /** - * Listing table data file which is not empty. - * If the table is a partitioned table, return file list which has same partition key. - * @param tajoConf - * @param tableDesc - * @param fileIndex - * @param numResultFiles - * @return - * @throws IOException - */ - public static FragmentProto[] getNonZeroLengthDataFiles(TajoConf tajoConf,TableDesc tableDesc, - int fileIndex, int numResultFiles) throws IOException { - FileSystem fs = tableDesc.getPath().getFileSystem(tajoConf); - - List<FileStatus> nonZeroLengthFiles = new ArrayList<FileStatus>(); - if (fs.exists(tableDesc.getPath())) { - getNonZeroLengthDataFiles(fs, tableDesc.getPath(), nonZeroLengthFiles, fileIndex, numResultFiles, - new AtomicInteger(0)); - } - - List<FileFragment> fragments = new ArrayList<FileFragment>(); - - //In the case of partitioned table, return same partition key data files. - int numPartitionColumns = 0; - if (tableDesc.hasPartition()) { - numPartitionColumns = tableDesc.getPartitionMethod().getExpressionSchema().getColumns().size(); - } - String[] previousPartitionPathNames = null; - for (FileStatus eachFile: nonZeroLengthFiles) { - FileFragment fileFragment = new FileFragment(tableDesc.getName(), eachFile.getPath(), 0, eachFile.getLen(), null); - - if (numPartitionColumns > 0) { - // finding partition key; - Path filePath = fileFragment.getPath(); - Path parentPath = filePath; - String[] parentPathNames = new String[numPartitionColumns]; - for (int i = 0; i < numPartitionColumns; i++) { - parentPath = parentPath.getParent(); - parentPathNames[numPartitionColumns - i - 1] = parentPath.getName(); - } - - // If current partitionKey == previousPartitionKey, add to result. - if (previousPartitionPathNames == null) { - fragments.add(fileFragment); - } else if (previousPartitionPathNames != null && Arrays.equals(previousPartitionPathNames, parentPathNames)) { - fragments.add(fileFragment); - } else { - break; - } - previousPartitionPathNames = parentPathNames; - } else { - fragments.add(fileFragment); - } - } - return FragmentConvertor.toFragmentProtoArray(fragments.toArray(new FileFragment[]{})); - } - - private static void getNonZeroLengthDataFiles(FileSystem fs, Path path, List<FileStatus> result, - int startFileIndex, int numResultFiles, - AtomicInteger currentFileIndex) throws IOException { - if (fs.isDirectory(path)) { - FileStatus[] files = fs.listStatus(path, StorageManager.hiddenFileFilter); - if (files != null && files.length > 0) { - for (FileStatus eachFile : files) { - if (result.size() >= numResultFiles) { - return; - } - if (eachFile.isDirectory()) { - getNonZeroLengthDataFiles(fs, eachFile.getPath(), result, startFileIndex, numResultFiles, - currentFileIndex); - } else if (eachFile.isFile() && eachFile.getLen() > 0) { - if (currentFileIndex.get() >= startFileIndex) { - result.add(eachFile); - } - currentFileIndex.incrementAndGet(); - } - } - } - } else { - FileStatus fileStatus = fs.getFileStatus(path); - if (fileStatus != null && fileStatus.getLen() > 0) { - if (currentFileIndex.get() >= startFileIndex) { - result.add(fileStatus); - } - currentFileIndex.incrementAndGet(); - if (result.size() >= numResultFiles) { - return; - } - } - } - } -} http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-core/src/main/java/org/apache/tajo/engine/planner/PlanningException.java ---------------------------------------------------------------------- diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/planner/PlanningException.java b/tajo-core/src/main/java/org/apache/tajo/engine/planner/PlanningException.java deleted file mode 100644 index 4fa88ee..0000000 --- a/tajo-core/src/main/java/org/apache/tajo/engine/planner/PlanningException.java +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tajo.engine.planner; - -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-core/src/main/java/org/apache/tajo/engine/planner/PreLogicalPlanVerifier.java ---------------------------------------------------------------------- diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/planner/PreLogicalPlanVerifier.java b/tajo-core/src/main/java/org/apache/tajo/engine/planner/PreLogicalPlanVerifier.java deleted file mode 100644 index f6d5540..0000000 --- a/tajo-core/src/main/java/org/apache/tajo/engine/planner/PreLogicalPlanVerifier.java +++ /dev/null @@ -1,290 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tajo.engine.planner; - -import org.apache.tajo.TajoConstants; -import org.apache.tajo.algebra.*; -import org.apache.tajo.catalog.CatalogService; -import org.apache.tajo.catalog.CatalogUtil; -import org.apache.tajo.catalog.TableDesc; -import org.apache.tajo.catalog.proto.CatalogProtos; -import org.apache.tajo.engine.query.QueryContext; -import org.apache.tajo.util.TUtil; - -import java.util.Set; -import java.util.Stack; - -public class PreLogicalPlanVerifier extends BaseAlgebraVisitor <PreLogicalPlanVerifier.Context, Expr> { - private CatalogService catalog; - - public PreLogicalPlanVerifier(CatalogService catalog) { - this.catalog = catalog; - } - - public static class Context { - QueryContext queryContext; - VerificationState state; - - public Context(QueryContext queryContext, VerificationState state) { - this.queryContext = queryContext; - this.state = state; - } - } - - public VerificationState verify(QueryContext queryContext, VerificationState state, Expr expr) throws PlanningException { - Context context = new Context(queryContext, state); - visit(context, new Stack<Expr>(), expr); - return context.state; - } - - public Expr visitProjection(Context context, Stack<Expr> stack, Projection expr) throws PlanningException { - super.visitProjection(context, stack, expr); - - Set<String> names = TUtil.newHashSet(); - Expr [] distinctValues = null; - - for (NamedExpr namedExpr : expr.getNamedExprs()) { - - if (namedExpr.hasAlias()) { - if (names.contains(namedExpr.getAlias())) { - context.state.addVerification(String.format("column name \"%s\" specified more than once", - namedExpr.getAlias())); - } else { - names.add(namedExpr.getAlias()); - } - } - - Set<GeneralSetFunctionExpr> exprs = ExprFinder.finds(namedExpr.getExpr(), OpType.GeneralSetFunction); - - // Currently, avg functions with distinct aggregation are not supported. - // This code does not allow users to use avg functions with distinct aggregation. - if (distinctValues != null) { - for (GeneralSetFunctionExpr setFunction : exprs) { - if (setFunction.getSignature().equalsIgnoreCase("avg")) { - if (setFunction.isDistinct()) { - throw new PlanningException("avg(distinct) function is not supported yet."); - } else { - throw new PlanningException("avg() function with distinct aggregation functions is not supported yet."); - } - } - } - } - } - return expr; - } - - @Override - public Expr visitLimit(Context context, Stack<Expr> stack, Limit expr) throws PlanningException { - stack.push(expr); - - if (ExprFinder.finds(expr.getFetchFirstNum(), OpType.Column).size() > 0) { - context.state.addVerification("argument of LIMIT must not contain variables"); - } - - visit(context, stack, expr.getFetchFirstNum()); - Expr result = visit(context, stack, expr.getChild()); - stack.pop(); - return result; - } - - @Override - public Expr visitGroupBy(Context context, Stack<Expr> stack, Aggregation expr) throws PlanningException { - super.visitGroupBy(context, stack, expr); - - // Enforcer only ordinary grouping set. - for (Aggregation.GroupElement groupingElement : expr.getGroupSet()) { - if (groupingElement.getType() != Aggregation.GroupType.OrdinaryGroup) { - context.state.addVerification(groupingElement.getType() + " is not supported yet"); - } - } - - Projection projection = null; - for (Expr parent : stack) { - if (parent.getType() == OpType.Projection) { - projection = (Projection) parent; - break; - } - } - - if (projection == null) { - throw new PlanningException("No Projection"); - } - - return expr; - } - - @Override - public Expr visitRelation(Context context, Stack<Expr> stack, Relation expr) throws PlanningException { - assertRelationExistence(context, expr.getName()); - return expr; - } - - private boolean assertRelationExistence(Context context, String tableName) { - String qualifiedName; - - if (CatalogUtil.isFQTableName(tableName)) { - qualifiedName = tableName; - } else { - qualifiedName = CatalogUtil.buildFQName(context.queryContext.getCurrentDatabase(), tableName); - } - - if (!catalog.existsTable(qualifiedName)) { - context.state.addVerification(String.format("relation \"%s\" does not exist", qualifiedName)); - return false; - } - return true; - } - - private boolean assertRelationNoExistence(Context context, String tableName) { - String qualifiedName; - - if (CatalogUtil.isFQTableName(tableName)) { - qualifiedName = tableName; - } else { - qualifiedName = CatalogUtil.buildFQName(context.queryContext.getCurrentDatabase(), tableName); - } - if(qualifiedName == null) { - System.out.println("A"); - } - if (catalog.existsTable(qualifiedName)) { - context.state.addVerification(String.format("relation \"%s\" already exists", qualifiedName)); - return false; - } - return true; - } - - private boolean assertUnsupportedStoreType(VerificationState state, String name) { - if (name != null && name.equals(CatalogProtos.StoreType.RAW.name())) { - state.addVerification(String.format("Unsupported store type :%s", name)); - return false; - } - return true; - } - - private boolean assertDatabaseExistence(VerificationState state, String name) { - if (!catalog.existDatabase(name)) { - state.addVerification(String.format("database \"%s\" does not exist", name)); - return false; - } - return true; - } - - private boolean assertDatabaseNoExistence(VerificationState state, String name) { - if (catalog.existDatabase(name)) { - state.addVerification(String.format("database \"%s\" already exists", name)); - return false; - } - return true; - } - - /////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Data Definition Language Section - /////////////////////////////////////////////////////////////////////////////////////////////////////////// - - - @Override - public Expr visitCreateDatabase(Context context, Stack<Expr> stack, CreateDatabase expr) - throws PlanningException { - super.visitCreateDatabase(context, stack, expr); - if (!expr.isIfNotExists()) { - assertDatabaseNoExistence(context.state, expr.getDatabaseName()); - } - return expr; - } - - @Override - public Expr visitDropDatabase(Context context, Stack<Expr> stack, DropDatabase expr) throws PlanningException { - super.visitDropDatabase(context, stack, expr); - if (!expr.isIfExists()) { - assertDatabaseExistence(context.state, expr.getDatabaseName()); - } - return expr; - } - - @Override - public Expr visitCreateTable(Context context, Stack<Expr> stack, CreateTable expr) throws PlanningException { - super.visitCreateTable(context, stack, expr); - if (!expr.isIfNotExists()) { - assertRelationNoExistence(context, expr.getTableName()); - } - assertUnsupportedStoreType(context.state, expr.getStorageType()); - return expr; - } - - @Override - public Expr visitDropTable(Context context, Stack<Expr> stack, DropTable expr) throws PlanningException { - super.visitDropTable(context, stack, expr); - if (!expr.isIfExists()) { - assertRelationExistence(context, expr.getTableName()); - } - return expr; - } - - /////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Insert or Update Section - /////////////////////////////////////////////////////////////////////////////////////////////////////////// - - public Expr visitInsert(Context context, Stack<Expr> stack, Insert expr) throws PlanningException { - Expr child = super.visitInsert(context, stack, expr); - - if (expr.hasTableName()) { - assertRelationExistence(context, expr.getTableName()); - } - - if (child != null && child.getType() == OpType.Projection) { - Projection projection = (Projection) child; - int projectColumnNum = projection.getNamedExprs().length; - - if (expr.hasTargetColumns()) { - int targetColumnNum = expr.getTargetColumns().length; - - if (targetColumnNum > projectColumnNum) { - context.state.addVerification("INSERT has more target columns than expressions"); - } else if (targetColumnNum < projectColumnNum) { - context.state.addVerification("INSERT has more expressions than target columns"); - } - } else { - if (expr.hasTableName()) { - String qualifiedName = expr.getTableName(); - if (TajoConstants.EMPTY_STRING.equals(CatalogUtil.extractQualifier(expr.getTableName()))) { - qualifiedName = CatalogUtil.buildFQName(context.queryContext.getCurrentDatabase(), - expr.getTableName()); - } - - TableDesc table = catalog.getTableDesc(qualifiedName); - if (table == null) { - context.state.addVerification(String.format("relation \"%s\" does not exist", qualifiedName)); - return null; - } - if (table.hasPartition()) { - int columnSize = table.getSchema().getColumns().size(); - columnSize += table.getPartitionMethod().getExpressionSchema().getColumns().size(); - if (projectColumnNum < columnSize) { - context.state.addVerification("INSERT has smaller expressions than target columns"); - } else if (projectColumnNum > columnSize) { - context.state.addVerification("INSERT has more expressions than target columns"); - } - } - } - } - } - - return expr; - } -} http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-core/src/main/java/org/apache/tajo/engine/planner/Projector.java ---------------------------------------------------------------------- diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/planner/Projector.java b/tajo-core/src/main/java/org/apache/tajo/engine/planner/Projector.java index d8499d0..7c2e81f 100644 --- a/tajo-core/src/main/java/org/apache/tajo/engine/planner/Projector.java +++ b/tajo-core/src/main/java/org/apache/tajo/engine/planner/Projector.java @@ -20,14 +20,16 @@ package org.apache.tajo.engine.planner; import org.apache.tajo.SessionVars; import org.apache.tajo.catalog.Schema; -import org.apache.tajo.engine.eval.EvalNode; +import org.apache.tajo.plan.util.PlannerUtil; +import org.apache.tajo.plan.Target; +import org.apache.tajo.plan.expr.EvalNode; import org.apache.tajo.storage.Tuple; import org.apache.tajo.worker.TaskAttemptContext; public class Projector { private final TaskAttemptContext context; private final Schema inSchema; - private final Target [] targets; + private final Target[] targets; // for projection private final int targetNum; http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-core/src/main/java/org/apache/tajo/engine/planner/SimpleAlgebraVisitor.java ---------------------------------------------------------------------- diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/planner/SimpleAlgebraVisitor.java b/tajo-core/src/main/java/org/apache/tajo/engine/planner/SimpleAlgebraVisitor.java deleted file mode 100644 index 8b34189..0000000 --- a/tajo-core/src/main/java/org/apache/tajo/engine/planner/SimpleAlgebraVisitor.java +++ /dev/null @@ -1,210 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tajo.engine.planner; - -import org.apache.tajo.algebra.*; - -import java.util.Stack; - -/** - * <code>SimpleAlgebraVisitor</code> provides a simple and fewer visit methods. It makes building concrete class easier. - */ -public abstract class SimpleAlgebraVisitor<CONTEXT, RESULT> extends BaseAlgebraVisitor<CONTEXT, RESULT> { - - public RESULT visit(CONTEXT ctx, Stack<Expr> stack, Expr expr) throws PlanningException { - RESULT result = null; - if (expr instanceof UnaryOperator) { - preHook(ctx, stack, expr); - result = visitUnaryOperator(ctx, stack, (UnaryOperator) expr); - postHook(ctx, stack, expr, result); - } else if (expr instanceof BinaryOperator) { - preHook(ctx, stack, expr); - result = visitBinaryOperator(ctx, stack, (BinaryOperator) expr); - postHook(ctx, stack, expr, result); - } else { - result = super.visit(ctx, stack, expr); - } - - return result; - } - - public RESULT visitUnaryOperator(CONTEXT ctx, Stack<Expr> stack, UnaryOperator expr) throws PlanningException { - stack.push(expr); - RESULT result = visit(ctx, stack, expr.getChild()); - stack.pop(); - return result; - } - - public RESULT visitBinaryOperator(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException { - stack.push(expr); - visit(ctx, stack, expr.getLeft()); - RESULT result = visit(ctx, stack, expr.getRight()); - stack.pop(); - return result; - } - - /////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Relational Operator Section - /////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public RESULT visitProjection(CONTEXT ctx, Stack<Expr> stack, Projection expr) throws PlanningException { - return super.visitProjection(ctx, stack, expr); - } - - @Override - public RESULT visitLimit(CONTEXT ctx, Stack<Expr> stack, Limit expr) throws PlanningException { - return super.visitLimit(ctx, stack, expr); - } - - @Override - public RESULT visitSort(CONTEXT ctx, Stack<Expr> stack, Sort expr) throws PlanningException { - return super.visitSort(ctx, stack, expr); - } - - @Override - public RESULT visitHaving(CONTEXT ctx, Stack<Expr> stack, Having expr) throws PlanningException { - return super.visitHaving(ctx, stack, expr); - } - - @Override - public RESULT visitGroupBy(CONTEXT ctx, Stack<Expr> stack, Aggregation expr) throws PlanningException { - return super.visitGroupBy(ctx, stack, expr); - } - - public RESULT visitFilter(CONTEXT ctx, Stack<Expr> stack, Selection expr) throws PlanningException { - return super.visitFilter(ctx, stack, expr); - } - - @Override - public RESULT visitJoin(CONTEXT ctx, Stack<Expr> stack, Join expr) throws PlanningException { - return super.visitJoin(ctx, stack, expr); - } - - @Override - public RESULT visitTableSubQuery(CONTEXT ctx, Stack<Expr> stack, TablePrimarySubQuery expr) throws PlanningException { - return super.visitTableSubQuery(ctx, stack, expr); - } - - @Override - public RESULT visitRelationList(CONTEXT ctx, Stack<Expr> stack, RelationList expr) throws PlanningException { - return super.visitRelationList(ctx, stack, expr); - } - - /////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Data Definition Language Section - /////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public RESULT visitCreateTable(CONTEXT ctx, Stack<Expr> stack, CreateTable expr) throws PlanningException { - return super.visitCreateTable(ctx, stack, expr); - } - - @Override - public RESULT visitDropTable(CONTEXT ctx, Stack<Expr> stack, DropTable expr) throws PlanningException { - return super.visitDropTable(ctx, stack, expr); - } - - @Override - public RESULT visitAlterTable(CONTEXT ctx, Stack<Expr> stack, AlterTable expr) throws PlanningException { - return super.visitAlterTable(ctx, stack, expr); - } - - /////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Insert or Update Section - /////////////////////////////////////////////////////////////////////////////////////////////////////////// - @Override - public RESULT visitInsert(CONTEXT ctx, Stack<Expr> stack, Insert expr) throws PlanningException { - return super.visitInsert(ctx, stack, expr); - } - - - /////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Other Predicates Section - /////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public RESULT visitBetween(CONTEXT ctx, Stack<Expr> stack, BetweenPredicate expr) throws PlanningException { - return super.visitBetween(ctx, stack, expr); - } - - @Override - public RESULT visitCaseWhen(CONTEXT ctx, Stack<Expr> stack, CaseWhenPredicate expr) throws PlanningException { - return super.visitCaseWhen(ctx, stack, expr); - } - - @Override - public RESULT visitValueListExpr(CONTEXT ctx, Stack<Expr> stack, ValueListExpr expr) throws PlanningException { - return super.visitValueListExpr(ctx, stack, expr); - } - - /////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Functions and General Set Function Section - /////////////////////////////////////////////////////////////////////////////////////////////////////////// - @Override - public RESULT visitFunction(CONTEXT ctx, Stack<Expr> stack, FunctionExpr expr) throws PlanningException { - return super.visitFunction(ctx, stack, expr); - } - - @Override - public RESULT visitCountRowsFunction(CONTEXT ctx, Stack<Expr> stack, CountRowsFunctionExpr expr) - throws PlanningException { - return super.visitCountRowsFunction(ctx, stack, expr); - } - - @Override - public RESULT visitGeneralSetFunction(CONTEXT ctx, Stack<Expr> stack, GeneralSetFunctionExpr expr) - throws PlanningException { - return super.visitGeneralSetFunction(ctx, stack, expr); - } - - @Override - public RESULT visitWindowFunction(CONTEXT ctx, Stack<Expr> stack, WindowFunctionExpr expr) throws PlanningException { - return super.visitWindowFunction(ctx, stack, expr); - } - - /////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Literal Section - /////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public RESULT visitDataType(CONTEXT ctx, Stack<Expr> stack, DataTypeExpr expr) throws PlanningException { - return super.visitDataType(ctx, stack, expr); - } - - @Override - public RESULT visitLiteral(CONTEXT ctx, Stack<Expr> stack, LiteralValue expr) throws PlanningException { - return super.visitLiteral(ctx, stack, expr); - } - - @Override - public RESULT visitNullLiteral(CONTEXT ctx, Stack<Expr> stack, NullLiteral expr) throws PlanningException { - return super.visitNullLiteral(ctx, stack, expr); - } - - @Override - public RESULT visitTimestampLiteral(CONTEXT ctx, Stack<Expr> stack, TimestampLiteral expr) throws PlanningException { - return super.visitTimestampLiteral(ctx, stack, expr); - } - - @Override - public RESULT visitTimeLiteral(CONTEXT ctx, Stack<Expr> stack, TimeLiteral expr) throws PlanningException { - return super.visitTimeLiteral(ctx, stack, expr); - } -} http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-core/src/main/java/org/apache/tajo/engine/planner/Target.java ---------------------------------------------------------------------- diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/planner/Target.java b/tajo-core/src/main/java/org/apache/tajo/engine/planner/Target.java deleted file mode 100644 index 6a16d3c..0000000 --- a/tajo-core/src/main/java/org/apache/tajo/engine/planner/Target.java +++ /dev/null @@ -1,129 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tajo.engine.planner; - -import com.google.gson.annotations.Expose; -import org.apache.tajo.catalog.Column; -import org.apache.tajo.common.TajoDataTypes.DataType; -import org.apache.tajo.engine.eval.EvalNode; -import org.apache.tajo.engine.eval.FieldEval; -import org.apache.tajo.engine.json.CoreGsonHelper; -import org.apache.tajo.json.GsonObject; -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 CoreGsonHelper.toJson(this, Target.class); - } -}
